README - replace code snippets with examples - direct execution and display utilities (#1137)
This commit is contained in:
parent
9bf5160eea
commit
a10fec7fa6
5 changed files with 254 additions and 8 deletions
94
README.md
94
README.md
|
|
@ -338,6 +338,8 @@ to the `@tool` decorator.
|
||||||
```python
|
```python
|
||||||
"""Example showing structured output with tools."""
|
"""Example showing structured output with tools."""
|
||||||
|
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from mcp.server.fastmcp import FastMCP
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
@ -365,12 +367,8 @@ def get_weather(city: str) -> WeatherData:
|
||||||
condition="sunny",
|
condition="sunny",
|
||||||
wind_speed=5.2,
|
wind_speed=5.2,
|
||||||
)
|
)
|
||||||
```
|
|
||||||
|
|
||||||
_Full example: [examples/snippets/servers/structured_output.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/structured_output.py)_
|
|
||||||
<!-- /snippet-source -->
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Using TypedDict for simpler structures
|
# Using TypedDict for simpler structures
|
||||||
class LocationInfo(TypedDict):
|
class LocationInfo(TypedDict):
|
||||||
latitude: float
|
latitude: float
|
||||||
|
|
@ -437,6 +435,9 @@ def get_temperature(city: str) -> float:
|
||||||
# Returns: {"result": 22.5}
|
# Returns: {"result": 22.5}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
_Full example: [examples/snippets/servers/structured_output.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/structured_output.py)_
|
||||||
|
<!-- /snippet-source -->
|
||||||
|
|
||||||
### Prompts
|
### Prompts
|
||||||
|
|
||||||
Prompts are reusable templates that help LLMs interact with your server effectively:
|
Prompts are reusable templates that help LLMs interact with your server effectively:
|
||||||
|
|
@ -814,21 +815,46 @@ uv run mcp install server.py -f .env
|
||||||
|
|
||||||
For advanced scenarios like custom deployments:
|
For advanced scenarios like custom deployments:
|
||||||
|
|
||||||
|
<!-- snippet-source examples/snippets/servers/direct_execution.py -->
|
||||||
```python
|
```python
|
||||||
|
"""Example showing direct execution of an MCP server.
|
||||||
|
|
||||||
|
This is the simplest way to run an MCP server directly.
|
||||||
|
cd to the `examples/snippets` directory and run:
|
||||||
|
uv run direct-execution-server
|
||||||
|
or
|
||||||
|
python servers/direct_execution.py
|
||||||
|
"""
|
||||||
|
|
||||||
from mcp.server.fastmcp import FastMCP
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
mcp = FastMCP("My App")
|
mcp = FastMCP("My App")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
@mcp.tool()
|
||||||
|
def hello(name: str = "World") -> str:
|
||||||
|
"""Say hello to someone."""
|
||||||
|
return f"Hello, {name}!"
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Entry point for the direct execution server."""
|
||||||
mcp.run()
|
mcp.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
_Full example: [examples/snippets/servers/direct_execution.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/direct_execution.py)_
|
||||||
|
<!-- /snippet-source -->
|
||||||
|
|
||||||
Run it with:
|
Run it with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python server.py
|
python servers/direct_execution.py
|
||||||
# or
|
# or
|
||||||
uv run mcp run server.py
|
uv run mcp run servers/direct_execution.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that `uv run mcp run` or `uv run mcp dev` only supports server using FastMCP and not the low-level server variant.
|
Note that `uv run mcp run` or `uv run mcp dev` only supports server using FastMCP and not the low-level server variant.
|
||||||
|
|
@ -1277,9 +1303,30 @@ async def main():
|
||||||
|
|
||||||
When building MCP clients, the SDK provides utilities to help display human-readable names for tools, resources, and prompts:
|
When building MCP clients, the SDK provides utilities to help display human-readable names for tools, resources, and prompts:
|
||||||
|
|
||||||
|
<!-- snippet-source examples/snippets/clients/display_utilities.py -->
|
||||||
```python
|
```python
|
||||||
|
"""Client display utilities example.
|
||||||
|
|
||||||
|
This example shows how to use the SDK's display utilities to show
|
||||||
|
human-readable names for tools, resources, and prompts.
|
||||||
|
|
||||||
|
cd to the `examples/snippets` directory and run:
|
||||||
|
uv run display-utilities-client
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
|
||||||
|
from mcp import ClientSession, StdioServerParameters
|
||||||
|
from mcp.client.stdio import stdio_client
|
||||||
from mcp.shared.metadata_utils import get_display_name
|
from mcp.shared.metadata_utils import get_display_name
|
||||||
from mcp.client.session import ClientSession
|
|
||||||
|
# Create server parameters for stdio connection
|
||||||
|
server_params = StdioServerParameters(
|
||||||
|
command="uv", # Using uv to run the server
|
||||||
|
args=["run", "server", "fastmcp_quickstart", "stdio"],
|
||||||
|
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def display_tools(session: ClientSession):
|
async def display_tools(session: ClientSession):
|
||||||
|
|
@ -1301,8 +1348,39 @@ async def display_resources(session: ClientSession):
|
||||||
for resource in resources_response.resources:
|
for resource in resources_response.resources:
|
||||||
display_name = get_display_name(resource)
|
display_name = get_display_name(resource)
|
||||||
print(f"Resource: {display_name} ({resource.uri})")
|
print(f"Resource: {display_name} ({resource.uri})")
|
||||||
|
|
||||||
|
templates_response = await session.list_resource_templates()
|
||||||
|
for template in templates_response.resourceTemplates:
|
||||||
|
display_name = get_display_name(template)
|
||||||
|
print(f"Resource Template: {display_name}")
|
||||||
|
|
||||||
|
|
||||||
|
async def run():
|
||||||
|
"""Run the display utilities example."""
|
||||||
|
async with stdio_client(server_params) as (read, write):
|
||||||
|
async with ClientSession(read, write) as session:
|
||||||
|
# Initialize the connection
|
||||||
|
await session.initialize()
|
||||||
|
|
||||||
|
print("=== Available Tools ===")
|
||||||
|
await display_tools(session)
|
||||||
|
|
||||||
|
print("\n=== Available Resources ===")
|
||||||
|
await display_resources(session)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Entry point for the display utilities client."""
|
||||||
|
asyncio.run(run())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
_Full example: [examples/snippets/clients/display_utilities.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/display_utilities.py)_
|
||||||
|
<!-- /snippet-source -->
|
||||||
|
|
||||||
The `get_display_name()` function implements the proper precedence rules for displaying names:
|
The `get_display_name()` function implements the proper precedence rules for displaying names:
|
||||||
|
|
||||||
- For tools: `title` > `annotations.title` > `name`
|
- For tools: `title` > `annotations.title` > `name`
|
||||||
|
|
|
||||||
71
examples/snippets/clients/display_utilities.py
Normal file
71
examples/snippets/clients/display_utilities.py
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
"""Client display utilities example.
|
||||||
|
|
||||||
|
This example shows how to use the SDK's display utilities to show
|
||||||
|
human-readable names for tools, resources, and prompts.
|
||||||
|
|
||||||
|
cd to the `examples/snippets` directory and run:
|
||||||
|
uv run display-utilities-client
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
|
||||||
|
from mcp import ClientSession, StdioServerParameters
|
||||||
|
from mcp.client.stdio import stdio_client
|
||||||
|
from mcp.shared.metadata_utils import get_display_name
|
||||||
|
|
||||||
|
# Create server parameters for stdio connection
|
||||||
|
server_params = StdioServerParameters(
|
||||||
|
command="uv", # Using uv to run the server
|
||||||
|
args=["run", "server", "fastmcp_quickstart", "stdio"],
|
||||||
|
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def display_tools(session: ClientSession):
|
||||||
|
"""Display available tools with human-readable names"""
|
||||||
|
tools_response = await session.list_tools()
|
||||||
|
|
||||||
|
for tool in tools_response.tools:
|
||||||
|
# get_display_name() returns the title if available, otherwise the name
|
||||||
|
display_name = get_display_name(tool)
|
||||||
|
print(f"Tool: {display_name}")
|
||||||
|
if tool.description:
|
||||||
|
print(f" {tool.description}")
|
||||||
|
|
||||||
|
|
||||||
|
async def display_resources(session: ClientSession):
|
||||||
|
"""Display available resources with human-readable names"""
|
||||||
|
resources_response = await session.list_resources()
|
||||||
|
|
||||||
|
for resource in resources_response.resources:
|
||||||
|
display_name = get_display_name(resource)
|
||||||
|
print(f"Resource: {display_name} ({resource.uri})")
|
||||||
|
|
||||||
|
templates_response = await session.list_resource_templates()
|
||||||
|
for template in templates_response.resourceTemplates:
|
||||||
|
display_name = get_display_name(template)
|
||||||
|
print(f"Resource Template: {display_name}")
|
||||||
|
|
||||||
|
|
||||||
|
async def run():
|
||||||
|
"""Run the display utilities example."""
|
||||||
|
async with stdio_client(server_params) as (read, write):
|
||||||
|
async with ClientSession(read, write) as session:
|
||||||
|
# Initialize the connection
|
||||||
|
await session.initialize()
|
||||||
|
|
||||||
|
print("=== Available Tools ===")
|
||||||
|
await display_tools(session)
|
||||||
|
|
||||||
|
print("\n=== Available Resources ===")
|
||||||
|
await display_resources(session)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Entry point for the display utilities client."""
|
||||||
|
asyncio.run(run())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -18,3 +18,5 @@ packages = ["servers", "clients"]
|
||||||
server = "servers:run_server"
|
server = "servers:run_server"
|
||||||
client = "clients.stdio_client:main"
|
client = "clients.stdio_client:main"
|
||||||
completion-client = "clients.completion_client:main"
|
completion-client = "clients.completion_client:main"
|
||||||
|
direct-execution-server = "servers.direct_execution:main"
|
||||||
|
display-utilities-client = "clients.display_utilities:main"
|
||||||
|
|
|
||||||
27
examples/snippets/servers/direct_execution.py
Normal file
27
examples/snippets/servers/direct_execution.py
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
"""Example showing direct execution of an MCP server.
|
||||||
|
|
||||||
|
This is the simplest way to run an MCP server directly.
|
||||||
|
cd to the `examples/snippets` directory and run:
|
||||||
|
uv run direct-execution-server
|
||||||
|
or
|
||||||
|
python servers/direct_execution.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
|
mcp = FastMCP("My App")
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def hello(name: str = "World") -> str:
|
||||||
|
"""Say hello to someone."""
|
||||||
|
return f"Hello, {name}!"
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Entry point for the direct execution server."""
|
||||||
|
mcp.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
"""Example showing structured output with tools."""
|
"""Example showing structured output with tools."""
|
||||||
|
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from mcp.server.fastmcp import FastMCP
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
@ -27,3 +29,69 @@ def get_weather(city: str) -> WeatherData:
|
||||||
condition="sunny",
|
condition="sunny",
|
||||||
wind_speed=5.2,
|
wind_speed=5.2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Using TypedDict for simpler structures
|
||||||
|
class LocationInfo(TypedDict):
|
||||||
|
latitude: float
|
||||||
|
longitude: float
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def get_location(address: str) -> LocationInfo:
|
||||||
|
"""Get location coordinates"""
|
||||||
|
return LocationInfo(latitude=51.5074, longitude=-0.1278, name="London, UK")
|
||||||
|
|
||||||
|
|
||||||
|
# Using dict[str, Any] for flexible schemas
|
||||||
|
@mcp.tool()
|
||||||
|
def get_statistics(data_type: str) -> dict[str, float]:
|
||||||
|
"""Get various statistics"""
|
||||||
|
return {"mean": 42.5, "median": 40.0, "std_dev": 5.2}
|
||||||
|
|
||||||
|
|
||||||
|
# Ordinary classes with type hints work for structured output
|
||||||
|
class UserProfile:
|
||||||
|
name: str
|
||||||
|
age: int
|
||||||
|
email: str | None = None
|
||||||
|
|
||||||
|
def __init__(self, name: str, age: int, email: str | None = None):
|
||||||
|
self.name = name
|
||||||
|
self.age = age
|
||||||
|
self.email = email
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def get_user(user_id: str) -> UserProfile:
|
||||||
|
"""Get user profile - returns structured data"""
|
||||||
|
return UserProfile(name="Alice", age=30, email="alice@example.com")
|
||||||
|
|
||||||
|
|
||||||
|
# Classes WITHOUT type hints cannot be used for structured output
|
||||||
|
class UntypedConfig:
|
||||||
|
def __init__(self, setting1, setting2):
|
||||||
|
self.setting1 = setting1
|
||||||
|
self.setting2 = setting2
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def get_config() -> UntypedConfig:
|
||||||
|
"""This returns unstructured output - no schema generated"""
|
||||||
|
return UntypedConfig("value1", "value2")
|
||||||
|
|
||||||
|
|
||||||
|
# Lists and other types are wrapped automatically
|
||||||
|
@mcp.tool()
|
||||||
|
def list_cities() -> list[str]:
|
||||||
|
"""Get a list of cities"""
|
||||||
|
return ["London", "Paris", "Tokyo"]
|
||||||
|
# Returns: {"result": ["London", "Paris", "Tokyo"]}
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def get_temperature(city: str) -> float:
|
||||||
|
"""Get temperature as a simple float"""
|
||||||
|
return 22.5
|
||||||
|
# Returns: {"result": 22.5}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue