Build
Build an MCP server
An MCP server is a process that speaks JSON-RPC 2.0 over a transport. Local servers speak over stdio (the client spawns the server as a child process). Remote servers speak over Server-Sent Events (SSE) for the server-to-client stream and HTTP POST for the client-to-server requests. The protocol itself provides no authentication, no sandboxing, no secrets management. Those are the server author's job.
The shape of an MCP server
At runtime, a server is a long-running process that reads JSON-RPC 2.0 messages on one side and writes responses on the other. The 3 message shapes are fixed: Requests carry a method, params, and an id; Responses match an id and carry either a result or an error; Notifications carry a method and params and have no id.
Transport choice follows deployment. For a tool that runs on the developer's laptop, use stdio. The agent client (Claude Code, Claude Desktop, Cursor, Windsurf) spawns the server binary, writes JSON-RPC frames to its stdin, and reads frames from its stdout. For a hosted tool, use the SSE plus HTTP POST pair, or the newer Streamable HTTP transport. The wire format is identical; only the framing changes.
The 3 primitives you expose
Servers expose 3 kinds of capability. Pick the shape that matches what the model needs.
- Resources. Read-only data the model can reference. Each Resource is identified by a URI and carries a content type. Use Resources for file contents, database schemas, API response bodies, anything the model reads but does not act on.
- Tools. Invocable verbs with side effects. Each Tool ships a JSON Schema for its arguments. The client uses the schema to format the call; the server executes and returns a structured result or an error. Use Tools for actions: writing a record, sending an email, deploying a build.
- Prompts. Parameterized message templates the server offers to the user. Use Prompts when the server wants to suggest how the model should approach a specific task against this server's data.
The initialize handshake
Before any tool call lands, the client and server negotiate capabilities. The
client opens with an initialize request carrying its protocol version
and the capabilities it supports (Roots for filesystem boundaries, Sampling for
server-initiated LLM completions, Elicitation for user prompts). The server
responds with its protocol version and the primitives it exposes (Resources,
Tools, Prompts). The client sends notifications/initialized to
confirm. Only then does tools/list or resources/read
traffic begin.
Advertise only what you implement. A client that sees tools in your
capabilities map will call tools/list and expect a valid response.
A server that advertises a capability and returns errors loses trust fast.
The security responsibility
A stdio server runs as a child process of the agent client with the same OS
permissions the client has. That includes environment variables, API tokens, files
in the user's home directory, and outbound network access. Installing a third-party
MCP server carries the same threat profile as running npm install or
executing a downloaded binary.
Two recent incidents make the shape of the risk concrete. In April 2026, researchers disclosed a design flaw in the MCP STDIO transport where configuration input flows directly into subprocess commands without sanitization. Ad-hoc input filtering does not close it because the transport spec itself permits subprocess execution at the configuration layer. The flaw reached 150M+ downloads across Letta AI, LangFlow, and Windsurf.
In June 2025, CVE-2025-6514 hit the mcp-remote proxy (CVSS 9.6).
mcp-remote bridges local stdio clients to remote HTTP servers. When
connecting to a malicious remote server, the server returned a crafted
authorization_endpoint URL during OAuth discovery. The open
npm package passed that URL to the OS shell, and a URI shaped like
a:$(cmd.exe /c whoami) triggered pre-auth Remote Code Execution on
the client machine. The fix shipped in v0.1.16 on June 17, 2025.
If you ship a server, the build implications are direct. Validate every input
before it reaches a shell. Sanitize URLs you receive during OAuth discovery
before any process is spawned with them. Never pass user-controlled strings to
child_process.exec, PowerShell, or any shell that interprets
metacharacters. Treat tool descriptions as untrusted when they come back from
tools/list on a server you do not own; the 4 spec-level attack
patterns (Tool Poisoning, Cross-Server Shadowing, Rug Pulls, Return Value
Injection) all exploit the trust the LLM places in those strings.
Official SDKs
Start from the official SDKs published at github.com/modelcontextprotocol.
The wire protocol is identical across them; SDK choice follows host language.
- Python SDK.
modelcontextprotocol/python-sdk. Decorator-driven Tool and Resource registration. Best fit for data-science and agent tooling on Python runtimes. - TypeScript SDK.
modelcontextprotocol/typescript-sdk. Async/await primitives, ships as ESM. Best fit for Node servers and Cloudflare Workers. - C# SDK. Maintained jointly with Microsoft. Targets .NET 8+ and integrates with Semantic Kernel.
- Java SDK. Maintained jointly with Spring AI. Targets JDK 17+.
- Kotlin, Rust, Go, Swift SDKs. Community-maintained, varying stability. Check the official spec repo for the current status before relying on one.
After you build it
Once the server runs locally and the client invokes a Tool successfully, 3 steps get it in front of users.
Publish. Push to GitHub under a clear name. Register the server
with the Linux Foundation's official MCP registry at
registry.modelcontextprotocol.io. The canonical registry is the
index every major agent client and discovery tool federates from.
Get it scored. Submit the repository to the MCPowered scanner. The trust score combines a static scan of the source (looking for the 4 attack patterns above), a behavioral scan in a sandbox (network calls, file reads, subprocess spawns the server actually performs), supply-chain provenance (publisher identity, repository signals, install volume curve), and incident history. The methodology is published; the score is free.
Harden against the known attack classes. The security best-practices spoke walks through the concrete mitigations: signing tool descriptions to prevent rug pulls, scoping OAuth tokens per session, validating URI inputs before subprocess execution, redacting secrets from log output. Run the checklist before you mark the server production-ready.