Skip to content
AI 知识地图 0.18 · 2026-07-30
关于与纠错文字目录 / Search
Understanding the principles

MCP Architecture: Enabling the MCP Host to Connect External Capabilities Within an Isolation Boundary

From MCP Host–MCP Client–MCP Server, JSON-RPC, capability negotiation, and three types of primitives, understand what MCP standardizes, and who remains responsible for authorization and execution security.

Core idea MCP turns the connection between AI applications and tools/data sources from M×N dedicated adapters into a shared protocol; it specifies communication and discovery, but does not make trust, authorization, or side-effect decisions on behalf of the MCP Host or the user.
After reading this, you should be able to:Draw Host, Client, Server, and transport boundaries; manually trace initialization and tool calls; distinguish control of Tools, Resources, and Prompts; design least-privilege, timeout, and audit policies.
  1. Host selects and trusts a Server
  2. Create an isolated Client for the Server
  3. Negotiate version and bidirectional capabilities
  4. Discover primitives and build a local catalog
  5. The model proposes or the application selects an operation
  6. After Host authorization, send a minimal request
  7. Verify results and record side effects
  8. Cancel, reconnect, or close the session

1The protocol solves for reuse, not whether the model will call toolsPositioning

After the model already has function calling capability, why is MCP still needed? To answer this question, we must first distinguish what problem each of the two mechanisms solves. Tool calling describes how the model produces structured intent: when the model receives a request, it outputs a structured representation of "I want to call a certain function and what the parameters are," but it does not know or care what system is behind that function. MCP, on the other hand, describes how the application discovers, reads, and calls capabilities from different providers—that is, after the model has expressed its intent, actually finding that tool, reading its input and output definitions, sending the call over, and bringing the result back; these connection-level tasks are the scope that MCP is concerned with.

Separate these two layers, and the value of MCP becomes clear. Suppose there are M Hosts (host programs that carry AI applications) that need to connect to N external systems (tool providers). Without a common protocol, each Host would have to write a separate adapter for each system, the number of connections is approximately M×N, and the discovery logic, error handling, and cancellation mechanism for each pair combination would need to be reimplemented. After introducing a common protocol, each Host only needs to implement one Client, and each provider only needs to implement one Server, reducing the main workload from M×N to nearly M+N. This is the core problem MCP solves: not "making the model learn to call tools," but eliminating duplicate integration and standardizing the connection contract.

But one overinterpretation must be avoided: this does not mean "write once and be compatible forever." What the protocol standardizes is the boundary of message exchange—what messages exist for discovery, negotiation, errors, cancellation, and audit, who sends them, and at what stage they take effect; whereas schema (the parameter structure of a specific tool), semantics (the business meaning of parameters), permissions (who is allowed to do what), and the protocol version itself still change as the business evolves. MCP will not eliminate these changes for the application, nor will it decide for the model "whether a certain tool should be called," nor decide for the user "whether this call should be authorized." It only lets these changes have a common contract boundary to rely on.

Therefore, MCP can be understood as a common connection protocol between Host and external capabilities: its inputs are diverse AI applications and tool providers, and its outputs are unified discovery, invocation, error, and lifecycle messages. It reduces the number of dedicated adapters from approximately M×N to M+N, solving the problem of duplicate integration; what it standardizes is the exchange contract itself, not guaranteeing schema compatibility forever, and it is not responsible for deciding whether the model should call tools or whether the user authorizes the call. Only by grasping this boundary can one understand exactly where the responsibilities of each message and each role covered by the protocol in the following chapters lie.

2Three Roles and One-to-One SessionsArchitecture

MCP splits a single connection into three roles—Host, Client, and Server—rather than loosely calling it an “application.” This split is not about naming; it is to clarify what each knows and what it should not get by default.

Host is the AI application itself that the user interacts with. It owns the complete session and is responsible for model selection, user consent, and security policies, and it knows the user goals it needs to achieve, which connections it needs to establish, and which policies to follow. Client is created by Host for each Server separately: if one Host connects to three Servers, there are three Clients. Each Client maintains only its dedicated session with that one Server, is responsible for routing protocol messages, and knows only that single Server’s capabilities and session state. Server is the provider that exposes capabilities, focused on a set of tools, resources, or prompts; it can run in a local process or on a remote service, and it receives only the minimum parameters needed to complete one request.

The core of the responsibility boundaries among these three layers is “what to know” and “what should not be obtained by default.” Host needs user goals, connections, and policies, but it should not by default obtain any Server’s internal credentials—internal keys belong to the Server itself. Client needs a single Server’s capabilities and session state, but it should not by default get other Servers’ private context; another Server’s internal data should not appear in a Client’s session. Server needs the parameters required to complete a request, but it should not by default receive the full conversation, nor should it by default receive arbitrary local data.

So the whole process can be understood as follows: the inputs are the user session, a single connection, and service capabilities; the output is a three-layer responsibility division: Host holds user goals and policies, Client maintains only one Server’s session, and Server receives only the minimum parameters needed to complete a request. This division makes it possible to isolate cross-source context: data from different Servers does not cross over at the Client layer, because each Client only guards its own single connection.

Finally, one point needs to be clarified: a one-to-one session describes a communication boundary, not a trust declaration. The fact that a Client maintains a one-to-one session with a Server only means that there is a dedicated message channel between them; it does not mean that this Server is already trusted, nor that the Server has the right to read the full conversation. What is isolated is context and message routing; trust still needs to be decided separately by Host policies and user consent.

RoleWhat it should knowWhat it should not get by default
HostUser goals, connections, and policiesServer’s internal credentials
ClientA single Server’s capabilities and sessionOther Servers’ private context
ServerParameters needed to complete a requestFull conversation and arbitrary local data

3The Data Layer and Transport Layer Must Be Understood SeparatelyLayering

When seeing the two connection methods, stdio and remote HTTP, it is easy to think they are two different MCPs. In fact, MCP needs to be understood as two independent layers: the data layer defines what the protocol itself “says,” and the transport layer defines “how these words are delivered.”

The data layer defines the semantics of JSON-RPC requests, responses, notifications, lifecycle, and various primitives. That is, operations such as tool discovery, invocation, error returns, and cancellation each correspond to what method, what fields they carry, and what lifecycle stage they are in; all of this is determined by the data layer. The transport layer is responsible for process or network connections, message framing, and authentication: it solves how messages are reliably delivered between the two endpoints. stdio is commonly used in scenarios where the Host launches a local Server—the Host spawns a child process and communicates with it via standard input and output; Streamable HTTP is more suitable for remote services, sending and receiving messages over HTTP connections.

The key conclusion of layering is: the same upper-layer methods do not imply the same threats. Whether over stdio or HTTP, the method semantics of the data layer are the same, but the risks exposed by the two transports are completely different. A local process inherits file and environment risks on the host—a local Server can naturally read files that the host can read and inherits the host's environment variables; a remote endpoint adds risks such as network identity, tokens, tenant isolation, and replay, expanding the attack surface from “a local program” to “untrusted entities on the network.”

Precisely for this reason, authorization belongs to transport and application security, not something automatically provided by the data-layer protocol. Successfully establishing a connection only proves that the two parties can communicate; it never proves that a particular tool call matches the user's intent. A successful HTTP connection handshake and successful token validation only indicate “who the peer is and that the connection works”; as for “whether the tool call it is now requesting should be allowed,” this must still be judged separately by the application layer based on user consent and policy.

Separating these two layers, the input is the same protocol message and the specific connection method, and the output is two sets of understanding: data-layer semantics and transport-layer risks: the data layer defines JSON-RPC methods, lifecycle, and primitives, and the transport layer handles stdio or HTTP connections, framing, and authentication. Same upper-layer methods do not mean the same risks; both local processes and remote services must separately make identity, permission, and content trust judgments—you cannot assume that the security boundary is the same just because “the protocol is the same.”

4Complete example: step-by-step tracing of an initialization and tool callCase walkthrough

Apply the role and layering concepts from the previous sections to a real message flow, and you can see which inspectable states a connection goes through from zero to getting a result. Take the weather Server as an example: the Client connects to it from scratch, eventually gets the weather result, and every step in between is a state point where you can stop and verify.

Step one, the Client sends an initialize request, declaring the protocol version it supports, its Client capabilities, and implementation information. Step two, the Server returns the negotiated version, the capabilities it provides such as tools and resources, and its own implementation information; if the two sides' versions are incompatible, the Client should disconnect rather than force itself to continue. Step three, the Client sends a notifications/initialized notification, confirming that initialization is complete and both sides enter the normal operating period. Step four, the Client calls tools/list and gets the input schema for the get_weather(city) tool—that is, it tells the Client: to call it, you need to pass a city parameter, and what that parameter looks like.

At this point the connection is ready; what actually does the work is the next few steps. The model proposes a structured intent like {city:"Hangzhou"}; the Host first performs policy and consent checks, and only after confirming that the call complies with user authorization does the Client send tools/call. The Server returns content, or returns a protocol error; the key point is that the Host receives a result with a source label—it treats that result as untrusted data for the model to interpret, not automatically as instructions to execute. The text returned by the Server does not directly drive subsequent actions; it is merely “content claimed by some source,” and the final interpretation is subject to the model and the Host's policies.

Think of the time cost of the whole process as a sum: the MCP total latency is roughly equal to the sum of connection negotiation, capability discovery, policy decision, tool execution, and model consumption. This is why various optimizations appear later. Caching the tool list can save time on capability discovery, but it has a prerequisite: once you receive a list change notification or re-establish the connection, you must rebuild the cache based on the new capabilities; you cannot continue using the old list. After a request times out, you should cancel it and stop waiting, to avoid a late “ghost result” triggering a duplicate operation after the action has already advanced—both stale caches and blind retries are unsafe.

So the input to this initialization example is the Client/Server versions, capabilities, and the weather tool's schema, and the output is a negotiated session and a source-labeled weather result. The two sides first initialize, then confirm initialized, discover tools, and call after Host approval; the total latency consists of the sum of connection negotiation, discovery, policy decision, tool execution, and model consumption. Caching can reduce discovery time, but version changes, timeouts, or late results all make stale caches and blind retries unsafe.

TtotalTconnection negotiation+Tdiscovery+Tpolicy+Ttools+Tmodel

5Original diagram: Host is the sole coordination and trust convergence point across ServersVisualization

Why shouldn't Server A directly read Server B, or directly read the full session? A structure diagram can make this constraint clear. In the diagram, Host is at the center, containing model and policy inside, with two mutually isolated Clients attached beneath it: one connected to a local Server, the other connected to a remote Server. There is no channel between the two Clients, and there is no direct connection between the local Server and the remote Server either.

The core relationship expressed in Figure 1 is: protocol connections can be reused, but trust cannot be transferred. Host can reuse the same connection mechanism to connect to multiple Servers, but this by no means implies that Server A can thereby use Host as a conduit to access Server B's data. Host must maintain connection isolation and control where context converges. Each Server receives only the minimum information needed to complete the request, and the returned results are converged locally by Host and understood uniformly by the model, rather than being exchanged among Servers.

The input to this architecture diagram is multiple Servers and the context each of them requires, and the output is a set of isolated Client sessions coordinated by Host. Host passes only the minimum information to each Server and converges results locally, thereby preventing Servers from directly connecting to each other and obtaining cross-source data. Server A cannot obtain Server B's context, and should not obtain the full conversation, because the full conversation belongs to Host's session layer, not to any Server's request parameters.

The last point must be made clear: the isolation in the diagram represents design responsibility, not protocol enforcement. The protocol itself will not prevent leakage — if Host proactively copies the full session to a Server, or allows multiple Servers to share the same set of credentials, leakage will still occur, and the protocol will not step in to block it. Isolation can be established only if Host actually implements the design convention of "minimum information transfer + local convergence", not by relying on the transport layer or data layer to guard it.

Host: user consent · model · policy · auditClient A1:1 with Server AClient B1:1 with Server BHost performs unified cross-source orchestrationOnly pass the minimum necessary context; do not share the full sessionIsolated, no direct connectionServer A · local filesstdio · process and file permissionsTools / ResourcesServer B · remote ticketsHTTP · identity and tenant boundaryTools / Prompts

Scroll horizontally to view the full diagram on small screens.

Figure 1 Protocol connections can be reused, but trust cannot be transferred; Host must maintain connection isolation and control where context converges.

6Three Server Primitive Types Have Different Control SubjectsPrimitive

Tools, Resources, and Prompts all seem to be “things the Server provides to the model,” but their respective control subjects and risks are not the same. Treating them as the same category is the cause of many implementation mistakes.

The typical controller of Tools is model-proposed and Host-approved: the model expresses the intention to invoke some action, and the Host performs a policy check before allowing it. The operation it performs is discovering and invoking actions, and the main risks are side effects, parameters, and permissions—tools really change state and consume resources, so whether the parameters are valid and whether the caller has permission must be checked before approval.

The controller of Resources is the application, not the model. The application chooses which context data to read, and the operation is listing and reading these resources. Its main risks are unauthorized reads, injection, and staleness: resource content is context data that may be injected with malicious instructions, or may be outdated but still used by the application as if it were fresh.

The controller of Prompts is the user. The user chooses to obtain reusable prompt templates, and the operation is pulling these templates. Its main risks are hidden instructions and version drift: templates may contain instructions that are opaque to the user, and template versions may become inconsistent with user expectations after updates.

To summarize the distinction among the three: the model proposes a Tool, the application selects a Resource, the user selects a Prompt, and the Host is responsible for the final policy check. The core confusion this division resolves is treating all Server content as the same kind of model input—in fact, their controllers are different, and so are their validation responsibilities.

There is also a reversed-direction case: the Server may in turn use capabilities exposed by the Client, such as sampling, roots, or elicitation. When the message direction reverses and the Server requests a capability on the Client side, the trust direction also reverses—originally the Host reviewed Server output, but now it must review the requests the Server makes. Regardless of direction, however, the Host must not skip user consent, input validation, or output isolation just because the message “comes from MCP.” Any primitive—whether a tool, resource, prompt, or reverse capability—can still be unauthorized, stale, or contain prompt injection; these risks do not automatically disappear just because the protocol is involved.

PrimitiveTypical ControllerOperationMain Risks
ToolsModel proposes, Host approvesDiscover and invoke actionsSide effects, parameters, and permissions
ResourcesApplication selectsList/read context dataUnauthorized reads, injection, and staleness
PromptsUser selectsObtain reusable templatesHidden instructions and version drift

7Capability negotiation is not an authorization listSecurity

When a Server declares during capability negotiation that it supports tools, does that mean it allows calling all of its tools? No. Capability negotiation and authorization are two judgments with different inputs and outputs.

The input to capability negotiation is the protocol features supported by both parties, and the output is the set of methods that can be used in this session—it answers the question, 'At the protocol level, what can we say to each other?' The input to authorization is subject, resource, action, and scope, and the output is whether a specific request is permitted—it answers the question, 'Can this user perform this action on that resource?' Capabilities only indicate that protocol features are available; they do not indicate which specific subject can access which resource. A Server that declares support for tools can only be interpreted as 'the protocol supports the tools capability,' not as 'any user can call all tools.'

Therefore, the flow on the Host side should be: first verify the Server's identity and configuration, confirm who the peer is and whether the configuration matches expectations; then apply an allowlist to tools item by item, along with parameter constraints, user/project scoping, and risk classification, rather than 'grant access simply because it is supported.' The Server side likewise must not outsource authorization to the Client: it must not trust the user ID sent by the Client; it must still perform real resource authorization—because the identity claimed by the Client may be forged, and the authoritative judgment must lie with the end that controls the resource.

Transport-layer security measures must also be implemented in layers. Local Servers should use least-privilege process permissions and a clean environment, so they have only the minimal permissions needed to do their work and do not inherit the full capabilities of the host machine; remote Servers should use short-lived, audience-bound tokens that expire quickly and can only be used for the specified audience, reducing their value if stolen and reused.

Finally, any content returned by a Server must be treated as untrusted data. In particular, resource text or tool descriptions must never override system policies—a tool description that says 'ignore previous rules' does not gain higher authority because it was returned via MCP. Capability negotiation tells the Host 'it can be called,' authorization tells the Host 'this call is permitted,' and content trustworthiness requires a separate judgment; the three cannot substitute for one another.

8Failure recovery must cover timeouts, cancellation, reconnection, and idempotencyReliability

The tool has already executed but the response was lost in transit—what happens if you retry? The answer depends on whether the action is a read or a write.

Read operations can usually be retried safely: if you check the weather once and don't get the result, checking again has zero side effects; even if the two results differ slightly, no state is corrupted. Writes are different—if a "deduction" has actually succeeded and only the response was lost, blindly retrying will deduct twice. So writes must carry an idempotency key, or first query the state before deciding whether to retry. An idempotency key lets the Server recognize that "this is the second arrival of the same logical request" and thus execute the effect only once; querying state first means proactively confirming whether the previous attempt actually succeeded or not.

Timeouts and cancellation also need clear semantics. Each request should have a configurable timeout; even if progress notifications are received, you must still keep a maximum time limit and not wait indefinitely just because "there is progress". After cancellation, the Server should do its best to terminate the ongoing action, but the Host cannot treat cancellation as "the action definitely did not happen". Cancellation only means the Host is no longer waiting; it cannot prove that the remote action has not completed—the action may have finished just before the cancellation signal arrived, while the response is still stuck in transit. Faced with this uncertain state of "action completed, response delayed", the Host must handle it explicitly; if no state query capability is available, it can only report "result uncertain".

After reconnecting, versions and capabilities must be renegotiated; you cannot keep using the assumptions from the old session. The cached capability list and negotiated version from the old session may have changed after disconnection and reconnection, so you must reinitialize and reconfirm them, rather than continuing to send messages based on the previous state.

Finally, sufficient logs are needed to locate failures. Logs should at least correlate these items: Host request, Client session, Server identity, tool, parameter summary, user approval, result, and side-effect ID. With these correlations, when a problem occurs you can determine whether the error occurred in the model, Host, transport, or Server, rather than only knowing that "some step failed".

Putting it all together: the inputs to the recovery mechanism are request ID, timeout, action type, idempotency key, and known side effects; the outputs are decisions to retry, query state, cancel, or stop. Read operations can usually be retried; write operations should first use an idempotency key or query the result; after reconnection, renegotiate. Cancellation only means the Host is no longer waiting; it cannot prove that the remote action has not completed, and when no state query is available you must report uncertain.

9When to Use Model Context Protocol (MCP), When to Use a Direct API or Internal FunctionSelection

Does wrapping every function as an MCP Server make it more standard? No, it does not. The value of MCP is highly scenario-dependent, and the choice should be based on specific requirements, not on whether it is “popular” or “more standard.”

MCP's contract value is greatest in three situations: when you need to reuse across multiple MCP Hosts, when you need dynamic discovery capability, or when you are targeting a third-party ecosystem. If you want the same set of tools to be discoverable and callable by different AI applications, or if you want external developers to integrate with your capability ecosystem, then unified discovery, negotiation, error, and lifecycle messages are tangible benefits. Conversely, for stable functions within a single process, extremely low-latency hot paths, or cases where a mature service SDK can already be used directly, direct invocation is often simpler — adding an extra MCP Server and connection layer for an in-process function only needlessly increases latency and attack surface.

Also note that MCP does not replace business APIs. An MCP Server is often just a mapping of existing business APIs into capabilities for AI applications: the actual execution still relies on the APIs behind it, while MCP provides a unified discovery and invocation entry point. When selecting, the dimensions to compare are connection reuse, version governance, authentication, observability, latency, and attack surface, and each must be grounded in concrete numbers and risks, not skipped over because “everyone is using it.”

A sound way to proceed is to start from the smallest surface: first build a minimal read-only MCP Server that exposes only query capabilities, verify the reuse and governance benefits, and then gradually expose write tools. Write operations bring side effects and idempotency responsibility, and should only be opened after sufficient evidence, not fully exposed from the start.

Therefore, the inputs to technology selection are reuse scope, discovery needs, latency, authentication, governance cost, and attack surface, and the output is one of three options: MCP, a direct API, or an internal function. Cross-Host ecosystem reuse is best suited to MCP, while stable hot paths within a single process often suit direct invocation. Adopting MCP only means a more unified connection contract; it absolutely does not mean that business APIs, SDKs, or security governance can be omitted — the protocol standardizes “how to connect,” but “what business to do, how to authorize, and how to govern” still must be done by you.

10First, clarify: Protocol, SDK, Server, and Agent are not the same layer.Concept Disambiguation

When someone says they "installed an MCP," they might mean completely different things—this is where the confusion begins. Under the four letters MCP, there are actually at least four layers stacked, and they must be separated.

MCP itself is a message and lifecycle specification: it defines what messages like initialize, initialized, tools/list, and tools/call look like and in what order they proceed. The SDK is the code library that implements this specification: it wraps the messages defined in the specification into functions and classes that can be called directly, making it easier for developers to use in specific languages. The Server is the running program that exposes capabilities: it uses the SDK (or handwritten implementation) to expose a set of tools, resources, and prompts, and waits for a Client to connect. The Agent is the application logic that decides whether and how to use capabilities: it understands user goals, determines whether to call a tool, and how to interpret the returned results.

The distinctions among these four layers are not abstract classifications; they directly affect troubleshooting. A Server can contain no model at all—it merely provides capabilities and makes no reasoning decisions. An Agent can also completely bypass MCP and directly call internal functions—when it does not need external capabilities, it will not go through the protocol at all. If these layers are mixed together, SDK bugs, protocol version incompatibilities, tool semantic errors, and model decision errors will all be lumped together as "MCP failure," and as a result, you cannot even locate which layer is responsible. An SDK written incorrectly is a code library problem; a version mismatch is a negotiation problem; a tool returning incorrect data is a semantic problem; the model choosing the wrong tool is a decision problem—they are not the same fault and cannot be fixed in the same way.

Therefore, the most easily confused point must be nailed down: MCP standardizes "how to connect and exchange," and it does not guarantee that tools are genuine, does not guarantee security, does not guarantee authorization, and does not guarantee suitability for the current task. The protocol lets you discover and call a tool, but whether that tool actually does what it claims, whether it is allowed to be called, and whether it is suitable for the task at hand—these judgments are all outside the protocol, and are respectively the responsibility of the SDK implementation, the Server's authorization, and the Agent's decision. Only by separating the specification, the code library, the running program, and the application logic can you truly explain what each link is doing in a single call.

11Connect the causal chainSynthesis

String together the mechanisms from the previous sections in the order they run, and you get a causal chain that leads from “problems” all the way to “verifiable practices.” Each step is both the result of the previous link and the precondition for the next.

The first link is the Host selecting and trusting a Server. Trust is not granted by the protocol; it is a decision the Host makes based on identity verification and configuration checks. This step sets the starting point of the whole chain: whom to use and how much to trust.

The second link is creating an isolated Client for this Server. One Client per Server, with sessions isolated from each other, and no direct connections between Servers. Here the Host keeps the convergence point of cross-source context firmly under its own control.

The third link is negotiating version and bidirectional capabilities. The two parties exchange protocol versions and capabilities each supports through initialize; if versions are incompatible, they disconnect. Capability negotiation here only answers “what the protocol can do,” not “what is allowed.”

The fourth link is discovering primitives and building a local catalog. The Client obtains lists and input schemas for tools, resources, and prompts through tools/list and similar means, and the Host builds its own catalog from these for later selection by models or applications.

The fifth link is a model proposing or an application selecting an operation. At this point, the capability catalog built earlier is actually used: the model expresses tool intent, or the application selects a resource to read, or the user selects a prompt to use—because the controlling subject differs, the semantics of this step also differ.

The sixth link is the Host sending a minimal request after authorization. The Host first performs policy and consent checks, then sends only the minimum parameters needed to complete the request. Capability negotiation is completed here by authorization judgment; the Server must still perform its own resource authorization and cannot trust the identity passed from the Client.

The seventh link is validating results and recording side effects. Returned content is treated as untrusted data; the Host records results and side-effect IDs, providing a basis for later audit and failure recovery.

The eighth link is cancellation, reconnection, or closing the session. On timeout, cancel and stop waiting; on disconnection, reconnect and renegotiate; on completion, close the session. Write operations are safeguarded by idempotency keys or status queries, and uncertain results that arrive late are explicitly reported rather than silently ignored.

This chain turns the role division of “the Host holds policy, the Client maintains a single session, and the Server provides capabilities” into an eight-step process that can be verified step by step. The boundary of each link is clear: capability, authorization, and content trustworthiness are three distinct judgments, and no link can be replaced by the result of the previous link.

Sources and Adaptation Notes
Access date: 2026-07-22