MCPMCP Python SDK 2.2 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
24 small wins to finish your pathNext lesson

Context: what a tool can reach while it runs

A tool's arguments come from the model. Everything else, like the server's own resources or a channel back to the client, comes from the Context.

Exampleshop.py
from mcp.server import MCPServer
from mcp.server.mcpserver import Context

mcp = MCPServer("Shop support")


@mcp.resource("policy://refunds")
def refund_policy() -> str:
    """The shop's refund policy."""
    return "Full refund within 30 days of delivery."


@mcp.tool()
async def refund_rules(ctx: Context) -> str:
    """Tell the model the refund rules before it promises anything."""
    [policy] = await ctx.read_resource("policy://refunds")
    return f"Policy: {policy.content}"

A parameter annotated Context is filled in by the SDK on every request. ctx.read_resource reads one of the server's own resources through the same path a client uses, so the policy text lives in one place and both the application and the tool read it.

Example
import asyncio

from mcp import Client
from shop import mcp


async def main():
    async with Client(mcp) as client:
        tools = await client.list_tools()
        print(tools.tools[0].input_schema)

        result = await client.call_tool("refund_rules", {})
        print(result.content[0].text)


asyncio.run(main())

The model never sees ctx. The input schema has no properties at all, and the tool is called with {}. The Context is between your function and the SDK.

The tool is async def because read_resource is awaited. A plain def tool is fine for work that does not wait on anything; the SDK runs it in a separate thread so it never blocks the server.

What else is on it

  • ctx.report_progress(...): tell the client how far a slow tool has got. Lesson 13.
  • ctx.request_context.lifespan_context: objects the server built at startup, such as a database. Lesson 12.
  • ctx.headers: the HTTP headers of the request, or None when the server is not reached over HTTP (lesson 16).
  • ctx.session: the channel back to this client, for notifications like a changed tool list.
Try it yourself
  • Name the parameter context instead of ctx. Does anything change?
  • Print ctx.request_id from inside the tool.
  • Give refund_rules an order_id: str argument and include it in the answer.

Little by little, you're building something great.