← Back to Blog

MODEL CONTEXT PROTOCOL EXPLAINED: MCP FOR OSINT

Published: 2026-05-24

Model Context Protocol (MCP) is an open standard that defines how AI assistants communicate with external tools and data sources. It was designed to solve a specific fragmentation problem: every AI platform previously had its own proprietary integration format, forcing developers to implement the same tool multiple times for different AI clients. MCP standardizes the contract so a single server implementation works with any compliant client.

THE PROBLEM BEFORE MCP

Before MCP, AI tool integration was entirely platform-specific. OpenAI had plugins — a custom format that described tools via OpenAPI specs and required hosting an HTTPS endpoint with specific headers. Anthropic had its own tool use specification, defined inline in each API request. Google had its own function calling format. If you wanted the same WHOIS lookup tool available in ChatGPT, Claude Desktop, and Claude Code, you wrote three separate integration layers.

This was not just an inconvenience for developers — it created an ecosystem lock-in problem. Tools built for one AI client couldn't be reused in another without porting work. This friction meant most tools were built once, for one platform, and stayed there. The result was a fragmented landscape where a powerful tool like a real-time breach lookup was available in Claude but not in a custom AI assistant built on GPT-4, or vice versa.

MCP changes the economics: build the server once, and it works with every MCP-compliant client. Claude Desktop, Claude Code, and any other host that implements the MCP client protocol can call the same server with no changes on the server side. This is a meaningful shift for infrastructure-level tools like OSINT frameworks that benefit from being available everywhere an analyst might be working.

THE ARCHITECTURE

MCP involves three actors in every interaction:

The host is the AI application the user interacts with — Claude Desktop, Claude Code, or a custom application embedding an MCP client. The host is responsible for managing the user conversation and launching MCP servers.

The client is a component running inside the host that implements the MCP client protocol. It establishes the connection to MCP servers, sends requests, and relays responses back to the host. In Claude Desktop, the client is built in. In custom applications, you instantiate it from the MCP SDK.

The server is the external process that exposes tools, resources, and prompts. It receives JSON-RPC requests over the established transport, executes the requested operations, and returns results. The server knows nothing about the host — it only knows MCP. OpenOSINT's mcp_server.py is an MCP server.

Transport is stdio by default: the host launches the server as a subprocess, writes JSON-RPC messages to its stdin, and reads responses from its stdout. This is the simplest possible IPC — no sockets, no port negotiation, no authentication tokens. The host manages the subprocess lifecycle. HTTP with Server-Sent Events is also supported for networked deployments where the server cannot be a local subprocess.

The session lifecycle follows a handshake: the client sends an initialize request with its protocol version and capabilities, the server responds with its own version and capabilities, and the client sends an initialized notification to confirm. After that, the session is active and tool calls can proceed.

TOOL SCHEMAS

Tools are the primary unit of functionality in an MCP server. Each tool is described by three fields: a machine-readable name, a natural-language description, and a JSON Schema for its input parameters.

The name is what appears in the tool call — it must be stable and unique within the server. The description is what the AI model reads to decide when to use the tool. A vague description produces misuse; a precise description produces correct tool selection. The inputSchema is a standard JSON Schema object that specifies parameters, their types, which are required, and what each one means. The model uses the schema to construct valid parameter objects without hallucinating parameter names or types.

A well-written tool definition for an IP lookup looks like this in the server implementation:

Tool(
    name="search_ip",
    description=(
        "Look up geolocation, ASN, and hostname data for an IPv4 or IPv6 address. "
        "Returns country, region, city, ISP, organization, and coordinates. "
        "Use for any IP address found during an investigation."
    ),
    inputSchema={
        "type": "object",
        "properties": {
            "ip": {
                "type": "string",
                "description": "The IP address to look up (IPv4 or IPv6)"
            }
        },
        "required": ["ip"]
    }
)

Bad descriptions lead to the model calling search_ip when it should call search_abuseipdb, or vice versa. Every word in the description is model-facing documentation, not human-facing documentation. Write it accordingly.

MCP VS. DIRECT FUNCTION CALLING

When you use Anthropic's API directly — as OpenOSINT does in its standalone REPL — you define tools inline in each API request. The tool definitions are part of the request payload. This works well for a controlled application where the set of tools is fixed and you control the full stack.

With MCP, tools are defined once in the server and advertised to any connecting client via the tools/list method. The client fetches the list at session start. If the server adds a new tool, clients automatically see it on the next session without any code changes on the client side.

The tradeoff: direct tool use requires less setup (no subprocess, no protocol negotiation) and gives you full control over the request. MCP requires running a server process but enables multi-client reuse and decoupling of tool development from client development. For a framework like OpenOSINT where the same 14 tools should be accessible from multiple AI clients, MCP is the right choice for the server component while direct tool use remains the right choice for the standalone agentic REPL.

The OSINT with MCP article covers the practical setup steps for connecting OpenOSINT to Claude Desktop.

OPENOSINT AS AN MCP SERVER

openosint/mcp_server.py instantiates mcp.Server and registers two handlers: one for tools/list (returns the full list of tool definitions) and one for tools/call (executes the named tool with the provided arguments).

The tools/call handler maps each tool name to its corresponding async Python function. When a client calls search_email, the handler calls run_email_osint(email=args["email"]), awaits the result, and returns it as a TextContent object. The entire MCP transport layer — JSON-RPC framing, stdio management, session negotiation — is handled by the mcp Python SDK. The server code focuses on the tool mapping, not the protocol.

An example JSON-RPC exchange for an IP lookup over the stdio transport:

Request (client → server):
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search_ip",
    "arguments": {"ip": "8.8.8.8"}
  }
}

Response (server → client):
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "IP: 8.8.8.8\nHostname: dns.google\nOrg: AS15169 Google LLC\nCountry: US\nCity: Mountain View\n..."
      }
    ]
  }
}

To use OpenOSINT as an MCP server in Claude Desktop, add it to the mcpServers block in Claude Desktop's configuration file with the command python -m openosint.mcp_server. Claude Desktop will launch the subprocess, negotiate the session, and expose all 14 OSINT tools to the Claude model running in the desktop client. See the tools reference for the complete tool list and parameter documentation, and the AI agents article for how the agentic loop works when tools are invoked.

SEE ALSO


Home · Blog · Tools · GitHub