Every few months, something gets released that looks like infrastructure plumbing but turns out to matter more than the flashy launches. Model Context Protocol (MCP) is one of those things.
If you’re a developer working with LLMs, MCP will change how you integrate AI into your workflows. Here’s an early-adopter perspective on what it is, why it matters, and how to actually use it.
What Problem Does MCP Solve?
Today’s AI tools are context-starved. You paste code into ChatGPT, upload files to Claude, manually copy database schemas into prompts. Every session starts from scratch. Every context window is a blank slate.
This is absurd.
Your IDE knows your codebase. Your browser knows your tabs. Your database has a schema. Why are you the middleman copying information between tools that should talk to each other?
MCP is a protocol for AI models to access external context sources directly. Instead of “paste your code here,” the model can ask “what files are in this project?” and get an answer.
It’s not magic—it’s plumbing. But it’s plumbing that enables magic.
MCP Architecture for Developers
MCP has three components:
1. MCP Hosts: Applications that want to use AI (Claude Desktop, IDEs, custom apps)
2. MCP Servers: Programs that expose data/functionality to AI (database connectors, file system access, API wrappers)
3. The Protocol: JSON-RPC communication between hosts and servers
┌─────────────┐ MCP Protocol ┌─────────────┐
│ MCP Host │◄───────────────────►│ MCP Server │
│ (Claude) │ JSON-RPC/stdio │ (Your DB) │
└─────────────┘ └─────────────┘
The key insight: MCP servers are just programs that respond to standard queries. You can write one in any language, for any data source.
How it differs from function calling
Function calling (tool use) lets models invoke specific functions you’ve defined. MCP is broader—it lets models discover what’s available and query it dynamically.
# Function calling: You predefine everything
tools = [
{"name": "get_user", "parameters": {...}},
{"name": "list_orders", "parameters": {...}},
]
# MCP: Model discovers capabilities
# "What resources are available?"
# → ["users", "orders", "products", "analytics"]
# "What can I do with users?"
# → [list, get, search, ...]
MCP is more flexible, but requires more trust. You’re giving the model keys to explore, not just execute predefined actions.
Building an MCP Server
Let’s build a simple MCP server that exposes a PostgreSQL database. This is genuinely useful—suddenly Claude can query your database schema, understand relationships, and help with queries.
# db_mcp_server.py
import asyncio
import json
from mcp.server import Server
from mcp.types import Resource, Tool, TextContent
import asyncpg
server = Server("postgres-explorer")
pool = None
@server.list_resources()
async def list_resources():
"""List available database resources."""
async with pool.acquire() as conn:
tables = await conn.fetch("""
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
""")
return [
Resource(
uri=f"postgres://tables/{t['table_name']}",
name=t['table_name'],
description=f"Table: {t['table_name']}"
)
for t in tables
]
@server.read_resource()
async def read_resource(uri: str):
"""Get schema for a specific table."""
table_name = uri.split("/")[-1]
async with pool.acquire() as conn:
columns = await conn.fetch("""
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = $1
ORDER BY ordinal_position
""", table_name)
schema = "\n".join([
f" {c['column_name']}: {c['data_type']}"
f" {'(nullable)' if c['is_nullable'] == 'YES' else ''}"
for c in columns
])
return TextContent(
type="text",
text=f"Table: {table_name}\n\n{schema}"
)
@server.list_tools()
async def list_tools():
"""Expose query capability as a tool."""
return [
Tool(
name="query",
description="Execute a read-only SQL query",
inputSchema={
"type": "object",
"properties": {
"sql": {"type": "string", "description": "SQL query"}
},
"required": ["sql"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict):
"""Execute the query tool."""
if name != "query":
raise ValueError(f"Unknown tool: {name}")
sql = arguments["sql"]
# Safety: only allow SELECT
if not sql.strip().upper().startswith("SELECT"):
return TextContent(
type="text",
text="Error: Only SELECT queries allowed"
)
async with pool.acquire() as conn:
rows = await conn.fetch(sql)
return TextContent(
type="text",
text=json.dumps([dict(r) for r in rows], default=str)
)
async def main():
global pool
pool = await asyncpg.create_pool(
"postgresql://user:pass@localhost/mydb"
)
await server.run()
if __name__ == "__main__":
asyncio.run(main())
Configure Claude Desktop to use this server:
// claude_desktop_config.json
{
"mcpServers": {
"postgres": {
"command": "python",
"args": ["/path/to/db_mcp_server.py"]
}
}
}
Now Claude can explore your database schema, understand table relationships, and help write queries—with real context, not guesses.
Use Cases That Make Sense
After building several MCP integrations, here’s where they shine:
Database introspection
The example above. Claude understanding your actual schema instead of inventing tables that don’t exist. Worth the setup for any database-heavy work.
Documentation access
Point an MCP server at your internal docs, and Claude can reference them when answering questions. Better than pasting docs into prompts.
@server.list_resources()
async def list_resources():
docs_path = Path("/path/to/docs")
return [
Resource(
uri=f"docs://{p.relative_to(docs_path)}",
name=p.stem,
description=f"Documentation: {p.stem}"
)
for p in docs_path.rglob("*.md")
]
Git repository analysis
Give Claude read access to your git history. “What changed in the last week?” “Who usually works on this file?” “Show me the commit that introduced this function.”
External API wrappers
Wrap frequently-used APIs as MCP tools. Instead of explaining API semantics in every prompt, Claude can discover and call them directly.
At Entropy Labs, we built an MCP server for our internal APIs. Now Claude can check deployment status, query metrics, and look up customer data—all without manual copy-paste.
Current Limitations
MCP is early-stage. Expect rough edges:
1. Ecosystem is immature. Pre-built servers exist for common tools (filesystem, GitHub, Slack), but you’ll write custom ones for anything domain-specific.
2. Security requires thought. MCP servers have access to real systems. A poorly-written server can expose sensitive data or allow unintended actions. Audit carefully.
3. Performance varies. Large resource lists or slow database queries can delay responses. Implement timeouts and pagination.
4. Discovery UX is evolving. Models don’t always explore available resources effectively. Sometimes you need to prompt “check the available MCP resources” explicitly.
5. Not all hosts support it equally. Claude Desktop has full support. Third-party integrations are catching up.
Security Considerations
MCP gives AI models access to real systems. Take security seriously:
1. Principle of least privilege. Your MCP server for database exploration should use a read-only database user. Don’t give Claude DROP TABLE permissions.
2. Input validation. The model controls tool inputs. Validate everything. SQL injection is a real risk if you’re not careful.
# Bad: Direct interpolation
sql = f"SELECT * FROM {arguments['table']}"
# Good: Whitelist validation
allowed_tables = ["users", "orders", "products"]
if arguments["table"] not in allowed_tables:
raise ValueError("Invalid table")
3. Rate limiting. Models can call tools repeatedly. Implement rate limits to prevent runaway queries.
4. Audit logging. Log every MCP call with timestamps and context. You’ll want this when debugging or investigating unexpected behavior.
5. Network isolation. Run MCP servers with minimal network access. They shouldn’t be able to reach arbitrary endpoints.
The Bigger Picture
MCP is part of a larger trend: AI systems becoming first-class participants in developer workflows, not just chat windows you paste into.
Where this leads:
IDE integration. Your editor’s AI isn’t just autocompleting—it’s understanding your entire project, git history, and documentation.
Agentic workflows. AI that can actually do things: run tests, check CI status, deploy to staging. MCP provides the plumbing.
Custom enterprise AI. Organizations can expose internal knowledge bases, APIs, and databases to AI tools without sending data to external services.
Standardization. MCP is open spec. If it gains adoption, we’ll see interoperability between AI tools that currently don’t talk to each other.
This is infrastructure work. It’s not as exciting as a new model release. But it’s what turns capable models into capable systems.
Getting Started
If you want to experiment:
- Install Claude Desktop and enable MCP in settings
- Try existing servers: Filesystem, GitHub, and Postgres servers exist as reference implementations
- Build something small: Start with a read-only server exposing one data source
- Iterate on discovery: Watch how Claude explores resources and tune your server’s descriptions
The learning curve is manageable if you’ve built APIs before. The mental shift is thinking about what context would help the model, then building servers to provide it.
The Bottom Line
MCP solves the “context starvation” problem that limits current AI tools. It’s not a product—it’s infrastructure that makes better products possible.
For developers, the implications are:
- Less copy-paste, more integration
- AI tools that understand your environment, not generic examples
- Custom workflows that weren’t possible before
If you’re building AI-powered developer tools, MCP is worth learning now. The ecosystem is early, but the direction is clear.
And honestly? Building MCP servers is kind of fun. There’s something satisfying about giving Claude access to your systems and watching it figure things out.
