docs: add snippet verification for docs/ pages (#2115)
This commit is contained in:
parent
cfbbd7d71a
commit
1ef124e4a8
26 changed files with 446 additions and 43 deletions
6
.github/workflows/shared.yml
vendored
6
.github/workflows/shared.yml
vendored
|
|
@ -61,7 +61,7 @@ jobs:
|
|||
uv run --frozen --no-sync coverage combine
|
||||
uv run --frozen --no-sync coverage report
|
||||
|
||||
readme-snippets:
|
||||
doc-snippets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
|
@ -74,5 +74,5 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: uv sync --frozen --all-extras --python 3.10
|
||||
|
||||
- name: Check README snippets are up to date
|
||||
run: uv run --frozen scripts/update_readme_snippets.py --check
|
||||
- name: Check doc snippets are up to date
|
||||
run: uv run --frozen scripts/update_doc_snippets.py --check
|
||||
|
|
|
|||
|
|
@ -55,9 +55,9 @@ repos:
|
|||
language: system
|
||||
files: ^(pyproject\.toml|uv\.lock)$
|
||||
pass_filenames: false
|
||||
- id: readme-snippets
|
||||
name: Check README snippets are up to date
|
||||
entry: uv run --frozen python scripts/update_readme_snippets.py --check
|
||||
- id: doc-snippets
|
||||
name: Check doc snippets are up to date
|
||||
entry: uv run --frozen python scripts/update_doc_snippets.py --check
|
||||
language: system
|
||||
files: ^(README\.md|examples/.*\.py|scripts/update_readme_snippets\.py)$
|
||||
files: ^(README\.md|docs/.*\.md|examples/.*\.py|scripts/update_doc_snippets\.py)$
|
||||
pass_filenames: false
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ if __name__ == "__main__":
|
|||
mcp.run(transport="streamable-http")
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/fastmcp_quickstart.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/fastmcp_quickstart.py)_
|
||||
_Full example: [examples/snippets/servers/fastmcp_quickstart.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/fastmcp_quickstart.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
You can install this server in [Claude Code](https://docs.claude.com/en/docs/claude-code/mcp) and interact with it right away. First, run the server:
|
||||
|
|
|
|||
|
|
@ -225,6 +225,7 @@ For OAuth 2.1 client authentication, see [Authorization](authorization.md#client
|
|||
|
||||
Clients can provide a `list_roots_callback` so that servers can discover the client's workspace roots (directories, project folders, etc.):
|
||||
|
||||
<!-- snippet-source examples/snippets/clients/roots_example.py -->
|
||||
```python
|
||||
from mcp import ClientSession, types
|
||||
from mcp.shared.context import RequestContext
|
||||
|
|
@ -250,6 +251,9 @@ session = ClientSession(
|
|||
)
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/clients/roots_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/clients/roots_example.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
When a `list_roots_callback` is provided, the client automatically declares the `roots` capability (with `listChanged=True`) during initialization.
|
||||
|
||||
### Roots Change Notifications
|
||||
|
|
@ -265,6 +269,7 @@ await session.send_roots_list_changed()
|
|||
|
||||
For servers that use the older SSE transport, use `sse_client()` from `mcp.client.sse`:
|
||||
|
||||
<!-- snippet-source examples/snippets/clients/sse_client.py -->
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
|
|
@ -284,6 +289,9 @@ async def main():
|
|||
asyncio.run(main())
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/clients/sse_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/clients/sse_client.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
The `sse_client()` function accepts optional `headers`, `timeout`, `sse_read_timeout`, and `auth` parameters. The SSE transport is considered legacy; prefer [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#streamable-http) for new servers.
|
||||
|
||||
## Ping
|
||||
|
|
@ -302,6 +310,7 @@ result = await session.send_ping()
|
|||
|
||||
Pass a `logging_callback` to receive log messages from the server:
|
||||
|
||||
<!-- snippet-source examples/snippets/clients/logging_client.py -->
|
||||
```python
|
||||
from mcp import ClientSession, types
|
||||
|
||||
|
|
@ -318,6 +327,9 @@ session = ClientSession(
|
|||
)
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/clients/logging_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/clients/logging_client.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
### Setting the Server Log Level
|
||||
|
||||
Request that the server change its minimum log level:
|
||||
|
|
|
|||
|
|
@ -42,22 +42,29 @@ Both return an `EmptyResult` on success. If the remote side does not respond wit
|
|||
|
||||
Either side can cancel a previously-issued request by sending a `CancelledNotification`:
|
||||
|
||||
<!-- snippet-source examples/snippets/clients/cancellation.py -->
|
||||
```python
|
||||
import mcp.types as types
|
||||
from mcp import ClientSession
|
||||
|
||||
# Send a cancellation notification
|
||||
await session.send_notification(
|
||||
types.ClientNotification(
|
||||
types.CancelledNotification(
|
||||
params=types.CancelledNotificationParams(
|
||||
requestId="request-id-to-cancel",
|
||||
reason="User navigated away",
|
||||
|
||||
async def cancel_request(session: ClientSession) -> None:
|
||||
"""Send a cancellation notification for a previously-issued request."""
|
||||
await session.send_notification(
|
||||
types.ClientNotification(
|
||||
types.CancelledNotification(
|
||||
params=types.CancelledNotificationParams(
|
||||
requestId="request-id-to-cancel",
|
||||
reason="User navigated away",
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/clients/cancellation.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/clients/cancellation.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
The `CancelledNotificationParams` fields:
|
||||
|
||||
- `requestId` (optional): The ID of the request to cancel. Required for non-task cancellations.
|
||||
|
|
@ -106,6 +113,7 @@ During initialization, the client sends `LATEST_PROTOCOL_VERSION`. If the server
|
|||
|
||||
MCP uses [JSON Schema 2020-12](https://json-schema.org/draft/2020-12) for tool input schemas, output schemas, and elicitation schemas. When using Pydantic models, schemas are generated automatically via `model_json_schema()`:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/json_schema_example.py -->
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
|
@ -132,6 +140,9 @@ schema = SearchParams.model_json_schema()
|
|||
# }
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/json_schema_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/json_schema_example.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
For FastMCP tools, input schemas are derived automatically from function signatures. For structured output, the output schema is derived from the return type annotation.
|
||||
|
||||
## Pagination
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ _Full example: [examples/snippets/servers/basic_resource.py](https://github.com/
|
|||
|
||||
Resources with URI parameters (e.g., `{name}`) are registered as templates. When a client reads a templated resource, the URI parameters are extracted and passed to the function:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/resource_templates.py -->
|
||||
```python
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
|
||||
|
|
@ -117,6 +118,9 @@ def get_user_profile(user_id: str) -> str:
|
|||
return f'{{"user_id": "{user_id}", "name": "User {user_id}"}}'
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/resource_templates.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/resource_templates.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
Clients read a template resource by providing a concrete URI:
|
||||
|
||||
```python
|
||||
|
|
@ -137,6 +141,7 @@ def get_readme(owner: str, repo: str) -> str:
|
|||
|
||||
Resources can return binary data by returning `bytes` instead of `str`. Set the `mime_type` to indicate the content type:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/binary_resources.py -->
|
||||
```python
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
|
||||
|
|
@ -150,14 +155,17 @@ def get_logo() -> bytes:
|
|||
return f.read()
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/binary_resources.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/binary_resources.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
Binary content is automatically base64-encoded and returned as `BlobResourceContents` in the MCP response.
|
||||
|
||||
#### Resource Subscriptions
|
||||
|
||||
Clients can subscribe to resource updates. Use the low-level server API to handle subscription and unsubscription requests:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/resource_subscriptions.py -->
|
||||
```python
|
||||
import mcp.types as types
|
||||
from mcp.server.lowlevel import Server
|
||||
|
||||
server = Server("Subscription Example")
|
||||
|
|
@ -178,6 +186,9 @@ async def handle_unsubscribe(uri) -> None:
|
|||
subscriptions[str(uri)].discard("current_session")
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/resource_subscriptions.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/resource_subscriptions.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
When a subscribed resource changes, notify clients with `send_resource_updated()`:
|
||||
|
||||
```python
|
||||
|
|
@ -468,6 +479,7 @@ _Full example: [examples/snippets/servers/basic_prompt.py](https://github.com/mo
|
|||
|
||||
Prompts can include embedded resources to provide file contents or data alongside the conversation messages:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/prompt_embedded_resources.py -->
|
||||
```python
|
||||
import mcp.types as types
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
|
|
@ -497,10 +509,14 @@ def review_file(filename: str) -> list[base.Message]:
|
|||
]
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/prompt_embedded_resources.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/prompt_embedded_resources.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
#### Prompts with Image Content
|
||||
|
||||
Prompts can include images using `ImageContent` or the `Image` helper class:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/prompt_image_content.py -->
|
||||
```python
|
||||
import mcp.types as types
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
|
|
@ -524,10 +540,14 @@ def describe_image(image_path: str) -> list[base.Message]:
|
|||
]
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/prompt_image_content.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/prompt_image_content.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
#### Prompt Change Notifications
|
||||
|
||||
When your server dynamically adds or removes prompts, notify connected clients:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/prompt_change_notifications.py -->
|
||||
```python
|
||||
from mcp.server.fastmcp import Context, FastMCP
|
||||
from mcp.server.session import ServerSession
|
||||
|
|
@ -543,6 +563,9 @@ async def update_prompts(ctx: Context[ServerSession, None]) -> str:
|
|||
return "Prompts updated"
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/prompt_change_notifications.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/prompt_change_notifications.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
### Icons
|
||||
|
||||
MCP servers can provide icons for UI display. Icons can be added to the server implementation, tools, resources, and prompts:
|
||||
|
|
@ -608,6 +631,7 @@ _Full example: [examples/snippets/servers/images.py](https://github.com/modelcon
|
|||
|
||||
FastMCP provides an `Audio` class for returning audio data from tools, similar to `Image`:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/audio_example.py -->
|
||||
```python
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
from mcp.server.fastmcp.utilities.types import Audio
|
||||
|
|
@ -627,12 +651,16 @@ def get_audio_from_bytes(raw_audio: bytes) -> Audio:
|
|||
return Audio(data=raw_audio, format="wav")
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/audio_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/audio_example.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
The `Audio` class accepts `path` or `data` (mutually exclusive) and an optional `format` string. Supported formats include `wav`, `mp3`, `ogg`, `flac`, `aac`, and `m4a`. When using a file path, the MIME type is inferred from the file extension.
|
||||
|
||||
### Embedded Resource Results
|
||||
|
||||
Tools can return `EmbeddedResource` to attach file contents or data inline in the result:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/embedded_resource_results.py -->
|
||||
```python
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
from mcp.types import EmbeddedResource, TextResourceContents
|
||||
|
|
@ -655,13 +683,20 @@ def read_config(path: str) -> EmbeddedResource:
|
|||
)
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/embedded_resource_results.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/embedded_resource_results.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
For binary embedded resources, use `BlobResourceContents` with base64-encoded data:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/embedded_resource_results_binary.py -->
|
||||
```python
|
||||
import base64
|
||||
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
from mcp.types import BlobResourceContents, EmbeddedResource
|
||||
|
||||
mcp = FastMCP("Binary Embedded Resource Example")
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def read_binary_file(path: str) -> EmbeddedResource:
|
||||
|
|
@ -678,10 +713,14 @@ def read_binary_file(path: str) -> EmbeddedResource:
|
|||
)
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/embedded_resource_results_binary.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/embedded_resource_results_binary.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
### Tool Change Notifications
|
||||
|
||||
When your server dynamically adds or removes tools at runtime, notify connected clients so they can refresh their tool list:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/tool_change_notifications.py -->
|
||||
```python
|
||||
from mcp.server.fastmcp import Context, FastMCP
|
||||
from mcp.server.session import ServerSession
|
||||
|
|
@ -700,6 +739,9 @@ async def register_plugin(name: str, ctx: Context[ServerSession, None]) -> str:
|
|||
return f"Plugin '{name}' registered"
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/tool_change_notifications.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/tool_change_notifications.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
### Context
|
||||
|
||||
The Context object is automatically injected into tool and resource functions that request it via type hints. It provides access to MCP capabilities like logging, progress reporting, resource reading, user interaction, and request metadata.
|
||||
|
|
@ -978,6 +1020,7 @@ The `elicit()` method returns an `ElicitationResult` with:
|
|||
|
||||
To present a dropdown or selection list in elicitation forms, use `json_schema_extra` with an `enum` key on a `str` field. Do not use `Literal` -- use a plain `str` field with the enum constraint in the JSON schema:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/elicitation_enum.py -->
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
|
@ -1006,10 +1049,14 @@ async def pick_color(ctx: Context[ServerSession, None]) -> str:
|
|||
return "No color selected"
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/elicitation_enum.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/elicitation_enum.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
#### Elicitation Complete Notification
|
||||
|
||||
For URL mode elicitations, send a completion notification after the out-of-band interaction finishes. This tells the client that the elicitation is done and it may retry any blocked requests:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/elicitation_complete.py -->
|
||||
```python
|
||||
from mcp.server.fastmcp import Context, FastMCP
|
||||
from mcp.server.session import ServerSession
|
||||
|
|
@ -1018,9 +1065,7 @@ mcp = FastMCP("Elicit Complete Example")
|
|||
|
||||
|
||||
@mcp.tool()
|
||||
async def handle_oauth_callback(
|
||||
elicitation_id: str, ctx: Context[ServerSession, None]
|
||||
) -> str:
|
||||
async def handle_oauth_callback(elicitation_id: str, ctx: Context[ServerSession, None]) -> str:
|
||||
"""Called when OAuth flow completes out-of-band."""
|
||||
# ... process the callback ...
|
||||
|
||||
|
|
@ -1030,6 +1075,9 @@ async def handle_oauth_callback(
|
|||
return "Authorization complete"
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/elicitation_complete.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/elicitation_complete.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
### Sampling
|
||||
|
||||
Tools can interact with LLMs through sampling (generating text):
|
||||
|
|
@ -1101,6 +1149,7 @@ _Full example: [examples/snippets/servers/notifications.py](https://github.com/m
|
|||
|
||||
Clients can request a minimum logging level via `logging/setLevel`. Use the low-level server API to handle this:
|
||||
|
||||
<!-- snippet-source examples/snippets/servers/set_logging_level.py -->
|
||||
```python
|
||||
import mcp.types as types
|
||||
from mcp.server.lowlevel import Server
|
||||
|
|
@ -1117,6 +1166,9 @@ async def handle_set_level(level: types.LoggingLevel) -> None:
|
|||
current_level = level
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/set_logging_level.py](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/set_logging_level.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
When this handler is registered, the server automatically declares the `logging` capability during initialization.
|
||||
|
||||
### Authentication
|
||||
|
|
|
|||
16
examples/snippets/clients/cancellation.py
Normal file
16
examples/snippets/clients/cancellation.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import mcp.types as types
|
||||
from mcp import ClientSession
|
||||
|
||||
|
||||
async def cancel_request(session: ClientSession) -> None:
|
||||
"""Send a cancellation notification for a previously-issued request."""
|
||||
await session.send_notification(
|
||||
types.ClientNotification(
|
||||
types.CancelledNotification(
|
||||
params=types.CancelledNotificationParams(
|
||||
requestId="request-id-to-cancel",
|
||||
reason="User navigated away",
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
13
examples/snippets/clients/logging_client.py
Normal file
13
examples/snippets/clients/logging_client.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
from mcp import ClientSession, types
|
||||
|
||||
|
||||
async def handle_log(params: types.LoggingMessageNotificationParams) -> None:
|
||||
"""Handle log messages from the server."""
|
||||
print(f"[{params.level}] {params.data}")
|
||||
|
||||
|
||||
session = ClientSession(
|
||||
read_stream,
|
||||
write_stream,
|
||||
logging_callback=handle_log,
|
||||
)
|
||||
22
examples/snippets/clients/roots_example.py
Normal file
22
examples/snippets/clients/roots_example.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
from mcp import ClientSession, types
|
||||
from mcp.shared.context import RequestContext
|
||||
|
||||
|
||||
async def handle_list_roots(
|
||||
context: RequestContext[ClientSession, None],
|
||||
) -> types.ListRootsResult:
|
||||
"""Return the client's workspace roots."""
|
||||
return types.ListRootsResult(
|
||||
roots=[
|
||||
types.Root(uri="file:///home/user/project", name="My Project"),
|
||||
types.Root(uri="file:///home/user/data", name="Data Folder"),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# Pass the callback when creating the session
|
||||
session = ClientSession(
|
||||
read_stream,
|
||||
write_stream,
|
||||
list_roots_callback=handle_list_roots,
|
||||
)
|
||||
16
examples/snippets/clients/sse_client.py
Normal file
16
examples/snippets/clients/sse_client.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import asyncio
|
||||
|
||||
from mcp import ClientSession
|
||||
from mcp.client.sse import sse_client
|
||||
|
||||
|
||||
async def main():
|
||||
async with sse_client("http://localhost:8000/sse") as (read_stream, write_stream):
|
||||
async with ClientSession(read_stream, write_stream) as session:
|
||||
await session.initialize()
|
||||
|
||||
tools = await session.list_tools()
|
||||
print(f"Available tools: {[t.name for t in tools.tools]}")
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
16
examples/snippets/servers/audio_example.py
Normal file
16
examples/snippets/servers/audio_example.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
from mcp.server.fastmcp import FastMCP
|
||||
from mcp.server.fastmcp.utilities.types import Audio
|
||||
|
||||
mcp = FastMCP("Audio Example")
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def get_audio_from_file(file_path: str) -> Audio:
|
||||
"""Return audio from a file path (format auto-detected from extension)."""
|
||||
return Audio(path=file_path)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def get_audio_from_bytes(raw_audio: bytes) -> Audio:
|
||||
"""Return audio from raw bytes with explicit format."""
|
||||
return Audio(data=raw_audio, format="wav")
|
||||
10
examples/snippets/servers/binary_resources.py
Normal file
10
examples/snippets/servers/binary_resources.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
from mcp.server.fastmcp import FastMCP
|
||||
|
||||
mcp = FastMCP("Binary Resource Example")
|
||||
|
||||
|
||||
@mcp.resource("images://logo.png", mime_type="image/png")
|
||||
def get_logo() -> bytes:
|
||||
"""Return a binary image resource."""
|
||||
with open("logo.png", "rb") as f:
|
||||
return f.read()
|
||||
15
examples/snippets/servers/elicitation_complete.py
Normal file
15
examples/snippets/servers/elicitation_complete.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
from mcp.server.fastmcp import Context, FastMCP
|
||||
from mcp.server.session import ServerSession
|
||||
|
||||
mcp = FastMCP("Elicit Complete Example")
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def handle_oauth_callback(elicitation_id: str, ctx: Context[ServerSession, None]) -> str:
|
||||
"""Called when OAuth flow completes out-of-band."""
|
||||
# ... process the callback ...
|
||||
|
||||
# Notify the client that the elicitation is done
|
||||
await ctx.session.send_elicit_complete(elicitation_id)
|
||||
|
||||
return "Authorization complete"
|
||||
25
examples/snippets/servers/elicitation_enum.py
Normal file
25
examples/snippets/servers/elicitation_enum.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
from pydantic import BaseModel, Field
|
||||
|
||||
from mcp.server.fastmcp import Context, FastMCP
|
||||
from mcp.server.session import ServerSession
|
||||
|
||||
mcp = FastMCP("Enum Elicitation Example")
|
||||
|
||||
|
||||
class ColorPreference(BaseModel):
|
||||
color: str = Field(
|
||||
description="Pick your favorite color",
|
||||
json_schema_extra={"enum": ["red", "green", "blue", "yellow"]},
|
||||
)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def pick_color(ctx: Context[ServerSession, None]) -> str:
|
||||
"""Ask the user to pick a color from a list."""
|
||||
result = await ctx.elicit(
|
||||
message="Choose a color:",
|
||||
schema=ColorPreference,
|
||||
)
|
||||
if result.action == "accept":
|
||||
return f"You picked: {result.data.color}"
|
||||
return "No color selected"
|
||||
19
examples/snippets/servers/embedded_resource_results.py
Normal file
19
examples/snippets/servers/embedded_resource_results.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
from mcp.server.fastmcp import FastMCP
|
||||
from mcp.types import EmbeddedResource, TextResourceContents
|
||||
|
||||
mcp = FastMCP("Embedded Resource Example")
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def read_config(path: str) -> EmbeddedResource:
|
||||
"""Read a config file and return it as an embedded resource."""
|
||||
with open(path) as f:
|
||||
content = f.read()
|
||||
return EmbeddedResource(
|
||||
type="resource",
|
||||
resource=TextResourceContents(
|
||||
uri=f"file://{path}",
|
||||
text=content,
|
||||
mimeType="application/json",
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import base64
|
||||
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
from mcp.types import BlobResourceContents, EmbeddedResource
|
||||
|
||||
mcp = FastMCP("Binary Embedded Resource Example")
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def read_binary_file(path: str) -> EmbeddedResource:
|
||||
"""Read a binary file and return it as an embedded resource."""
|
||||
with open(path, "rb") as f:
|
||||
data = base64.b64encode(f.read()).decode()
|
||||
return EmbeddedResource(
|
||||
type="resource",
|
||||
resource=BlobResourceContents(
|
||||
uri=f"file://{path}",
|
||||
blob=data,
|
||||
mimeType="application/octet-stream",
|
||||
),
|
||||
)
|
||||
23
examples/snippets/servers/json_schema_example.py
Normal file
23
examples/snippets/servers/json_schema_example.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class SearchParams(BaseModel):
|
||||
query: str = Field(description="Search query string")
|
||||
max_results: int = Field(default=10, description="Maximum results to return")
|
||||
|
||||
|
||||
# Pydantic generates a JSON Schema 2020-12 compatible schema:
|
||||
schema = SearchParams.model_json_schema()
|
||||
# {
|
||||
# "properties": {
|
||||
# "query": {"description": "Search query string", "type": "string"},
|
||||
# "max_results": {
|
||||
# "default": 10,
|
||||
# "description": "Maximum results to return",
|
||||
# "type": "integer",
|
||||
# },
|
||||
# },
|
||||
# "required": ["query"],
|
||||
# "title": "SearchParams",
|
||||
# "type": "object",
|
||||
# }
|
||||
12
examples/snippets/servers/prompt_change_notifications.py
Normal file
12
examples/snippets/servers/prompt_change_notifications.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
from mcp.server.fastmcp import Context, FastMCP
|
||||
from mcp.server.session import ServerSession
|
||||
|
||||
mcp = FastMCP("Dynamic Prompts")
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def update_prompts(ctx: Context[ServerSession, None]) -> str:
|
||||
"""Update available prompts and notify clients."""
|
||||
# ... modify prompts ...
|
||||
await ctx.session.send_prompt_list_changed()
|
||||
return "Prompts updated"
|
||||
26
examples/snippets/servers/prompt_embedded_resources.py
Normal file
26
examples/snippets/servers/prompt_embedded_resources.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import mcp.types as types
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
from mcp.server.fastmcp.prompts import base
|
||||
|
||||
mcp = FastMCP("Embedded Resource Prompt Example")
|
||||
|
||||
|
||||
@mcp.prompt()
|
||||
def review_file(filename: str) -> list[base.Message]:
|
||||
"""Review a file with its contents embedded."""
|
||||
file_content = open(filename).read()
|
||||
return [
|
||||
base.UserMessage(
|
||||
content=types.TextContent(type="text", text=f"Please review {filename}:"),
|
||||
),
|
||||
base.UserMessage(
|
||||
content=types.EmbeddedResource(
|
||||
type="resource",
|
||||
resource=types.TextResourceContents(
|
||||
uri=f"file://{filename}",
|
||||
text=file_content,
|
||||
mimeType="text/plain",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
20
examples/snippets/servers/prompt_image_content.py
Normal file
20
examples/snippets/servers/prompt_image_content.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import mcp.types as types
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
from mcp.server.fastmcp.prompts import base
|
||||
from mcp.server.fastmcp.utilities.types import Image
|
||||
|
||||
mcp = FastMCP("Image Prompt Example")
|
||||
|
||||
|
||||
@mcp.prompt()
|
||||
def describe_image(image_path: str) -> list[base.Message]:
|
||||
"""Prompt that includes an image for analysis."""
|
||||
img = Image(path=image_path)
|
||||
return [
|
||||
base.UserMessage(
|
||||
content=types.TextContent(type="text", text="Describe this image:"),
|
||||
),
|
||||
base.UserMessage(
|
||||
content=img.to_image_content(),
|
||||
),
|
||||
]
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue