An MCP server is the piece of code that gives an AI application access to your tools and data through one standard protocol, instead of a custom integration for every app. This guide covers what a server is, the parts it exposes, how it talks to clients, how to build a minimal one, and what to lock down before you ship it. Every claim links to the official MCP docs, the spec, or Anthropic's launch post.
What is an MCP server?
The Model Context Protocol (MCP) is an open standard that Anthropic open-sourced on Nov 25, 2024 for "connecting AI assistants to the systems where data lives." The pitch was to replace "fragmented integrations with a single protocol" (Anthropic announcement). The launch shipped three pieces: the specification and SDKs, local MCP server support in the Claude Desktop apps, and an open-source repository of MCP servers (Anthropic; repo: modelcontextprotocol/servers).
The official docs define an MCP server as "a program that provides context to MCP clients." That applies whether it runs on your laptop or on someone else's platform (MCP architecture overview).
One scope note from the docs is worth keeping in mind: MCP "focuses solely on the protocol for context exchange—it does not dictate how AI applications use LLMs or manage the provided context" (architecture). Your agent framework still owns the loop, memory and approvals.
How do MCP hosts, clients and servers fit together?
MCP has three participants (architecture):
- Host: the AI application, such as Claude Desktop, Claude Code or VS Code. It coordinates one or more clients.
- Client: a component inside the host that keeps a dedicated connection to one server. The host creates one client per server.
- Server: the program that exposes context and actions.
The docs' example: when VS Code connects to the Sentry MCP server and to a local filesystem server, it creates two separate client objects, one per connection (architecture).
What can an MCP server expose?
Servers offer three core primitives (architecture):
| Primitive | What it is | Example |
|---|---|---|
| Tools | Executable functions the AI app can invoke | File operations, API calls, database queries |
| Resources | Data sources that provide context | File contents, database records, API responses |
| Prompts | Reusable templates for interacting with the model | System prompts, few-shot examples |
Each primitive has list methods (*/list) for discovery, plus retrieval or execution methods such as tools/call. Lists can change at runtime (architecture). The docs' database example uses all three: tools to run queries, a resource holding the schema, and a prompt with few-shot examples.
Clients can offer things back to servers too. Elicitation lets a server ask the user for more information or for confirmation of an action. Sampling (asking the client's model for a completion) and logging are deprecated as of protocol version 2026-07-28. New servers should call LLM APIs directly and log to stderr or OpenTelemetry instead (architecture).
How does an MCP server talk to a client?
MCP has two layers (architecture).
Data layer: a JSON-RPC 2.0 protocol for discovery, primitives and notifications. The current docs describe MCP as stateless. Every request carries the protocol version and client capabilities in its _meta field. Servers must implement server/discover, which returns supported versions and capabilities, though clients don't have to call it first.
Transport layer: there are two transports.
- stdio: for local processes on the same machine, with no network overhead.
- Streamable HTTP: HTTP POST with optional Server-Sent Events for streaming. This is what remote servers use. It supports bearer tokens, API keys and custom headers, and MCP recommends OAuth for getting tokens.
In practice, a local stdio server typically serves one client, while a remote Streamable HTTP server typically serves many (architecture).
A tool call is plain JSON-RPC. The client lists tools with tools/list and gets back each tool's name, title, description and inputSchema (a JSON Schema). Then it invokes one with tools/call, passing name and arguments (tools spec).
How do I build a simple MCP server?
The official Build an MCP server tutorial builds a weather server with two tools, get_alerts and get_forecast. It covers Python, TypeScript, Java, Kotlin, C#, Ruby, Rust and Go. The Python version, condensed:
uv init weather && cd weather
uv venv && source .venv/bin/activate
uv add "mcp[cli]"
from mcp.server import MCPServer
mcp = MCPServer("weather")
@mcp.tool()
async def get_alerts(state: str) -> str:
"""Get weather alerts for a US state.
Args:
state: Two-letter US state code (e.g. CA, NY)
"""
... # call the API, return text
if __name__ == "__main__":
mcp.run(transport="stdio")
What the tutorial tells you:
- Versions: Python 3.10+ and the Python MCP SDK 2.0.0 or higher.
- Tool definitions:
MCPServergenerates them from your type hints and docstrings. - Never write to stdout in a stdio server. It "will corrupt the JSON-RPC messages and break your server." That means no
print()in Python and noconsole.log()in TypeScript. Log to stderr instead. - Connecting to Claude Desktop: add the server under
mcpServersinclaude_desktop_config.json, give an absolute path, then fully quit and restart the app. - TypeScript:
serveStdionegotiates the protocol revision with each client. The tutorial suggests checking both eras with the Inspector CLI (--protocol-era modernand--protocol-era legacy).
How should tool results and errors be returned?
From the tools spec:
- Results go in a
contentarray (text, image, audio, resource links, embedded resources). Structured data can also go instructuredContent. If you declare anoutputSchema, servers must return conforming results. - Errors come in two kinds. Protocol errors (unknown tool, malformed request) use standard JSON-RPC errors. Tool execution errors (API failures, bad input, business-logic failures) come back as a normal result with
isError: true, so the model can see them and retry. Clients should pass execution errors to the model. - Tool names should be 1–128 characters from
A-Z a-z 0-9 _ - ., and unique within a server. Clients that combine several servers should prefix names to avoid collisions. - State across calls: MCP "has no protocol-level session." To keep state between calls (a cart, a browser context), return an explicit handle from a creation tool and accept it on later calls. Check the caller's authorization against that handle on every call.
Is an MCP server safe to give to an agent?
Only with guardrails. The spec puts responsibilities on both sides (tools spec).
- Humans in the loop: "There SHOULD always be a human in the loop with the ability to deny tool invocations." Apps should show which tools are exposed, indicate when they're invoked, and ask for confirmation.
- Servers MUST:
- validate all tool inputs
- implement access controls
- rate-limit invocations
- sanitize outputs
- Clients SHOULD:
- confirm sensitive operations
- show tool inputs before calling
- validate results before passing them to the model
- set timeouts and log tool usage for audits
- Annotations: clients MUST treat tool annotations as untrusted unless the server is trusted.
- Secrets in headers: don't mark secrets or personal data with
x-mcp-header, because those values become HTTP headers that intermediaries can see.
The protocol tells the client to ask a human. It doesn't make the action safe to repeat. If an approved tool charges a card or sends an email, your agent still needs to make sure a retry or a resumed run can't fire it twice. That's the side-effect problem our templates are built around. See LangGraph idempotent approval and OpenAI Agents SDK approval + resume.
FAQ
What is the difference between an MCP server and an MCP client?
The server is the program that exposes tools, resources and prompts. The client lives inside the host app and keeps one dedicated connection to one server (architecture).
Should I use stdio or Streamable HTTP?
Use stdio for a local server launched by the host on the same machine. Use Streamable HTTP for a remote server that many clients reach over the network, ideally with OAuth-issued tokens (architecture).
What are MCP tools, resources and prompts?
Tools are functions the AI app can call. Resources are data it can read for context. Prompts are reusable interaction templates (architecture).
Why does my stdio MCP server break when I add print statements?
Stdout carries the JSON-RPC messages, so anything else written there corrupts them. Log to stderr instead (build-server tutorial).
Does MCP require human approval for tool calls?
The spec says there SHOULD always be a human able to deny tool invocations, and clients SHOULD confirm sensitive operations. The protocol doesn't force a particular UI (tools spec).
Who created MCP?
Anthropic open-sourced it on Nov 25, 2024. It was created by David Soria Parra and Justin Spahr-Summers (Anthropic).
Related on Agent Signal:
- LangGraph vs CrewAI: which agent framework to use
- AI agent memory: types, architecture and tools
- Duplicate tool calls after resume
Agent Signal is a weekly newsletter for people building AI agents, with tested templates at tryagentsignal.com.