Suresh

7. All you need to know about Model Context Protocol

7. All you need to know about Model Context Protocol

Language models are evolving fast, but there is still one major bottleneck: context handling and tool use.

Until recently, traditional tool-calling methods, like OpenAI’s function-calling or LangChain’s tool chaining, involved hardcoding how models interact with external APIs. Every tool call needed heavy prompting, tight coupling between instructions and schemas, and lots of fragile orchestration.

Model Context Protocol (MCP) offers a cleaner way forward.

MCP makes tool use, memory access, knowledge retrieval, and action planning structured and dynamic. Instead of cramming everything into giant prompts, models interact with external systems through lightweight, organized APIs. Before we go deeper, lets understand a bit more on the shortcomings of plain old tool calling.

In the traditional tool-calling setup:

Tools must be registered manually inside prompts. This makes the consuming application and the source system (or target system, depending on how you see this) coupled tightly with each other.

Context must be squashed into the system message or conversation history.

Models have no idea what tools exist unless you re-feed that knowledge every time.

JSON-based function calling is rigid; if a tool schema changes, the whole setup can break.

This does not scale well when you have multiple tools, dynamic APIs, agentic workflows, or real-time changes.

How MCP is a game changer

MCP introduces a server that acts as a live context manager. The server holds the available tools, memory, and actions. The model can query the server as needed instead of memorizing everything inside the prompt.

Key differences:

Dynamic Discovery: Models ask for available tools at runtime.

Structured Context: Memory, tools, and actions are handled separately from the prompt, reducing clutter. Fetching memory and tool information externally saves large prompt overhead.

Adaptability: Models can adjust when tools change without needing new prompts or retraining. New tools, memories, or knowledge sources can be added without touching the model instructions

Scalable Planning: Agents can fetch plans, update goals, and reason with fresh context rather than working from stale memory. This is absolutely critical when building agentic systems.

Sample MCP Server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# mcp_server.py
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()

# Define your "tools" - each tool is just a function the server can call
def get_weather(location: str) -> dict:
    return {"location": location, "forecast": "Sunny", "temperature": "25°C"}

def add_numbers(a: int, b: int) -> dict:
    return {"result": a + b}

# Map tool names to actual functions
TOOLS = {
    "get_weather": get_weather,
    "add_numbers": add_numbers,
}

@app.get("/mcp/tools")
async def list_tools():
    return JSONResponse({tool_name: {"description": f"Function: {tool_name}"} for tool_name in TOOLS.keys()})

@app.post("/mcp/invoke")
async def invoke_tool(request: Request):
    params = request.query_params
    body = await request.json()
    
    tool_name = params.get("tool_name")
    if not tool_name or tool_name not in TOOLS:
        return JSONResponse({"error": "Tool not found"}, status_code=404)
    
    tool_func = TOOLS[tool_name]
    tool_params = body.get("params", {})

    try:
        result = tool_func(**tool_params)
        return JSONResponse({"result": result})
    except Exception as e:
        return JSONResponse({"error": str(e)}, status_code=400)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="localhost", port=8000)

To consume the MCP Server above, the client code looks like below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# mcp_client.py
import requests

# List all available tools
tools_response = requests.get("http://localhost:8000/mcp/tools")
tools = tools_response.json()

print("Available tools:")
for tool_name in tools:
    print(f" - {tool_name}")

# Example: Invoke 'get_weather'
response = requests.post(
    "http://localhost:8000/mcp/invoke",
    params={"tool_name": "get_weather"},
    json={"params": {"location": "Columbus, OH"}},
)
print("\nWeather tool response:")
print(response.json())

# Example: Invoke 'add_numbers'
response = requests.post(
    "http://localhost:8000/mcp/invoke",
    params={"tool_name": "add_numbers"},
    json={"params": {"a": 10, "b": 20}},
)
print("\nAdd numbers tool response:")
print(response.json())

To be able to run the code, you need a few libraries in your python virtual environment.

1
pip install mcp fastapi uvicorn httpx openai pandas

The above code shows how you can create a basic MCP Server and a Client. The client first makes a HTTP request to the server, gets all tools available, and then it invokes get_weather tool, and also calls another tool add_numbers.

This is the absolute basic MCP Server/Client one can write. In this case, client invokes MCP Server directly, and no LLM is involved in decision making. In a typical Agentic AI solution,you would have LLMs reason about which tool to call based on the flow and situation, provided you have the tools exposed by MCP Server.

The model or agent does not need a giant static prompt anymore. It queries the server when it needs information or tools and acts accordingly.

comments powered by Disqus