Skip to content

Commit 5be78af

Browse files
authored
Merge branch 'main' into main
2 parents 1099d6a + 95b44fb commit 5be78af

20 files changed

+1066
-185
lines changed

README.md

Lines changed: 277 additions & 169 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: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""Client display utilities example.
2+
3+
This example shows how to use the SDK's display utilities to show
4+
human-readable names for tools, resources, and prompts.
5+
6+
cd to the `examples/snippets` directory and run:
7+
uv run display-utilities-client
8+
"""
9+
10+
import asyncio
11+
import os
12+
13+
from mcp import ClientSession, StdioServerParameters
14+
from mcp.client.stdio import stdio_client
15+
from mcp.shared.metadata_utils import get_display_name
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"],
21+
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
22+
)
23+
24+
25+
async def display_tools(session: ClientSession):
26+
"""Display available tools with human-readable names"""
27+
tools_response = await session.list_tools()
28+
29+
for tool in tools_response.tools:
30+
# get_display_name() returns the title if available, otherwise the name
31+
display_name = get_display_name(tool)
32+
print(f"Tool: {display_name}")
33+
if tool.description:
34+
print(f" {tool.description}")
35+
36+
37+
async def display_resources(session: ClientSession):
38+
"""Display available resources with human-readable names"""
39+
resources_response = await session.list_resources()
40+
41+
for resource in resources_response.resources:
42+
display_name = get_display_name(resource)
43+
print(f"Resource: {display_name} ({resource.uri})")
44+
45+
templates_response = await session.list_resource_templates()
46+
for template in templates_response.resourceTemplates:
47+
display_name = get_display_name(template)
48+
print(f"Resource Template: {display_name}")
49+
50+
51+
async def run():
52+
"""Run the display utilities example."""
53+
async with stdio_client(server_params) as (read, write):
54+
async with ClientSession(read, write) as session:
55+
# Initialize the connection
56+
await session.initialize()
57+
58+
print("=== Available Tools ===")
59+
await display_tools(session)
60+
61+
print("\n=== Available Resources ===")
62+
await display_resources(session)
63+
64+
65+
def main():
66+
"""Entry point for the display utilities client."""
67+
asyncio.run(run())
68+
69+
70+
if __name__ == "__main__":
71+
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: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ 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"
21+
direct-execution-server = "servers.direct_execution:main"
22+
display-utilities-client = "clients.display_utilities: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: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""Example showing direct execution of an MCP server.
2+
3+
This is the simplest way to run an MCP server directly.
4+
cd to the `examples/snippets` directory and run:
5+
uv run direct-execution-server
6+
or
7+
python servers/direct_execution.py
8+
"""
9+
10+
from mcp.server.fastmcp import FastMCP
11+
12+
mcp = FastMCP("My App")
13+
14+
15+
@mcp.tool()
16+
def hello(name: str = "World") -> str:
17+
"""Say hello to someone."""
18+
return f"Hello, {name}!"
19+
20+
21+
def main():
22+
"""Entry point for the direct execution server."""
23+
mcp.run()
24+
25+
26+
if __name__ == "__main__":
27+
main()
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")

0 commit comments

Comments
 (0)