MCP Explained: Model Context Protocol for AI Agents
MCP (Model Context Protocol) is the standard for connecting AI agents to external tools and data sources. Here's how it works, when to use it, and how to build MCP servers.
MCP (Model Context Protocol) is an open standard for connecting AI models to external tools, data sources, and services. It defines a protocol that lets any AI agent — Claude, GPT-4, Gemini — connect to any tool server using the same interface. Here's what it is, how it works, and when you should build your own MCP server.
What MCP solves
Before MCP, tool integration for AI agents was bespoke: every agent had its own function-calling format, every tool integration was one-off, and switching between agents meant rewriting all your tool code.
MCP defines a standard:
AI Model (client) ←→ MCP Protocol ←→ MCP Server (your tools)
Any MCP-compatible model can connect to any MCP-compatible server. Write your tool once; use it with any agent.
MCP architecture
An MCP server exposes three resource types:
| Type | Description | Example |
|------|-------------|---------|
| Tools | Functions the AI can call | bash_execute, db_query, file_write |
| Resources | Data the AI can read | Files, DB records, API responses |
| Prompts | Reusable prompt templates | code_review, summarize, debug |
The transport can be:
- stdio — server runs as a subprocess, communication via stdin/stdout (local tools)
- HTTP/SSE — server runs as a web service (remote tools, team-shared tools)
Building an MCP server in Go
A minimal MCP server that exposes a run_query tool for PostgreSQL:
package main
import (
"context"
"encoding/json"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
func main() {
server := mcp.NewServer("postgres-tools", "1.0.0")
server.AddTool(mcp.Tool{
Name: "run_query",
Description: "Execute a read-only SQL query against the database",
InputSchema: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"query": map[string]interface{}{
"type": "string",
"description": "SELECT query to execute",
},
},
"required": []string{"query"},
},
}, handleRunQuery)
server.ServeStdio()
}
func handleRunQuery(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
query := req.Params.Arguments["query"].(string)
// Safety: only allow SELECT
if !strings.HasPrefix(strings.TrimSpace(strings.ToUpper(query)), "SELECT") {
return mcp.ErrorResult("Only SELECT queries allowed"), nil
}
rows, err := db.QueryContext(ctx, query)
if err != nil {
return mcp.ErrorResult(err.Error()), nil
}
result := formatRows(rows)
return mcp.TextResult(result), nil
}
Run it as a local stdio server in Claude Code:
// .claude/settings.json
{
"mcpServers": {
"postgres-tools": {
"command": "/usr/local/bin/postgres-mcp-server",
"args": [],
"env": {
"DATABASE_URL": "postgres://..."
}
}
}
}
MCP vs function calling vs tool use
| | MCP | Function Calling (OpenAI) | Tool Use (Anthropic) | |--|-----|--------------------------|---------------------| | Standard | Open, multi-vendor | OpenAI-specific | Anthropic-specific | | Reusable | ✅ Any MCP client | ❌ OpenAI only | ❌ Claude only | | Server hosting | Yes (stdio or HTTP) | No (inline functions) | No (inline tools) | | Resources/Prompts | ✅ Built in | ❌ No | ❌ No | | Maturity | 2024–2026 standard | Mature | Mature |
Use MCP when: you want to share tools across models, build a team-shared tool server, or expose persistent services (database, file system, external APIs) to agents.
Use native tool use when: you're building a one-off integration for a specific model and don't need reusability.
Practical MCP servers worth building
For solo developers:
filesystem-mcp— read/write files with path restrictionspostgres-mcp— read-only DB queries (great for data exploration with agents)github-mcp— list PRs, read issues, post commentsslack-mcp— read messages, post notificationsaws-mcp— CloudWatch logs, ECS task status, S3 operations
For product teams:
analytics-mcp— query your metrics DBdocs-mcp— search internal documentationsupport-mcp— access customer support ticketsdeploy-mcp— trigger deployments, check service health
Security considerations
MCP servers run with whatever permissions the server process has. Key security rules:
- Read-only by default — only add write tools when explicitly needed
- Validate all inputs — SQL injection is real even in "trusted" agent contexts
- Rate limit tool calls — agents can call tools in tight loops
- Audit logs — log every tool call with the calling model's identity
- Never expose secrets as resources — return transformed data, not raw credentials
FAQ
What is MCP (Model Context Protocol)? MCP is an open standard developed by Anthropic for connecting AI models to external tools and data sources. It defines a common protocol so AI agents can use tools written by anyone, and tool authors can write once and support any MCP-compatible model.
Who supports MCP? Claude (Anthropic), Cursor, Windsurf, and a growing list of IDE integrations. The protocol is open-source and available on GitHub at modelcontextprotocol/specification.
Is MCP the same as function calling? No — function calling is a model-specific feature (OpenAI, Anthropic). MCP is a client-server protocol that works at a higher level: MCP servers can expose tools, resources, and prompt templates, and any MCP-compatible model can connect to any MCP server.
Do I need MCP if I'm only using Claude? Not necessarily. If you're building tools for Claude Code specifically, the hooks and skills system may be sufficient. MCP is most valuable when you want tool reusability across models or when building team-shared tool servers.
How is MCP different from Claude Code skills? Skills provide domain knowledge (context, rules, examples) to a coding agent. MCP provides tools (callable functions) to an agent. They're complementary: skills tell the agent what to do; MCP tools give it capabilities to do it.
Written by Shihab Shahriar Antor — AI Engineer & Founder of Shahriar Labs. See also: My AI Agent Skills Stack · The Tools I Built to Make AI Coding Agents 10x Better.