-
Notifications
You must be signed in to change notification settings - Fork 3.8k
docs: cover the remaining Tier 1 audit items #3325
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| from mcp.server import Server, ServerRequestContext | ||
| from mcp.types import CallToolRequestParams, CallToolResult, ListToolsResult, PaginatedRequestParams, TextContent, Tool | ||
|
|
||
| FIND_BOOK = Tool( | ||
| name="find_book", | ||
| description="Find one book by ISBN, or by title and author.", | ||
| input_schema={ | ||
| "type": "object", | ||
| "properties": { | ||
| "isbn": {"type": "string", "pattern": "^[0-9]{13}$"}, | ||
| "title": {"type": "string"}, | ||
| "author": {"type": "string"}, | ||
| }, | ||
| "oneOf": [{"required": ["isbn"]}, {"required": ["title", "author"]}], | ||
| "additionalProperties": False, | ||
| }, | ||
| ) | ||
|
|
||
|
|
||
| async def list_tools(ctx: ServerRequestContext, params: PaginatedRequestParams | None) -> ListToolsResult: | ||
| return ListToolsResult(tools=[FIND_BOOK]) | ||
|
|
||
|
|
||
| async def call_tool(ctx: ServerRequestContext, params: CallToolRequestParams) -> CallToolResult: | ||
| args = params.arguments or {} | ||
| found = f"ISBN {args['isbn']}" if "isbn" in args else f"{args['title']!r} by {args['author']}" | ||
| return CallToolResult(content=[TextContent(type="text", text=f"Found {found} on shelf C-3.")]) | ||
|
|
||
|
|
||
| server = Server("Bookshop", on_list_tools=list_tools, on_call_tool=call_tool) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| from mcp.server import MCPServer | ||
| from mcp.types import EmbeddedResource, TextResourceContents | ||
|
|
||
| mcp = MCPServer("Brand kit") | ||
|
|
||
|
|
||
| @mcp.resource("brand://guidelines", mime_type="text/markdown") | ||
| def guidelines() -> str: | ||
| """How to use the brand assets.""" | ||
| return "# Brand guidelines\n\nUse the primary colour for calls to action.\n" | ||
|
|
||
|
|
||
| @mcp.tool() | ||
| def brand_guidelines() -> EmbeddedResource: | ||
| """The brand guidelines as a Markdown document.""" | ||
| return EmbeddedResource( | ||
| resource=TextResourceContents(uri="brand://guidelines", mime_type="text/markdown", text=guidelines()) | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| from pathlib import Path | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 [quality] New docs examples/claims added without the chapter behavioral tests every existing tutorial has sweep: Extended reasoning...Repo convention (tests/docs_src/test_media.py, test_prompts.py, test_lowlevel.py all open with "every claim the page makes, proved against the real SDK" and import/exercise every prior tutorial: media 001-004, prompts 001-003, lowlevel 001-006) is that each docs_src tutorial gets a behavioral test; the five new modules (docs_src/media/tutorial005.py, docs_src/prompts/tutorial004-006.py, docs_src/lowlevel/tutorial007.py) are only covered by the test_shape.py import-only floor, and likewise tests/docs_src/test_deprecated.py's header says each prose claim on docs/deprecated.md is executed, yet the two new sections' claims (legacy ping both directions with the printed '2025-11-25' output, roots list_changed end-to-end via on_roots_list_changed, the notification being 'silently dropped' on modern connections) have no test. Concrete cost: the rendered JSON/output blocks and behavioral assertions on these pages can silently drift from real SDK behavior — exactly the drift these chapter tests exist to prevent — and future refactors won't fail CI when they break the examples' runtime behavi Verification: nit — Convention is real and violated. tests/docs_src/test_media.py:1, test_prompts.py:1 and test_lowlevel.py:1 all open with "every claim the page makes, proved against the real SDK", and their imports stop just short of the new files: test_media.py:9
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Intentional for this PR: it is scoped to the narrative coverage the tier audit needs and adds no tests. The new |
||
|
|
||
| from mcp.server import MCPServer | ||
| from mcp.server.mcpserver import Message, UserMessage | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 [quality] nit: New prompt examples import Message/UserMessage from Extended reasoning...docs/servers/prompts.md line 88 (the bullet under tutorial002, unchanged by this PR) states " Verification: nit — Factually accurate quality finding. docs_src/prompts/tutorial004.py:4 ( |
||
| from mcp.types import EmbeddedResource, TextResourceContents | ||
|
|
||
| mcp = MCPServer("Code Helper") | ||
|
|
||
| STYLE_GUIDE_FILE = Path(__file__).parent / "style-guide.md" # or the path to your file on disk | ||
|
|
||
|
|
||
| @mcp.resource("style://python", mime_type="text/markdown") | ||
| def style_guide() -> str: | ||
| """The team's Python style guide.""" | ||
| return STYLE_GUIDE_FILE.read_text(encoding="utf-8") | ||
|
|
||
|
|
||
| @mcp.prompt() | ||
| def review_code(code: str) -> list[Message]: | ||
| """Review a piece of code against the team style guide.""" | ||
| guide = TextResourceContents(uri="style://python", mime_type="text/markdown", text=style_guide()) | ||
| return [ | ||
| UserMessage(EmbeddedResource(resource=guide)), | ||
| UserMessage(f"Review this code against the style guide above:\n\n{code}"), | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| from pathlib import Path | ||
|
|
||
| from mcp.server import MCPServer | ||
| from mcp.server.mcpserver import Image, Message, UserMessage | ||
|
|
||
| mcp = MCPServer("Code Helper") | ||
|
|
||
| DIAGRAM_FILE = Path(__file__).parent / "architecture.png" # or the path to your file on disk | ||
|
|
||
|
|
||
| @mcp.prompt() | ||
| def explain_component(component: str) -> list[Message]: | ||
| """Explain one component using the architecture diagram.""" | ||
| return [ | ||
| UserMessage(Image(path=DIAGRAM_FILE)), | ||
| UserMessage(f"Where does {component} sit in this architecture, and what does it talk to?"), | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| from contextlib import suppress | ||
|
|
||
| from mcp.server import MCPServer | ||
| from mcp.server.mcpserver import Context | ||
| from mcp.server.mcpserver.prompts import Prompt | ||
|
|
||
| mcp = MCPServer("Code Helper") | ||
|
|
||
|
|
||
| @mcp.prompt() | ||
| def review_code(code: str) -> str: | ||
| """Review a piece of code.""" | ||
| return f"Please review this code:\n\n{code}" | ||
|
|
||
|
|
||
| @mcp.tool() | ||
| async def save_template(name: str, instruction: str, ctx: Context) -> str: | ||
| """Save an instruction as a prompt the user can pick from the menu.""" | ||
|
|
||
| def template(code: str) -> str: | ||
| return f"{instruction}\n\n{code}" | ||
|
|
||
| with suppress(ValueError): # replace an existing entry of the same name | ||
| mcp.remove_prompt(name) | ||
| mcp.add_prompt(Prompt.from_function(template, name=name, description=instruction)) | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
|
||
| await ctx.notify_prompts_changed() | ||
| await ctx.session.send_prompt_list_changed() | ||
| return f"Saved '{name}' to the prompt menu." | ||
|
claude[bot] marked this conversation as resolved.
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟣 Pre-existing: new "Changing the list at runtime" section claims ctx.session.send_prompt_list_changed() notifies pre-2026 clients, but MCPServer advertises prompts.listChanged: false in every legacy handshake, so spec-compliant legacy clients ignore the notification the tutorial teaches
Extended reasoning...
docs/servers/prompts.md:183 (and the recap at line 195, backed by docs_src/prompts/tutorial006.py:27) states "
await ctx.session.send_prompt_list_changed()sends it to the calling client when that client is pre-2026". The notification is indeed written to the legacy standalone stream, but the server never declared it would send it: every MCPServer path builds the InitializeResult capabilities viacreate_initialization_options()with a defaultNotificationOptions()(src/mcp/server/mcpserver/server.py:1024 and :1115, src/mcp/server/runner.py:431 for the streamable-HTTP manager path), andServer.get_capabilitiesthen setsPromptsCapability(list_changed=False)for handshake-era versions (src/mcp/server/lowlevel/server.py:588-595) —notification_optionsis only honored for modern versions via thesubscriptions/listenderivation. The MCP spec makesprompts.listChangedthe opt-in that tells a client to expect and handlenotifications/prompts/list_changed, so a spec-compliant pre-2026 host that checks the negotiated capability ignores the notification (or never wires up aVerification: pre-existing — the capability mismatch is real but lives in src/ code this docs-only PR did not touch. New docs/servers/prompts.md:183 teaches "
await ctx.session.send_prompt_list_changed()sends it to the calling client when that client is pre-2026" (tutorial006.py:27 calls it), yet every MCPServer legacy handshake advertises prompts.listChanged: false: src/mcp/server/mcpserver/server.py:1024