Rewiring the Agentic AI Stack with MCP: A Deep Dive into MCP Spec
Agentic AI systems are no more neat stacks. They are a web of tools, docs, databases, APIs and file systems. All trying to talk to each other. In this chaos, LLMs are set to become the reasoning engines. But we've been strapping them into this chaos with glue code so far. What’s missing is a common language - not another agent framework.
MCP is set to change that - with structured contracts.
MCP defines a set of typed structured primitives that standardize how LLM systems:
🔎Discover and read context (Resources)
🛠️ Execute actions (Tools)
📜Guide interactions (Prompts)
🚧Stay within boundaries (Roots)
🤖Generate completions (Sampling)
MCP doesn’t just define what these components are - it as well formalizes how they communicate using JSON-RPC over transport layers e.g. stdio and SSE.
⚙️ MCP Architecture
MCP follows server-client architecture:
🎙️Hosts: These are LLM applications that initiate connections
👨💼Clients: Maintain 1:1 connections with servers, inside the host application
🌐 Servers: Provide context, tools and prompts to the clients
At runtime - the LLM application - be it an IDE or a shell UI which acts as a host. Inside this host - one or more MCP client spins up. This client connects to the MCP servers living locally or remotely. Each server exposes 1 or more of the MCP primitives and the communication happens via JSON-RPC messages over a transport pipe fully typed and fully observable.
This design ensures that each part of the Agentic system becomes modular, inspectable and programmable.
...and this is where the real shift begins.
In this article - we’ll study five key constructs that MCP introduces - and how they redefine the architecture of Agentic AI systems.
Each of these is a protocol-native building block. Together, they reshape how Agentic systems reason, act and interact in MCP driven system.
- Resources: Clean way to expose data to the model
- Tools: Actions the model can call with guardrails
- Prompts: Reusable templates to guide model behavior
- Roots: Boundaries that define where the model can operate
- Sampling: Safe, trackable LLM responses through the client
Let's dive it
1️⃣ Resource: How MCP redefines context handling
In MCP - a "Resource" is a typed and uniquely identified reference to data that can be accessed by LLM through a client-server interaction. A Resource can be - PDFs docs, source code files, database query outputs, log files, JSON, HTML, etc.
Resources have following properties:
- Application-controlled: The client decides which context is relevant and when it decides to use it.
- Uniformly structured: Every resource has a URI, a MIME type and a human-readable name
- Surfaceable: Resources can be shown to users or selected automatically by agents.
- Composable: Resources can be read, cached, filtered or passed into tools.
By separating resource identity from usage logic - MCP allows clients and agents to treat structured data as discoverable context.
🤔 How MCP Redefines Resource Handling
🕰️ Before MCP
Let's take an example...
Let’s walk through how a simple task of RAG gets transformed completely when re-architected with MCP.
Pre-MCP - developers had to stitch everything themselves i.e. read the PDF ->perform chunking ->create embeddings -> store embeddings in VDB -> perform semantic search retrievals.
Post retrieval - Agents then manually inject the context into the prompts. Everything lived inside the code.
❌ The LLM had no clue what existed in the VDB. The search was opaque and tightly coupled.
🚀 What changes with MCP: A Modular RAG via Protocol
1. resources/list - Make files discoverable
MCP exposes PDFs as resources with metadata, like URI, name and MIME type.
Clients now know that a document exists. The LLM interface can present it to users or heuristically fetch it.
2. resources/read - Let clients fetch contents
Instead of hardcoding file reads, your server exposes a unified interface. No assumptions about file system or format. The client requests it as needed.
3. embed_and_index - Chunk, embed, and index the document
Instead of embedding in orchestration code, expose it as a tool.
LLMs can call this directly to prep documents for retrieval.
4. semantic_query - Let the agent query semantically
The agent now just says: "I want to search that repo of strategy docs" — without knowing how it works under the hood.
📌 The architectural shift that comes in - A recap
Before MCP:
- Vector search pipelines were code-only
- Agents didn’t know what existed or how to invoke logic
After MCP:
Context is now addressable, invocable, and observable. MCP turns your vector DB into a context API — not just a background store.
- Discovery = resources/list
- Reading = resources/read
- Ingestion = tool: embed_and_index
- Retrieval = tool: semantic_query
2️⃣ Tools: How MCP Redefines Tool Execution
In MCP - Tools are the most powerful primitives. They enable servers to expose executable capabilities to clients and LLMs in a contract-driven manner.
Unlike traditional tool use in agent frameworks where function wrappers are manually defined and registered, MCP tools are declarative and protocol-native.
Tools represent real-world operations like API calls, calculations, database writes, or file system operations that can be:
- Discovered by the client via tools/list
- Invoked by the client or LLM via tools/call
- Constrained by input schemas and safety annotations
They are model-controlled, meaning that tools are designed to be invoked by LLMs -optionally with human-in-the-loop review -and come with metadata that guides usage (e.g. destructive, idempotent and read-only).
🤔 How MCP Redefines Tool Handling
🕰️ Before MCP
All tool execution was:
- Manually wrapped in LangChain or AutoGen functions
- Buried in orchestration code
- Controlled entirely by developers
❌ The model didn’t know what tools were available, what they accepted, or how safe they were to use.
🚀 What changes with MCP: Tools as Typed Contracts
- tools/list - Make tools discoverable: You define and expose all callable actions with descriptions, JSON Schemas, and safety hints.
- tools/call — Perform tool execution via agent
LLMs or clients now invoke this tool directly, with full visibility and auditability.
📎 Tools return structured responses. If something goes wrong, you return a typed error—not a broken trace.
Recommended by LinkedIn
📌 The architectural shift that comes in - A recap
Before MCP:
- Tools were opaque Python functions
- LLMs couldn’t discover, introspect, or reason about actions
After MCP:
- Every tool is typed, listed, and invocable via protocol
- LLMs participate in workflows, not just text prompts
- Tool usage becomes inspectable and safe-by-contract
Your server is no longer a black box of glue logic. It’s a composable interface of callable actions.
Additionally - Tools can include behavioral hints:
- readOnlyHint → Doesn’t change system state
- destructiveHint → Might delete or mutate data
- idempotentHint → Safe to retry
- openWorldHint → Talks to external systems
3️⃣ Prompts: Declarative, Discoverable and Reusable in MCP
In MCP, Prompts are reusable, parameterized templates that define how conversations with LLMs should start. They allow servers to expose common workflows, guidance scaffolds, and templated user interactions in a standardized way.
Unlike arbitrary prompt strings buried in code, MCP Prompts are:
- User-controlled → Clients decide which prompt to invoke
- Discoverable → Exposed via prompts/list with metadata
- Parameterized → Accept arguments like "language" or "fileUri"
- Composable → Can include resource context or be chained into multi-turn workflows
Prompts help standardize how LLMs are guided into tasks. Each prompt is defined as a:
- Name → Unique ID like explain-code
- Description → Natural language summary
- Arguments → List of input parameters with type and requirements
They’re served through prompts/list and retrieved using prompts/get, optionally embedding resources and previous turns.
🤔 How MCP Redefines Prompt Handling
🕰️ Before MCP
Prompt workflows were:
- Buried in app logic or scripts
- Non-reusable across tools or UI
- Completely opaque to the client or LLM
❌ These prompts were neither visible nor inspectable. Reusability, introspection, or tool-like control was absent.
🚀 What changes with MCP: Prompts as Structured Interfaces
- prompts/list - Enumerate available workflows
The server surfaces prompts with metadata and arguments.
- prompts/get — Retrieve a parameterized prompt
Clients or UIs can select a prompt and invoke it dynamically.
📌 The architectural shift that comes in - A recap
Before MCP:
- Prompts were string blobs
- LLMs had no knowledge of reusable scaffolds
After MCP:
- Prompts are typed, discoverable, and user-controllable
- UIs and agents can surface them as commands or workflows
- Context and inputs are structured, not injected
Prompts become first-class building blocks in LLM workflows - not just strings in a script.
4️⃣ Roots: How MCP Redefines Resource Scoping
In MCP, Roots are a foundational primitive that define the boundaries within which a server should operate. A root is essentially a URI prefix - like a workspace - that informs the server where to look for resources. Think of roots as the “project folder” or “scope boundary” for an MCP server. This is especially important in agentic systems where the same server may serve multiple domains.
They are:
- Client-declared → The client tells the server what areas are in-scope
- Workspace-bounded → Helps organize multi-root setups (e.g. frontend repo + backend API)
- Non-enforcing, but respected → Servers aren’t blocked by roots, but are expected to prioritize them
- URI-native → Works across protocols (file://, http://, screen://, db://)
🤔 How MCP Redefines Resource Scoping
🕰️ Before MCP
There was no formal scoping of what a server should operate on.
You had to hardcode file paths or environment-specific logic inside your orchestration layer.
❌ Result:
- No introspection
- No separation of workspaces
- No flexibility when switching clients/projects
🚀 What changes with MCP: Roots as Declarative Boundaries
- Clients declare roots during initialization: This tells the server: “Only operate inside these zones.”
2. Server uses roots to scope resource discovery: The server chooses files under the provided root and ignores unrelated paths.
📌 The architectural shift that comes in - A recap
Before MCP:
- Servers operated blindly across filesystem or APIs
- No workspace awareness, no path hints
- Developers had to write access guards manually
After MCP:
- Roots make scoping explicit and client-driven
- Agents operate within declared URI spaces
- Multi-root systems are easy to organize and introspect
Roots don’t add logic - they add boundaries. They let you say: “This is your world. Don’t wander beyond.”
5️⃣ Sampling: How MCP Redefines LLM Completion
In MCP, Sampling introduces a formal protocol for servers to request LLM completions from the client. It decouples prompt invocation from backend code and hands over the control and visibility to the client and users - safely, structurally, and auditably.
🤔 How MCP Redefines LLM Completion
🕰️ Before MCP
LLM completions were coded imperatively:
❌ This was:
- Hardcoded to a provider (e.g., OpenAI)
- Inflexible to switch models
- Opaque to the system
- Prompt injection-prone
- Impossible to review/modify
🚀 With MCP — Sampling via sampling/createMessage
In MCP, your server emits a structured request like this:
🔁 The client:
- Reviews the prompt
- Selects a suitable model based on modelPreferences
- Injects relevant context (includeContext)
- Returns a structured completion like following:
The request is typed, traceable, and can be modified by the client or user before invocation.
📌 The architectural shift that comes in - A recap
Before MCP:
- Completion logic was opaque
- Context and safety weren’t enforced
- Models couldn’t be flexibly selected
- Errors and retries were manual
After MCP:
- Servers send structured message arrays
- Clients control model routing, safety checks, and approvals
- Users can audit and inspect what LLMs see
- Agents can request completions while maintaining security guarantees
MCP turns LLM invocation into a structured, inspectable system primitive - not just another SDK call buried in backend logic
This deep dive was just the beginning. Over the weekend, I tore through the MCP specification to map out what it really changes for us as AI architects - not just syntactically, but structurally. In the coming weeks, I’ll explore each of these primitives in hands-on setups, compare them with traditional (non-MCP) patterns, and share practical insights on where MCP truly shines -and where it still needs work. Stay tuned...
Technology Lead
3moExcellent summarization and details Rohit Sharma. Many thanks for sharing