Building MCP servers

An MCP server is a small program that exposes tools, resources, or prompts. You can write one in under 100 lines of TypeScript or Python. Most of the work is thinking about what to expose and how.

The SDKs

Anthropic maintains official MCP SDKs in:

Community SDKs exist for Go, Rust, Java, and more. The protocol is simple enough to implement from scratch if needed.

Server lifecycle

Every MCP server handles six message types:

  1. initialize, client says hi, negotiates protocol version and capabilities
  2. list_tools / list_resources / list_prompts, client asks what's available
  3. call_tool, client executes a tool
  4. read_resource, client reads a resource
  5. get_prompt, client fetches a filled prompt
  6. shutdown, client is disconnecting

Minimal TypeScript example

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new Server(
  { name: "hello-mcp", version: "0.1.0" },
  { capabilities: { tools: {} } }
);

server.setRequestHandler("tools/list", async () => ({
  tools: [{
    name: "say_hello",
    description: "Returns a greeting",
    inputSchema: {
      type: "object",
      properties: { name: { type: "string" } },
      required: ["name"]
    }
  }]
}));

server.setRequestHandler("tools/call", async (req) => {
  const { name, arguments: args } = req.params;
  if (name === "say_hello") {
    return {
      content: [{ type: "text", text: `Hello, ${args.name}!` }]
    };
  }
  throw new Error("Unknown tool");
});

await server.connect(new StdioServerTransport());

Design patterns

Thin wrapping of an existing API

Most MCP servers just wrap an HTTP API (GitHub, Notion, Stripe). Each tool corresponds to one API endpoint. Thin wrappers are the most common and usually best, they're easy to maintain and update.

Aggregate over multiple systems

Sometimes a single tool should hit multiple systems, e.g, a "find person" tool that searches LinkedIn, your CRM, and your email. Useful but harder to maintain.

Resource-first

For data-heavy servers (document stores, databases), resources are the right primitive. Model the data as addressable URIs, let the client pin specific items into context.

What to NOT do

Testing your server

The official SDKs ship with an inspector tool (@modelcontextprotocol/inspector). It connects to your server, lists tools, lets you call them manually, and shows raw protocol traffic. Use it before connecting your server to a real agent.

Publishing

If your MCP is generally useful, publish it to npm (TypeScript) or PyPI (Python). Add an entry to your README showing how to install and configure. See the Directory for inspiration.