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
commit 6d092af6fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 85 additions and 28 deletions

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

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.

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>.

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
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
```

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,6 +262,7 @@ 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 -->
@ -267,6 +272,7 @@ Tools will return structured results by default, if their return type
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
@ -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:

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

View file

@ -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

View file

@ -25,6 +25,7 @@ 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:**
@ -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": {
@ -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

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 \

View file

@ -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.

View file

@ -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)

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