diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 000000000..0346342db --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,23 @@ +default: true + +# MD004 ul-style - Unordered list style +MD004: false + +# MD007 ul-indent - Unordered list indentation +MD007: + indent: 4 + +# MD013 line-length - Line length +MD013: false + +# MD029 ol-prefix - Ordered list item prefix +MD029: false + +# MD033 no-inline-html Inline HTML +MD033: false + +# MD041 first-line-heading/first-line-h1 +MD041: false + +# MD059 descriptive-link-text +MD059: false diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 35e12261a..61672c07b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,6 +7,13 @@ repos: - id: prettier types_or: [yaml, json5] + - repo: https://github.com/DavidAnson/markdownlint-cli2 + rev: v0.18.1 + hooks: + - id: markdownlint-cli2 + args: ["--fix"] + types: [markdown] + - repo: local hooks: - id: ruff-format diff --git a/CLAUDE.md b/CLAUDE.md index 619f3bb44..7f17b56f0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -26,15 +26,19 @@ This document contains critical information about working with this codebase. Fo - Bug fixes require regression tests - For commits fixing bugs or adding features based on user reports add: + ```bash git commit --trailer "Reported-by:" ``` + Where `` is the name of the user. - For commits related to a Github issue, add + ```bash git commit --trailer "Github-Issue:#" ``` + - NEVER ever mention a `co-authored-by` or similar aspects. In particular, never mention the tool used to create the commit message or PR. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 05c32c605..985a28566 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -60,7 +60,7 @@ representative at an online or offline event. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at -mcp-coc@anthropic.com. +. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the @@ -116,7 +116,7 @@ the community. This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. +. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). @@ -124,5 +124,5 @@ enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. +. Translations are available at +. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 929e5f504..a57781ff4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,7 @@ Thank you for your interest in contributing to the MCP Python SDK! This document 3. Fork the repository 4. Clone your fork: `git clone https://github.com/YOUR-USERNAME/python-sdk.git` 5. Install dependencies: + ```bash uv sync --frozen --all-extras --dev ``` @@ -25,16 +26,19 @@ uv sync --frozen --all-extras --dev 3. Make your changes 4. Ensure tests pass: -```bash + +```bash uv run pytest ``` 5. Run type checking: + ```bash uv run pyright ``` 6. Run linting: + ```bash uv run ruff check . uv run ruff format . diff --git a/README.md b/README.md index 412143a9f..ac7f676a2 100644 --- a/README.md +++ b/README.md @@ -17,39 +17,39 @@ ## Table of Contents - [MCP Python SDK](#mcp-python-sdk) - - [Overview](#overview) - - [Installation](#installation) - - [Adding MCP to your python project](#adding-mcp-to-your-python-project) - - [Running the standalone MCP development tools](#running-the-standalone-mcp-development-tools) - - [Quickstart](#quickstart) - - [What is MCP?](#what-is-mcp) - - [Core Concepts](#core-concepts) - - [Server](#server) - - [Resources](#resources) - - [Tools](#tools) - - [Structured Output](#structured-output) - - [Prompts](#prompts) - - [Images](#images) - - [Context](#context) - - [Completions](#completions) - - [Elicitation](#elicitation) - - [Authentication](#authentication) - - [Running Your Server](#running-your-server) - - [Development Mode](#development-mode) - - [Claude Desktop Integration](#claude-desktop-integration) - - [Direct Execution](#direct-execution) - - [Mounting to an Existing ASGI Server](#mounting-to-an-existing-asgi-server) - - [Examples](#examples) - - [Echo Server](#echo-server) - - [SQLite Explorer](#sqlite-explorer) - - [Advanced Usage](#advanced-usage) - - [Low-Level Server](#low-level-server) - - [Writing MCP Clients](#writing-mcp-clients) - - [MCP Primitives](#mcp-primitives) - - [Server Capabilities](#server-capabilities) - - [Documentation](#documentation) - - [Contributing](#contributing) - - [License](#license) + - [Overview](#overview) + - [Installation](#installation) + - [Adding MCP to your python project](#adding-mcp-to-your-python-project) + - [Running the standalone MCP development tools](#running-the-standalone-mcp-development-tools) + - [Quickstart](#quickstart) + - [What is MCP?](#what-is-mcp) + - [Core Concepts](#core-concepts) + - [Server](#server) + - [Resources](#resources) + - [Tools](#tools) + - [Structured Output](#structured-output) + - [Prompts](#prompts) + - [Images](#images) + - [Context](#context) + - [Completions](#completions) + - [Elicitation](#elicitation) + - [Authentication](#authentication) + - [Running Your Server](#running-your-server) + - [Development Mode](#development-mode) + - [Claude Desktop Integration](#claude-desktop-integration) + - [Direct Execution](#direct-execution) + - [Mounting to an Existing ASGI Server](#mounting-to-an-existing-asgi-server) + - [Examples](#examples) + - [Echo Server](#echo-server) + - [SQLite Explorer](#sqlite-explorer) + - [Advanced Usage](#advanced-usage) + - [Low-Level Server](#low-level-server) + - [Writing MCP Clients](#writing-mcp-clients) + - [MCP Primitives](#mcp-primitives) + - [Server Capabilities](#server-capabilities) + - [Documentation](#documentation) + - [Contributing](#contributing) + - [License](#license) [pypi-badge]: https://img.shields.io/pypi/v/mcp.svg [pypi-url]: https://pypi.org/project/mcp/ @@ -93,6 +93,7 @@ If you haven't created a uv-managed project yet, create one: ``` Alternatively, for projects using pip for dependencies: + ```bash pip install "mcp[cli]" ``` @@ -132,11 +133,13 @@ def get_greeting(name: str) -> str: ``` You can install this server in [Claude Desktop](https://claude.ai/download) and interact with it right away by running: + ```bash mcp install server.py ``` Alternatively, you can test it with the MCP Inspector: + ```bash mcp dev server.py ``` @@ -253,9 +256,10 @@ async def fetch_weather(city: str) -> str: #### Structured Output Tools will return structured results by default, if their return type -annotation is compatible. Otherwise, they will return unstructured results. +annotation is compatible. Otherwise, they will return unstructured results. Structured output supports these return types: + - Pydantic models (BaseModel subclasses) - TypedDicts - Dataclasses and other classes with type hints @@ -267,17 +271,17 @@ Classes without type hints cannot be serialized for structured output. Only classes with properly annotated attributes will be converted to Pydantic models for schema generation and validation. -Structured results are automatically validated against the output schema -generated from the annotation. This ensures the tool returns well-typed, +Structured results are automatically validated against the output schema +generated from the annotation. This ensures the tool returns well-typed, validated data that clients can easily process. **Note:** For backward compatibility, unstructured results are also -returned. Unstructured results are provided for backward compatibility +returned. Unstructured results are provided for backward compatibility with previous versions of the MCP specification, and are quirks-compatible with previous versions of FastMCP in the current version of the SDK. -**Note:** In cases where a tool function's return type annotation -causes the tool to be classified as structured _and this is undesirable_, +**Note:** In cases where a tool function's return type annotation +causes the tool to be classified as structured _and this is undesirable_, the classification can be suppressed by passing `structured_output=False` to the `@tool` decorator. @@ -440,6 +444,7 @@ async def long_task(files: list[str], ctx: Context) -> str: MCP supports providing completion suggestions for prompt arguments and resource template parameters. With the context parameter, servers can provide completions based on previously resolved values: Client usage: + ```python from mcp.client.session import ClientSession from mcp.types import ResourceTemplateReference @@ -465,6 +470,7 @@ async def use_completion(session: ClientSession): ``` Server implementation: + ```python from mcp.server import Server from mcp.types import ( @@ -496,6 +502,7 @@ async def handle_completion( return Completion(values=filtered) return None ``` + ### Elicitation Request additional information from users during tool execution: @@ -537,6 +544,7 @@ async def book_table(date: str, party_size: int, ctx: Context) -> str: ``` The `elicit()` method returns an `ElicitationResult` with: + - `action`: "accept", "decline", or "cancel" - `data`: The validated response (only when accepted) - `validation_error`: Any validation error message @@ -576,6 +584,7 @@ mcp = FastMCP( For a complete example with separate Authorization Server and Resource Server implementations, see [`examples/servers/simple-auth/`](examples/servers/simple-auth/). **Architecture:** + - **Authorization Server (AS)**: Handles OAuth flows, user authentication, and token issuance - **Resource Server (RS)**: Your MCP server that validates tokens and serves protected resources - **Client**: Discovers AS through RFC 9728, obtains tokens, and uses them with the MCP server @@ -627,6 +636,7 @@ if __name__ == "__main__": ``` Run it with: + ```bash python server.py # or @@ -704,10 +714,12 @@ app.mount("/math", math.mcp.streamable_http_app()) ``` For low level server with Streamable HTTP implementations, see: + - Stateful server: [`examples/servers/simple-streamablehttp/`](examples/servers/simple-streamablehttp/) - Stateless server: [`examples/servers/simple-streamablehttp-stateless/`](examples/servers/simple-streamablehttp-stateless/) The streamable HTTP transport supports: + - Stateful and stateless operation modes - Resumability with event stores - JSON or SSE response formats @@ -880,6 +892,7 @@ async def query_db(name: str, arguments: dict) -> list: ``` The lifespan API provides: + - A way to initialize resources when the server starts and clean them up when it stops - Access to initialized resources through the request context in handlers - Type-safe context passing between lifespan and request handlers @@ -1006,6 +1019,7 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]: ``` Tools can return data in three ways: + 1. **Content only**: Return a list of content blocks (default behavior before spec revision 2025-06-18) 2. **Structured data only**: Return a dictionary that will be serialized to JSON (Introduced in spec revision 2025-06-18) 3. **Both**: Return a tuple of (content, structured_data) preferred option to use for backwards compatibility @@ -1131,6 +1145,7 @@ async def display_resources(session: ClientSession): ``` The `get_display_name()` function implements the proper precedence rules for displaying names: + - For tools: `title` > `annotations.title` > `name` - For other objects: `title` > `name` @@ -1189,7 +1204,6 @@ async def main(): For a complete working example, see [`examples/clients/simple-auth-client/`](examples/clients/simple-auth-client/). - ### MCP Primitives The MCP protocol defines three core primitives that servers can implement: diff --git a/SECURITY.md b/SECURITY.md index 8c09400cc..654515610 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,4 +1,5 @@ # Security Policy + Thank you for helping us keep the SDKs and systems they interact with secure. ## Reporting Security Issues diff --git a/examples/clients/simple-auth-client/README.md b/examples/clients/simple-auth-client/README.md index cf6050b1c..224040712 100644 --- a/examples/clients/simple-auth-client/README.md +++ b/examples/clients/simple-auth-client/README.md @@ -47,7 +47,7 @@ The client will open your browser for authentication. After completing OAuth, yo ## Example -``` +```markdown 🔐 Simple MCP Auth Client Connecting to: http://localhost:3001 diff --git a/examples/clients/simple-chatbot/README.MD b/examples/clients/simple-chatbot/README.MD index 22996d962..482109f97 100644 --- a/examples/clients/simple-chatbot/README.MD +++ b/examples/clients/simple-chatbot/README.MD @@ -25,11 +25,12 @@ This example demonstrates how to integrate the Model Context Protocol (MCP) into ```plaintext LLM_API_KEY=your_api_key_here ``` + **Note:** The current implementation is configured to use the Groq API endpoint (`https://api.groq.com/openai/v1/chat/completions`) with the `llama-3.2-90b-vision-preview` model. If you plan to use a different LLM provider, you'll need to modify the `LLMClient` class in `main.py` to use the appropriate endpoint URL and model parameters. 3. **Configure servers:** - The `servers_config.json` follows the same structure as Claude Desktop, allowing for easy integration of multiple servers. + The `servers_config.json` follows the same structure as Claude Desktop, allowing for easy integration of multiple servers. Here's an example: ```json @@ -46,9 +47,11 @@ This example demonstrates how to integrate the Model Context Protocol (MCP) into } } ``` + Environment variables are supported as well. Pass them as you would with the Claude Desktop App. Example: + ```json { "mcpServers": { @@ -72,7 +75,7 @@ This example demonstrates how to integrate the Model Context Protocol (MCP) into ``` 2. **Interact with the assistant:** - + The assistant will automatically detect available tools and can respond to queries based on the tools provided by the configured servers. 3. **Exit the session:** @@ -86,6 +89,7 @@ This example demonstrates how to integrate the Model Context Protocol (MCP) into - **Server Integration**: Supports any MCP-compatible server, tested with various server implementations including Uvicorn and Node.js. ### Class Structure + - **Configuration**: Manages environment variables and server configurations - **Server**: Handles MCP server initialization, tool discovery, and execution - **Tool**: Represents individual tools with their properties and formatting @@ -107,5 +111,3 @@ This example demonstrates how to integrate the Model Context Protocol (MCP) into - If it's a direct response → return to user - Tool results are sent back to LLM for interpretation - Final response is presented to user - - diff --git a/examples/servers/simple-auth/README.md b/examples/servers/simple-auth/README.md index a15ad1daf..21d51e83a 100644 --- a/examples/servers/simple-auth/README.md +++ b/examples/servers/simple-auth/README.md @@ -4,7 +4,6 @@ This example demonstrates OAuth 2.0 authentication with the Model Context Protoc --- - ## Running the Servers ### Step 1: Start Authorization Server @@ -18,6 +17,7 @@ uv run mcp-simple-auth-as --port=9000 ``` **What it provides:** + - OAuth 2.0 flows (registration, authorization, token exchange) - Simple credential-based authentication (no external provider needed) - Token introspection endpoint for Resource Servers (`/introspect`) @@ -38,7 +38,6 @@ uv run mcp-simple-auth-rs --port=8001 --auth-server=http://localhost:9000 --tra ``` - ### Step 3: Test with Client ```bash @@ -47,15 +46,16 @@ cd examples/clients/simple-auth-client MCP_SERVER_PORT=8001 MCP_TRANSPORT_TYPE=streamable_http uv run mcp-simple-auth-client ``` - ## How It Works ### RFC 9728 Discovery **Client → Resource Server:** + ```bash curl http://localhost:8001/.well-known/oauth-protected-resource ``` + ```json { "resource": "http://localhost:8001", @@ -64,9 +64,11 @@ curl http://localhost:8001/.well-known/oauth-protected-resource ``` **Client → Authorization Server:** + ```bash curl http://localhost:9000/.well-known/oauth-authorization-server ``` + ```json { "issuer": "http://localhost:9000", @@ -75,7 +77,6 @@ curl http://localhost:9000/.well-known/oauth-authorization-server } ``` - ## Legacy MCP Server as Authorization Server (Backwards Compatibility) For backwards compatibility with older MCP implementations, a legacy server is provided that acts as an Authorization Server (following the old spec where MCP servers could optionally provide OAuth): @@ -88,6 +89,7 @@ uv run mcp-simple-auth-legacy --port=8002 ``` **Differences from the new architecture:** + - **MCP server acts as AS:** The MCP server itself provides OAuth endpoints (old spec behavior) - **No separate RS:** The server handles both authentication and MCP tools - **Local token validation:** Tokens are validated internally without introspection @@ -103,6 +105,7 @@ MCP_SERVER_PORT=8002 MCP_TRANSPORT_TYPE=streamable_http uv run mcp-simple-auth-c ``` The client will: + 1. Try RFC 9728 discovery at `/.well-known/oauth-protected-resource` (404 on legacy server) 2. Fall back to direct OAuth discovery at `/.well-known/oauth-authorization-server` 3. Complete authentication with the MCP server acting as its own AS @@ -112,6 +115,7 @@ This ensures existing MCP servers (which could optionally act as Authorization S ## Manual Testing ### Test Discovery + ```bash # Test Resource Server discovery endpoint (new architecture) curl -v http://localhost:8001/.well-known/oauth-protected-resource @@ -121,6 +125,7 @@ curl -v http://localhost:9000/.well-known/oauth-authorization-server ``` ### Test Token Introspection + ```bash # After getting a token through OAuth flow: curl -X POST http://localhost:9000/introspect \ diff --git a/examples/servers/simple-streamablehttp-stateless/README.md b/examples/servers/simple-streamablehttp-stateless/README.md index 2abb60614..b87250b35 100644 --- a/examples/servers/simple-streamablehttp-stateless/README.md +++ b/examples/servers/simple-streamablehttp-stateless/README.md @@ -10,7 +10,6 @@ A stateless MCP server example demonstrating the StreamableHttp transport withou - Task lifecycle scoped to individual requests - Suitable for deployment in multi-node environments - ## Usage Start the server: @@ -35,7 +34,6 @@ The server exposes a tool named "start-notification-stream" that accepts three a - `count`: Number of notifications to send (e.g., 5) - `caller`: Identifier string for the caller - ## Client -You can connect to this server using an HTTP client. For now, only the TypeScript SDK has streamable HTTP client examples, or you can use [Inspector](https://github.com/modelcontextprotocol/inspector) for testing. \ No newline at end of file +You can connect to this server using an HTTP client. For now, only the TypeScript SDK has streamable HTTP client examples, or you can use [Inspector](https://github.com/modelcontextprotocol/inspector) for testing. diff --git a/examples/servers/simple-streamablehttp/README.md b/examples/servers/simple-streamablehttp/README.md index f850b7286..983636717 100644 --- a/examples/servers/simple-streamablehttp/README.md +++ b/examples/servers/simple-streamablehttp/README.md @@ -40,16 +40,14 @@ This server includes resumability support through the InMemoryEventStore. This e - Reconnect to the server after a disconnection - Resume event streaming from where they left off using the Last-Event-ID header - The server will: + - Generate unique event IDs for each SSE message - Store events in memory for later replay - Replay missed events when a client reconnects with a Last-Event-ID header Note: The InMemoryEventStore is designed for demonstration purposes only. For production use, consider implementing a persistent storage solution. - - ## Client -You can connect to this server using an HTTP client, for now only Typescript SDK has streamable HTTP client examples or you can use [Inspector](https://github.com/modelcontextprotocol/inspector) \ No newline at end of file +You can connect to this server using an HTTP client, for now only Typescript SDK has streamable HTTP client examples or you can use [Inspector](https://github.com/modelcontextprotocol/inspector)