{
  "slug": "building-mcp-servers",
  "title": "Building an MCP Server",
  "description": "Implementation guide for MCP servers: architecture roles, the three server primitives, stdio vs Streamable HTTP transports, official SDKs, server lifecycle, remote-server concerns, testing with MCP Inspector, and publishing to the official registry.",
  "category": "Guide",
  "tags": [
    "mcp",
    "tools",
    "protocols",
    "agents",
    "implementation"
  ],
  "updated": "2026-07-10",
  "premium": false,
  "canonical": "https://changegamer.ai/resources/building-mcp-servers",
  "markdown": "https://changegamer.ai/resources/building-mcp-servers.md",
  "outline": [
    {
      "depth": 2,
      "text": "Key facts",
      "anchor": "key-facts"
    },
    {
      "depth": 2,
      "text": "Architecture: host, client, server",
      "anchor": "architecture-host-client-server"
    },
    {
      "depth": 2,
      "text": "The three server primitives",
      "anchor": "the-three-server-primitives"
    },
    {
      "depth": 2,
      "text": "Transports: stdio and Streamable HTTP",
      "anchor": "transports-stdio-and-streamable-http"
    },
    {
      "depth": 2,
      "text": "Official SDKs",
      "anchor": "official-sdks"
    },
    {
      "depth": 2,
      "text": "Minimal server lifecycle",
      "anchor": "minimal-server-lifecycle"
    },
    {
      "depth": 2,
      "text": "Remote-server concerns",
      "anchor": "remote-server-concerns"
    },
    {
      "depth": 2,
      "text": "Testing: MCP Inspector",
      "anchor": "testing-mcp-inspector"
    },
    {
      "depth": 2,
      "text": "Publishing and discovery",
      "anchor": "publishing-and-discovery"
    },
    {
      "depth": 2,
      "text": "ChangeGamer's /mcp endpoint",
      "anchor": "changegamer-s-mcp-endpoint"
    },
    {
      "depth": 2,
      "text": "Verified sources",
      "anchor": "verified-sources"
    }
  ],
  "related": [
    {
      "slug": "mcp-server-discovery",
      "title": "Finding and Evaluating MCP Servers",
      "description": "How to discover, assess and safely integrate MCP servers into agent pipelines.",
      "url": "https://changegamer.ai/resources/mcp-server-discovery"
    },
    {
      "slug": "mcp-vs-a2a",
      "title": "MCP vs A2A: Two Protocols, Two Roles",
      "description": "Compact comparison of the Model Context Protocol (agent↔tool) and the Agent2Agent Protocol (agent↔agent): purpose, topology, transport, discovery, auth, governance, and when to use each.",
      "url": "https://changegamer.ai/resources/mcp-vs-a2a"
    },
    {
      "slug": "mcp-apps-explained",
      "title": "MCP Apps Explained: The Official Interactive-UI Extension for MCP",
      "description": "What MCP Apps (SEP-1865) is: the ui:// resource scheme and sandboxed-iframe/JSON-RPC bridge it defines for MCP tools to return rendered UI instead of plain text, how it relates to the community MCP-UI project and OpenAI's Apps SDK, and which hosts support it.",
      "url": "https://changegamer.ai/resources/mcp-apps-explained"
    },
    {
      "slug": "mcp-2026-spec-revision",
      "title": "MCP Goes Stateless: The 2026-07-28 Spec Revision Explained",
      "description": "What changes in MCP's largest revision since launch: SEP-2575/SEP-2567 remove the session handshake and Mcp-Session-Id header for explicit state handles, new Mcp-Method/Mcp-Name routing headers, full JSON Schema 2020-12 tool schemas, and six authorization-hardening SEPs — shipped as final, on schedule, on 2026-07-28.",
      "url": "https://changegamer.ai/resources/mcp-2026-spec-revision"
    }
  ],
  "furtherReading": [
    {
      "slug": "mcp-oauth-implementation",
      "title": "How to Implement OAuth 2.1 for an MCP Server",
      "description": "A wire-level implementation walkthrough for OAuth 2.1 on a remote MCP server: what the discovery documents actually contain, CIMD vs. Dynamic Client Registration in your server code, per-SEP detail from the 2026-07-28 hardening set, and token-validation mechanics.",
      "url": "https://changegamer.ai/articles/mcp-oauth-implementation"
    },
    {
      "slug": "mcp-server-in-production",
      "title": "MCP Server in Production: How to Build, Ship and Run One",
      "description": "The operator playbook for taking an MCP server past the quickstart: transport choice, OAuth 2.1 auth, tool design, versioning against a moving spec, testing across clients, distribution, observability, cost and the failure modes that show up once real clients connect.",
      "url": "https://changegamer.ai/articles/mcp-server-in-production"
    }
  ],
  "body": "The Model Context Protocol (MCP) gives a host application a uniform way to connect an AI model to external tools, data, and prompt templates. This guide covers what you need to implement a server — from wire format to deployment. For finding and evaluating existing servers see /resources/mcp-server-discovery; for OAuth 2.1 auth on remote servers see /resources/mcp-server-authentication.\n\n## Key facts\n\n- Every MCP deployment involves three roles — a host application, a client managing one connection per server, and the server itself — exchanging JSON-RPC 2.0 messages.\n- Servers expose three distinct primitives suited to different jobs: tools for the agent to *do* something, resources for it to *read* subscribable URI-identified data, and prompts for distributing ready-made, parameterized instruction snippets.\n- The two standard transports have very different footprints: stdio runs locally as a child process with zero network exposure, while Streamable HTTP runs as a remote endpoint that has to check where each incoming connection claims to originate from, guarding against DNS-rebinding attacks.\n- Every session, on either transport, follows the same lifecycle: initialize, initialized, discovery (listing tools/resources/prompts), invocation, and shutdown.\n- Remote Streamable HTTP servers carry extra concerns local stdio servers don't: PKCE-based OAuth belongs on that side, a missing session ID leaves the server effectively stateless, and CORS needs to be locked down to known client origins.\n- MCP Inspector is the official tool for manually connecting to a server, browsing its primitives, and inspecting the raw JSON-RPC traffic.\n- Publishing to the official registry means adding a `server.json` manifest describing the server, then running the `mcp-publisher` CLI to log in and publish.\n\n## Architecture: host, client, server\n\nThree roles exist in every MCP deployment:\n\n- **Host** — the application that owns the model interaction (e.g. Claude for Desktop, a custom agent). It spawns or connects to MCP servers and mediates access.\n- **Client** — a component inside the host that manages one connection to one MCP server, running the JSON-RPC 2.0 message exchange.\n- **Server** — the process or endpoint you build. It declares capabilities during initialization and handles requests for tools, resources, and prompts.\n\nAll messages between client and server are JSON-RPC 2.0 objects: requests carry an `id`, `method`, and optional `params`; responses carry the same `id` plus `result` or `error`. Notifications are one-way (no `id`, no response expected).\n\n## The three server primitives\n\n**Tools** are model-invoked functions. The client calls `tools/list` to discover them; the model selects and calls one via `tools/call`. Each tool has a `name`, `description`, and an `inputSchema` (JSON Schema). Results are returned as typed content blocks (text, image, audio, resource link). Use tools when the agent needs to *do* something — query an API, run a calculation, write to a database.\n\n**Resources** are read-only data the client can subscribe to: files, database rows, live feeds. They are identified by URI. Use resources when the agent needs to *read* structured data that may change over time.\n\n**Prompts** are named, parameterised prompt templates served by the server. The client fetches them via `prompts/get` and injects them into the conversation. Use prompts to share curated instruction fragments without embedding them in the client.\n\n## Transports: stdio and Streamable HTTP\n\nThe current MCP spec (stable revision: **2025-11-25**; treat as a snapshot, verify at modelcontextprotocol.io) defines two standard transports.\n\n**stdio (local)** — the host launches the server as a child process. JSON-RPC messages are exchanged over stdin/stdout, delimited by newlines. The server MUST NOT write anything to stdout except valid MCP messages; use stderr for logs. stdio carries zero network exposure and is the right choice for local tools running on the same machine.\n\n**Streamable HTTP (remote)** — the server runs as an independent network process. All client messages are HTTP POST requests to a single MCP endpoint; the server may respond with `application/json` (single response) or `text/event-stream` (SSE stream for multi-message responses). An optional `Mcp-Session-Id` header supports stateful sessions. The server MUST validate the `Origin` header on every incoming connection to prevent DNS rebinding attacks.\n\n## Official SDKs\n\nAll SDKs are under the `modelcontextprotocol` GitHub org. Treat version numbers as a snapshot; verify current releases before pinning.\n\n| Language | Package | Install |\n|---|---|---|\n| TypeScript | `@modelcontextprotocol/sdk` | `npm install @modelcontextprotocol/sdk` |\n| Python | `mcp` | `pip install mcp` (or `uv add \"mcp[cli]\"`) |\n| Kotlin | `modelcontextprotocol/kotlin-sdk` | Maven/Gradle — maintained with JetBrains |\n| Go | `modelcontextprotocol/go-sdk` | `go get` — maintained with Google |\n| Swift | `modelcontextprotocol/swift-sdk` | Swift Package Manager |\n| C# | `modelcontextprotocol/csharp-sdk` | NuGet (`ModelContextProtocol`) — maintained with Microsoft; reached v1.0 (WebSearch-corroborated, not independently re-fetched this cycle) |\n\n## Minimal server lifecycle\n\nRegardless of transport, every session follows this sequence:\n\n1. **initialize** — client sends `initialize` with `protocolVersion` and its capabilities; server responds with its `protocolVersion`, `capabilities` (which primitives it supports), and `serverInfo`. The negotiated version governs the session.\n2. **initialized** — client sends the `notifications/initialized` notification; the session is now open for normal requests.\n3. **discovery** — client may call `tools/list`, `resources/list`, `prompts/list` to enumerate what the server offers.\n4. **invocation** — client sends `tools/call` (or equivalent) with the tool name and arguments; server runs the handler and returns a content array.\n5. **shutdown** — for stdio, the host closes stdin; for Streamable HTTP, the client sends `HTTP DELETE` with the session ID (if the server issued one).\n\nTypeScript minimal example (using `@modelcontextprotocol/sdk`):\n\n```typescript\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\n\nconst server = new McpServer({ name: \"example\", version: \"1.0.0\" });\n\nserver.registerTool(\"ping\", {\n  description: \"Return a pong\",\n  inputSchema: { message: z.string().optional() },\n}, async ({ message }) => ({\n  content: [{ type: \"text\", text: `pong: ${message ?? \"\"}` }],\n}));\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n```\n\n## Remote-server concerns\n\n**Authentication** — remote Streamable HTTP servers should implement OAuth 2.1 with PKCE. Full detail is in /resources/mcp-server-authentication.\n\n**Statelessness** — servers that do not issue an `Mcp-Session-Id` are effectively stateless: each POST is independent. This simplifies horizontal scaling but means the server cannot hold in-memory state across requests.\n\n**CORS** — if the server will be called from browser-hosted clients, set `Access-Control-Allow-Origin` appropriately. Restrict origins to known client domains where possible.\n\n**Session handling** — if issuing session IDs, use cryptographically random values (UUID v4 or equivalent). Clients that receive HTTP 404 on a session-bearing request must start a new `initialize` exchange.\n\n## Testing: MCP Inspector\n\nThe official interactive testing tool is **MCP Inspector** (`@modelcontextprotocol/inspector` on npm). Run it with:\n\n```bash\nnpx @modelcontextprotocol/inspector\n```\n\nIt provides a UI to connect to any MCP server, browse its tools/resources/prompts, send calls manually, and inspect the raw JSON-RPC messages. Source: github.com/modelcontextprotocol/inspector.\n\n## Publishing and discovery\n\nThe official registry is at **registry.modelcontextprotocol.io**. To publish, add a `server.json` file to your repository (schema: `https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json`) describing your server's name, version, transport type, and endpoint URL, then use the `mcp-publisher` CLI (`mcp-publisher login github` → `mcp-publisher publish`). Publishing to the registry seeds downstream aggregators and client-vendor marketplaces. For evaluation criteria and security checks to apply before connecting to third-party servers, see /resources/mcp-server-discovery.\n\n## ChangeGamer's /mcp endpoint\n\nChangeGamer runs a remote MCP server at `https://changegamer.ai/mcp` using the Streamable HTTP transport. It is unauthenticated — no OAuth flow is required to connect. It is open and read-only. Premium resource bodies still require an `api_key` argument passed to the `get_resource` tool; this is an application-layer key check, not OAuth. ChangeGamer does not implement RFC 9728 Protected Resource Metadata.\n\n## Verified sources\n\n- MCP spec (stable 2025-11-25): https://modelcontextprotocol.io/specification/2025-11-25\n- MCP spec changelog (2025-11-25 vs 2025-06-18): https://modelcontextprotocol.io/specification/2025-11-25/changelog\n- MCP transports spec: https://modelcontextprotocol.io/specification/2025-11-25/basic/transports\n- MCP tools concept: https://modelcontextprotocol.io/docs/concepts/tools\n- MCP quickstart (server): https://modelcontextprotocol.io/quickstart/server\n- TypeScript SDK (npm: @modelcontextprotocol/sdk): https://github.com/modelcontextprotocol/typescript-sdk\n- Python SDK (PyPI: mcp): https://github.com/modelcontextprotocol/python-sdk\n- C# SDK, reached v1.0 (WebSearch-corroborated via the official repo and Microsoft .NET blog; not independently re-fetched this cycle): https://github.com/modelcontextprotocol/csharp-sdk\n- MCP Inspector (npm: @modelcontextprotocol/inspector): https://github.com/modelcontextprotocol/inspector\n- Official MCP registry: https://registry.modelcontextprotocol.io/\n- MCP registry GitHub (server.json spec): https://github.com/modelcontextprotocol/registry",
  "sources": [
    "https://modelcontextprotocol.io/specification/2025-11-25",
    "https://modelcontextprotocol.io/specification/2025-11-25/changelog",
    "https://modelcontextprotocol.io/specification/2025-11-25/basic/transports",
    "https://modelcontextprotocol.io/docs/concepts/tools",
    "https://modelcontextprotocol.io/quickstart/server",
    "https://github.com/modelcontextprotocol/typescript-sdk",
    "https://github.com/modelcontextprotocol/python-sdk",
    "https://github.com/modelcontextprotocol/csharp-sdk",
    "https://github.com/modelcontextprotocol/inspector",
    "https://registry.modelcontextprotocol.io/",
    "https://github.com/modelcontextprotocol/registry"
  ]
}