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:
Stanley Law
2025-07-10 16:43:49 +08:00
committed by GitHub
parent f55831ee79
commit 6d092af6fd
12 changed files with 85 additions and 28 deletions
+14
View File
@@ -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
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
```
+27 -7
View File
@@ -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
View File
@@ -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
+6 -4
View File
@@ -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
+9 -4
View File
@@ -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)
+10
View File
@@ -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