TechByteByByte

MCP and Agents

The standardization problem for tool integration specifically, and how MCP addresses it — directly extending Module 6-7's tool-calling foundation to work consistently across many external capabilities.

#AI Agents#AI#MCP#Level 8

Begin with the problem

MCP standardizes how an AI application discovers and calls external tools and resources. The network boundary adds authentication, trust, and lifecycle concerns.

MCP client → discover server capabilities → request tool/resource → server responds → client continues

What you will learn

  • Define MCP clients, servers, tools, resources, and prompts.
  • Follow discovery and tool invocation across the MCP boundary.
  • Understand what MCP standardizes and what security work remains application-specific.
  • Decide when MCP reduces integration work and when a direct API is simpler.

Current real-system grounding: The Model Context Protocol specification documents interoperable tools and resources; Google’s Agents overview gives a current managed-agent example.

These official links document available product features. They do not reveal every provider’s private implementation, hidden reasoning, default setting, or internal limit.

1. The problem this module solves

Module 22 covered orchestration frameworks broadly. This module zooms in on a specific, real problem within that space: how does an agent integrate with many external tools and services without custom integration code for each one? MCP (Model Context Protocol) addresses exactly this, directly extending Module 6-7’s tool-calling foundation.


2. The Tool Integration Problem

Module 6-7 covered ONE agent's tool registry -- straightforward for a HANDFUL of custom tools.

But a capable agent might need access to: a shipping API, a
CRM system, a file system, a database, a web search service, an
internal wiki -- each POTENTIALLY built by a DIFFERENT team, with
DIFFERENT conventions, requiring custom integration code
for every single one.

This is precisely a standardization problem — without a common protocol, connecting an agent to N different external services requires N different, custom integration efforts, each with its own quirks.


3. What MCP Standardizes

MCP defines a STANDARD way for:

- A SERVER (representing an external capability -- a shipping API,
  a database) to EXPOSE its tools, resources, and prompts in a
  CONSISTENT, discoverable format

- A CLIENT (the agent) to DISCOVER and USE those capabilities without
  needing SERVICE-SPECIFIC integration code
flowchart LR
    subgraph Servers
        S1[Shipping MCP Server]
        S2[CRM MCP Server]
        S3[File System MCP Server]
    end
    Agent[Agent / MCP Client] -->|standardized protocol| S1
    Agent -->|standardized protocol| S2
    Agent -->|standardized protocol| S3

4. MCP Server, Client, Tools, Resources, Prompts

MCP ConceptWhat It IsConnects To
ServerExposes a specific capability (shipping, CRM, files) through the standard protocol
ClientThe agent-side component that connects to and uses MCP serversModule 5’s LLM-as-brain, now with standardized tool access
Toolsthe SAME concept as Module 6 — actions the agent can invoke — now discoverable through a standard interfaceModule 6-7
ResourcesREAD-ONLY content a server exposes (a document, a data record) — directly connecting to your RAG course’s retrieval conceptYour RAG course
Promptsreusable, server-provided prompt templates for common tasks against that server’s capabilityYour Prompt Engineering course

5. Why This Matters for Agents

WITHOUT MCP:      integrating a new external service means WRITING
                 custom tool-wrapper code (Module 6's ToolRegistry
                 pattern, hand-built per service) EVERY single time

WITH MCP:             connecting to a NEW MCP-compatible server is
                     standardized -- the agent's client
                     discovers available tools automatically, with
                     NO service-specific integration code required

This directly extends Module 6’s tool schema concept — MCP is the “how do many different services expose that schema consistently” answer, precisely analogous to how HTTP standardized how web servers and browsers communicate, regardless of what’s actually running on either end.


6. A Real Developer Example

TechCorp connects their support agent to MULTIPLE external systems via MCP:

MCP ServerExposesUsed For
Shipping MCP Servercheck_shipping_status toolModule 6’s shipping lookup, now standardized
CRM MCP Servercheck_customer_history tool, customer records as resourcesreal cross-session context, directly Module 11’s memory retrieval
Internal Wiki MCP ServerPolicy documents as resourcesDirectly your RAG course’s retrieval, exposed through MCP

The agent’s MCP client connects to all three, discovers their available tools and resources through the SAME standardized interface, and the agent’s reasoning (Module 5) can select from ALL of them — without TechCorp writing custom integration code for each individual service.


7. A Simple Agentic AI Connection

MCP directly connects to Module 15’s multi-agent systems — different specialist agents in a coordinated system can share access to the SAME MCP servers, avoiding duplicated integration effort across agents that each need, say, shipping or CRM access.


8. How Is This Used in AI?

🤖 How Is This Used in AI?

Production agent systems increasingly use MCP to connect agents to diverse external capabilities — internal APIs, databases, file systems, third-party services — through one standardized protocol, directly reducing the custom integration burden Module 6’s hand-built ToolRegistry pattern would otherwise require for every single new capability.


9. Real-World Applications

  • Agents needing access to many, diverse external systems (CRM, shipping, internal databases, file systems)
  • Organizations wanting to expose internal capabilities to multiple different agents without custom integration per agent
  • Multi-agent systems (Module 15) sharing common external tool access

10. Common Mistakes

Incorrect idea: Assuming MCP replaces the need to understand tool schemas and function calling.

Why it is incorrect: As shown directly in Section 4, MCP tools are the SAME concept from Module 6-7, just discoverable through a standardized protocol.

Incorrect idea: Building custom integration code for every new external service when an MCP server already exists (or could be built once, reused everywhere).

Why it is incorrect: As shown directly in Section 5, MCP can reduce this repeated integration work by providing a shared protocol.

Incorrect idea: Treating MCP resources the same as MCP tools.

Why it is incorrect: As shown directly in Section 4, resources are read-only content, while tools perform actions — a real, meaningful distinction.


11. Limitations

  • MCP requires the external service to actually implement an MCP server — services without one still need custom integration, exactly as before
  • Standardization adds a real abstraction layer — debugging a specific integration issue may require understanding both MCP’s protocol AND the underlying service’s actual behavior

12. Quick Reference

flowchart TD
    Agent[Agent<br/>MCP Client] --> Discover[Discover Tools/Resources/Prompts]
    Discover --> S1[MCP Server A]
    Discover --> S2[MCP Server B]
    Discover --> S3[MCP Server C]
    S1 -.->|standardized protocol| Agent
    S2 -.->|standardized protocol| Agent
    S3 -.->|standardized protocol| Agent

13. Code — Implementing a Simplified MCP Server and Client

🎯 Target of this example: implement Section 6’s real developer example directly — a simplified MCP server exposing tools through a standardized discovery interface, and a client connecting to multiple servers, exactly Section 3’s standardization principle made into working code.

Example 1 — Simple

from dataclasses import dataclass

@dataclass
class MCPTool:
    """An MCP-style tool descriptor -- the SAME schema
    concept from Module 6, now standardized under MCP's protocol."""
    name: str
    description: str
    parameters: dict

class MCPServer:
    """A simplified MCP server stand-in -- exposes tools
    through a STANDARDIZED interface, so ANY MCP-compatible client
    (agent) can discover and use them without custom integration
    code per tool (Section 3)."""

    def __init__(self, name: str):
        self.name = name
        self.tools: dict = {}

    def register_tool(self, tool: MCPTool, fn):
        self.tools[tool.name] = (tool, fn)

    def list_tools(self) -> list:
        """The STANDARDIZED discovery mechanism -- any MCP client
        can call this, regardless of which specific server it's
        talking to."""
        return [{"name": t.name, "description": t.description} for t, fn in self.tools.values()]

    def call_tool(self, name: str, **kwargs) -> dict:
        if name not in self.tools:
            return {"error": f"Tool '{name}' not found on this server"}
        tool, fn = self.tools[name]
        return {"result": fn(**kwargs)}

class MCPClient:
    """A simplified agent-side MCP client -- connects to
    MULTIPLE MCP servers and can discover/call tools from ANY of
    them through the SAME standardized interface."""

    def __init__(self):
        self.connected_servers: list = []

    def connect(self, server: MCPServer):
        self.connected_servers.append(server)

    def discover_all_tools(self) -> dict:
        return {server.name: server.list_tools() for server in self.connected_servers}

shipping_server = MCPServer("shipping_service")
shipping_server.register_tool(
    MCPTool("check_shipping_status", "Checks a package's delivery status.", {"tracking_number": "string"}),
    lambda tracking_number: f"Package {tracking_number}: delivered",
)

crm_server = MCPServer("crm_service")
crm_server.register_tool(
    MCPTool("check_customer_history", "Looks up a customer's interaction history.", {"customer_id": "string"}),
    lambda customer_id: f"Customer {customer_id}: 2 prior tickets",
)

client = MCPClient()
client.connect(shipping_server)
client.connect(crm_server)

all_tools = client.discover_all_tools()
for server_name, tools in all_tools.items():
    print(f"{server_name}: {tools}")

result = shipping_server.call_tool("check_shipping_status", tracking_number="1Z999")
print(f"\nTool call result: {result}")

Expected Output:

shipping_service: [{'name': 'check_shipping_status', 'description':
"Checks a package's delivery status."}]
crm_service: [{'name': 'check_customer_history', 'description':
"Looks up a customer's interaction history."}]

Tool call result: {'result': 'Package 1Z999: delivered'}

What we conclude from this example: the SAME MCPClient class correctly discovers tools from TWO different servers (shipping and CRM) through the identical interface — exactly Section 6’s real developer example, demonstrating how MCP can reduce the amount of service-specific integration code an application needs.

Example 2 — Intermediate

from dataclasses import dataclass

@dataclass
class MCPResource:
    """Directly implements Section 4's RESOURCE concept -- READ-ONLY content, distinct from a TOOL (which performs an
    action)."""
    uri: str
    content: str

class MCPServerWithResources:
    """Extends Example 1 to distinguish TOOLS from RESOURCES --
    exactly Section 10's warning about NOT conflating the two."""

    def __init__(self, name: str):
        self.name = name
        self.tools: dict = {}
        self.resources: dict = {}

    def register_tool(self, name: str, description: str, fn):
        self.tools[name] = {"description": description, "fn": fn}

    def register_resource(self, uri: str, content: str):
        self.resources[uri] = content

    def list_capabilities(self) -> dict:
        return {
            "tools": list(self.tools.keys()),
            "resources": list(self.resources.keys()),
        }

    def read_resource(self, uri: str) -> str:
        return self.resources.get(uri, "Resource not found")

wiki_server = MCPServerWithResources("internal_wiki")
wiki_server.register_tool("search_wiki", "Searches internal documentation.", lambda q: f"Results for: {q}")
wiki_server.register_resource("wiki://travel-policy", "International hotel limit is $200/night.")

capabilities = wiki_server.list_capabilities()
print(f"Server capabilities: {capabilities}")

resource_content = wiki_server.read_resource("wiki://travel-policy")
print(f"\nResource content (read-only, no action performed): {resource_content}")

Expected Output:

Server capabilities: {'tools': ['search_wiki'], 'resources':
['wiki://travel-policy']}

Resource content (read-only, no action performed): International
hotel limit is $200/night.

What we conclude from this example: tools and resources are correctly tracked as SEPARATE categories — search_wiki is an action-performing tool, while wiki://travel-policy is read-only content accessed directly, without invoking any tool function at all — exactly Section 4’s distinction, made concretely observable.

Example 3 — Production Grade

from dataclasses import dataclass, field

@dataclass
class ToolCallRecord:
    server_name: str
    tool_name: str
    arguments: dict
    result: str

class UnifiedMCPAgent:
    """A production-style agent COMBINING Section 6's multi-server
    real developer example into ONE working system -- the agent's
    reasoning can select from tools across ALL connected servers, with
    every call TRACKED by which server it actually came from (directly
    connecting to Module 21's observability, applied to MCP)."""

    def __init__(self):
        self.servers: dict = {}
        self.call_history: list = []

    def connect_server(self, server):
        self.servers[server.name] = server

    def find_tool_server(self, tool_name: str) -> str:
        """Directly implements Section 5's discovery mechanism --
        searching ACROSS all connected servers to find
        which one provides a specific tool."""
        for server_name, server in self.servers.items():
            if tool_name in server.tools:
                return server_name
        return None

    def call_tool(self, tool_name: str, **kwargs) -> ToolCallRecord:
        server_name = self.find_tool_server(tool_name)
        if server_name is None:
            return ToolCallRecord("none", tool_name, kwargs, "Tool not found on any connected server")

        result = self.servers[server_name].call_tool(tool_name, **kwargs)
        record = ToolCallRecord(server_name, tool_name, kwargs, str(result))
        self.call_history.append(record)
        return record

class MCPServer:
    def __init__(self, name):
        self.name = name
        self.tools = {}
    def register_tool(self, name, fn):
        self.tools[name] = fn
    def call_tool(self, name, **kwargs):
        return {"result": self.tools[name](**kwargs)}

shipping = MCPServer("shipping_service")
shipping.register_tool("check_shipping_status", lambda tracking_number: f"Package {tracking_number}: delivered")

crm = MCPServer("crm_service")
crm.register_tool("check_customer_history", lambda customer_id: f"Customer {customer_id}: 2 prior tickets")

agent = UnifiedMCPAgent()
agent.connect_server(shipping)
agent.connect_server(crm)

record1 = agent.call_tool("check_shipping_status", tracking_number="1Z999")
record2 = agent.call_tool("check_customer_history", customer_id="C4471")

for record in agent.call_history:
    print(f"[{record.server_name}] {record.tool_name}({record.arguments}) -> {record.result}")

Expected Output:

[shipping_service] check_shipping_status({'tracking_number':
'1Z999'}) -> {'result': 'Package 1Z999: delivered'}
[crm_service] check_customer_history({'customer_id': 'C4471'}) ->
{'result': 'Customer C4471: 2 prior tickets'}

What we conclude from this example: the agent correctly routes each tool call to the RIGHT server automatically — without the agent’s reasoning needing to know in advance which specific server provides which tool — and every call is tracked with its originating server, exactly the kind of unified, observable multi-server integration MCP is designed to make possible.


14. Interview Questions

Q: What real problem does MCP solve for agents needing access to multiple external services?

Ans: Without a standard protocol, connecting an agent to many different external services — a shipping API, a CRM system, a database — would require custom, service-specific integration code for each one, multiplying integration effort as the number of connected services grows. MCP defines a standard way for servers to expose their tools, resources, and prompts, and for a client (the agent) to discover and use those capabilities without needing custom integration code per service.

Q: Distinguish MCP tools from MCP resources.

Ans: MCP tools are the same concept as tools covered earlier in this course — actions the agent can invoke, discoverable through MCP’s standardized interface. MCP resources are different — read-only content a server exposes, like a document or data record, directly connecting to a RAG system’s retrieval concept, accessed directly rather than invoked as an action.

Q: Why is MCP described as analogous to how HTTP standardized web communication?

Ans: Before HTTP, there was no common protocol for how clients (browsers) and servers communicated, requiring custom approaches for each connection. HTTP standardized this so any HTTP-compliant browser can communicate with any HTTP-compliant server, regardless of what’s actually running on either end. MCP does the same thing for agent-tool integration — any MCP-compatible client (agent) can discover and use any MCP-compatible server’s capabilities through the same standardized protocol, without needing custom, service-specific integration code.

Q: Design an MCP-based architecture for an agent needing access to three different internal systems, and explain the benefit over building custom integrations for each.

Ans: I’d implement three MCP servers — one wrapping each internal system’s capabilities (tools for actions, resources for read-only content) — and connect the agent’s MCP client to all three. The agent’s reasoning can then discover and select from tools across all three systems through one unified, standardized interface, rather than the agent needing separate, custom integration logic for each system’s unique API conventions. The real benefit is that adding a fourth system later only requires building one new MCP server, without touching the agent’s existing integration code at all — and other agents needing the same systems could reuse the exact same servers.


15. What You Should Remember

  • MCP solves a real standardization problem for connecting agents to many external services — eliminating custom, service- specific integration code for each one.
  • MCP tools are the same concept from Module 6-7, discoverable through a standardized protocol; MCP resources are distinct — read-only content, not actions — verified directly through code tracking both categories separately.
  • A unified MCP client can discover and route tool calls across multiple servers automatically — verified directly through an agent correctly calling tools from two different connected servers without knowing in advance which server hosts which tool.

16. Quick Practice

For an agent in your own domain needing access to at least three different external systems, sketch out what MCP servers you would build, and specify which capabilities each would expose as tools versus resources.

17. Next Step

Next: Module 24 — Production Agent Architecture — closing Level 8: the complete, consolidated system diagram bringing together every concept from this entire course into one production-grade design.

Author
TechByteByByte Editorial Team
Reviewed by
TechByteByByte Admin
Published
Last reviewed