Back to Articles|Published on October 28, 2026|12 min read

Reliable Context Article

Model Context Protocol (MCP) Explained

MCP's hosts, clients, servers, tools, resources and prompts under the stateless 2026-07-28 revision, with a JSON-RPC example and its gaps on provenance.

By Reliable Context Research

Model Context Protocol (MCP) Explained

Summary

  1. 01MCP replaces a matrix of custom integrations with a shared interface between AI applications and external data sources and tools.
  2. 02The host manages clients, permissions and conversation context. Each client connects to one server, which exposes tools, resources and prompts.
  3. 03Tools are model-controlled, resources are application-driven and prompts are user-controlled. Their control models distinguish when each primitive is used.
  4. 04Requests carry their own protocol version and client capabilities. Servers must not rely on earlier requests to establish that context.
  5. 05MCP standardizes the channel, while server design determines whether returned facts carry sources, supporting passages, timestamps and explicit statuses.
Inside this article
  1. 01The integration problem
  2. 02Architecture: hosts, clients and servers
  3. 03Server primitives: tools, resources and prompts
  4. 04Client features and capability negotiation
  5. 05Message format, statelessness and transports
  6. 06Worked example: a supplier-facts server
  7. 07What MCP does not guarantee
  8. 08Design checklist for fact-returning servers

The integration problem

A language model is only as useful as the context it can reach. In an organization, that context is spread across document stores, databases, ticketing systems and line-of-business applications. Before a shared protocol existed, every pairing of an AI application with a data source needed its own connector. When Anthropic introduced the Model Context Protocol (MCP) on 25 November 2024, it described the problem in those terms: "Every new data source requires its own custom implementation, making truly connected systems difficult to scale", and presented MCP as "a new standard for connecting AI assistants to the systems where data lives" [1].

The current specification describes MCP as "an open protocol that enables seamless integration between LLM applications and external data sources and tools", and says it takes inspiration from the Language Server Protocol, which standardized how editors support programming languages [2]. The analogy is useful: one protocol on each side replaces a matrix of one-off integrations.

This article explains MCP as an interface contract: who the parties are, what they can exchange, and how a request looks on the wire. It then asks a question the protocol leaves open: what does a server owe an agent about where a returned value came from?

Which revision this describes

MCP revisions are named by date. As of 28 October 2026, the specification's "latest" address resolves to revision 2026-07-28. That revision changed the protocol substantially from 2025-11-25 and earlier: it removed the initialize handshake and protocol-level sessions, made every request self-contained, added a mandatory server/discover method, and deprecated the Roots, Sampling and Logging features [3]. The specification calls revisions that use per-request metadata "modern" and those that use the initialize handshake "legacy" [4]. Much published material, including many tutorials, describes the legacy model. Everything below follows 2026-07-28 unless stated.

2.0JSON-RPC version used for MCP messages
-32602Error for a request missing required protocol version or client capabilities metadata

Architecture: hosts, clients and servers

MCP "follows a client-host-server architecture where each host can run multiple client instances" [5]. The three roles are distinct:

RoleWhat it isResponsibilities in the specification
HostThe AI application the user interacts with: a chat interface, an IDE, an agent runtimeCreates and manages clients; controls connection permissions; enforces security policies and consent requirements; handles user authorization decisions; coordinates the model; aggregates context across clients
ClientA connector inside the hostCommunicates with exactly one server; attaches protocol version and capabilities to every request; routes messages; maintains security boundaries between servers
ServerA program that exposes context and capabilitiesExposes resources, tools and prompts; can be a local process or a remote service; must respect security constraints

Source: MCP, Architecture.

The one-client-per-server rule matters for isolation. One of the stated design principles is that "servers should not be able to read the whole conversation, nor 'see into' other servers": the full conversation history stays with the host, and cross-server interactions are controlled by the host [5]. A server that returns supplier data never sees what a second server returned about contracts, unless the host chooses to pass it.

Server primitives: tools, resources and prompts

Servers offer three kinds of feature. The specification distinguishes them by who decides when they are used:

PrimitiveControl modelPurposeMain methods
ToolsModel-controlled: "the language model can discover and invoke tools automatically"Functions the model can execute: query a database, call an API, computetools/list, tools/call
ResourcesApplication-driven: the host decides how to incorporate themContext and data identified by a URI, such as files, records or schemasresources/list, resources/read, resources/templates/list
PromptsUser-controlled: exposed so that "the user being able to explicitly select them"Templated messages and workflowsprompts/list, prompts/get

Sources: Tools, Resources, Prompts.

Tools carry a name, an optional title and description, an inputSchema (JSON Schema), and optionally an outputSchema and annotations describing behavior. Results can contain unstructured content (text, image, audio, resource links, embedded resources) and structured content in a structuredContent field that conforms to the outputSchema if one is declared. The specification states that clients "MUST consider tool annotations to be untrusted unless they come from trusted servers", and that there "SHOULD always be a human in the loop with the ability to deny tool invocations" [6].

Resources are identified by a URI and have a name, optional title, description, mimeType and size. Their contents are returned as text or base64 binary. Resources, templates and content blocks support three optional annotations: audience ("user", "assistant"), priority (0.0 to 1.0) and lastModified (an ISO 8601 timestamp) [7]. Keep that list in mind; it is the only provenance-like metadata the core resource model defines.

Prompts are reusable templates with arguments. The prompts page notes that "user-controlled" refers to who decides when the prompt is used, not who authors its content [8].

Whether an agent's context can be audited depends on what the server returns, which is a server design question.

Client features and capability negotiation

Clients can also offer features to servers. In 2026-07-28, the active one is elicitation: "server-initiated requests for additional information from users", in a form mode (structured data validated against a JSON schema) or a URL mode, which directs the user to an external URL for "sensitive interactions that must not pass through the MCP client" [2][9]. Roots (exposing file-system boundaries to a server) and Sampling (a server asking the host's model for a completion) remain functional but are deprecated; the changelog suggests passing paths as tool parameters instead of Roots and integrating directly with model provider APIs instead of Sampling [3].

Because servers no longer send requests to clients, a server that needs user input mid-operation uses the Multi Round-Trip Requests pattern: it answers with a result whose resultType is "input_required" and whose inputRequests describe what it needs; the client gathers the input and retries the original request, with a new JSON-RPC id, carrying inputResponses [10][6].

Capability negotiation is per request. Clients put their capabilities in _meta under io.modelcontextprotocol/clientCapabilities on every request; servers advertise theirs in response to server/discover, which every server must implement and which clients may call first [5][11]. A server "MUST NOT rely on capabilities the client has not declared" and returns a MissingRequiredClientCapabilityError if it needs one [12].

Message format, statelessness and transports

MCP messages are JSON-RPC 2.0, UTF-8 encoded. There are requests (with an id), responses (a result or an error, echoing the id) and notifications (no id) [12].

The 2026-07-28 revision is explicitly stateless: "all the information needed to process a request is contained in the request itself", and servers "MUST NOT rely on prior requests over the same connection to establish context (e.g., capabilities, protocol version, client identity)". State that spans requests "MUST be referenced by an explicit identifier the client passes on each request" [12]. Every request must carry io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities in _meta; a request missing them is rejected with error -32602.

Two standard transports are defined [13]:

  • stdio: newline-delimited JSON-RPC over the standard input and output of a subprocess the client launches; typical for local servers.
  • Streamable HTTP: each message is an HTTP POST to a single endpoint; replies arrive as a JSON object or a request-scoped server-sent-events stream; typical for remote servers.

For HTTP, the specification provides an authorization framework; stdio servers instead take credentials from their environment [12].

Worked example: a supplier-facts server

Halden Therapeutics AG (a fictional company) runs an MCP server, halden-supplier-facts, that answers questions about approved suppliers. An agent in a procurement assistant asks for the GMP certificate expiry date of Velmar Chemie GmbH (also fictional).

1. Discover the tool. The client lists tools. This request shows the required _meta; the specification's own examples omit it for brevity.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "procurement-assistant", "version": "3.2.0" },
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resultType": "complete",
    "tools": [
      {
        "name": "get_supplier_fact",
        "description": "Return one fact about an approved supplier, with its source.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "supplier_id": { "type": "string" },
            "property": { "type": "string" }
          },
          "required": ["supplier_id", "property"]
        },
        "outputSchema": {
          "type": "object",
          "properties": {
            "value": { "type": "string" },
            "status": { "type": "string", "enum": ["asserted", "unknown", "conflict"] },
            "source_uri": { "type": "string" },
            "evidence": { "type": "string" },
            "observed_at": { "type": "string" }
          },
          "required": ["status"]
        }
      }
    ],
    "ttlMs": 300000,
    "cacheScope": "private"
  }
}

The ttlMs and cacheScope fields are required on list results in this revision [3]. The outputSchema is Halden's design, not part of MCP.

2. Call the tool. (The _meta block is omitted from here on, as in the specification's examples.)

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "get_supplier_fact",
    "arguments": { "supplier_id": "S-77", "property": "gmp_certificate_expiry" }
  }
}
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "resultType": "complete",
    "structuredContent": {
      "value": "2027-05-31",
      "status": "asserted",
      "source_uri": "halden://documents/gmp-cert/DE-XX-2025-0193",
      "evidence": "valid until 31.05.2027",
      "observed_at": "2026-02-10T09:47:00Z"
    },
    "content": [
      { "type": "text", "text": "{\"value\":\"2027-05-31\",\"status\":\"asserted\",...}" },
      {
        "type": "resource_link",
        "uri": "halden://documents/gmp-cert/DE-XX-2025-0193",
        "name": "GMP certificate DE-XX-2025-0193",
        "mimeType": "application/pdf"
      }
    ],
    "isError": false
  }
}

A tool returning structured content "SHOULD also return the serialized JSON in a TextContent block" for backward compatibility, which is why the text block repeats it [6]. The resource_link lets the host fetch the source.

3. Read the source.

{ "jsonrpc": "2.0", "id": 3, "method": "resources/read",
  "params": { "uri": "halden://documents/gmp-cert/DE-XX-2025-0193" } }

The server returns the document in contents (here as a base64 blob with mimeType application/pdf), plus the required ttlMs and cacheScope.

Every field that makes this answer checkable (status, source_uri, evidence, observed_at) was defined by Halden. A different server could return {"value": "2027-05-31"} and be equally conformant.

Figure 01
From supplier question to source document
  1. 01Discover the tool

    List tools to discover the supplier-fact function and its input and output schemas.

  2. 02Call the tool

    Call get_supplier_fact with the supplier identifier and requested property. The result includes a value, status, source, evidence and observation time.

  3. 03Read the source

    Use the resource link to fetch the source document. The server returns its contents with the required cache fields.

What MCP does not guarantee

MCP standardizes the channel. It does not standardize the evidence. The specification is direct about its own limits: "While MCP itself cannot enforce these security principles at the protocol level", implementors should build consent and authorization flows, access controls and data protections [2]. For data quality and provenance, the gaps are these:

Question an auditor asksWhat core MCP providesGap
Where did this value come from?Nothing specific; a server may add a resource_link or put fields in structuredContentNo standard source or evidence field
When was it true, and when was it read?lastModified annotation on resources and content blocksOne timestamp, meaning "last modified", not valid time or observation time
Which server answered?serverInfo in result _metaThe specification says clientInfo and serverInfo "are self-reported by the sender and are not verified by the protocol" and should not be relied on for security decisions [12]
Is the tool what it claims to be?description and annotationsAnnotations "MUST" be treated as untrusted unless from trusted servers [6]
Is "no result" a negative or a failure?isError flag for tool execution errorsNo standard way to say "checked, not found" versus "not checked"
Can the answer be replayed later?Statelessness and explicit identifiers make requests self-describingThe server's data may have changed; nothing in MCP pins a version

None of this is a defect in a transport protocol. HTTP does not tell you whether a web page is true either. But it means that putting a system behind an MCP server does not make its answers defensible. Whether an agent's context can be audited depends on what the server returns, which is a server design question. The site's glossary entry on context engineering covers the wider discipline; the live article on permission-aware RAG evaluation addresses the access side.

Figure 02
Protocol features and fact-server responsibilities
What core MCP provides
  • Structured tool results can conform to a declared output schema.
  • Resource annotations include audience, priority and last-modified time.
  • Explicit identifiers let clients reference state across self-contained requests.
What fact servers must design
  • Return a stable source identifier, the exact supporting passage and a resource link alongside the value.
  • Separate when the fact applies, when its source was observed and when the value changed.
  • Make unknown or conflicting results explicit, and include a record or version identifier for later review.

Design checklist for fact-returning servers

For teams building MCP servers that return facts an agent will act on:

  1. Declare an outputSchema and return structuredContent, so clients can validate results instead of parsing prose.
  2. Return the source with the value: a stable source identifier, the exact supporting passage, and a resource_link to the document.
  3. Separate the times: when the fact applies, when the source was observed, when the value was last changed. Do not overload lastModified.
  4. Make negatives explicit: return unknown or conflict as statuses, with the reason, rather than an empty result or an error.
  5. Version the answer: include a record or version identifier so that a later reviewer can retrieve the same value, as the stateless model's "explicit identifier" rule encourages.
  6. Use a vendor prefix for custom _meta keys: the specification reserves the io.modelcontextprotocol/ prefix and asks third-party extensions to use their own [12].
  7. Keep consent and authorization in the host: the specification places user consent, tool confirmation and authorization decisions there.
  8. Track the revision: support server/discover, return UnsupportedProtocolVersionError for versions you do not serve, and plan for the deprecations listed in the changelog.

An MCP server that fronts a system of record can only pass on the evidence that system holds; Reliable Context is designed so that every value it returns carries a cited, dated source.

External Sources (13)

Published by

Reliable Context Research

Reliable Context is a system of record for organizations that fuse private and public information and must defend every value they act on: one canonical record per real thing, ambiguity shown rather than hidden, and provenance behind every value.

Our product · Evidence and editorial standards · Contact

Request access

Editorial note

Researched and written by Reliable Context Research with AI-assisted research tools; sources are cited inline and checked before publication. Report an error: https://reliablecontext.com/corrections.