05.01 · MCP Protocol Deep Dive
Level: Advanced
Pre-reading: 05 · MCP Servers & Tool Use
Protocol Design
MCP uses JSON-RPC 2.0 as the message format. All messages (requests, responses, notifications) conform to the standard JSON-RPC envelope.
sequenceDiagram
participant Client as MCP Client
participant Server as MCP Server
Client->>Server: initialize { protocolVersion, capabilities }
Server-->>Client: { serverInfo, capabilities }
Client->>Server: tools/list {}
Server-->>Client: { tools: [ {name, description, inputSchema} ] }
Client->>Server: tools/call { name: "create_pr", arguments: {...} }
Server-->>Client: { content: [ {type: "text", text: "PR #42 created"} ] }
Transport Mechanisms
| Transport | When to Use | How It Works |
|---|---|---|
| stdio | Local servers on same machine | Client spawns server as subprocess; communicates via stdin/stdout |
| HTTP + SSE | Remote or containerised servers | Client sends POST requests; server streams responses via Server-Sent Events |
| WebSocket | Bidirectional, low-latency | Experimental, not yet standard |
stdio is the dominant transport for IDE integrations (VS Code, Cursor). HTTP+SSE is used for shared cloud-hosted MCP servers in CI/CD pipelines.
Tool Schema
Each tool is described via a JSON Schema inputSchema. This is exactly what the LLM sees when deciding whether to call the tool.
{
"name": "create_pull_request",
"description": "Creates a pull request in a GitHub repository. Use when you have finished code changes and tests and need developer review.",
"inputSchema": {
"type": "object",
"properties": {
"owner": { "type": "string", "description": "Repository owner or organisation" },
"repo": { "type": "string", "description": "Repository name" },
"title": { "type": "string", "description": "PR title — concise, include JIRA ID" },
"body": { "type": "string", "description": "PR description with changes summary and test evidence" },
"head": { "type": "string", "description": "Branch with changes" },
"base": { "type": "string", "description": "Target branch — usually 'main' or 'develop'" }
},
"required": ["owner", "repo", "title", "body", "head", "base"]
}
}
Description Quality Is Critical
The LLM uses the description field to decide when to call this tool. Vague descriptions lead to wrong tool selection. Be explicit about when the tool should be called, not just what it does.
Resources
MCP resources represent data the LLM can read (not execute). They follow a URI scheme:
| URI Pattern | Example | Content |
|---|---|---|
github://repo/owner/name/path |
github://repo/acme/order-service/src/OrderService.java |
File content |
jira://ticket/PROJ-123 |
jira://ticket/ORDER-4821 |
Ticket JSON |
postgres://schema/orders |
postgres://schema/orders |
Table DDL and sample rows |
Resources can be:
- Static — requested once and cached
- Dynamic — re-fetched on each access
- Subscribed — client receives push notifications when resource changes
Sampling (Server → Client LLM Calls)
MCP supports a sampling capability: the server can ask the client to make an LLM call on its behalf. This is used by smart MCP servers that need to reason about their own tool results.
sequenceDiagram
participant Client
participant Server
Client->>Server: tools/call { "find_relevant_test" }
Server->>Client: sampling/createMessage { prompt: "Which test covers PaymentService.charge?" }
Client->>Client: LLM inference
Client-->>Server: { content: "PaymentServiceIntegrationTest" }
Server-->>Client: { content: "Found: PaymentServiceIntegrationTest.java" }
This enables MCP servers to be intelligent without embedding an LLM themselves.
MCP Security Considerations
| Risk | Mitigation |
|---|---|
| Tool scope creep | Only expose tools the agent needs — separate servers per use case |
| Prompt injection via tool results | Sanitise all MCP server responses before injecting into LLM context |
| Credential exposure | MCP server process handles credentials; agent process never touches them |
| Unauthorised tool invocation | Authenticate MCP client-to-server connections with API keys or mTLS |
| Data exfiltration via resources | Restrict resource URIs to read-only, relevant data only |
See 08 · AI Security for the full security model.
Can a single MCP server expose both GitHub and JIRA tools?
Yes, but it's better practice to separate them. Separate processes with separate credentials mean a compromised GitHub token doesn't expose JIRA data. The MCP client (your agent) can connect to multiple servers simultaneously.
How do you version an MCP server API?
MCP itself is versioned (protocolVersion in the initialize handshake). For your tool schemas, include a version in the server name or use semantic versioning in the server description. Avoid breaking changes to inputSchema of existing tools — add new tools instead.