Tool Use

Model Context Protocol

Anthropic's open standard for connecting LLMs to external tools and data sources. MCP decouples tool providers from AI clients — one MCP server works with any MCP-compatible LLM client.

Open
Standard
Provider-agnostic
Clients
Anthropic
Origin

Table of Contents

SECTION 01

What problem MCP solves

Before MCP, every LLM application reinvented tool integration from scratch. Want your Claude app to access your database? Write a custom wrapper. Want to reuse that wrapper in your LangChain app? Rewrite it. Want to give your OpenAI app the same capability? Rewrite it again. Every AI client had its own incompatible tool protocol.

MCP (Model Context Protocol) is Anthropic's answer to this: a standardised, open protocol where tools are exposed as MCP servers and LLM applications connect as MCP clients. Write a database MCP server once; use it with Claude Desktop, VS Code Copilot, Cursor, or any other MCP client without modification.

It's the USB of AI tools: a standard connector so any tool works with any client. As of 2024, MCP is supported natively in Claude Desktop, many IDE plugins, and major agent frameworks.

SECTION 02

MCP architecture

┌───────────────────────────────────┐
│         MCP Client                │
│  (Claude Desktop, IDE plugin,     │
│   LangChain, custom app)          │
└──────────────┬────────────────────┘
               │ MCP Protocol (JSON-RPC over stdio/SSE)
               │
┌──────────────▼────────────────────┐
│         MCP Server                │
│  Exposes:                         │
│   • Tools (functions to call)     │
│   • Resources (data to read)      │
│   • Prompts (prompt templates)    │
└──────────────┬────────────────────┘
               │
┌──────────────▼────────────────────┐
│  External System                  │
│  (database, API, filesystem,      │
│   calendar, Slack, GitHub...)     │
└───────────────────────────────────┘

MCP uses JSON-RPC 2.0 as the wire protocol. The client discovers what tools, resources, and prompts the server offers, then calls them on behalf of the LLM. The LLM never directly touches the external system — the MCP server is the controlled interface.

SECTION 03

Building an MCP server

pip install mcp
from mcp.server.fastmcp import FastMCP

# Create an MCP server
mcp = FastMCP("my-tools")

@mcp.tool()
def search_database(query: str, table: str = "products") -> list[dict]:
    '''Search the product database for items matching the query.

    Args:
        query: Search query string
        table: Table to search (products, orders, customers)
    Returns:
        List of matching records as dicts
    '''
    import sqlite3
    conn = sqlite3.connect("mydb.sqlite")
    cursor = conn.execute(
        f"SELECT * FROM {table} WHERE description LIKE ? LIMIT 10",
        (f"%{query}%",)
    )
    cols = [d[0] for d in cursor.description]
    return [dict(zip(cols, row)) for row in cursor.fetchall()]

@mcp.resource("schema://products")
def get_product_schema() -> str:
    '''Return the database schema for reference.'''
    return "products: id, name, description, price, stock"

@mcp.prompt()
def product_analysis_prompt(product_name: str) -> str:
    '''Template for analysing a product.'''
    return f"Analyse the product '{product_name}' covering: pricing strategy, target market, and competitive positioning."

if __name__ == "__main__":
    mcp.run()  # runs as stdio server by default
SECTION 04

Connecting to Claude

In Claude Desktop, add your server to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "my-tools": {
      "command": "python",
      "args": ["/path/to/your/server.py"]
    }
  }
}

For programmatic use with the Anthropic Python SDK:

import asyncio
from anthropic import Anthropic
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def chat_with_mcp():
    server_params = StdioServerParameters(
        command="python", args=["server.py"]
    )
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()

            # Discover tools
            tools = await session.list_tools()
            anthropic_tools = [
                {"name": t.name, "description": t.description,
                 "input_schema": t.inputSchema}
                for t in tools.tools
            ]

            client = Anthropic()
            response = client.messages.create(
                model="claude-sonnet-4-5",
                max_tokens=1024,
                tools=anthropic_tools,
                messages=[{"role": "user", "content": "Find products matching 'wireless headphones'"}]
            )
            # ... handle tool calls as normal

asyncio.run(chat_with_mcp())
SECTION 05

MCP vs plain tool use

Use plain tool use (direct Anthropic API tools parameter) when: you're building a self-contained application, your tools are tightly coupled to your app logic, or you don't need to share tools across different AI clients.

Use MCP when: you want to share tools across multiple AI applications (Claude Desktop + VS Code + your app), you're building tools for the broader ecosystem, your tool server runs as a long-lived process serving multiple clients, or you want to use existing MCP servers from the community without writing wrappers.

The practical difference: MCP adds a network layer and a discovery protocol. For a simple single-app integration, this overhead is unnecessary. For tools that should be broadly accessible and reusable, MCP is the right abstraction.

SECTION 06

MCP ecosystem and registries

The MCP ecosystem has grown rapidly since Anthropic open-sourced the protocol in late 2024. Key sources for pre-built MCP servers:

Official Anthropic servers: filesystem, GitHub, GitLab, Google Drive, Slack, Postgres, SQLite, Puppeteer (browser automation), and more at github.com/modelcontextprotocol/servers.

Community servers: thousands of community-built servers for specific services. The MCP registry at mcp.so catalogues available servers by category.

Framework integrations: LangChain, LlamaIndex, and AutoGen have MCP adapter libraries so you can use MCP servers as tools within those frameworks without writing custom adapters.

Before writing a custom MCP server, search the registry — there's a good chance someone has already built what you need for common services (Notion, Jira, Salesforce, databases, etc.).

SECTION 07

Gotchas

stdio transport blocks on large outputs. The default stdio transport reads/writes line-by-line, which struggles with large tool results (e.g., a database query returning 10,000 rows). Always paginate large results from MCP tools, returning at most a few KB per call. Use SSE transport for streaming use cases.

Server lifecycle matters. MCP servers launched by Claude Desktop start fresh for each session. If your server holds state (open DB connections, cached data), you need to re-initialise on each connect. For stateful servers, run them as long-lived processes and connect via SSE rather than stdio.

Tool descriptions are still critical. MCP doesn't change the fact that the LLM picks tools based on their descriptions. An MCP server with poorly-written tool descriptions will be used incorrectly, regardless of the protocol.

MCP Server Implementation Patterns

The Model Context Protocol (MCP) standardizes how AI applications connect to external data sources and tools through a client-server architecture. An MCP server exposes resources, tools, and prompts via a JSON-RPC interface; an MCP client (typically an LLM application or IDE) discovers and invokes these capabilities at runtime without requiring custom integration code for each data source.

Capability TypePurposeWhen to UseExample
ResourcesExpose structured dataRead-heavy, cacheable contentFile contents, DB records
ToolsExpose callable actionsSide-effecting operationscreate_issue, send_email
PromptsExpose prompt templatesReusable instruction patternscode_review_template
SamplingRequest model inferenceServer-driven LLM callsSummarize before returning

MCP servers communicate over stdio (for local processes) or HTTP with Server-Sent Events (for remote servers). The stdio transport is ideal for development and local tool integrations — the client spawns the server as a subprocess and communicates through standard input/output streams. The HTTP+SSE transport enables deploying MCP servers as persistent network services, supporting multiple concurrent clients and enabling centralized tool infrastructure shared across an organization.

Security boundaries are a critical consideration in MCP deployments. An MCP server that exposes file system access or shell execution capabilities should be run with the minimum required permissions and should validate all inputs from the LLM client. Since the LLM generates tool arguments, a prompt injection attack on the model could lead to malicious tool calls — MCP servers should treat all incoming arguments as untrusted and enforce their own validation logic independent of the LLM layer.

MCP's resource abstraction handles pagination and streaming for large data sources. Resources that return large payloads — a full codebase, a long document, a large database query result — can use cursor-based pagination to return data in chunks that fit within context window limits. The LLM client decides how many resource pages to fetch based on the task requirements, and the MCP server manages the underlying data access pattern transparently.

Authorization in MCP is deliberately out of scope for the core protocol, allowing implementers to use OAuth, API keys, mTLS, or any other auth mechanism appropriate for their environment. In practice, most production MCP servers that access sensitive resources use OAuth 2.0, with the MCP client handling the OAuth flow and passing access tokens in the request headers. The server validates tokens and enforces access control at the resource and tool level before executing any operations on behalf of the requesting agent.