Skip to content

What is MCP? The Protocol Layer for AI Agent Communication

The Problem

I was building an AI agent system. Multiple agents needed to talk to each other and to external services. I started with custom APIs for each connection.

It was a mess.

Every time I added a new agent or service, I had to write new integration code. The GitHub agent needed one API format. The Slack agent needed another. My calendar agent spoke a different dialect altogether.

Agent A (Planner) ---> Custom API A ---> Service A
Agent B (Executor) ---> Custom API B ---> Service B
Agent C (Reviewer) ---> Custom API C ---> Service C
Each arrow = Different integration code
Total = 3 agents x N services = Growing complexity

Then I discovered MCP (Model Context Protocol). Suddenly, I understood the problem wasn’t my code. It was that I was building for a world where agents use APIs designed for humans.

What MCP Actually Is

MCP is an open standard that serves as the protocol layer for AI agent communication. Think of it like HTTP, but for AI agents instead of web browsers.

┌─────────────────────────────────────────────────────────────┐
│ BEFORE: Custom APIs │
│ │
│ Claude ──────► GitHub API (format A) │
│ Claude ──────► Slack API (format B) │
│ Claude ──────► Database (format C) │
│ │
│ Each integration = Custom code │
├─────────────────────────────────────────────────────────────┤
│ AFTER: MCP Protocol │
│ │
│ Claude ──────► MCP Protocol ◄────── GitHub MCP Server │
│ ◄────── Slack MCP Server │
│ ◄────── Database MCP Server │
│ │
│ One protocol = Multiple services │
└─────────────────────────────────────────────────────────────┘

The key insight: just as HTTP standardized how browsers talk to servers, MCP standardizes how AI agents talk to tools, APIs, and other agents.

My First MCP Server

I started by creating a simple MCP server that my agents could use. Here’s what the structure looks like:

mcp-server/index.ts
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js'
const server = new Server(
{ name: 'agent-communication-server', version: '1.0.0' },
{ capabilities: { tools: {} } }
)
// Tell agents what tools are available
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'delegate_task',
description: 'Delegate a task to another agent',
inputSchema: {
type: 'object',
properties: {
agent_id: { type: 'string', description: 'Target agent ID' },
task: { type: 'string', description: 'Task description' },
},
required: ['agent_id', 'task'],
},
},
],
}
})
// Execute when an agent calls a tool
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params
if (name === 'delegate_task') {
const result = await routeToAgent(args.agent_id, args.task)
return {
content: [{ type: 'text', text: JSON.stringify(result) }],
}
}
throw new Error(`Unknown tool: ${name}`)
})
async function main() {
const transport = new StdioServerTransport()
await server.connect(transport)
}
main().catch(console.error)

The beauty is in the discovery. An agent doesn’t need prior knowledge of what tools exist. It just asks the server: “What can you do?”

How Agents Discover Tools

I was confused at first about how agents know what tools are available. The answer is in the protocol itself.

When an MCP server connects to an AI client (like Claude), it advertises its capabilities:

┌─────────────┐ ┌─────────────┐
│ AI Client │ │ MCP Server │
│ (Claude) │ │ │
└──────┬──────┘ └──────┬──────┘
│ │
│ 1. Initialize connection │
│ ─────────────────────────────────► │
│ │
│ 2. Server responds with │
│ capabilities │
│ ◄───────────────────────────────── │
│ │
│ 3. Request: "What tools?" │
│ ─────────────────────────────────► │
│ │
│ 4. Server sends tool list │
│ ◄───────────────────────────────── │
│ │
│ 5. Call tool with arguments │
│ ─────────────────────────────────► │
│ │
│ 6. Server executes, returns result │
│ ◄───────────────────────────────── │
│ │

No documentation needed. No API keys to manage per agent. The protocol handles it.

Agent-to-Agent Communication

This is where it gets interesting. The Reddit discussion I found had a key insight: “Your agent talks to their agents through MCPs.”

I tested this pattern. My planning agent delegates to a code reviewer agent through MCP:

agent-orchestration.ts
async function orchestrateCodeReview(prUrl: string) {
// Step 1: Fetch PR data via GitHub MCP
const pr = await callMCPTool('github', 'get_pr', { url: prUrl })
// Step 2: Delegate to specialized code review agent
const review = await callMCPTool('agent-bus', 'delegate_task', {
agent_id: 'code-reviewer',
task: 'Review this PR for security issues',
context: { pr_data: pr }
})
// Step 3: If issues found, notify via Slack MCP
if (review.issues.length > 0) {
await callMCPTool('slack', 'send_message', {
channel: '#security',
text: `Security issues found: ${review.summary}`
})
}
return review
}

The planning agent doesn’t know how to review code. It doesn’t know how Slack works. It just knows how to use MCP tools.

The JSON-RPC Foundation

Under the hood, MCP uses JSON-RPC 2.0. This means structured, parseable communication:

mcp-request.json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_issue",
"arguments": {
"title": "Bug in agent delegation",
"body": "Details here..."
}
}
}
mcp-response.json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{ "type": "text", "text": "Issue #42 created successfully" }
]
}
}

This structure means any AI client can parse responses without custom parsers.

Configuration for Multi-Agent Systems

I configured my MCP servers in Claude’s settings to enable multi-agent communication:

claude-settings.json
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
},
"slack": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-slack"],
"env": { "SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}" }
},
"agent-bus": {
"command": "node",
"args": ["/agents/communication-bus/index.js"],
"transport": "stdio"
}
}
}

Now my agents have access to all these tools without additional integration code.

MCP vs Traditional Integration

I compared my MCP approach to what I was doing before:

┌────────────────┬─────────────────────┬─────────────────────┐
│ Aspect │ Traditional API │ MCP Protocol │
├────────────────┼─────────────────────┼─────────────────────┤
│ Discovery │ Read docs manually │ Built-in tool list │
│ Standard │ Per-vendor format │ Open protocol │
│ Multi-client │ Custom for each │ Works everywhere │
│ Maintenance │ Update each client │ Update server only │
│ Token cost │ No consideration │ Designed for AI │
└────────────────┴─────────────────────┴─────────────────────┘

The token cost consideration is important. MCP servers are designed with AI context windows in mind. Bloated schemas cost more tokens. MCP encourages focused, minimal tool definitions.

Real-World Pattern: Agent Delegation

I implemented a pattern where one agent delegates to another:

User: "Review my PR and notify the team if there are issues"
Claude Agent Workflow:
┌────────────────────────────────────────────────────────────┐
│ 1. Use GitHub MCP to fetch PR │
│ └── Tool: github.get_pr │
│ │
│ 2. Analyze code for issues │
│ └── Internal analysis │
│ │
│ 3. If issues found, use Slack MCP to notify │
│ └── Tool: slack.send_message │
│ │
│ 4. All without human intervention │
└────────────────────────────────────────────────────────────┘

This is what the emerging agent economy looks like. Agents orchestrating other agents through standardized protocols.

The “API is the New UI” Shift

The insight that clicked for me: we’re transitioning from human-centric to agent-centric interfaces.

Traditional Model:
┌─────────────────────────────────────────────────────────────┐
│ │
│ Humans ──────► UI (buttons, forms) ──────► Backend │
│ Primary interface │
│ │
│ APIs ──────► Secondary, often incomplete │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ Agent-First Model: │
│ │
│ Agents ──────► MCP/API (tools, structured data) │
│ Primary interface │
│ │
│ UI ──────► Secondary, for human oversight only │
│ │
└─────────────────────────────────────────────────────────────┘

Google’s signal: when they added a CLI to Workspace, they acknowledged that agents don’t need the UI. The largest productivity suite is now optimizing for programmatic access.

Common Mistakes I Made

Mistake 1: Building UI-First

I spent weeks on beautiful dashboards before realizing agents don’t care about aesthetics. They need structured outputs, not styled components.

Mistake 2: Over-Engineering MCP Servers

My first MCP server had 50 tools. Each call cost hundreds of tokens in discovery. I refactored to 8 focused tools. Token costs dropped 80%.

Mistake 3: Ignoring Agent Traffic Patterns

Agents make different API calls than humans. A human might check email 10 times a day. An agent might query a database 100 times per task. I had to adjust my rate limiting.

The Three Primitives

MCP servers expose three types of capabilities:

┌─────────────────────────────────────────────────────────────┐
│ MCP Primitives │
├─────────────────────────────────────────────────────────────┤
│ │
│ TOOLS (Actions) │
│ • Executable functions │
│ • Side effects allowed │
│ • Examples: create_issue, send_email, query_database │
│ │
│ RESOURCES (Data) │
│ • Read-only data sources │
│ • No side effects │
│ • Examples: file://logs, database://tables │
│ │
│ PROMPTS (Templates) │
│ • Pre-defined prompt templates │
│ • Reusable instructions │
│ • Examples: code-review-template, summarize-logs │
│ │
└─────────────────────────────────────────────────────────────┘

Tools are what I use most. Resources for data access. Prompts for standardizing agent behavior.

MCP vs Other Approaches

I considered alternatives before committing to MCP:

┌────────────────┬─────────────────┬─────────────────┬─────────────────┐
│ Aspect │ MCP │ Custom REST API │ Message Queue │
├────────────────┼─────────────────┼─────────────────┼─────────────────┤
│ Discovery │ Built-in │ Manual docs │ N/A │
│ Standard │ Open protocol │ Per-vendor │ Per-impl │
│ Multi-client │ Native │ Custom │ Custom │
│ Agent-focused │ Yes │ No │ Partial │
│ Learning curve │ Medium │ Low │ High │
│ Ecosystem │ Growing │ Everywhere │ Enterprise │
└────────────────┴─────────────────┴─────────────────┴─────────────────┘

MCP won because it’s purpose-built for AI agents. The discovery mechanism alone saves hours of integration work.

When to Use MCP

MCP is the right choice when:

  • You have AI agents that need tool access
  • Multiple clients (Claude, ChatGPT, custom agents) need the same tools
  • You want to avoid per-client integration code
  • You’re building for the agent economy

MCP might be overkill when:

  • You only have one client
  • Your tools are simple HTTP calls
  • You don’t need tool discovery
  • Your audience is only human users

Summary

MCP (Model Context Protocol) is the HTTP of the agent economy. It standardizes how AI agents communicate with tools, data sources, and each other.

The shift is fundamental: “Your API is the new UI.” Programs, not humans, become the primary consumers of software.

For developers, the question isn’t whether to build MCP servers, but how quickly you can make your services agent-accessible.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments