…
Skip to content
Topics
On this page

What is MCP (Model Context Protocol)

The Model Context Protocol (MCP) is an open protocol that standardises how AI applications connect to external tools, data sources and prompt templates. It was introduced by Anthropic in November 2024 , and it lets one AI assistant reach many systems through a single message format instead of a custom integration for each one.

  • Host: The AI application, such as a chat assistant or an integrated development environment, that the user interacts with directly.
  • Client: A protocol component inside the host that maintains one dedicated connection to one server.
  • Server: A program that wraps an external system, such as an issue tracker, and exposes its capabilities over MCP.
  • Primitives: Servers offer three kinds of capability: tools (actions), resources (readable data) and prompts (reusable templates).
  • JSON-RPC 2.0: Every MCP message is a JSON-RPC 2.0 request, response or notification, a small standard for remote procedure calls in JSON.
  • Transports: Messages travel over stdio for local servers or over streamable HTTP for remote servers.
One AI assistant connected to three engineering tools through MCPAn AI assistant on the left speaks one protocol, MCP, carried as JSON-RPC 2.0 messages. On the right, three MCP servers wrap an issue tracker, a PostgreSQL database and a logs service, and each one exposes a tool such as search_issues, run_query or recent_errors. The tool names are illustrative.AI assistantMCP hostMCPJSON-RPC 2.0Issue trackersearch_issuesPostgreSQLrun_queryLogs servicerecent_errors
One AI assistant connected to three engineering tools through MCP

For example, an engineering team connects its AI assistant to three MCP servers, one each for the issue tracker, the PostgreSQL database and the logs service, so the assistant can look up an issue, query a table and read recent errors.

Key Characteristics of the Model Context Protocol

  • Open standard: The specification is public, so any model provider, host application or tool vendor can implement it.
  • Model-agnostic: MCP defines how the host communicates with servers, not which language model the host application uses.
  • Discoverable: A client asks a server which tools it offers at runtime, so capabilities do not need to be hard-coded in the host.
  • Self-describing tools: Each tool carries a name, a description and an input schema in JSON Schema, which the model reads to decide how to call it.
  • Stateful sessions: A connection begins with an initialize handshake in which both sides agree on a protocol version and capabilities.
  • Reusable servers: One server, such as a PostgreSQL server, works with every MCP-compatible host without changes.

How MCP Works

  1. Configure: The user or an administrator registers the servers the host may use, typically in a configuration file.
  2. Connect: The host creates one client per server, and each client starts or opens a connection over stdio or streamable HTTP.
  3. Initialize: The client sends an initialize request, and the server replies with its protocol version, name and capabilities.
  4. Discover: The client calls tools/list, and the host passes the tool names, descriptions and schemas to the model.
  5. Call: When the model requests a tool, the client sends tools/call with the arguments, and the server runs the action.
  6. Return: The server replies with content blocks, usually text, which the host appends to the model's context for the next reasoning step.

Example: A Teaching Model of MCP Messages

The program below is a teaching model of the protocol, not a complete implementation. A toy issue tracker server answers a list of JSON-RPC 2.0 requests and prints each response.

Python
# A teaching model of the MCP message flow, not a complete implementation.
import json

ISSUES = {"ENG-101": {"title": "Checkout returns 500 on empty cart", "status": "open"},
          "ENG-102": {"title": "Slow query on orders table", "status": "in progress"}}

TOOLS = [{"name": "get_issue",
          "description": "Fetch one issue from the issue tracker by its id.",
          "inputSchema": {"type": "object",
                          "properties": {"issue_id": {"type": "string"}},
                          "required": ["issue_id"]}}]

def handle(request):
    method, params = request["method"], request.get("params", {})
    if "id" not in request:
        return None  # a notification: the server sends no response
    if method == "initialize":
        result = {"protocolVersion": "2025-06-18",
                  "capabilities": {"tools": {}},
                  "serverInfo": {"name": "issue-tracker", "version": "0.1.0"}}
    elif method == "tools/list":
        result = {"tools": TOOLS}
    elif method == "tools/call" and params.get("name") == "get_issue":
        issue = ISSUES.get(params["arguments"]["issue_id"])
        text = json.dumps(issue) if issue else "No such issue"
        result = {"content": [{"type": "text", "text": text}], "isError": issue is None}
    else:
        return {"jsonrpc": "2.0", "id": request["id"],
                "error": {"code": -32601, "message": f"Method not found: {method}"}}
    return {"jsonrpc": "2.0", "id": request["id"], "result": result}

requests = [
    {"jsonrpc": "2.0", "id": 1, "method": "initialize",
     "params": {"protocolVersion": "2025-06-18", "capabilities": {},
                "clientInfo": {"name": "demo-host", "version": "1.0"}}},
    {"jsonrpc": "2.0", "method": "notifications/initialized"},
    {"jsonrpc": "2.0", "id": 2, "method": "tools/list"},
    {"jsonrpc": "2.0", "id": 3, "method": "tools/call",
     "params": {"name": "get_issue", "arguments": {"issue_id": "ENG-101"}}},
    {"jsonrpc": "2.0", "id": 4, "method": "issues/delete"},
]

for req in requests:
    resp = handle(req)
    print(">>", req["method"])
    if resp is None:
        print("<< (no response to a notification)")
    elif "error" in resp:
        print("<<", json.dumps(resp["error"]))
    elif req["method"] == "initialize":
        print("<< server:", resp["result"]["serverInfo"]["name"], "| capabilities:", list(resp["result"]["capabilities"]))
    elif req["method"] == "tools/list":
        print("<< tools:", [t["name"] for t in resp["result"]["tools"]])
    else:
        print("<< text:", resp["result"]["content"][0]["text"])
Output
>> initialize
<< server: issue-tracker | capabilities: ['tools']
>> notifications/initialized
<< (no response to a notification)
>> tools/list
<< tools: ['get_issue']
>> tools/call
<< text: {"title": "Checkout returns 500 on empty cart", "status": "open"}
>> issues/delete
<< {"code": -32601, "message": "Method not found: issues/delete"}
  • Handshake first: The initialize exchange comes before any tool call, and the notifications/initialized message has no id, so it receives no response.
  • Discovery: The tools/list result carries the input schema that tells the model which arguments get_issue needs.
  • Standard errors: An unknown method returns JSON-RPC error code -32601, so every client handles the failure the same way.

Applications of the Model Context Protocol

  • Engineering assistants: Reading issues, database records and application logs during debugging, as in the example above.
  • Coding agents: Giving an AI agent in a code editor access to repositories, tests and documentation.
  • Data analysis: Allowing an assistant to execute read-only SQL queries against a reporting database.
  • Knowledge retrieval: Exposing internal documents as resources, a route to agentic RAG without custom connectors.
  • Workflow automation: Creating tickets, posting notifications or triggering builds through tools with explicit schemas.

Advantages

  • Less integration work: A tool is wrapped once as a server and then reused by every compatible host application.
  • Consistent interface: Discovery, invocation and error handling follow one message format across all servers.
  • Clear boundaries: The server owns credentials and access rules, so the model never sees a database password.
  • Composability: A host can connect to several servers simultaneously and combine their tools within a single task.

Limitations

  • Security exposure: A tool result can carry hidden instructions, so MCP servers widen the surface for prompt injection.
  • Trust in servers: A third-party server runs with the permissions it is given, so each one needs review before use.
  • Context cost: Every registered tool description consumes tokens in the model's context window.
  • Evolving specification: Versions, transports and authorisation requirements continue to evolve, so implementations need regular maintenance.
  • Not a model feature: MCP still depends on the model's tool calling ability to choose the right tool and arguments.

The roles behind these steps are covered in MCP architecture, and a working server is built in build an MCP server in Python.

Quick Quiz

Pick an answer to check yourself. Nothing is saved.

Question 1 / 3

  1. 1. Which message format does the Model Context Protocol use?

Frequently Asked Questions

What is MCP used for?

MCP connects AI applications to external tools and data through one standard protocol. A team can wrap an issue tracker, a database or a logs service as an MCP server and use it from any compatible assistant.

Is Anthropic MCP only for Claude?

No. Anthropic introduced MCP, but it is an open protocol, and the host decides which model it uses. Any application that implements the client side can connect to MCP servers.

What is the difference between MCP tools and resources?

A tool is an action the model can request, such as running a query or creating an issue. A resource is data the host can read and add to the context, such as a file or a database schema.

Does MCP replace APIs?

No. An MCP server usually calls the service's existing API internally. MCP standardises how the AI application reaches the server, while the API remains the way the server reaches the service.

Is it safe to connect an AI assistant to a database through MCP?

It can be, when the server uses a read-only account, limits which tables it exposes and logs every call. Risky tools such as writes or deletes should require human approval.