Skip to content

Commit 9bf5160

Browse files
authored
README - replace code snippets with examples (#1136)
1 parent 49991fd commit 9bf5160

File tree

12 files changed

+585
-169
lines changed

12 files changed

+585
-169
lines changed

README.md

Lines changed: 195 additions & 165 deletions
Large diffs are not rendered by default.

examples/snippets/clients/__init__.py

Whitespace-only changes.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"""MCP client example showing completion usage.
2+
3+
This example demonstrates how to use the completion feature in MCP clients.
4+
cd to the `examples/snippets` directory and run:
5+
uv run completion-client
6+
"""
7+
8+
import asyncio
9+
import os
10+
11+
from mcp import ClientSession, StdioServerParameters
12+
from mcp.client.stdio import stdio_client
13+
from mcp.types import PromptReference, ResourceTemplateReference
14+
15+
# Create server parameters for stdio connection
16+
server_params = StdioServerParameters(
17+
command="uv", # Using uv to run the server
18+
args=["run", "server", "completion", "stdio"], # Server with completion support
19+
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
20+
)
21+
22+
23+
async def run():
24+
"""Run the completion client example."""
25+
async with stdio_client(server_params) as (read, write):
26+
async with ClientSession(read, write) as session:
27+
# Initialize the connection
28+
await session.initialize()
29+
30+
# List available resource templates
31+
templates = await session.list_resource_templates()
32+
print("Available resource templates:")
33+
for template in templates.resourceTemplates:
34+
print(f" - {template.uriTemplate}")
35+
36+
# List available prompts
37+
prompts = await session.list_prompts()
38+
print("\nAvailable prompts:")
39+
for prompt in prompts.prompts:
40+
print(f" - {prompt.name}")
41+
42+
# Complete resource template arguments
43+
if templates.resourceTemplates:
44+
template = templates.resourceTemplates[0]
45+
print(f"\nCompleting arguments for resource template: {template.uriTemplate}")
46+
47+
# Complete without context
48+
result = await session.complete(
49+
ref=ResourceTemplateReference(type="ref/resource", uri=template.uriTemplate),
50+
argument={"name": "owner", "value": "model"},
51+
)
52+
print(f"Completions for 'owner' starting with 'model': {result.completion.values}")
53+
54+
# Complete with context - repo suggestions based on owner
55+
result = await session.complete(
56+
ref=ResourceTemplateReference(type="ref/resource", uri=template.uriTemplate),
57+
argument={"name": "repo", "value": ""},
58+
context_arguments={"owner": "modelcontextprotocol"},
59+
)
60+
print(f"Completions for 'repo' with owner='modelcontextprotocol': {result.completion.values}")
61+
62+
# Complete prompt arguments
63+
if prompts.prompts:
64+
prompt_name = prompts.prompts[0].name
65+
print(f"\nCompleting arguments for prompt: {prompt_name}")
66+
67+
result = await session.complete(
68+
ref=PromptReference(type="ref/prompt", name=prompt_name),
69+
argument={"name": "style", "value": ""},
70+
)
71+
print(f"Completions for 'style' argument: {result.completion.values}")
72+
73+
74+
def main():
75+
"""Entry point for the completion client."""
76+
asyncio.run(run())
77+
78+
79+
if __name__ == "__main__":
80+
main()
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""MCP client example using stdio transport.
2+
3+
This is a documentation example showing how to write an MCP client.
4+
cd to the `examples/snippets/clients` directory and run:
5+
uv run client
6+
"""
7+
8+
import asyncio
9+
import os
10+
11+
from pydantic import AnyUrl
12+
13+
from mcp import ClientSession, StdioServerParameters, types
14+
from mcp.client.stdio import stdio_client
15+
from mcp.shared.context import RequestContext
16+
17+
# Create server parameters for stdio connection
18+
server_params = StdioServerParameters(
19+
command="uv", # Using uv to run the server
20+
args=["run", "server", "fastmcp_quickstart", "stdio"], # We're already in snippets dir
21+
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
22+
)
23+
24+
25+
# Optional: create a sampling callback
26+
async def handle_sampling_message(
27+
context: RequestContext, params: types.CreateMessageRequestParams
28+
) -> types.CreateMessageResult:
29+
print(f"Sampling request: {params.messages}")
30+
return types.CreateMessageResult(
31+
role="assistant",
32+
content=types.TextContent(
33+
type="text",
34+
text="Hello, world! from model",
35+
),
36+
model="gpt-3.5-turbo",
37+
stopReason="endTurn",
38+
)
39+
40+
41+
async def run():
42+
async with stdio_client(server_params) as (read, write):
43+
async with ClientSession(read, write, sampling_callback=handle_sampling_message) as session:
44+
# Initialize the connection
45+
await session.initialize()
46+
47+
# List available prompts
48+
prompts = await session.list_prompts()
49+
print(f"Available prompts: {[p.name for p in prompts.prompts]}")
50+
51+
# Get a prompt (greet_user prompt from fastmcp_quickstart)
52+
if prompts.prompts:
53+
prompt = await session.get_prompt("greet_user", arguments={"name": "Alice", "style": "friendly"})
54+
print(f"Prompt result: {prompt.messages[0].content}")
55+
56+
# List available resources
57+
resources = await session.list_resources()
58+
print(f"Available resources: {[r.uri for r in resources.resources]}")
59+
60+
# List available tools
61+
tools = await session.list_tools()
62+
print(f"Available tools: {[t.name for t in tools.tools]}")
63+
64+
# Read a resource (greeting resource from fastmcp_quickstart)
65+
resource_content = await session.read_resource(AnyUrl("greeting://World"))
66+
content_block = resource_content.contents[0]
67+
if isinstance(content_block, types.TextContent):
68+
print(f"Resource content: {content_block.text}")
69+
70+
# Call a tool (add tool from fastmcp_quickstart)
71+
result = await session.call_tool("add", arguments={"a": 5, "b": 3})
72+
result_unstructured = result.content[0]
73+
if isinstance(result_unstructured, types.TextContent):
74+
print(f"Tool result: {result_unstructured.text}")
75+
result_structured = result.structuredContent
76+
print(f"Structured tool result: {result_structured}")
77+
78+
79+
def main():
80+
"""Entry point for the client script."""
81+
asyncio.run(run())
82+
83+
84+
if __name__ == "__main__":
85+
main()

examples/snippets/pyproject.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ requires = ["setuptools", "wheel"]
1212
build-backend = "setuptools.build_meta"
1313

1414
[tool.setuptools]
15-
packages = ["servers"]
15+
packages = ["servers", "clients"]
1616

1717
[project.scripts]
18-
server = "servers:run_server"
18+
server = "servers:run_server"
19+
client = "clients.stdio_client:main"
20+
completion-client = "clients.completion_client:main"

examples/snippets/servers/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ def run_server():
2121
if len(sys.argv) < 2:
2222
print("Usage: server <server-name> [transport]")
2323
print("Available servers: basic_tool, basic_resource, basic_prompt, tool_progress,")
24-
print(" sampling, elicitation, completion, notifications")
24+
print(" sampling, elicitation, completion, notifications,")
25+
print(" fastmcp_quickstart, structured_output, images")
2526
print("Available transports: stdio (default), sse, streamable-http")
2627
sys.exit(1)
2728

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
FastMCP quickstart example.
3+
4+
cd to the `examples/snippets/clients` directory and run:
5+
uv run server fastmcp_quickstart stdio
6+
"""
7+
8+
from mcp.server.fastmcp import FastMCP
9+
10+
# Create an MCP server
11+
mcp = FastMCP("Demo")
12+
13+
14+
# Add an addition tool
15+
@mcp.tool()
16+
def add(a: int, b: int) -> int:
17+
"""Add two numbers"""
18+
return a + b
19+
20+
21+
# Add a dynamic greeting resource
22+
@mcp.resource("greeting://{name}")
23+
def get_greeting(name: str) -> str:
24+
"""Get a personalized greeting"""
25+
return f"Hello, {name}!"
26+
27+
28+
# Add a prompt
29+
@mcp.prompt()
30+
def greet_user(name: str, style: str = "friendly") -> str:
31+
"""Generate a greeting prompt"""
32+
styles = {
33+
"friendly": "Please write a warm, friendly greeting",
34+
"formal": "Please write a formal, professional greeting",
35+
"casual": "Please write a casual, relaxed greeting",
36+
}
37+
38+
return f"{styles.get(style, styles['friendly'])} for someone named {name}."

examples/snippets/servers/images.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""Example showing image handling with FastMCP."""
2+
3+
from PIL import Image as PILImage
4+
5+
from mcp.server.fastmcp import FastMCP, Image
6+
7+
mcp = FastMCP("Image Example")
8+
9+
10+
@mcp.tool()
11+
def create_thumbnail(image_path: str) -> Image:
12+
"""Create a thumbnail from an image"""
13+
img = PILImage.open(image_path)
14+
img.thumbnail((100, 100))
15+
return Image(data=img.tobytes(), format="png")
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""Example showing lifespan support for startup/shutdown with strong typing."""
2+
3+
from collections.abc import AsyncIterator
4+
from contextlib import asynccontextmanager
5+
from dataclasses import dataclass
6+
7+
from mcp.server.fastmcp import Context, FastMCP
8+
9+
10+
# Mock database class for example
11+
class Database:
12+
"""Mock database class for example."""
13+
14+
@classmethod
15+
async def connect(cls) -> "Database":
16+
"""Connect to database."""
17+
return cls()
18+
19+
async def disconnect(self) -> None:
20+
"""Disconnect from database."""
21+
pass
22+
23+
def query(self) -> str:
24+
"""Execute a query."""
25+
return "Query result"
26+
27+
28+
@dataclass
29+
class AppContext:
30+
"""Application context with typed dependencies."""
31+
32+
db: Database
33+
34+
35+
@asynccontextmanager
36+
async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
37+
"""Manage application lifecycle with type-safe context."""
38+
# Initialize on startup
39+
db = await Database.connect()
40+
try:
41+
yield AppContext(db=db)
42+
finally:
43+
# Cleanup on shutdown
44+
await db.disconnect()
45+
46+
47+
# Pass lifespan to server
48+
mcp = FastMCP("My App", lifespan=app_lifespan)
49+
50+
51+
# Access type-safe lifespan context in tools
52+
@mcp.tool()
53+
def query_db(ctx: Context) -> str:
54+
"""Tool that uses initialized resources."""
55+
db = ctx.request_context.lifespan_context.db
56+
return db.query()
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Example showing structured output with tools."""
2+
3+
from pydantic import BaseModel, Field
4+
5+
from mcp.server.fastmcp import FastMCP
6+
7+
mcp = FastMCP("Structured Output Example")
8+
9+
10+
# Using Pydantic models for rich structured data
11+
class WeatherData(BaseModel):
12+
"""Weather information structure."""
13+
14+
temperature: float = Field(description="Temperature in Celsius")
15+
humidity: float = Field(description="Humidity percentage")
16+
condition: str
17+
wind_speed: float
18+
19+
20+
@mcp.tool()
21+
def get_weather(city: str) -> WeatherData:
22+
"""Get weather for a city - returns structured data."""
23+
# Simulated weather data
24+
return WeatherData(
25+
temperature=72.5,
26+
humidity=45.0,
27+
condition="sunny",
28+
wind_speed=5.2,
29+
)

0 commit comments

Comments
 (0)