Skip to content

docs: cover the remaining Tier 1 audit items - #3325

Merged
maxisbey merged 1 commit into
mainfrom
docs/tier1-gaps
Aug 17, 2026
Merged

docs: cover the remaining Tier 1 audit items#3325
maxisbey merged 1 commit into
mainfrom
docs/tier1-gaps

Conversation

@maxisbey

@maxisbey maxisbey commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Adds the narrative coverage the SEP-1730 docs audit still flags as missing on main, and nothing else. Each item goes on the page that already owns the feature, as a short section plus a docs_src example (or an inline snippet on the deprecated-features page, the one page that calls deprecated APIs). Follows #3320, which the prompt and media examples rely on.

Motivation and Context

Audit item Where
Tools: embedded resources servers/media.md "Embedding a resource" + docs_src/media/tutorial005.py
Prompts: embedded resources servers/prompts.md "More than text / Embedding a file" + docs_src/prompts/tutorial004.py
Prompts: image content servers/prompts.md "Attaching an image" + docs_src/prompts/tutorial005.py
Prompts: change notifications servers/prompts.md "Changing the list at runtime" + docs_src/prompts/tutorial006.py
Ping deprecated.md "ping on a legacy session" (inline snippet)
Roots: change notifications deprecated.md "Roots change notifications" (inline snippet)
JSON Schema 2020-12 advanced/low-level-server.md "The dialect is JSON Schema 2020-12" + docs_src/lowlevel/tutorial007.py, one-sentence pointer in servers/tools.md

How Has This Been Tested?

Docs and docs_src only. The existing tests/docs_src/test_shape.py imports and reference-checks the new example modules, tests/test_examples.py lints the inline snippets, pyright covers docs_src/, and scripts/docs/build.sh builds strictly with no issues. Each example was also run by hand against an in-memory Client in both protocol modes.

Breaking Changes

None.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

AI Disclaimer

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

📚 Documentation preview

Preview https://pr-3325.mcp-python-docs.pages.dev
Deployment https://da137e78.mcp-python-docs.pages.dev
Commit 918cc78
Triggered by @maxisbey
Updated 2026-08-17 16:15:46 UTC

@maxisbey maxisbey changed the title docs: close the remaining Tier 1 documentation gaps docs: cover the remaining Tier 1 audit items Aug 17, 2026
@maxisbey
maxisbey marked this pull request as ready for review August 17, 2026 14:43

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 10 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread docs_src/prompts/tutorial006.py
Comment thread docs_src/prompts/tutorial006.py
@@ -0,0 +1,25 @@
from pathlib import Path

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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:docs_src/(media/tutorial005|prompts/tutorial00[4-6]|lowlevel/tutorial007)\.py [also at: docs_src/media/tutorial005.py:1 - [quality] Five new docs_src tutorials (media/tutorial005, prompts/tutorial004-006, lowlevel/tutorial007) and the two new]

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 from docs_src.media import tutorial001, tutorial002, tutorial003, tutorial004 (no 005), test_prompts.py:9 `from docs_src.prompts import tutoria

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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 docs_src modules are still import-checked by test_shape.py, type-checked by pyright and the fences ruff-linted by test_examples.py; behavioural chapter tests for them can follow separately if we want them.

AI Disclaimer

from pathlib import Path

from mcp.server import MCPServer
from mcp.server.mcpserver import Message, UserMessage

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [quality] nit: New prompt examples import Message/UserMessage from mcp.server.mcpserver, contradicting the same page's prose and every existing docs_src example sweep:from mcp\.server\.mcpserver import .*(UserMessage|Message)

Extended reasoning...

docs/servers/prompts.md line 88 (the bullet under tutorial002, unchanged by this PR) states "UserMessage and AssistantMessage come from mcp.server.mcpserver.prompts.base", and every pre-existing docs_src example imports them from that path (docs_src/prompts/tutorial002.py:2, docs_src/mrtr/tutorial004.py:2). The two new examples rendered on the very same page a few sections later import the same symbols from the top-level re-export instead (docs_src/prompts/tutorial004.py:4 from mcp.server.mcpserver import Message, UserMessage; docs_src/prompts/tutorial005.py:4). Concrete cost: the prompts page now contradicts itself about where these classes live — a reader who follows the earlier bullet and then copies tutorial004 sees two different canonical import paths for the same names on one page, and the docs_src corpus loses its single established spelling. Fix in one sweep: change the two new files to from mcp.server.mcpserver.prompts.base import ... (or, if the top-level spelling is now preferred, update the line-88 prose and the older examples in a follow-up).

Verification: nit — Factually accurate quality finding. docs_src/prompts/tutorial004.py:4 (from mcp.server.mcpserver import Message, UserMessage) and tutorial005.py:4 import from the top-level re-export, while the same rendered page states at docs/servers/prompts.md:88 that "UserMessage and AssistantMessage come from mcp.server.mcpserver.prompts.base", and all pre-existing examples import from that pa

Adds the narrative coverage and examples the SEP-1730 docs audit still
flagged as missing on main: a tool returning an EmbeddedResource
(media page), prompt messages carrying an embedded file and an image
plus adding prompts at runtime with the list-changed notification
(prompts page), ping and roots change notifications on a legacy session
(deprecated-features page), and the JSON Schema 2020-12 dialect
(low-level server page, with a pointer from tools). Docs and docs_src
only.

No-Verification-Needed: docs and docs_src examples only

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beyond the inline finding, two other candidates were examined and ruled out this run: the new ping section's SEP-2575 attribution is correct (the repo's own interaction-requirements notes credit SEP-2575 with deleting ping from the schema), and tutorial007's unguarded args['isbn']/args['title'] access only misbehaves for clients that violate the tool's advertised oneOf schema — an accepted simplification in the low-level examples, which don't validate arguments server-side.

Extended reasoning...

This run produced one confirmed finding (posted inline) plus two newly investigated candidates that were ruled out; since neither ruled-out item was covered in the prior two reviews on earlier pushed versions, a brief informational note recording them is warranted. The SEP-2575 attribution in docs/deprecated.md was verified against tests/interaction/_requirements.py, which repeatedly attributes the ping removal to SEP-2575 ("ping deleted from the schema, no replacement"), so the misattribution concern does not hold. The tutorial007 KeyError candidate describes a crash only reachable when a client sends arguments violating the advertised schema — the low-level Server never validates input_schema by design, and the docs example's simplification matches the rest of the low-level tutorial series. The hunt exited on max_rounds and a confirmed finding exists, so approval is off the table; this note is informational only and does not restate the inline finding.

Comment thread docs/servers/prompts.md
```

* `mcp.add_prompt(Prompt.from_function(fn, name=..., description=...))` registers a function exactly as `@mcp.prompt()` would, and `mcp.remove_prompt(name)` is the reverse. `add_prompt` keeps an existing entry of the same name rather than overwrite it, so the tool removes any old one first to make saving a replace. `prompts/list` reflects the change immediately.
* `await ctx.notify_prompts_changed()` sends `notifications/prompts/list_changed` to every `2026-07-28` client listening on a `subscriptions/listen` stream (**[Subscriptions](../handlers/subscriptions.md)**). `await ctx.session.send_prompt_list_changed()` sends it to the calling client when that client is pre-2026 (**[Serving legacy clients](../run/legacy-clients.md)**). Call both; each does nothing when there is nobody to tell.

Copy link
Copy Markdown
Contributor

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 via create_initialization_options() with a default NotificationOptions() (src/mcp/server/mcpserver/server.py:1024 and :1115, src/mcp/server/runner.py:431 for the streamable-HTTP manager path), and Server.get_capabilities then sets PromptsCapability(list_changed=False) for handshake-era versions (src/mcp/server/lowlevel/server.py:588-595) — notification_options is only honored for modern versions via the subscriptions/listen derivation. The MCP spec makes prompts.listChanged the opt-in that tells a client to expect and handle notifications/prompts/list_changed, so a spec-compliant pre-2026 host that checks the negotiated capability ignores the notification (or never wires up a

Verification: 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

@maxisbey
maxisbey merged commit 9057285 into main Aug 17, 2026
44 of 45 checks passed
@maxisbey
maxisbey deleted the docs/tier1-gaps branch August 17, 2026 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant