# How to Implement the MCP Protocol for Tool Integration

> Learn how to implement the MCP protocol for seamless tool integration with LLM agents. Discover, invoke, and manage tools using a standardized JSON schema and HTTP API.

- Repository: [Bojie Li/ai-agent-book](https://github.com/bojieli/ai-agent-book)
- Tags: how-to-guide
- Published: 2026-07-26

---

**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`](https://github.com/bojieli/ai-agent-book/blob/main/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`](https://github.com/bojieli/ai-agent-book/blob/main/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`](https://github.com/bojieli/ai-agent-book/blob/main/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`](https://github.com/bojieli/ai-agent-book/blob/main/mcp_tool_schema.json) at startup.

### YouTube Subtitle Crawler Example

```json
{
  "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.

```python

# 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`](https://github.com/bojieli/ai-agent-book/blob/main/mcp_servers_config.yaml) (located under `mcp_server_proxy/src/configs/`). The loader reads this configuration to instantiate `MCPServerExecutor` instances for each tool.

```yaml

# 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`](https://github.com/bojieli/ai-agent-book/blob/main/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`](https://github.com/bojieli/ai-agent-book/blob/main/mcp_tool_schema.json).
2. Instantiates executors defined in [`mcp_servers_config.yaml`](https://github.com/bojieli/ai-agent-book/blob/main/mcp_servers_config.yaml).
3. Exposes the unified endpoint `http://HOST:PORT/mcp` that accepts JSON RPC calls:

```json
{
  "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`](https://github.com/bojieli/ai-agent-book/blob/main/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.

```python

# 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.

```python

# 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`](https://github.com/bojieli/ai-agent-book/blob/main/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`](https://github.com/bojieli/ai-agent-book/blob/main/mcp_servers_config.yaml) and launch the [`mcp_server_proxy.py`](https://github.com/bojieli/ai-agent-book/blob/main/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`](https://github.com/bojieli/ai-agent-book/blob/main/agent.py) and [`mcp_server_proxy.py`](https://github.com/bojieli/ai-agent-book/blob/main/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.