chore: add markdownlint on pre-commit hook and lint md files (#996)
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
This commit is contained in:
@@ -7,6 +7,20 @@ repos:
|
||||
- id: prettier
|
||||
types_or: [yaml, json5]
|
||||
|
||||
- repo: https://github.com/igorshubovych/markdownlint-cli
|
||||
rev: v0.45.0
|
||||
hooks:
|
||||
- id: markdownlint
|
||||
args:
|
||||
[
|
||||
"--fix",
|
||||
"--config",
|
||||
"pyproject.toml",
|
||||
"--configPointer",
|
||||
"/tool/markdown/lint",
|
||||
]
|
||||
types: [markdown]
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: ruff-format
|
||||
|
||||
@@ -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:<name>"
|
||||
```
|
||||
|
||||
Where `<name>` is the name of the user.
|
||||
|
||||
- For commits related to a Github issue, add
|
||||
|
||||
```bash
|
||||
git commit --trailer "Github-Issue:#<number>"
|
||||
```
|
||||
|
||||
- NEVER ever mention a `co-authored-by` or similar aspects. In particular, never
|
||||
mention the tool used to create the commit message or PR.
|
||||
|
||||
|
||||
+4
-4
@@ -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.
|
||||
<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.
|
||||
<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.
|
||||
<https://www.contributor-covenant.org/faq>. Translations are available at
|
||||
<https://www.contributor-covenant.org/translations>.
|
||||
|
||||
+6
-1
@@ -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,22 +26,26 @@ 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 .
|
||||
```
|
||||
|
||||
7. Update README snippets if you modified example code:
|
||||
|
||||
```bash
|
||||
uv run scripts/update_readme_snippets.py
|
||||
```
|
||||
|
||||
@@ -95,6 +95,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]"
|
||||
```
|
||||
@@ -134,11 +135,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
|
||||
uv run mcp install server.py
|
||||
```
|
||||
|
||||
Alternatively, you can test it with the MCP Inspector:
|
||||
|
||||
```bash
|
||||
uv run mcp dev server.py
|
||||
```
|
||||
@@ -232,6 +235,7 @@ def get_settings() -> str:
|
||||
"debug": false
|
||||
}"""
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
@@ -258,15 +262,17 @@ def get_weather(city: str, unit: str = "celsius") -> str:
|
||||
# This would normally call a weather API
|
||||
return f"Weather in {city}: 22degrees{unit[0].upper()}"
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/basic_tool.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_tool.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
#### 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
|
||||
@@ -278,17 +284,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.
|
||||
|
||||
@@ -407,6 +413,7 @@ def debug_error(error: str) -> list[base.Message]:
|
||||
base.AssistantMessage("I'll help debug that. What have you tried so far?"),
|
||||
]
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/basic_prompt.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_prompt.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
@@ -456,6 +463,7 @@ async def long_running_task(task_name: str, ctx: Context, steps: int = 5) -> str
|
||||
|
||||
return f"Task '{task_name}' completed"
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/tool_progress.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/tool_progress.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
@@ -464,6 +472,7 @@ _Full example: [examples/snippets/servers/tool_progress.py](https://github.com/m
|
||||
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
|
||||
@@ -542,6 +551,7 @@ async def handle_completion(
|
||||
|
||||
return None
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/completion.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/completion.py)_
|
||||
<!-- /snippet-source -->
|
||||
### Elicitation
|
||||
@@ -592,10 +602,12 @@ async def book_table(
|
||||
# Date available
|
||||
return f"[SUCCESS] Booked for {date} at {time}"
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/elicitation.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/elicitation.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
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
|
||||
@@ -631,6 +643,7 @@ async def generate_poem(topic: str, ctx: Context) -> str:
|
||||
return result.content.text
|
||||
return str(result.content)
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/sampling.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/sampling.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
@@ -659,6 +672,7 @@ async def process_data(data: str, ctx: Context) -> str:
|
||||
|
||||
return f"Processed: {data}"
|
||||
```
|
||||
|
||||
_Full example: [examples/snippets/servers/notifications.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/notifications.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
@@ -697,6 +711,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
|
||||
@@ -748,6 +763,7 @@ if __name__ == "__main__":
|
||||
```
|
||||
|
||||
Run it with:
|
||||
|
||||
```bash
|
||||
python server.py
|
||||
# or
|
||||
@@ -827,10 +843,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
|
||||
@@ -1003,6 +1021,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
|
||||
@@ -1129,6 +1148,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
|
||||
@@ -1254,6 +1274,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`
|
||||
|
||||
@@ -1312,7 +1333,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:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Security Policy
|
||||
|
||||
Thank you for helping us keep the SDKs and systems they interact with secure.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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.
|
||||
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.
|
||||
|
||||
@@ -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)
|
||||
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)
|
||||
|
||||
@@ -129,3 +129,13 @@ filterwarnings = [
|
||||
# pywin32 internal deprecation warning
|
||||
"ignore:getargs.*The 'u' format is deprecated:DeprecationWarning"
|
||||
]
|
||||
|
||||
[tool.markdown.lint]
|
||||
default=true
|
||||
MD004=false # ul-style - Unordered list style
|
||||
MD007.indent=2 # ul-indent - Unordered list indentation
|
||||
MD013=false # line-length - Line length
|
||||
MD029=false # ol-prefix - Ordered list item prefix
|
||||
MD033=false # no-inline-html Inline HTML
|
||||
MD041=false # first-line-heading/first-line-h1
|
||||
MD059=false # descriptive-link-text
|
||||
|
||||
Reference in New Issue
Block a user