What you will be able to do
- Tell apart the host, client and server roles in MCP and say which one owns conversation history, consent and orchestration
- Choose between a local stdio server and a remote Streamable HTTP server, and say what each one must and must not do on the wire
- Register a local or remote MCP server with Claude Code using claude mcp add
- Declare server capabilities so clients know which primitives the server supports
- Define a tool with inputSchema and an optional outputSchema, handle tools/call, and return content, structuredContent or an input_required result
- Expose resources by URI and templates, and secure file:// resources against directory traversal
- Expose prompts with arguments through prompts/list and prompts/get, and return the correct errors for bad input
Key concept
MCP server — An MCP server is a focused, independent program that offers tools, resources and prompts to a host application. It reaches the host through a client that talks only to that server. The host keeps the conversation and makes the security decisions, so the server only has to implement the protocol messages for the primitives it advertises.
1.Hosts, clients and servers
MCP splits an integration into three roles, and many server-development questions come down to which role owns a given job. The host is the application the user runs. It creates and manages multiple client instances, controls their connection permissions and lifecycle, enforces security policies and consent requirements, and coordinates the AI/LLM integration. A client lives inside the host and communicates with exactly one server. It attaches the protocol version and capabilities to every request and routes messages in both directions. The server is the part you write. It exposes resources, tools and prompts, and it can be a local process or a remote service.
| Role | Responsibilities |
|---|---|
| Host | Creates and manages multiple client instances; enforces security policies and consent; handles user authorization decisions; coordinates AI/LLM integration and sampling; aggregates context across clients |
| Client | Communicates with exactly one server; attaches protocol version and capabilities to every request; routes messages both ways; manages subscriptions and notifications; keeps security boundaries between servers |
| Server | Exposes resources, tools and prompts; operates independently with focused responsibilities; requests client input (sampling, elicitation, roots) via InputRequiredResult within a reply; can be a local process or a remote service |
The split is intentional. The specification says servers should be extremely easy to build because host applications handle the complex orchestration. It also says servers should be highly composable: each one provides focused functionality in isolation, and several can be combined through the shared protocol. Isolation sets a hard limit on server design. A server receives only the context it needs, and it cannot see into other servers. Cross-server interactions are controlled by the host. If a server needs something from the client side, such as sampling, elicitation or roots, it does not reach into the host. It asks for that input inside its reply.
How a client reaches a server is the communication pattern, and it also decides how you deploy the server. Over stdio, the client launches the server as a child process. The server reads JSON-RPC messages from stdin and writes JSON-RPC messages to stdout. Each message is a single request, notification or response. Messages are delimited by newlines and must not contain embedded newlines. Because stdout carries the protocol, the server must not write anything to it that is not a valid MCP message. The client likewise must not write anything to the server's stdin that is not a valid MCP message. Logging goes to stderr, which the client may capture, forward or ignore. The client should not treat stderr output as an error. To shut down, the client closes the input stream to the child process, waits for the server to exit, and forcibly terminates it if it does not exit in a reasonable time.
The other transport defined in the specification is Streamable HTTP, used for remote servers. The server exposes a single HTTP endpoint, the MCP endpoint, that accepts POST. The client sends every JSON-RPC request or notification as its own HTTP POST. It must include an Accept header listing both application/json and text/event-stream. The server answers each request with either one JSON object or a Server-Sent Events stream scoped to that request. When running locally, a server should bind only to localhost (127.0.0.1) rather than all network interfaces, must validate the Origin header, and should implement authentication. Raw network sockets are not one of the two transports these specification pages define. Claude Code's own configuration additionally accepts a WebSocket entry of type ws with a wss:// URL.
Deployment is therefore a choice of where the server runs. A launch command such as npx -y @example/mcp-server means the server runs on your machine over stdio. A URL such as https://mcp.example.com/mcp means the server is remote. You register either kind with Claude Code through claude mcp add:
claude mcp add example --env API_KEY=your-key -- npx -y @example/mcp-serverclaude mcp add --transport http example https://mcp.example.com/mcp2.Declaring what the server supports
Before any primitive is used, both sides declare what they support. Servers declare capabilities such as tool support, resource subscriptions and prompt templates. Clients declare capabilities such as sampling support and elicitation handling. Both sides must respect the declared capabilities for the whole interaction. For a server author, this means every feature you implement has to be advertised, and a client can only invoke tools if your server declares the tool capability. Features can be added gradually: the core protocol is small, and extra capabilities are negotiated as needed.
{
"capabilities": {
"resources": {
"listChanged": true,
"subscribe": true
}
}
}Each primitive has its own capability object. For resources, listChanged says whether the server will send a notification when the list of available resources changes. subscribe says whether it supports update notifications for specific resources, requested through subscriptions/listen. A server that offers resources without either feature can declare an empty object, "resources": {}. Tools and prompts use the same listChanged flag.
The server sends the notification notifications/tools/list_changed. The client learns about the new tool by calling tools/list again. Declaring listChanged is the server's promise that it will send this notification.
3.Authoring tools: definitions, calls and results
A tool definition has a unique name, an optional display title, a description, optional icons, an inputSchema, an optional outputSchema and optional annotations. The inputSchema must be a valid JSON Schema object, not null. If it has no $schema field, it defaults to draft 2020-12. For a tool with no parameters, the recommended schema is { "type": "object", "additionalProperties": false }, which accepts only empty objects. Tool names should be 1 to 128 characters long, are treated as case-sensitive, and should use only ASCII letters, digits, underscore, hyphen and dot. Names should be unique within a server. getUser, DATA_EXPORT_v2 and admin.tools.list are all valid.
Clients discover tools with tools/list, which is paginated by cursor. The response can include nextCursor, plus ttlMs and cacheScope hints. Clients run a tool with tools/call, passing the tool name and arguments that match the inputSchema:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"location": "New York"
}
}
}A completed result has resultType "complete", a content array and an isError flag. If the tool declares an outputSchema, the result also carries structuredContent. Servers must return structured results that conform to the schema, and clients should validate them against it. The schema can describe an object or an array. A tool can also return resultType "input_required" instead of finishing. For example, it might include an elicitation/create input request that asks the user for a GitHub username, along with an opaque requestState. The client then calls tools/call again with inputResponses and the same requestState.
| type | Carries |
|---|---|
| text | A text string |
| image | base64 data plus a mimeType, optionally with audience and priority annotations |
| audio | base64 data plus a mimeType |
| resource_link | A uri, name, description and mimeType that point to a resource |
| resource | An embedded resource with its uri, mimeType and text |
Tools can take real actions, so the specification expects the application to show which tools are exposed to the model, mark each invocation clearly, and ask the user for confirmation before operations. Changes to the tool list are announced with notifications/tools/list_changed.
A platform engineer is integrating a new MCP server into an internal Claude Code agent. The vendor's documentation instructs users to run `npx internal-tools-mcp` as a local process on the same machine that hosts the agent, and gives no network endpoint. Which transport type should the engineer configure for this server?
Correct answer: A — stdio
- A. Correct. When documentation gives a command to run rather than a URL, the server is a local process communicating over stdin/stdout, which is the stdio transport.
- B. Incorrect. SSE is used for cloud-hosted or remote servers reachable by URL, not a local command.
- C. Incorrect. Streamable HTTP also requires a URL endpoint; it does not apply to a locally run command.
- D. Incorrect. WebSocket is not one of the MCP transport types supported by the Agent SDK's mcpServers configuration.
Sources6
4.Exposing resources
Tools perform actions. Resources are data the server makes readable, and each one is identified by a URI. Besides the uri, a resource has a name and optional title, description, icons, mimeType and size. Clients list resources with resources/list and fetch them with resources/read:
{
"jsonrpc": "2.0",
"id": 2,
"method": "resources/read",
"params": {
"uri": "file:///project/src/main.rs"
}
}The result holds a contents array. Each entry has either a text field or a base64-encoded blob for binary data. For parameterised families of resources, a server publishes templates through resources/templates/list. For example, a uriTemplate of file:///{path} covers every file in a project. Annotations help the client decide what to use. audience is "user", "assistant" or both. priority runs from 0.0 (entirely optional) to 1.0 (effectively required). lastModified is an ISO 8601 timestamp. Clients may offer resources in a tree or list for the user to pick from, let users search and filter them, or include context automatically based on heuristics or the model's selection. A server announces list changes with notifications/resources/list_changed. It sends notifications/resources/updated for resources a client requested through subscriptions/listen, and each notification carries the subscriptionId in _meta.
Resource handling is a security boundary. Servers must validate every resource URI. They must sanitize file paths when serving file:// resources, must encode binary data properly, and should apply access controls and permission checks to sensitive resources. An unknown URI returns error -32602 with the message "Resource not found".
Sources5
5.Exposing prompts
The third primitive is the prompt: a named, reusable message template. A prompt has a name, an optional title, description and icons, and an optional list of arguments, each of which can be marked required. Clients discover prompts with prompts/list. They fill one in with prompts/get, passing values for its arguments:
{
"jsonrpc": "2.0",
"id": 2,
"method": "prompts/get",
"params": {
"name": "code_review",
"arguments": {
"code": "def hello():\n print('world')"
}
}
}The server returns a description and a messages array. Each message has a role of user or assistant and one content item. The item can be text, image, audio, a resource_link or an embedded resource, so a prompt can bring server data into the conversation. An embedded resource needs a valid URI, the correct MIME type, and either text or base64 blob data. Servers should validate prompt arguments before processing them. An invalid prompt name or a missing required argument returns -32602 (Invalid params), and internal failures return -32603. Changes to the prompt list are announced with notifications/prompts/list_changed.
Sources7
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.An MCP server can read the whole conversation and inspect other connected servers to build better answers.Why is that wrong?
Servers are isolated. They receive only the context they need, the host keeps the full conversation, and the host controls any interaction between servers.
Covered in Hosts, clients and servers
2.A stdio MCP server can print debug output to stdout, because the client will simply ignore anything that is not a protocol message.Why is that wrong?
On stdio, stdout carries the protocol itself, so stray output corrupts the message stream. Debug and error logging belongs on stderr.
Covered in Hosts, clients and servers
3.If a server has handlers for tools/call, clients can invoke its tools whether or not the server advertised them.Why is that wrong?
Capabilities are negotiated, and both sides must respect them. A server has to declare the tools capability before tools can be invoked.
Covered in Declaring what the server supports
4.A file:// resource URI from the client can be mapped straight onto the filesystem, because the client only asks for resources the server listed.Why is that wrong?
The server must validate every resource URI and sanitize file paths itself. Otherwise a crafted URI can escape the intended directory.
Covered in Exposing resources
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“Communicates with exactly one server”
↩︎ Hosts, clients and servers“Can be local processes or remote services”
↩︎ Hosts, clients and servers“Request client input (sampling, elicitation, roots) via InputRequiredResult within a reply”
↩︎ Hosts, clients and servers“Servers declare capabilities like tool support, resource subscriptions, and prompt templates”
↩︎ Declaring what the server supports“Expose resources, tools and prompts via MCP primitives”
↩︎ Key concept“Full conversation history stays with the host”
↩︎ Exam trap 1“Tool invocation requires the server to declare tool capabilities”
↩︎ Exam trap 3 - 2.
“The server reads JSON-RPC messages from stdin and writes JSON-RPC messages to stdout.”
↩︎ Hosts, clients and servers“Messages are delimited by newlines, and MUST NOT contain embedded newlines.”
↩︎ Hosts, clients and servers“The server MUST NOT write anything to its stdout that is not a valid MCP message.”
↩︎ Exam trap 2 - 3.https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-httpOfficial docs
“The server exposes a single HTTP endpoint (the MCP endpoint) that accepts POST.”
↩︎ Hosts, clients and servers - 4.https://code.claude.com/docs/en/mcpOfficial docs
“A launch command such as npx -y @example/mcp-server: the server runs on your machine.”
↩︎ Hosts, clients and servers“A URL such as https://mcp.example.com/mcp: the server is remote.”
↩︎ Hosts, clients and servers - 5.
“listChanged: whether the server will emit notifications when the list of available resources changes.”
↩︎ Declaring what the server supports“uri: Unique identifier for the resource”
↩︎ Exposing resources“Servers MUST validate all resource URIs”
↩︎ Exposing resources“Servers MUST sanitize file paths to prevent directory traversal attacks when serving file:// resources”
↩︎ Exam trap 4 - 6.
“inputSchema: JSON Schema defining expected parameters”
↩︎ Authoring tools: definitions, calls and results“Servers MUST provide structured results that conform to this schema.”
↩︎ Authoring tools: definitions, calls and results“Present confirmation prompts to the user for operations, to ensure a human is in the loop”
↩︎ Authoring tools: definitions, calls and results - 7.
“arguments: Optional list of arguments for customization”
↩︎ Exposing prompts“Missing required arguments: -32602 (Invalid params)”
↩︎ Exposing prompts