Architecture Overview
Claude Code (MCP Client)
↓ JSON-RPC over stdio/SSE
Your MCP Server
↓ Your code
External Service (API, DB, SaaS)Three Primitives
| Primitive | What It Does | Example |
|---|---|---|
| Tools | Actions the agent can take | create_issue, send_email |
| Resources | Data the agent can read | file://config.json, db://users |
| Prompts | Templates for common tasks | summarize_code, review_pr |
TypeScript Implementation
1. Project Setup
npx @anthropic/create-mcp-server my-server
cd my-server2. Define Tools
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server({ name: "my-server", version: "1.0.0" }, {
capabilities: { tools: {} }
});
server.setRequestHandler("tools/list", async () => ({
tools: [{
name: "create_ticket",
description: "Create a support ticket in our system",
inputSchema: {
type: "object",
properties: {
title: { type: "string", description: "Ticket title" },
priority: { type: "string", enum: ["low", "medium", "high"] }
},
required: ["title"]
}
}]
}));
server.setRequestHandler("tools/call", async (request) => {
if (request.params.name === "create_ticket") {
const { title, priority } = request.params.arguments;
// Call your API here
const ticket = await createTicket(title, priority);
return { content: [{ type: "text", text: `Created ticket #${ticket.id}` }] };
}
});
const transport = new StdioServerTransport();
await server.connect(transport);3. Define Resources
server.setRequestHandler("resources/list", async () => ({
resources: [{
uri: "config://app-settings",
name: "Application Settings",
mimeType: "application/json"
}]
}));
server.setRequestHandler("resources/read", async (request) => {
if (request.params.uri === "config://app-settings") {
return { contents: [{ uri: request.params.uri, text: JSON.stringify(settings) }] };
}
});Python Implementation
from mcp.server import Server
from mcp.types import Tool, TextContent
server = Server("my-server")
@server.list_tools()
async def list_tools():
return [Tool(
name="search_docs",
description="Search internal documentation",
inputSchema={"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]}
)]
@server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "search_docs":
results = search(arguments["query"])
return [TextContent(type="text", text=str(results))]
if __name__ == "__main__":
import asyncio
from mcp.server.stdio import stdio_server
asyncio.run(stdio_server(server))Testing
Add to .mcp.json:
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["./dist/index.js"]
}
}
}Restart Claude Code and test: "Use my-server to create a ticket titled 'Fix login bug'"
Deployment Patterns
| Pattern | When to Use |
|---|---|
| Local stdio | Dev tools, personal workflows |
| Docker | Team-shared servers |
| SSE (HTTP) | Remote/cloud deployment |
| npm package | Public distribution |
FAQ
Q: What is an MCP server? A: A program that exposes tools, resources, and prompts to AI agents via the Model Context Protocol — letting agents interact with external services.
Q: Which language should I use? A: TypeScript for web APIs and npm distribution. Python for data science and ML tools.
Q: How do I publish my MCP server?
A: Publish to npm (npx my-mcp-server) or PyPI (pip install my-mcp-server). Add to the MCP servers registry.