MCP Server Spec: Required Behavior and Optional Capabilities

The MCP server specification separates what every server must do from what it may offer. Knowing the split helps you plan a reliable server, pick compatible clients, and record the implementation choices your team needs to share.

Updated 6 min read

The MCP server specification defines exactly which behaviors every server must implement and which it may offer as optional capabilities. Required behavior is narrow by design, so any compliant client and server can connect; optional capabilities let servers expose tools, resources, and prompts to match their particular use case.

Knowing the split matters when you build a server, evaluate a client library, or check whether two implementations will work together. Tools like fenbs keep those implementation choices in Decisions and rules so every AI connected to the project reads the agreed approach rather than guessing from the spec alone.

What the specification covers

The specification, published at modelcontextprotocol.io (opens in a new tab), defines the full protocol between an MCP client and server. It covers message format, connection lifecycle, capability negotiation, data types, error codes, and each optional feature.

The protocol runs on JSON-RPC 2.0. Requests carry a method and an id. Notifications carry a method with no id. Responses are matched to requests by id. That base layer is the same whether the server runs as a local process or a remote HTTP endpoint.

The spec also describes the two standard transports — stdio for local servers and Streamable HTTP for remote ones — and the message shapes for each optional feature. See mcp server architecture for a wider picture of how the pieces connect.

Required behavior every server must implement

Only a small set of behaviors is required. A server that implements them can connect to any compliant client, even one that offers no optional capabilities.

  • Respond to the initialize request with the server's name, version, and the capabilities it supports.
  • Accept the initialized notification that tells the server the client is ready.
  • Return well-formed JSON-RPC 2.0 responses, including error objects with the correct numeric code and message string.
  • Handle shutdown gracefully when the client closes the connection.
  • If tools are declared in the capabilities response, respond correctly to tools/list.

The initialization handshake is where required and optional behavior first meet. The server declares its capabilities during initialize; the client declares its own. Neither side must offer the same set, but both must complete the handshake correctly for the session to proceed.

Recording the decisions your team makes about required behavior — the capabilities you will and will not implement — keeps later reviewers from reopening settled questions. fenbs is one place to store that record.

Optional capabilities a server may offer

Optional capabilities are declared in the initialize response. A client checks which ones the server lists before calling their methods. Calling a method the server did not declare is a protocol error.

  • Tools: tools/list and tools/call. The most common capability; most client apps require it.
  • Resources: resources/list, resources/read, and optionally resources/subscribe. For exposing file contents, database rows, or other named data.
  • Prompts: prompts/list and prompts/get. For providing reusable prompt templates with typed arguments.
  • Logging: logging/setLevel and log-message notifications from server to client.
  • Completions: completion/complete. Lets a client offer argument suggestions as the user types.

Sampling — the capability that let a server ask the client to run an inference call — is deprecated in the 2026-07-28 version of the specification. Check the current spec at modelcontextprotocol.io before building a server that depends on it.

How fenbs helps

Record the capabilities your server targets

Add the protocol version, the optional capabilities you chose to implement, and the clients you have tested against as Decisions and rules in fenbs. Every AI assistant connected to the project reads those rules first, so no one rebuilds a choice that is already settled. Create a free account at fenbs.ai, set up a project for the server work, and write the first decisions today.

Create a free account

Free for one person · No credit card · Works with Claude, ChatGPT, Cursor and more

Protocol versions and capability negotiation

Both client and server send a protocolVersion string during initialization. They agree on the highest version both support. If no shared version exists, the client closes the connection.

Version negotiation means a server built for a later spec revision can still talk to an older client, as long as both sides share at least one compatible version. Keep a note of the version your server targets and the clients you have tested — and revisit that note when a client updates.

Transport requirements

The spec defines two transports. Stdio uses standard input and output: the client starts the server as a child process and exchanges JSON-RPC messages through stdin and stdout. Streamable HTTP uses HTTP POST for client-to-server messages and a response stream for server-to-client ones.

Stdio is the transport for local servers. Claude Code and Claude Desktop both use it when they start a local server. Streamable HTTP is for remote servers that clients connect to over a network. The older SSE transport is still described in the spec but new implementations should prefer Streamable HTTP. See mcp server hosting for the deployment side.

Error handling requirements

Error responses must use the JSON-RPC 2.0 error object: a numeric code, a message string, and an optional data field. The spec reserves standard codes for parse errors, invalid requests, method-not-found, invalid parameters, and internal errors.

For tool-level errors — when a tool runs but produces a bad result — the response is a successful JSON-RPC response with isError: true in the tool content. That distinction matters: an AI assistant can read a tool error and explain it; a JSON-RPC error means the communication itself failed.

Reading the spec to make compatibility decisions

The most practical way to use the spec is to check declared capabilities before assuming a client supports something. A client may support tools without supporting resources or prompts. Look at what it declares, not just its name.

When you evaluate an existing server — from the best MCP servers list or the mcp server directory — compare its declared capabilities against what your client actually needs. A mismatch is easier to find before you write integration code than after.

How to do this with fenbs

  1. Create a free account and set up a project for the server you are building or evaluating.
  2. Add a Decisions and rules entry for the protocol version your server targets, with the date and the person who decided it.
  3. Record which optional capabilities you are implementing and why — and which you are deliberately leaving out.
  4. Add a context note for each client you have tested: the client name, the version, and the result.
  5. When the spec or a client updates, revisit each entry. Record a new decision that supersedes any choice that has changed.

fenbs does not store spec documents or run MCP connections itself. For the specification, keep the official link at modelcontextprotocol.io (opens in a new tab) in a project note and check it directly when you need the current text.

Questions people ask.

Is implementing tools required by the MCP spec?

No. Tools are an optional capability. A server declares them in the initialize response, and a client only calls tools/list and tools/call if the server declared them. The only required behaviors cover the initialization handshake and well-formed JSON-RPC 2.0 messages.

What happens if a client and server declare different protocol versions?

They negotiate the highest version both support. If no shared version exists, the client closes the connection. In practice, most current implementations share at least one compatible version, so this rarely blocks a connection.

What is the difference between a tool error and a JSON-RPC error in MCP?

A JSON-RPC error means the communication failed: the request was malformed, the method did not exist, or the server had an internal fault. A tool error means the call completed but the tool found a problem; the response is a success with isError: true in the tool content.

Is sampling still part of the MCP spec?

Sampling is deprecated in the 2026-07-28 version of the specification. Check the current spec at modelcontextprotocol.io before building a server that relies on it, as the behavior described in older guides may no longer apply.

Where is the MCP server specification published?

The specification is at modelcontextprotocol.io/specification. Check that page for the current version rather than relying on third-party summaries, which may not reflect recent changes.

Start with one thing.

Free for one person · No credit card · Works with Claude, ChatGPT, Cursor and more

There is nothing to set up first. Write one line and you’ve started.