MCP and Tool Protocols
Introduction
As the agent ecosystem evolves, standardizing tool description, discovery, and invocation has become a critical challenge. Anthropic's Model Context Protocol (MCP) and Google's Agent-to-Agent (A2A) protocol represent two important directions in tool standardization.
Model Context Protocol (MCP)
Background and Motivation
Before MCP, every AI application needed custom integration code for each data source and tool. This led to the "M x N problem"---M applications x N tools = M x N integrations.
MCP proposes a unified protocol allowing any MCP client to connect to any MCP server, reducing M x N to M + N.
Architecture
graph TB
subgraph "MCP Architecture"
subgraph "Host (Host Application)"
APP[AI Application<br/>Claude Desktop / IDE]
CLIENT1[MCP Client 1]
CLIENT2[MCP Client 2]
CLIENT3[MCP Client 3]
APP --- CLIENT1
APP --- CLIENT2
APP --- CLIENT3
end
subgraph "MCP Servers"
SERVER1[Filesystem Server<br/>Local File I/O]
SERVER2[GitHub Server<br/>Repos/PRs/Issues]
SERVER3[Database Server<br/>Query/Write]
end
CLIENT1 <-->|JSON-RPC| SERVER1
CLIENT2 <-->|JSON-RPC| SERVER2
CLIENT3 <-->|JSON-RPC| SERVER3
SERVER1 --> FS[(Local Files)]
SERVER2 --> GH[(GitHub API)]
SERVER3 --> DB[(Database)]
end
Core Concepts
MCP servers can provide three types of capabilities:
| Type | Description | Controlled By | Example |
|---|---|---|---|
| Resources | Data and content (similar to GET) | Application controlled | File contents, database records |
| Tools | Executable functions (similar to POST) | Model controlled (LLM decides to call) | Send email, create PR |
| Prompts | Predefined templates | User controlled | Code review template |
Transport Layer
MCP supports two transport methods:
# 1. Stdio Transport (local inter-process communication)
# Suitable for local tools (filesystem, local databases, etc.)
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
}
}
}
# 2. SSE Transport (HTTP Server-Sent Events)
# Suitable for remote services
{
"mcpServers": {
"remote-db": {
"url": "https://mcp.example.com/sse",
"transport": "sse"
}
}
}
Writing an MCP Server
# Python MCP server example
from mcp.server import Server
from mcp.types import Tool, TextContent
server = Server("my-tools")
@server.list_tools()
async def list_tools():
return [
Tool(
name="query_database",
description="Query an SQLite database. Input a SQL query statement and return results.",
inputSchema={
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "SQL query statement (only SELECT supported)"
}
},
"required": ["query"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "query_database":
query = arguments["query"]
# Safety check
if not query.strip().upper().startswith("SELECT"):
return [TextContent(type="text", text="Error: only SELECT queries are supported")]
results = execute_sql(query)
return [TextContent(type="text", text=format_results(results))]
# Run the server
if __name__ == "__main__":
import asyncio
from mcp.server.stdio import stdio_server
asyncio.run(stdio_server(server))
MCP Client
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def use_mcp_tool():
server_params = StdioServerParameters(
command="python",
args=["my_mcp_server.py"]
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# List available tools
tools = await session.list_tools()
# Call a tool
result = await session.call_tool(
"query_database",
{"query": "SELECT * FROM users LIMIT 10"}
)
print(result)
MCP Ecosystem
Commonly used official and community MCP servers:
| Server | Functionality |
|---|---|
@modelcontextprotocol/server-filesystem |
Filesystem operations |
@modelcontextprotocol/server-github |
GitHub integration |
@modelcontextprotocol/server-postgres |
PostgreSQL queries |
@modelcontextprotocol/server-slack |
Slack messaging |
@modelcontextprotocol/server-memory |
Knowledge graph memory |
@modelcontextprotocol/server-puppeteer |
Browser automation |
@modelcontextprotocol/server-brave-search |
Brave search |
Google A2A Protocol
Agent-to-Agent Protocol
Google's A2A protocol focuses on communication between agents, rather than between agents and tools.
graph LR
subgraph "A2A Architecture"
CA[Client Agent<br/>Delegator] <-->|A2A Protocol| SA[Server Agent<br/>Executor]
CA -->|Send Task| SA
SA -->|Return Result| CA
SA -->|Send Artifact| CA
end
Core Concepts
- Agent Card: Description of an agent's capabilities (like a resume)
- Task: Unit of work passed between agents
- Artifact: Task output (files, data, etc.)
- Message: Communication messages between agents
A2A vs MCP
| Dimension | MCP | A2A |
|---|---|---|
| Focus | Agent <-> Tools/Data | Agent <-> Agent |
| Protocol Type | Tool calling protocol | Task delegation protocol |
| Server Side | Tool server | Agent server |
| Communication Pattern | Request-response | Task lifecycle |
| Proposed By | Anthropic | |
| Complementarity | Provides tool capabilities | Provides collaboration capabilities |
The two protocols are complementary and can be used simultaneously: agents use tools via MCP and collaborate with other agents via A2A.
Tool Description Standards
OpenAPI / Swagger
The traditional API description standard, which can be converted to LLM tool definitions:
# OpenAPI 3.0 Example
openapi: 3.0.0
paths:
/weather/{city}:
get:
summary: Get city weather
parameters:
- name: city
in: path
required: true
schema:
type: string
responses:
'200':
description: Weather information
# OpenAPI -> Function Calling conversion
def openapi_to_tools(spec):
tools = []
for path, methods in spec["paths"].items():
for method, details in methods.items():
tool = {
"type": "function",
"function": {
"name": f"{method}_{path.replace('/', '_')}",
"description": details.get("summary", ""),
"parameters": extract_parameters(details),
}
}
tools.append(tool)
return tools
Tool Description Best Practices
# Complete tool description template
tool_template = {
"name": "action_verb_noun", # verb_noun naming
"description": (
"One-sentence description of the tool's functionality. "
"When to use: specific usage scenarios. "
"When not to use: explicit exclusion conditions. "
"Notes: usage limitations or side effects."
),
"input_schema": {
"type": "object",
"properties": {
"param1": {
"type": "string",
"description": "Parameter meaning and format requirements",
"examples": ["example_value1", "example_value2"] # Non-standard but useful
}
},
"required": ["param1"]
}
}
Interoperability Challenges
Current Issues
- Protocol fragmentation: Different platforms use different tool definition formats
- Capability discovery: How agents discover available tools
- Authentication and authorization: Cross-service authentication management
- Version compatibility: Compatibility after tool updates
Solution Directions
- MCP as a unifying layer: More and more tools provide MCP interfaces
- Tool registries: Centralized management of tool discovery and versioning
- OAuth integration: MCP is adding OAuth support
Practical Recommendations
- Prioritize MCP as the tool integration approach for new projects
- Use the existing MCP server ecosystem to avoid redundant development
- For agent-to-agent collaboration scenarios, follow A2A protocol developments
- Keep tool descriptions clear and complete
Further Reading
- Claude Agent SDK - An agent framework using MCP
- Anthropic. "Model Context Protocol" Documentation (modelcontextprotocol.io)
- Google. "Agent-to-Agent Protocol" Specification