|
34 | 34 | - [Examples](#examples)
|
35 | 35 | - [Echo Server](#echo-server)
|
36 | 36 | - [SQLite Explorer](#sqlite-explorer)
|
| 37 | +- [Advanced Usage](#advanced-usage) |
| 38 | + - [Low-Level Server](#low-level-server) |
| 39 | + - [Writing MCP Clients](#writing-mcp-clients) |
| 40 | + - [MCP Primitives](#mcp-primitives) |
| 41 | + - [Server Capabilities](#server-capabilities) |
37 | 42 | - [Documentation](#documentation)
|
38 | 43 | - [Contributing](#contributing)
|
39 | 44 | - [License](#license)
|
@@ -325,6 +330,144 @@ def query_data(sql: str) -> str:
|
325 | 330 | return f"Error: {str(e)}"
|
326 | 331 | ```
|
327 | 332 |
|
| 333 | +## Advanced Usage |
| 334 | + |
| 335 | +### Low-Level Server |
| 336 | + |
| 337 | +For more control, you can use the low-level server implementation directly. This gives you full access to the protocol and allows you to customize every aspect of your server: |
| 338 | + |
| 339 | +```python |
| 340 | +from mcp.server.lowlevel import Server, NotificationOptions |
| 341 | +from mcp.server.models import InitializationOptions |
| 342 | +import mcp.server.stdio |
| 343 | +import mcp.types as types |
| 344 | + |
| 345 | +# Create a server instance |
| 346 | +server = Server("example-server") |
| 347 | + |
| 348 | +@server.list_prompts() |
| 349 | +async def handle_list_prompts() -> list[types.Prompt]: |
| 350 | + return [ |
| 351 | + types.Prompt( |
| 352 | + name="example-prompt", |
| 353 | + description="An example prompt template", |
| 354 | + arguments=[ |
| 355 | + types.PromptArgument( |
| 356 | + name="arg1", |
| 357 | + description="Example argument", |
| 358 | + required=True |
| 359 | + ) |
| 360 | + ] |
| 361 | + ) |
| 362 | + ] |
| 363 | + |
| 364 | +@server.get_prompt() |
| 365 | +async def handle_get_prompt( |
| 366 | + name: str, |
| 367 | + arguments: dict[str, str] | None |
| 368 | +) -> types.GetPromptResult: |
| 369 | + if name != "example-prompt": |
| 370 | + raise ValueError(f"Unknown prompt: {name}") |
| 371 | + |
| 372 | + return types.GetPromptResult( |
| 373 | + description="Example prompt", |
| 374 | + messages=[ |
| 375 | + types.PromptMessage( |
| 376 | + role="user", |
| 377 | + content=types.TextContent( |
| 378 | + type="text", |
| 379 | + text="Example prompt text" |
| 380 | + ) |
| 381 | + ) |
| 382 | + ] |
| 383 | + ) |
| 384 | + |
| 385 | +async def run(): |
| 386 | + async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): |
| 387 | + await server.run( |
| 388 | + read_stream, |
| 389 | + write_stream, |
| 390 | + InitializationOptions( |
| 391 | + server_name="example", |
| 392 | + server_version="0.1.0", |
| 393 | + capabilities=server.get_capabilities( |
| 394 | + notification_options=NotificationOptions(), |
| 395 | + experimental_capabilities={}, |
| 396 | + ) |
| 397 | + ) |
| 398 | + ) |
| 399 | + |
| 400 | +if __name__ == "__main__": |
| 401 | + import asyncio |
| 402 | + asyncio.run(run()) |
| 403 | +``` |
| 404 | + |
| 405 | +### Writing MCP Clients |
| 406 | + |
| 407 | +The SDK provides a high-level client interface for connecting to MCP servers: |
| 408 | + |
| 409 | +```python |
| 410 | +from mcp import ClientSession, StdioServerParameters |
| 411 | +from mcp.client.stdio import stdio_client |
| 412 | + |
| 413 | +# Create server parameters for stdio connection |
| 414 | +server_params = StdioServerParameters( |
| 415 | + command="python", # Executable |
| 416 | + args=["example_server.py"], # Optional command line arguments |
| 417 | + env=None # Optional environment variables |
| 418 | +) |
| 419 | + |
| 420 | +async def run(): |
| 421 | + async with stdio_client(server_params) as (read, write): |
| 422 | + async with ClientSession(read, write) as session: |
| 423 | + # Initialize the connection |
| 424 | + await session.initialize() |
| 425 | + |
| 426 | + # List available prompts |
| 427 | + prompts = await session.list_prompts() |
| 428 | + |
| 429 | + # Get a prompt |
| 430 | + prompt = await session.get_prompt("example-prompt", arguments={"arg1": "value"}) |
| 431 | + |
| 432 | + # List available resources |
| 433 | + resources = await session.list_resources() |
| 434 | + |
| 435 | + # List available tools |
| 436 | + tools = await session.list_tools() |
| 437 | + |
| 438 | + # Read a resource |
| 439 | + resource = await session.read_resource("file://some/path") |
| 440 | + |
| 441 | + # Call a tool |
| 442 | + result = await session.call_tool("tool-name", arguments={"arg1": "value"}) |
| 443 | + |
| 444 | +if __name__ == "__main__": |
| 445 | + import asyncio |
| 446 | + asyncio.run(run()) |
| 447 | +``` |
| 448 | + |
| 449 | +### MCP Primitives |
| 450 | + |
| 451 | +The MCP protocol defines three core primitives that servers can implement: |
| 452 | + |
| 453 | +| Primitive | Control | Description | Example Use | |
| 454 | +|-----------|-----------------------|-----------------------------------------------------|------------------------------| |
| 455 | +| Prompts | User-controlled | Interactive templates invoked by user choice | Slash commands, menu options | |
| 456 | +| Resources | Application-controlled| Contextual data managed by the client application | File contents, API responses | |
| 457 | +| Tools | Model-controlled | Functions exposed to the LLM to take actions | API calls, data updates | |
| 458 | + |
| 459 | +### Server Capabilities |
| 460 | + |
| 461 | +MCP servers declare capabilities during initialization: |
| 462 | + |
| 463 | +| Capability | Feature Flag | Description | |
| 464 | +|-------------|------------------------------|------------------------------------| |
| 465 | +| `prompts` | `listChanged` | Prompt template management | |
| 466 | +| `resources` | `subscribe`<br/>`listChanged`| Resource exposure and updates | |
| 467 | +| `tools` | `listChanged` | Tool discovery and execution | |
| 468 | +| `logging` | - | Server logging configuration | |
| 469 | +| `completion`| - | Argument completion suggestions | |
| 470 | + |
328 | 471 | ## Documentation
|
329 | 472 |
|
330 | 473 | - [Model Context Protocol documentation](https://modelcontextprotocol.io)
|
|
0 commit comments