Building a Threat Intelligence Enrichment Agent with Multi-Source IOC Querying Using Claude

This guide demonstrates how to build an autonomous threat intelligence enrichment agent that leverages Claude's tool-use capabilities to automatically query multiple intelligence sources and analyze Indicators of Compromise (IOCs).

The anthropics/claude-cookbooks repository provides a complete implementation in tool_use/threat_intel_enrichment_agent.ipynb that transforms Claude into a security analyst capable of ingesting arbitrary IOCs and enriching them through simulated intelligence databases. This approach allows you to automate the correlation of IP addresses, file hashes, and domains with threat intelligence feeds without writing complex orchestration logic.

Architecture of the Threat Intelligence Enrichment Agent

The enrichment agent follows a modular, tool-based architecture that separates schema definitions, backend implementations, and orchestration logic into distinct layers.

Tool Schema Definition

At the core of the system is a tools list that describes each available intelligence source using JSON Schema. Each entry contains name, description, and input_schema properties that tell Claude exactly what arguments each tool expects and when to use it.

tools = [
    {
        "name": "lookup_ip_reputation",
        "description": "Query IP reputation database for threat intelligence",
        "input_schema": {
            "type": "object",
            "properties": {"ip_address": {"type": "string"}},
            "required": ["ip_address"],
        },
    },
    {
        "name": "lookup_file_hash",
        "description": "Query file hash against malware databases",
        "input_schema": {
            "type": "object",
            "properties": {
                "file_hash": {"type": "string"},
                "hash_type": {"type": "string"}
            },
            "required": ["file_hash", "hash_type"],
        },
    },
    {
        "name": "lookup_domain",
        "description": "Query domain reputation and categorization",
        "input_schema": {
            "type": "object",
            "properties": {"domain": {"type": "string"}},
            "required": ["domain"],
        },
    },
    {
        "name": "get_mitre_techniques",
        "description": "Retrieve MITRE ATT&CK techniques related to threat actors",
        "input_schema": {
            "type": "object",
            "properties": {"query": {"type": "string"}},
            "required": ["query"],
        },
    },
]

Simulated Backend Functions

The agent uses pure-Python stubs to simulate real intelligence APIs. In production, these would wrap actual services like VirusTotal or AbuseIPDB. The lookup_ip_reputation function in tool_use/threat_intel_enrichment_agent.ipynb demonstrates this pattern:

def lookup_ip_reputation(ip_address: str) -> dict:
    """Return a fabricated IP reputation record."""
    ip_database = {
        "203.0.113.42": {
            "ip": "203.0.113.42",
            "country": "Russia",
            "abuse_confidence_score": 87,
            "threat_types": ["botnet_c2", "malware_distribution"],
            "last_reported": "2024-01-15",
            "isp": "Example ISP"
        },
    }
    return ip_database.get(
        ip_address,
        {
            "ip": ip_address, 
            "country": "Unknown", 
            "abuse_confidence_score": 0, 
            "threat_types": []
        },
    )

Agent Loop and Orchestration

The run_threat_intel_agent function implements the main control flow that manages the conversation between Claude and the backend tools. It uses a SYSTEM_PROMPT to establish Claude's persona as a senior security analyst and sets MAX_TURNS to cap tool-use cycles and prevent runaway costs.

The loop repeatedly calls client.messages.create with the tools parameter attached. Claude responds with either:

  • stop_reason == "end_turn" – The analysis is complete, and the final text is returned.
  • stop_reason == "tool_use" – The response contains tool_use blocks requiring execution.

When tool use is requested, the loop extracts each block, executes the corresponding function, and feeds the JSON result back to Claude as a tool_result message.

Tool-Call Routing

The process_tool_call function acts as a router that maps tool names to their implementation handlers. This design makes adding new intelligence sources straightforward—simply extend the handlers dictionary with a new lambda:

def process_tool_call(tool_name: str, tool_input: dict) -> str:
    handlers = {
        "lookup_ip_reputation": lambda inp: lookup_ip_reputation(inp["ip_address"]),
        "lookup_file_hash": lambda inp: lookup_file_hash(inp["file_hash"], inp["hash_type"]),
        "lookup_domain": lambda inp: lookup_domain(inp["domain"]),
        "get_mitre_techniques": lambda inp: get_mitre_techniques(inp["query"]),
    }
    handler = handlers.get(tool_name)
    if handler is None:
        return json.dumps({"error": f"Unknown tool: {tool_name}"})
    return json.dumps(handler(tool_input), indent=2)

Implementing the Multi-Source Query Workflow

To build your own threat intelligence enrichment agent with multi-source IOC querying, you instantiate the tools list, define your backend handlers, and invoke the agent loop. The notebook in anthropics/claude-cookbooks provides the complete reference implementation.

The SYSTEM_PROMPT explicitly instructs Claude to "identify the IOC type and query the most relevant source first," which enables automatic tool selection without hardcoded routing logic. This means Claude intelligently chooses between IP reputation lookups, hash analysis, domain checks, and MITRE ATT&CK mapping based on the input context.

Running the Enrichment Agent

Execute the agent by calling run_threat_intel_agent with an IOC and its type. The function returns both the analysis text and a complete trace of tool calls for audit purposes.

analysis, calls = run_threat_intel_agent(
    ioc="203.0.113.42",
    ioc_type="ip_address",
)

print("=== ANALYSIS ====================================================")
print(analysis)
print("\n=== TOOL CALL TRACE =============================================")
for c in calls:
    print(f"- {c['tool']}({c['input']})")

The output includes a structured threat assessment report with confidence scores, geolocation data, associated threat actors, and MITRE ATT&CK technique mappings—providing actionable intelligence for security teams.

Summary

  • Claude's tool-use API enables building autonomous enrichment agents that automatically select and query multiple threat intelligence sources based on IOC type.
  • The architecture in tool_use/threat_intel_enrichment_agent.ipynb separates concerns between schema definitions (tools), backend implementations (lookup_ip_reputation and related stubs), and orchestration logic (run_threat_intel_agent).
  • The agent loop handles multi-turn conversations, automatically routing tool calls through process_tool_call and aggregating results into comprehensive security reports.
  • Extensibility is built-in—adding new intelligence sources requires only adding a tool schema and corresponding handler function.
  • Safety controls like MAX_TURNS prevent excessive API calls while the system prompt establishes clear analytical reasoning patterns.

Frequently Asked Questions

How does the agent decide which intelligence sources to query?

The agent relies on the system prompt and tool descriptions to make autonomous decisions. By instructing Claude to "identify the IOC type and query the most relevant source first" within the SYSTEM_PROMPT, Claude analyzes the input context and selects the appropriate tools from the available schemas. For composite investigations, Claude may chain multiple tool calls in sequence, using results from one query to inform subsequent lookups.

Can I replace the simulated backends with real threat intelligence APIs?

Yes. The lookup_ip_reputation, lookup_file_hash, lookup_domain, and get_mitre_techniques functions are designed as swappable stubs. Simply replace the dictionary-based return values with actual API calls to services like VirusTotal, AbuseIPDB, or your internal threat intelligence platform. Ensure your replacement functions return JSON-serializable dictionaries to maintain compatibility with the process_tool_call router.

What prevents the agent from making excessive API calls in an infinite loop?

The implementation includes a MAX_TURNS constant that caps the number of tool-use cycles allowed per IOC analysis. Once the agent reaches this limit, the loop terminates regardless of whether the investigation is complete. Additionally, Claude's stop_reason mechanism naturally concludes the workflow when the model determines sufficient information has been gathered to render a final analysis.

Where can I find the complete source code for this implementation?

The full implementation resides in the anthropics/claude-cookbooks repository at tool_use/threat_intel_enrichment_agent.ipynb. This Jupyter notebook contains the complete tool schemas, simulated backend functions, agent loop implementation, and example runs. The repository also includes CLAUDE.md for setup instructions regarding Anthropic SDK installation and API key configuration via environment variables.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →