How to Implement the MCP Protocol for Tool Integration

The MCP (Modular Communication Protocol) enables LLM-based agents to discover, invoke, and manage external tools through a standardized JSON schema and HTTP API, implemented via a three-layer architecture of tool schemas, server proxies, and client-side loaders.

To implement the MCP protocol for tool integration, you must bridge the gap between large language models and external capabilities using a declarative schema and async execution model. The bojieli/ai-agent-book repository provides a complete reference implementation that separates tool declaration from execution, allowing agents to dynamically load and call Python functions over HTTP without modifying core agent logic.

Understanding the MCP Architecture

The implementation follows a three-layer architecture that decouples tool definition from execution:

Layer Responsibility Main Implementation
Tool Schema Declares each tool’s name, input/output JSON schema, and endpoint type. mcp_tool_schema.json (generated by the server)
MCP Server Hosts concrete tool implementations behind a lightweight HTTP API. It loads the schema, registers executors, and forwards calls to the actual logic. mcp_server_proxy.py in chapter8/gaia-experience/AWorld/env/virtualpc-mcp/mcp_server/mcp_server_proxy/src/mcp_server_proxy/
Agent Side Loader Reads the server’s schema, builds a client façade, and injects the tools into the LLM’s toolbox. agent.load_mcp_tools() in chapter4/agent-with-event-trigger/agent.py

Step 1 – Define the Tool Schema

Create a JSON entry describing the tool’s contract following OpenAPI-style parameters (for requests) and responses (for results). The server merges all tool definitions into mcp_tool_schema.json at startup.

YouTube Subtitle Crawler Example

{
  "name": "youtube_subtitle_crawler",
  "description": "Fetch subtitles for a YouTube video given its URL.",
  "parameters": {
    "type": "object",
    "properties": {
      "url": { "type": "string", "description": "YouTube video URL" },
      "language": { "type": "string", "default": "en", "description": "Subtitle language code" }
    },
    "required": ["url"]
  },
  "responses": {
    "type": "object",
    "properties": {
      "subtitle_text": { "type": "string", "description": "Full subtitle transcript" }
    }
  }
}

Step 2 – Implement the Server-Side Tool

Each MCP tool lives in a server package (e.g., execution-tools, perception-tools). Implement a class with an async run method that receives the parsed JSON payload and returns a JSON-serializable response.


# chapter8/gaia-experience/AWorld/env/virtualpc-mcp/mcp_server/mcp_server_proxy/src/mcp_server_proxy/tools/youtube_subtitle_crawler.py

class YouTubeSubtitleCrawler:
    async def run(self, payload: dict) -> dict:
        url = payload["url"]
        lang = payload.get("language", "en")
        # Insert actual YouTube API or scraping logic here

        subtitle = await fetch_subtitle(url, lang)
        return {"subtitle_text": subtitle}

Step 3 – Configure the MCP Server

Register the class in mcp_servers_config.yaml (located under mcp_server_proxy/src/configs/). The loader reads this configuration to instantiate MCPServerExecutor instances for each tool.


# mcp_servers_config.yaml

youtube_subtitle_crawler:
  module: tools.youtube_subtitle_crawler
  class: YouTubeSubtitleCrawler
  host: 0.0.0.0
  port: 8001

Step 4 – Start the MCP Server

Launch the server via run_with_experience.py in chapter8/gaia-experience. The startup sequence performs three critical actions:

  1. Loads the consolidated tool schema from mcp_tool_schema.json.
  2. Instantiates executors defined in mcp_servers_config.yaml.
  3. Exposes the unified endpoint http://HOST:PORT/mcp that accepts JSON RPC calls:
{
  "tool_name": "youtube_subtitle_crawler",
  "arguments": { "url": "https://www.youtube.com/watch?v=abc123", "language": "en" }
}

The proxy forwards requests to the appropriate executor and returns responses to callers.

Step 5 – Load MCP Tools in the Agent

On the agent side, invoke await agent.load_mcp_tools() as implemented in chapter4/agent-with-event-trigger/agent.py. This method:

  • Contacts the MCP server’s /mcp endpoint via MCPServerProxy.
  • Retrieves the tool schema and builds thin Python wrappers for each tool.
  • Populates self.tools so LLM prompts can reference tools by name.

# chapter4/agent-with-event-trigger/agent.py

class Agent:
    async def load_mcp_tools(self):
        from mcp_server_proxy.mcp_server_proxy import MCPServerProxy
        proxy = MCPServerProxy(self.mcp_server_url, self.mcp_server_token)
        await proxy.fetch_schema()               # Pulls the JSON schema

        await proxy.register_tools(self)         # Creates callable stubs

        logger.info("MCP tools loaded")

Step 6 – Invoke Tools from LLM Prompts

Once loaded, the agent can execute tools directly. The LLM emits a function-call JSON block that the agent parses and forwards to the MCP proxy.


# chapter4/agent-with-event-trigger/example_with_mcp.py

async def demo():
    await agent.load_mcp_tools()
    result = await agent.tools["youtube_subtitle_crawler"](
        url="https://www.youtube.com/watch?v=abc123",
        language="en"
    )
    print(result["subtitle_text"])

The agent automatically serializes the call into MCP JSON RPC format, sends it over HTTP, and returns the JSON response to the caller.

Best Practices for MCP Implementation

Follow these guidelines when implementing the MCP protocol for production tool integration:

  • Stateless tool implementations – Design each run method to be stateless for horizontal scaling; each request must be independent.
  • Explicit JSON schemas – Define strict parameters and responses schemas to guarantee type safety on both client and server.
  • Versioned schema files – Maintain versioned mcp_tool_schema.json files to enable backward-compatible updates when tools evolve.
  • Secure token authentication – Use MCP_SERVER_TOKEN to prevent unauthorized tool usage via the HTTP endpoint.
  • Asynchronous execution – Always implement async def run to keep the agent responsive during I/O-heavy operations.

Summary

To implement the MCP protocol for tool integration:

  • Define tool contracts using OpenAPI-style JSON schemas that specify parameters and responses.
  • Implement tool logic as async Python classes with a run method that accepts and returns dictionaries.
  • Configure tools in mcp_servers_config.yaml and launch the mcp_server_proxy.py to expose an HTTP API.
  • Load tools dynamically in the agent using agent.load_mcp_tools() which fetches schemas and creates callable stubs.
  • Invoke tools through the agent’s toolbox dictionary, which handles JSON RPC serialization and HTTP transport automatically.

Frequently Asked Questions

What is the MCP protocol used for in AI agents?

The MCP (Modular Communication Protocol) provides a standardized interface for LLM-based agents to discover and invoke external tools without hard-coding function definitions. It separates tool declaration (JSON schema) from execution (HTTP API), allowing developers to add new capabilities to agents by simply deploying new MCP servers.

How does the MCP server handle security and authentication?

According to the ai-agent-book implementation, the MCPServerProxy class accepts a token parameter (mcp_server_token) that must match the server’s configured secret. This token is validated on every request to the /mcp endpoint, preventing unauthorized tool invocation while allowing distributed deployment of tool servers.

What format should the MCP tool schema follow?

The schema follows OpenAPI-style specifications with parameters (input) and responses (output) objects. Each tool definition must include a name, description, and JSON Schema definitions for its arguments and return values, enabling automatic validation and type inference on both the server and agent sides.

Can I implement synchronous tools with the MCP protocol?

While the protocol technically supports synchronous execution, the reference implementation in agent.py and mcp_server_proxy.py uses async def run methods exclusively. You should implement tools as asynchronous functions to prevent blocking the agent’s event loop during network I/O or heavy computation, ensuring the agent remains responsive to other events.

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 →