
Most people treat MCP as the thing that lets their agent call tools, as if it were a fancier function-calling wrapper. That mental model gets you through demos and breaks the moment you try to run something real. If you want to understand how MCP works under the hood, you have to stop thinking about it as a plugin format and start thinking about it as a stateful client-server protocol built on JSON-RPC 2.0.
Towards Data Science published a solid walkthrough of the protocol recently, MCP Explained: How Modern AI Agents Connect to the Real World, and it lines up with what I have been reading in the official Model Context Protocol spec. This post is my attempt to compress the mechanism into a mental model you can actually use when you design servers for Power Platform agents.
The Surface Behaviour: What You See When an Agent Calls an MCP Tool
From the outside, an MCP call looks trivial. You wire an MCP server into Copilot Studio or a Power Apps agent, the agent picks a tool, arguments get filled in, a result comes back, and the model uses it in the next turn. It feels indistinguishable from a REST connector.
That is the illusion. Underneath, three things are happening that a REST connector never does: the client and server negotiated capabilities before any tool call happened, the server is exposing tools, resources, and prompts as separate primitives, and the connection is a live session, not a stateless request. The agent is not just calling an endpoint. It is holding a conversation with a server that has told it what it can do.
Underneath: JSON-RPC, the Handshake, and Capability Negotiation
MCP rides on JSON-RPC 2.0. Every message is a JSON object with a method, params, and either an id (for requests) or no id (for notifications). Nothing exotic. What matters is the sequence.
When an MCP client connects to a server, the first thing it sends is an initialize request. This carries the client’s protocol version and its capabilities. The server responds with its own protocol version, its capabilities, and metadata like server name and version. The client then sends an initialized notification to confirm the handshake is done. Only after this does tool discovery happen, usually through a tools/list call.
Capability negotiation is the piece people miss. The server advertises whether it supports tools, resources, prompts, sampling, logging, and so on. The client picks up only what it understands. This is why an MCP server built against a newer spec can still work with an older client. Backward compatibility is baked into the protocol.
Then there are the three primitives:
- Tools are model-invoked. The agent decides when to call them.
- Resources are application-controlled. The host app decides what to expose.
- Prompts are user-invoked. Templates the user can trigger.
Most people conflate all three into tools. That is why their MCP servers feel bloated. If a chunk of data is really a reference document, it should be a resource, not a tool. Tools are for actions with side effects or computed answers.
Edges and Limits: Transports, Session State, Schema Drift, and Auth
MCP is transport-agnostic in principle but the two real options are stdio and HTTP with Server-Sent Events (or the newer streamable HTTP transport). Stdio is fine for local dev. For anything hosted, you are on HTTP, and that opens the usual questions about session identity, reconnection, and load balancing.
Session state is the first sharp edge. An MCP session is stateful. If your server is behind a load balancer with no sticky sessions, you will see broken initialize sequences and mysterious method not found errors after a reconnect. This is not a bug. It is the protocol working as designed against infrastructure that assumed statelessness.
Schema drift is the second. Tool schemas are exchanged at tools/list time. If your server changes a tool’s input schema mid-session without notifying the client via notifications/tools/list_changed, the agent will keep calling the old shape and fail silently or noisily depending on how strict your validation is. The new Dataverse MCP server tool shape is a good example of what a clean split between metadata inspection, querying, and search actually looks like in practice.
Auth is the third. The core MCP spec deliberately left auth as a transport concern for a long time. The newer authorization spec pins it to OAuth 2.1. If you are wiring an MCP server into an enterprise agent, this is where you spend most of your time, not on the tool logic itself.
What This Means When You Build an MCP Server for Power Platform Agents
A few concrete implications for anyone pointing Copilot Studio or Power Apps agents at MCP.
Design tool descriptions as retrieval hints, not documentation. I wrote about this in how Copilot Studio agent tool selection actually works. The orchestrator scores names, descriptions, and parameter names together. MCP does not change that. It just gives you a cleaner surface to expose them from.
Split tools, resources, and prompts properly. If you dump everything as tools, you inflate the tool count, degrade selection quality past ten to fifteen entries, and force the model to reason about things that should have been passive context.
Treat session lifetime as part of your design. Idle timeouts, reconnect logic, and schema change notifications are not edge cases. They are the load-bearing parts of a production MCP server. The same session and state management issues are a core reason AI agents fail in production when they worked fine in testing.
MCP is not a plugin format. It is a protocol. Build servers like protocol servers and the sharp edges stop cutting. Skip that and you are building another silo with extra JSON on top. In my day-to-day, that shift in framing is what changes the design.
Frequently Asked Questions
How does MCP work under the hood when an agent calls a tool?
MCP is a stateful client-server protocol built on JSON-RPC 2.0, not a simple function-calling wrapper. Before any tool call happens, the client and server go through a capability negotiation handshake, the server declares what it supports, and only then does tool discovery take place. The connection stays live as a session rather than being a stateless request like a REST call.
What is the MCP handshake and why does it matter?
When an MCP client connects to a server, it sends an initialize request containing its protocol version and capabilities, and the server responds with its own. The client then sends an initialized notification to confirm the exchange before any tools are listed or called. Skipping this step or misunderstanding it is a common reason real implementations break outside of demos.
What is the difference between MCP and a standard REST connector?
A REST connector is stateless, meaning each request stands alone with no shared context. MCP maintains a live session, negotiates capabilities upfront, and exposes tools, resources, and prompts as distinct primitives. This makes it better suited for agents that need to understand what a server can do before deciding how to use it.
Why does MCP use JSON-RPC 2.0 instead of a simpler format?
JSON-RPC 2.0 gives MCP a lightweight but structured message format that distinguishes requests from notifications and pairs responses to the correct request using an id field. This structure supports the sequenced, session-based communication that MCP requires, while remaining simple enough to implement across different clients and servers.
This post was inspired by MCP Explained: How Modern AI Agents Connect to the Real World via Towards Data Science.
Leave a Reply