Type-check docstring code examples via companion files and unified sync script - #2119

Open
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script
Open

Type-check docstring code examples via companion files and unified sync script#2119
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script

Conversation

@jonathanhefner

Copy link
Copy Markdown
Member

Docstring code examples in src/mcp/ were previously raw text — invisible to pyright and ruff, so type errors and style drift went unnoticed. This PR introduces a system for keeping those examples in standalone, type-checked companion files that are synced back into the docstrings automatically.

The old update_readme_snippets.py is replaced with sync_snippets.py, a superset that handles README.v2.md, docs/**/*.md, and src/**/*.py docstrings. It adds region extraction (# region / # endregion markers) so a single companion file can supply multiple snippets. For docstrings specifically, <!-- snippet-source #RegionName --> markers derive the companion path automatically from the target file's location (src/mcp/foo.pyexamples/snippets/docstrings/mcp/foo.py), avoiding line-length violations from embedding full paths.

42 code examples across the public API surface (MCPServer, Client, ClientSession, Context, ResponseRouter, task support, OAuth providers, etc.) are extracted into 19 companion files under examples/snippets/docstrings/mcp/, mirroring the source tree. Each example is wrapped in a named function with typed parameters, so pyright and ruff check them on every CI run — catching signature changes, renamed parameters, and moved imports at CI time rather than when a user copies a broken example.

Conventions for the snippet system (region naming, function-parameter pattern, # type: ignore prohibition, editing workflow) are documented in CLAUDE.md.


@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

@Kludex

Copy link
Copy Markdown
Member

@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

I said something like: "the examples/snippets are horribly lengthy, and complex". But yeah, I think ideally we want to have what would be an example as part of the docs.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

I said something like: "the examples/snippets are horribly lengthy, and complex".

Ah, I see. Agreed. I am working on getting more focused examples in place (e.g., without setup boilerplate).

But yeah, I think ideally we want to have what would be an example as part of the docs.

Agreed that they should be part of the docs, as in "embedded in the docs". Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

The way we've done it for the TypeScript SDK is to have, e.g., a examples/client/src/clientGuide.examples.ts file that is linted / type checked / etc, and to inject regions of that file into docs/client.md, which is what the user sees.

I slightly lean toward the way it's done the TypeScript SDK, but I don't have a strong preference. Which do you prefer?

@Kludex

Copy link
Copy Markdown
Member

Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

It's okay to live elsewhere, but for the perfect setup, that code should be tested.


Any approach is fine. Making sure that code is tested is the requirement here.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

@maxisbey

Copy link
Copy Markdown
Contributor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

Having the code tested would be nice, but that is a lot of overhead. Type checking and linting IMO is probably good enough at least to start with.

Comment threadREADME.v2.md Outdated
```
<!-- /snippet-source -->

_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_

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.

we should delete all these, or maybe have them as comments in the markdown. Not sure how helpful a link to the snippet actually is in the markdown since the code block contains the entire source anyway

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Makes sense. The snippet-source comment already contains the path (e.g., <!-- snippet-source examples/snippets/servers/basic_resource.py -->), so I've removed the links.

@Kludex

Copy link
Copy Markdown
Member

If we are making the examples simpler, then it's a good opportunity to test them.

I mean, the perfect world would be to add tests for that, so examples are tested and they actually work - given that in the past we got a lot of PRs/issues with example issues.

@Kludex

Copy link
Copy Markdown
Member

Otherwise, lint/type checker in them is fine.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Otherwise, lint/type checker in them is fine.

Since the examples in this PR are all in examples/snippets/docstrings/, they are all linted and type-checked. 👍

@Kludex@maxisbey Are there any further concerns? Is this okay to merge?

The new script is a superset of the old one. It continues to handle the
existing `<!-- snippet-source -->` markers in `README.v2.md`, and adds
support for syncing code snippets into Python docstrings and markdown
docs under `docs/`.
New capabilities beyond the old script:
- Region extraction from example files using `# region` / `# endregion`
markers, so a single example file can provide multiple snippets
- All source paths resolve relative to the repository root
- Scans `src/**/*.py` and `docs/**/*.md` in addition to the README
- Caches file contents and extracted regions for efficiency
The marker format uses HTML comments (`<!-- snippet-source -->` /
`<!-- /snippet-source -->`), which are invisible when rendered by
`mkdocstrings` and do not interfere with `pymdownx.superfences` code
fence parsing.
Add support for `<!-- snippet-source #region_name -->` markers that omit
the companion file path. The path is derived from the target file's
location using the mapping `src/X` → `examples/snippets/docstrings/X`.
This eliminates line-length violations on marker lines in docstrings,
since the full companion path no longer needs to be embedded in every
marker. The full-path form continues to work for non-`src/` targets like
markdown files.
Move inline code examples from docstrings in `src/mcp/` into standalone
companion files at `examples/snippets/docstrings/mcp/`, mirroring the
source tree structure. The `scripts/sync_snippets.py` script keeps the
docstring content in sync with the companion files via
`<!-- snippet-source #RegionName -->` markers.
This ensures all docstring examples are checked by pyright and ruff,
catching type errors and style drift that would otherwise go unnoticed
in raw docstring text. The pattern follows the TypeScript SDK's approach
of one companion file per source file, with each example in a named
function whose parameters supply typed context.
19 companion files cover 42 code examples across the public API surface:
`MCPServer`, `Client`, `ClientSession`, `Context`, `ResponseRouter`,
`ServerTaskContext`, `ExperimentalTaskHandlers`,
`ClientCredentialsOAuthProvider`, `PrivateKeyJWTOAuthProvider`,
`SignedJWTParameters`, and others.
All source markers use path-less form (`#RegionName`) — the companion
path is derived automatically from the target file location. Region
names follow `ClassName_methodName_variant` without abbreviation.
Pyright execution environment for the companion files suppresses only
"unused artifact" diagnostics inherent to example code
(`reportUnusedFunction`, `reportUnusedVariable`, `reportAbstractUsage`,
`reportUnusedClass`, `reportPrivateUsage`). All actual type-checking
rules remain enabled.
Add a "Docstring Code Examples" section covering the companion file
system: directory layout, `<!-- snippet-source #RegionName -->` markers,
`ClassName_methodName_variant` naming, the function-parameter pattern
for typed dependencies, and the prohibition on type-suppression comments
inside regions.
`sync_snippets.py` also syncs snippet-source markers in `docs/**/*.md`
and `README.v2.md`, not just `src/` docstrings. Add a short section
after "Docstring Code Examples" noting that these files use explicit
paths (path-less `#Region` markers are only supported in `src/` files).
The previous documentation had two flat sections where the docstring
section contained all the detail and the markdown section referred to it
vaguely. Reorganize into a `## Code Snippet System` intro covering
shared concepts (marker format, region extraction, naming conventions,
function wrappers, typed params, `# type: ignore` prohibition, pyright
workflow) with `### Markdown Code Examples` and
`### Docstring Code Examples` subsections covering only what is unique
to each target type.
The links to snippet source files are redundant since the code blocks
already contain the entire source. Removes all 33 occurrences.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanhefner@Kludex@maxisbey
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Type-check docstring code examples via companion files and unified sync script - #2119

Open
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script
Open

Type-check docstring code examples via companion files and unified sync script#2119
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script

Conversation

@jonathanhefner

Copy link
Copy Markdown
Member

Docstring code examples in src/mcp/ were previously raw text — invisible to pyright and ruff, so type errors and style drift went unnoticed. This PR introduces a system for keeping those examples in standalone, type-checked companion files that are synced back into the docstrings automatically.

The old update_readme_snippets.py is replaced with sync_snippets.py, a superset that handles README.v2.md, docs/**/*.md, and src/**/*.py docstrings. It adds region extraction (# region / # endregion markers) so a single companion file can supply multiple snippets. For docstrings specifically, <!-- snippet-source #RegionName --> markers derive the companion path automatically from the target file's location (src/mcp/foo.pyexamples/snippets/docstrings/mcp/foo.py), avoiding line-length violations from embedding full paths.

42 code examples across the public API surface (MCPServer, Client, ClientSession, Context, ResponseRouter, task support, OAuth providers, etc.) are extracted into 19 companion files under examples/snippets/docstrings/mcp/, mirroring the source tree. Each example is wrapped in a named function with typed parameters, so pyright and ruff check them on every CI run — catching signature changes, renamed parameters, and moved imports at CI time rather than when a user copies a broken example.

Conventions for the snippet system (region naming, function-parameter pattern, # type: ignore prohibition, editing workflow) are documented in CLAUDE.md.


@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

@Kludex

Copy link
Copy Markdown
Member

@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

I said something like: "the examples/snippets are horribly lengthy, and complex". But yeah, I think ideally we want to have what would be an example as part of the docs.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

I said something like: "the examples/snippets are horribly lengthy, and complex".

Ah, I see. Agreed. I am working on getting more focused examples in place (e.g., without setup boilerplate).

But yeah, I think ideally we want to have what would be an example as part of the docs.

Agreed that they should be part of the docs, as in "embedded in the docs". Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

The way we've done it for the TypeScript SDK is to have, e.g., a examples/client/src/clientGuide.examples.ts file that is linted / type checked / etc, and to inject regions of that file into docs/client.md, which is what the user sees.

I slightly lean toward the way it's done the TypeScript SDK, but I don't have a strong preference. Which do you prefer?

@Kludex

Copy link
Copy Markdown
Member

Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

It's okay to live elsewhere, but for the perfect setup, that code should be tested.


Any approach is fine. Making sure that code is tested is the requirement here.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

@maxisbey

Copy link
Copy Markdown
Contributor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

Having the code tested would be nice, but that is a lot of overhead. Type checking and linting IMO is probably good enough at least to start with.

Comment threadREADME.v2.md Outdated
```
<!-- /snippet-source -->

_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_

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.

we should delete all these, or maybe have them as comments in the markdown. Not sure how helpful a link to the snippet actually is in the markdown since the code block contains the entire source anyway

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Makes sense. The snippet-source comment already contains the path (e.g., <!-- snippet-source examples/snippets/servers/basic_resource.py -->), so I've removed the links.

@Kludex

Copy link
Copy Markdown
Member

If we are making the examples simpler, then it's a good opportunity to test them.

I mean, the perfect world would be to add tests for that, so examples are tested and they actually work - given that in the past we got a lot of PRs/issues with example issues.

@Kludex

Copy link
Copy Markdown
Member

Otherwise, lint/type checker in them is fine.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Otherwise, lint/type checker in them is fine.

Since the examples in this PR are all in examples/snippets/docstrings/, they are all linted and type-checked. 👍

@Kludex@maxisbey Are there any further concerns? Is this okay to merge?

The new script is a superset of the old one. It continues to handle the
existing `<!-- snippet-source -->` markers in `README.v2.md`, and adds
support for syncing code snippets into Python docstrings and markdown
docs under `docs/`.
New capabilities beyond the old script:
- Region extraction from example files using `# region` / `# endregion`
markers, so a single example file can provide multiple snippets
- All source paths resolve relative to the repository root
- Scans `src/**/*.py` and `docs/**/*.md` in addition to the README
- Caches file contents and extracted regions for efficiency
The marker format uses HTML comments (`<!-- snippet-source -->` /
`<!-- /snippet-source -->`), which are invisible when rendered by
`mkdocstrings` and do not interfere with `pymdownx.superfences` code
fence parsing.
Add support for `<!-- snippet-source #region_name -->` markers that omit
the companion file path. The path is derived from the target file's
location using the mapping `src/X` → `examples/snippets/docstrings/X`.
This eliminates line-length violations on marker lines in docstrings,
since the full companion path no longer needs to be embedded in every
marker. The full-path form continues to work for non-`src/` targets like
markdown files.
Move inline code examples from docstrings in `src/mcp/` into standalone
companion files at `examples/snippets/docstrings/mcp/`, mirroring the
source tree structure. The `scripts/sync_snippets.py` script keeps the
docstring content in sync with the companion files via
`<!-- snippet-source #RegionName -->` markers.
This ensures all docstring examples are checked by pyright and ruff,
catching type errors and style drift that would otherwise go unnoticed
in raw docstring text. The pattern follows the TypeScript SDK's approach
of one companion file per source file, with each example in a named
function whose parameters supply typed context.
19 companion files cover 42 code examples across the public API surface:
`MCPServer`, `Client`, `ClientSession`, `Context`, `ResponseRouter`,
`ServerTaskContext`, `ExperimentalTaskHandlers`,
`ClientCredentialsOAuthProvider`, `PrivateKeyJWTOAuthProvider`,
`SignedJWTParameters`, and others.
All source markers use path-less form (`#RegionName`) — the companion
path is derived automatically from the target file location. Region
names follow `ClassName_methodName_variant` without abbreviation.
Pyright execution environment for the companion files suppresses only
"unused artifact" diagnostics inherent to example code
(`reportUnusedFunction`, `reportUnusedVariable`, `reportAbstractUsage`,
`reportUnusedClass`, `reportPrivateUsage`). All actual type-checking
rules remain enabled.
Add a "Docstring Code Examples" section covering the companion file
system: directory layout, `<!-- snippet-source #RegionName -->` markers,
`ClassName_methodName_variant` naming, the function-parameter pattern
for typed dependencies, and the prohibition on type-suppression comments
inside regions.
`sync_snippets.py` also syncs snippet-source markers in `docs/**/*.md`
and `README.v2.md`, not just `src/` docstrings. Add a short section
after "Docstring Code Examples" noting that these files use explicit
paths (path-less `#Region` markers are only supported in `src/` files).
The previous documentation had two flat sections where the docstring
section contained all the detail and the markdown section referred to it
vaguely. Reorganize into a `## Code Snippet System` intro covering
shared concepts (marker format, region extraction, naming conventions,
function wrappers, typed params, `# type: ignore` prohibition, pyright
workflow) with `### Markdown Code Examples` and
`### Docstring Code Examples` subsections covering only what is unique
to each target type.
The links to snippet source files are redundant since the code blocks
already contain the entire source. Removes all 33 occurrences.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanhefner@Kludex@maxisbey
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Type-check docstring code examples via companion files and unified sync script - #2119

Open
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script
Open

Type-check docstring code examples via companion files and unified sync script#2119
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script

Conversation

@jonathanhefner

Copy link
Copy Markdown
Member

Docstring code examples in src/mcp/ were previously raw text — invisible to pyright and ruff, so type errors and style drift went unnoticed. This PR introduces a system for keeping those examples in standalone, type-checked companion files that are synced back into the docstrings automatically.

The old update_readme_snippets.py is replaced with sync_snippets.py, a superset that handles README.v2.md, docs/**/*.md, and src/**/*.py docstrings. It adds region extraction (# region / # endregion markers) so a single companion file can supply multiple snippets. For docstrings specifically, <!-- snippet-source #RegionName --> markers derive the companion path automatically from the target file's location (src/mcp/foo.pyexamples/snippets/docstrings/mcp/foo.py), avoiding line-length violations from embedding full paths.

42 code examples across the public API surface (MCPServer, Client, ClientSession, Context, ResponseRouter, task support, OAuth providers, etc.) are extracted into 19 companion files under examples/snippets/docstrings/mcp/, mirroring the source tree. Each example is wrapped in a named function with typed parameters, so pyright and ruff check them on every CI run — catching signature changes, renamed parameters, and moved imports at CI time rather than when a user copies a broken example.

Conventions for the snippet system (region naming, function-parameter pattern, # type: ignore prohibition, editing workflow) are documented in CLAUDE.md.


@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

@Kludex

Copy link
Copy Markdown
Member

@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

I said something like: "the examples/snippets are horribly lengthy, and complex". But yeah, I think ideally we want to have what would be an example as part of the docs.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

I said something like: "the examples/snippets are horribly lengthy, and complex".

Ah, I see. Agreed. I am working on getting more focused examples in place (e.g., without setup boilerplate).

But yeah, I think ideally we want to have what would be an example as part of the docs.

Agreed that they should be part of the docs, as in "embedded in the docs". Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

The way we've done it for the TypeScript SDK is to have, e.g., a examples/client/src/clientGuide.examples.ts file that is linted / type checked / etc, and to inject regions of that file into docs/client.md, which is what the user sees.

I slightly lean toward the way it's done the TypeScript SDK, but I don't have a strong preference. Which do you prefer?

@Kludex

Copy link
Copy Markdown
Member

Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

It's okay to live elsewhere, but for the perfect setup, that code should be tested.


Any approach is fine. Making sure that code is tested is the requirement here.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

@maxisbey

Copy link
Copy Markdown
Contributor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

Having the code tested would be nice, but that is a lot of overhead. Type checking and linting IMO is probably good enough at least to start with.

Comment threadREADME.v2.md Outdated
```
<!-- /snippet-source -->

_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_

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.

we should delete all these, or maybe have them as comments in the markdown. Not sure how helpful a link to the snippet actually is in the markdown since the code block contains the entire source anyway

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Makes sense. The snippet-source comment already contains the path (e.g., <!-- snippet-source examples/snippets/servers/basic_resource.py -->), so I've removed the links.

@Kludex

Copy link
Copy Markdown
Member

If we are making the examples simpler, then it's a good opportunity to test them.

I mean, the perfect world would be to add tests for that, so examples are tested and they actually work - given that in the past we got a lot of PRs/issues with example issues.

@Kludex

Copy link
Copy Markdown
Member

Otherwise, lint/type checker in them is fine.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Otherwise, lint/type checker in them is fine.

Since the examples in this PR are all in examples/snippets/docstrings/, they are all linted and type-checked. 👍

@Kludex@maxisbey Are there any further concerns? Is this okay to merge?

The new script is a superset of the old one. It continues to handle the
existing `<!-- snippet-source -->` markers in `README.v2.md`, and adds
support for syncing code snippets into Python docstrings and markdown
docs under `docs/`.
New capabilities beyond the old script:
- Region extraction from example files using `# region` / `# endregion`
markers, so a single example file can provide multiple snippets
- All source paths resolve relative to the repository root
- Scans `src/**/*.py` and `docs/**/*.md` in addition to the README
- Caches file contents and extracted regions for efficiency
The marker format uses HTML comments (`<!-- snippet-source -->` /
`<!-- /snippet-source -->`), which are invisible when rendered by
`mkdocstrings` and do not interfere with `pymdownx.superfences` code
fence parsing.
Add support for `<!-- snippet-source #region_name -->` markers that omit
the companion file path. The path is derived from the target file's
location using the mapping `src/X` → `examples/snippets/docstrings/X`.
This eliminates line-length violations on marker lines in docstrings,
since the full companion path no longer needs to be embedded in every
marker. The full-path form continues to work for non-`src/` targets like
markdown files.
Move inline code examples from docstrings in `src/mcp/` into standalone
companion files at `examples/snippets/docstrings/mcp/`, mirroring the
source tree structure. The `scripts/sync_snippets.py` script keeps the
docstring content in sync with the companion files via
`<!-- snippet-source #RegionName -->` markers.
This ensures all docstring examples are checked by pyright and ruff,
catching type errors and style drift that would otherwise go unnoticed
in raw docstring text. The pattern follows the TypeScript SDK's approach
of one companion file per source file, with each example in a named
function whose parameters supply typed context.
19 companion files cover 42 code examples across the public API surface:
`MCPServer`, `Client`, `ClientSession`, `Context`, `ResponseRouter`,
`ServerTaskContext`, `ExperimentalTaskHandlers`,
`ClientCredentialsOAuthProvider`, `PrivateKeyJWTOAuthProvider`,
`SignedJWTParameters`, and others.
All source markers use path-less form (`#RegionName`) — the companion
path is derived automatically from the target file location. Region
names follow `ClassName_methodName_variant` without abbreviation.
Pyright execution environment for the companion files suppresses only
"unused artifact" diagnostics inherent to example code
(`reportUnusedFunction`, `reportUnusedVariable`, `reportAbstractUsage`,
`reportUnusedClass`, `reportPrivateUsage`). All actual type-checking
rules remain enabled.
Add a "Docstring Code Examples" section covering the companion file
system: directory layout, `<!-- snippet-source #RegionName -->` markers,
`ClassName_methodName_variant` naming, the function-parameter pattern
for typed dependencies, and the prohibition on type-suppression comments
inside regions.
`sync_snippets.py` also syncs snippet-source markers in `docs/**/*.md`
and `README.v2.md`, not just `src/` docstrings. Add a short section
after "Docstring Code Examples" noting that these files use explicit
paths (path-less `#Region` markers are only supported in `src/` files).
The previous documentation had two flat sections where the docstring
section contained all the detail and the markdown section referred to it
vaguely. Reorganize into a `## Code Snippet System` intro covering
shared concepts (marker format, region extraction, naming conventions,
function wrappers, typed params, `# type: ignore` prohibition, pyright
workflow) with `### Markdown Code Examples` and
`### Docstring Code Examples` subsections covering only what is unique
to each target type.
The links to snippet source files are redundant since the code blocks
already contain the entire source. Removes all 33 occurrences.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanhefner@Kludex@maxisbey
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Type-check docstring code examples via companion files and unified sync script - #2119

Open
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script
Open

Type-check docstring code examples via companion files and unified sync script#2119
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script

Conversation

@jonathanhefner

Copy link
Copy Markdown
Member

Docstring code examples in src/mcp/ were previously raw text — invisible to pyright and ruff, so type errors and style drift went unnoticed. This PR introduces a system for keeping those examples in standalone, type-checked companion files that are synced back into the docstrings automatically.

The old update_readme_snippets.py is replaced with sync_snippets.py, a superset that handles README.v2.md, docs/**/*.md, and src/**/*.py docstrings. It adds region extraction (# region / # endregion markers) so a single companion file can supply multiple snippets. For docstrings specifically, <!-- snippet-source #RegionName --> markers derive the companion path automatically from the target file's location (src/mcp/foo.pyexamples/snippets/docstrings/mcp/foo.py), avoiding line-length violations from embedding full paths.

42 code examples across the public API surface (MCPServer, Client, ClientSession, Context, ResponseRouter, task support, OAuth providers, etc.) are extracted into 19 companion files under examples/snippets/docstrings/mcp/, mirroring the source tree. Each example is wrapped in a named function with typed parameters, so pyright and ruff check them on every CI run — catching signature changes, renamed parameters, and moved imports at CI time rather than when a user copies a broken example.

Conventions for the snippet system (region naming, function-parameter pattern, # type: ignore prohibition, editing workflow) are documented in CLAUDE.md.


@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

@Kludex

Copy link
Copy Markdown
Member

@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

I said something like: "the examples/snippets are horribly lengthy, and complex". But yeah, I think ideally we want to have what would be an example as part of the docs.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

I said something like: "the examples/snippets are horribly lengthy, and complex".

Ah, I see. Agreed. I am working on getting more focused examples in place (e.g., without setup boilerplate).

But yeah, I think ideally we want to have what would be an example as part of the docs.

Agreed that they should be part of the docs, as in "embedded in the docs". Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

The way we've done it for the TypeScript SDK is to have, e.g., a examples/client/src/clientGuide.examples.ts file that is linted / type checked / etc, and to inject regions of that file into docs/client.md, which is what the user sees.

I slightly lean toward the way it's done the TypeScript SDK, but I don't have a strong preference. Which do you prefer?

@Kludex

Copy link
Copy Markdown
Member

Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

It's okay to live elsewhere, but for the perfect setup, that code should be tested.


Any approach is fine. Making sure that code is tested is the requirement here.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

@maxisbey

Copy link
Copy Markdown
Contributor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

Having the code tested would be nice, but that is a lot of overhead. Type checking and linting IMO is probably good enough at least to start with.

Comment threadREADME.v2.md Outdated
```
<!-- /snippet-source -->

_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_

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.

we should delete all these, or maybe have them as comments in the markdown. Not sure how helpful a link to the snippet actually is in the markdown since the code block contains the entire source anyway

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Makes sense. The snippet-source comment already contains the path (e.g., <!-- snippet-source examples/snippets/servers/basic_resource.py -->), so I've removed the links.

@Kludex

Copy link
Copy Markdown
Member

If we are making the examples simpler, then it's a good opportunity to test them.

I mean, the perfect world would be to add tests for that, so examples are tested and they actually work - given that in the past we got a lot of PRs/issues with example issues.

@Kludex

Copy link
Copy Markdown
Member

Otherwise, lint/type checker in them is fine.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Otherwise, lint/type checker in them is fine.

Since the examples in this PR are all in examples/snippets/docstrings/, they are all linted and type-checked. 👍

@Kludex@maxisbey Are there any further concerns? Is this okay to merge?

The new script is a superset of the old one. It continues to handle the
existing `<!-- snippet-source -->` markers in `README.v2.md`, and adds
support for syncing code snippets into Python docstrings and markdown
docs under `docs/`.
New capabilities beyond the old script:
- Region extraction from example files using `# region` / `# endregion`
markers, so a single example file can provide multiple snippets
- All source paths resolve relative to the repository root
- Scans `src/**/*.py` and `docs/**/*.md` in addition to the README
- Caches file contents and extracted regions for efficiency
The marker format uses HTML comments (`<!-- snippet-source -->` /
`<!-- /snippet-source -->`), which are invisible when rendered by
`mkdocstrings` and do not interfere with `pymdownx.superfences` code
fence parsing.
Add support for `<!-- snippet-source #region_name -->` markers that omit
the companion file path. The path is derived from the target file's
location using the mapping `src/X` → `examples/snippets/docstrings/X`.
This eliminates line-length violations on marker lines in docstrings,
since the full companion path no longer needs to be embedded in every
marker. The full-path form continues to work for non-`src/` targets like
markdown files.
Move inline code examples from docstrings in `src/mcp/` into standalone
companion files at `examples/snippets/docstrings/mcp/`, mirroring the
source tree structure. The `scripts/sync_snippets.py` script keeps the
docstring content in sync with the companion files via
`<!-- snippet-source #RegionName -->` markers.
This ensures all docstring examples are checked by pyright and ruff,
catching type errors and style drift that would otherwise go unnoticed
in raw docstring text. The pattern follows the TypeScript SDK's approach
of one companion file per source file, with each example in a named
function whose parameters supply typed context.
19 companion files cover 42 code examples across the public API surface:
`MCPServer`, `Client`, `ClientSession`, `Context`, `ResponseRouter`,
`ServerTaskContext`, `ExperimentalTaskHandlers`,
`ClientCredentialsOAuthProvider`, `PrivateKeyJWTOAuthProvider`,
`SignedJWTParameters`, and others.
All source markers use path-less form (`#RegionName`) — the companion
path is derived automatically from the target file location. Region
names follow `ClassName_methodName_variant` without abbreviation.
Pyright execution environment for the companion files suppresses only
"unused artifact" diagnostics inherent to example code
(`reportUnusedFunction`, `reportUnusedVariable`, `reportAbstractUsage`,
`reportUnusedClass`, `reportPrivateUsage`). All actual type-checking
rules remain enabled.
Add a "Docstring Code Examples" section covering the companion file
system: directory layout, `<!-- snippet-source #RegionName -->` markers,
`ClassName_methodName_variant` naming, the function-parameter pattern
for typed dependencies, and the prohibition on type-suppression comments
inside regions.
`sync_snippets.py` also syncs snippet-source markers in `docs/**/*.md`
and `README.v2.md`, not just `src/` docstrings. Add a short section
after "Docstring Code Examples" noting that these files use explicit
paths (path-less `#Region` markers are only supported in `src/` files).
The previous documentation had two flat sections where the docstring
section contained all the detail and the markdown section referred to it
vaguely. Reorganize into a `## Code Snippet System` intro covering
shared concepts (marker format, region extraction, naming conventions,
function wrappers, typed params, `# type: ignore` prohibition, pyright
workflow) with `### Markdown Code Examples` and
`### Docstring Code Examples` subsections covering only what is unique
to each target type.
The links to snippet source files are redundant since the code blocks
already contain the entire source. Removes all 33 occurrences.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanhefner@Kludex@maxisbey
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Type-check docstring code examples via companion files and unified sync script - #2119

Open
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script
Open

Type-check docstring code examples via companion files and unified sync script#2119
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script

Conversation

@jonathanhefner

Copy link
Copy Markdown
Member

Docstring code examples in src/mcp/ were previously raw text — invisible to pyright and ruff, so type errors and style drift went unnoticed. This PR introduces a system for keeping those examples in standalone, type-checked companion files that are synced back into the docstrings automatically.

The old update_readme_snippets.py is replaced with sync_snippets.py, a superset that handles README.v2.md, docs/**/*.md, and src/**/*.py docstrings. It adds region extraction (# region / # endregion markers) so a single companion file can supply multiple snippets. For docstrings specifically, <!-- snippet-source #RegionName --> markers derive the companion path automatically from the target file's location (src/mcp/foo.pyexamples/snippets/docstrings/mcp/foo.py), avoiding line-length violations from embedding full paths.

42 code examples across the public API surface (MCPServer, Client, ClientSession, Context, ResponseRouter, task support, OAuth providers, etc.) are extracted into 19 companion files under examples/snippets/docstrings/mcp/, mirroring the source tree. Each example is wrapped in a named function with typed parameters, so pyright and ruff check them on every CI run — catching signature changes, renamed parameters, and moved imports at CI time rather than when a user copies a broken example.

Conventions for the snippet system (region naming, function-parameter pattern, # type: ignore prohibition, editing workflow) are documented in CLAUDE.md.


@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

@Kludex

Copy link
Copy Markdown
Member

@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

I said something like: "the examples/snippets are horribly lengthy, and complex". But yeah, I think ideally we want to have what would be an example as part of the docs.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

I said something like: "the examples/snippets are horribly lengthy, and complex".

Ah, I see. Agreed. I am working on getting more focused examples in place (e.g., without setup boilerplate).

But yeah, I think ideally we want to have what would be an example as part of the docs.

Agreed that they should be part of the docs, as in "embedded in the docs". Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

The way we've done it for the TypeScript SDK is to have, e.g., a examples/client/src/clientGuide.examples.ts file that is linted / type checked / etc, and to inject regions of that file into docs/client.md, which is what the user sees.

I slightly lean toward the way it's done the TypeScript SDK, but I don't have a strong preference. Which do you prefer?

@Kludex

Copy link
Copy Markdown
Member

Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

It's okay to live elsewhere, but for the perfect setup, that code should be tested.


Any approach is fine. Making sure that code is tested is the requirement here.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

@maxisbey

Copy link
Copy Markdown
Contributor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

Having the code tested would be nice, but that is a lot of overhead. Type checking and linting IMO is probably good enough at least to start with.

Comment threadREADME.v2.md Outdated
```
<!-- /snippet-source -->

_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_

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.

we should delete all these, or maybe have them as comments in the markdown. Not sure how helpful a link to the snippet actually is in the markdown since the code block contains the entire source anyway

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Makes sense. The snippet-source comment already contains the path (e.g., <!-- snippet-source examples/snippets/servers/basic_resource.py -->), so I've removed the links.

@Kludex

Copy link
Copy Markdown
Member

If we are making the examples simpler, then it's a good opportunity to test them.

I mean, the perfect world would be to add tests for that, so examples are tested and they actually work - given that in the past we got a lot of PRs/issues with example issues.

@Kludex

Copy link
Copy Markdown
Member

Otherwise, lint/type checker in them is fine.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Otherwise, lint/type checker in them is fine.

Since the examples in this PR are all in examples/snippets/docstrings/, they are all linted and type-checked. 👍

@Kludex@maxisbey Are there any further concerns? Is this okay to merge?

The new script is a superset of the old one. It continues to handle the
existing `<!-- snippet-source -->` markers in `README.v2.md`, and adds
support for syncing code snippets into Python docstrings and markdown
docs under `docs/`.
New capabilities beyond the old script:
- Region extraction from example files using `# region` / `# endregion`
markers, so a single example file can provide multiple snippets
- All source paths resolve relative to the repository root
- Scans `src/**/*.py` and `docs/**/*.md` in addition to the README
- Caches file contents and extracted regions for efficiency
The marker format uses HTML comments (`<!-- snippet-source -->` /
`<!-- /snippet-source -->`), which are invisible when rendered by
`mkdocstrings` and do not interfere with `pymdownx.superfences` code
fence parsing.
Add support for `<!-- snippet-source #region_name -->` markers that omit
the companion file path. The path is derived from the target file's
location using the mapping `src/X` → `examples/snippets/docstrings/X`.
This eliminates line-length violations on marker lines in docstrings,
since the full companion path no longer needs to be embedded in every
marker. The full-path form continues to work for non-`src/` targets like
markdown files.
Move inline code examples from docstrings in `src/mcp/` into standalone
companion files at `examples/snippets/docstrings/mcp/`, mirroring the
source tree structure. The `scripts/sync_snippets.py` script keeps the
docstring content in sync with the companion files via
`<!-- snippet-source #RegionName -->` markers.
This ensures all docstring examples are checked by pyright and ruff,
catching type errors and style drift that would otherwise go unnoticed
in raw docstring text. The pattern follows the TypeScript SDK's approach
of one companion file per source file, with each example in a named
function whose parameters supply typed context.
19 companion files cover 42 code examples across the public API surface:
`MCPServer`, `Client`, `ClientSession`, `Context`, `ResponseRouter`,
`ServerTaskContext`, `ExperimentalTaskHandlers`,
`ClientCredentialsOAuthProvider`, `PrivateKeyJWTOAuthProvider`,
`SignedJWTParameters`, and others.
All source markers use path-less form (`#RegionName`) — the companion
path is derived automatically from the target file location. Region
names follow `ClassName_methodName_variant` without abbreviation.
Pyright execution environment for the companion files suppresses only
"unused artifact" diagnostics inherent to example code
(`reportUnusedFunction`, `reportUnusedVariable`, `reportAbstractUsage`,
`reportUnusedClass`, `reportPrivateUsage`). All actual type-checking
rules remain enabled.
Add a "Docstring Code Examples" section covering the companion file
system: directory layout, `<!-- snippet-source #RegionName -->` markers,
`ClassName_methodName_variant` naming, the function-parameter pattern
for typed dependencies, and the prohibition on type-suppression comments
inside regions.
`sync_snippets.py` also syncs snippet-source markers in `docs/**/*.md`
and `README.v2.md`, not just `src/` docstrings. Add a short section
after "Docstring Code Examples" noting that these files use explicit
paths (path-less `#Region` markers are only supported in `src/` files).
The previous documentation had two flat sections where the docstring
section contained all the detail and the markdown section referred to it
vaguely. Reorganize into a `## Code Snippet System` intro covering
shared concepts (marker format, region extraction, naming conventions,
function wrappers, typed params, `# type: ignore` prohibition, pyright
workflow) with `### Markdown Code Examples` and
`### Docstring Code Examples` subsections covering only what is unique
to each target type.
The links to snippet source files are redundant since the code blocks
already contain the entire source. Removes all 33 occurrences.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanhefner@Kludex@maxisbey
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Type-check docstring code examples via companion files and unified sync script - #2119

Open
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script
Open

Type-check docstring code examples via companion files and unified sync script#2119
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script

Conversation

@jonathanhefner

Copy link
Copy Markdown
Member

Docstring code examples in src/mcp/ were previously raw text — invisible to pyright and ruff, so type errors and style drift went unnoticed. This PR introduces a system for keeping those examples in standalone, type-checked companion files that are synced back into the docstrings automatically.

The old update_readme_snippets.py is replaced with sync_snippets.py, a superset that handles README.v2.md, docs/**/*.md, and src/**/*.py docstrings. It adds region extraction (# region / # endregion markers) so a single companion file can supply multiple snippets. For docstrings specifically, <!-- snippet-source #RegionName --> markers derive the companion path automatically from the target file's location (src/mcp/foo.pyexamples/snippets/docstrings/mcp/foo.py), avoiding line-length violations from embedding full paths.

42 code examples across the public API surface (MCPServer, Client, ClientSession, Context, ResponseRouter, task support, OAuth providers, etc.) are extracted into 19 companion files under examples/snippets/docstrings/mcp/, mirroring the source tree. Each example is wrapped in a named function with typed parameters, so pyright and ruff check them on every CI run — catching signature changes, renamed parameters, and moved imports at CI time rather than when a user copies a broken example.

Conventions for the snippet system (region naming, function-parameter pattern, # type: ignore prohibition, editing workflow) are documented in CLAUDE.md.


@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

@Kludex

Copy link
Copy Markdown
Member

@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

I said something like: "the examples/snippets are horribly lengthy, and complex". But yeah, I think ideally we want to have what would be an example as part of the docs.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

I said something like: "the examples/snippets are horribly lengthy, and complex".

Ah, I see. Agreed. I am working on getting more focused examples in place (e.g., without setup boilerplate).

But yeah, I think ideally we want to have what would be an example as part of the docs.

Agreed that they should be part of the docs, as in "embedded in the docs". Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

The way we've done it for the TypeScript SDK is to have, e.g., a examples/client/src/clientGuide.examples.ts file that is linted / type checked / etc, and to inject regions of that file into docs/client.md, which is what the user sees.

I slightly lean toward the way it's done the TypeScript SDK, but I don't have a strong preference. Which do you prefer?

@Kludex

Copy link
Copy Markdown
Member

Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

It's okay to live elsewhere, but for the perfect setup, that code should be tested.


Any approach is fine. Making sure that code is tested is the requirement here.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

@maxisbey

Copy link
Copy Markdown
Contributor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

Having the code tested would be nice, but that is a lot of overhead. Type checking and linting IMO is probably good enough at least to start with.

Comment threadREADME.v2.md Outdated
```
<!-- /snippet-source -->

_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_

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.

we should delete all these, or maybe have them as comments in the markdown. Not sure how helpful a link to the snippet actually is in the markdown since the code block contains the entire source anyway

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Makes sense. The snippet-source comment already contains the path (e.g., <!-- snippet-source examples/snippets/servers/basic_resource.py -->), so I've removed the links.

@Kludex

Copy link
Copy Markdown
Member

If we are making the examples simpler, then it's a good opportunity to test them.

I mean, the perfect world would be to add tests for that, so examples are tested and they actually work - given that in the past we got a lot of PRs/issues with example issues.

@Kludex

Copy link
Copy Markdown
Member

Otherwise, lint/type checker in them is fine.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Otherwise, lint/type checker in them is fine.

Since the examples in this PR are all in examples/snippets/docstrings/, they are all linted and type-checked. 👍

@Kludex@maxisbey Are there any further concerns? Is this okay to merge?

The new script is a superset of the old one. It continues to handle the
existing `<!-- snippet-source -->` markers in `README.v2.md`, and adds
support for syncing code snippets into Python docstrings and markdown
docs under `docs/`.
New capabilities beyond the old script:
- Region extraction from example files using `# region` / `# endregion`
markers, so a single example file can provide multiple snippets
- All source paths resolve relative to the repository root
- Scans `src/**/*.py` and `docs/**/*.md` in addition to the README
- Caches file contents and extracted regions for efficiency
The marker format uses HTML comments (`<!-- snippet-source -->` /
`<!-- /snippet-source -->`), which are invisible when rendered by
`mkdocstrings` and do not interfere with `pymdownx.superfences` code
fence parsing.
Add support for `<!-- snippet-source #region_name -->` markers that omit
the companion file path. The path is derived from the target file's
location using the mapping `src/X` → `examples/snippets/docstrings/X`.
This eliminates line-length violations on marker lines in docstrings,
since the full companion path no longer needs to be embedded in every
marker. The full-path form continues to work for non-`src/` targets like
markdown files.
Move inline code examples from docstrings in `src/mcp/` into standalone
companion files at `examples/snippets/docstrings/mcp/`, mirroring the
source tree structure. The `scripts/sync_snippets.py` script keeps the
docstring content in sync with the companion files via
`<!-- snippet-source #RegionName -->` markers.
This ensures all docstring examples are checked by pyright and ruff,
catching type errors and style drift that would otherwise go unnoticed
in raw docstring text. The pattern follows the TypeScript SDK's approach
of one companion file per source file, with each example in a named
function whose parameters supply typed context.
19 companion files cover 42 code examples across the public API surface:
`MCPServer`, `Client`, `ClientSession`, `Context`, `ResponseRouter`,
`ServerTaskContext`, `ExperimentalTaskHandlers`,
`ClientCredentialsOAuthProvider`, `PrivateKeyJWTOAuthProvider`,
`SignedJWTParameters`, and others.
All source markers use path-less form (`#RegionName`) — the companion
path is derived automatically from the target file location. Region
names follow `ClassName_methodName_variant` without abbreviation.
Pyright execution environment for the companion files suppresses only
"unused artifact" diagnostics inherent to example code
(`reportUnusedFunction`, `reportUnusedVariable`, `reportAbstractUsage`,
`reportUnusedClass`, `reportPrivateUsage`). All actual type-checking
rules remain enabled.
Add a "Docstring Code Examples" section covering the companion file
system: directory layout, `<!-- snippet-source #RegionName -->` markers,
`ClassName_methodName_variant` naming, the function-parameter pattern
for typed dependencies, and the prohibition on type-suppression comments
inside regions.
`sync_snippets.py` also syncs snippet-source markers in `docs/**/*.md`
and `README.v2.md`, not just `src/` docstrings. Add a short section
after "Docstring Code Examples" noting that these files use explicit
paths (path-less `#Region` markers are only supported in `src/` files).
The previous documentation had two flat sections where the docstring
section contained all the detail and the markdown section referred to it
vaguely. Reorganize into a `## Code Snippet System` intro covering
shared concepts (marker format, region extraction, naming conventions,
function wrappers, typed params, `# type: ignore` prohibition, pyright
workflow) with `### Markdown Code Examples` and
`### Docstring Code Examples` subsections covering only what is unique
to each target type.
The links to snippet source files are redundant since the code blocks
already contain the entire source. Removes all 33 occurrences.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanhefner@Kludex@maxisbey
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Type-check docstring code examples via companion files and unified sync script - #2119

Open
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script
Open

Type-check docstring code examples via companion files and unified sync script#2119
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script

Conversation

@jonathanhefner

Copy link
Copy Markdown
Member

Docstring code examples in src/mcp/ were previously raw text — invisible to pyright and ruff, so type errors and style drift went unnoticed. This PR introduces a system for keeping those examples in standalone, type-checked companion files that are synced back into the docstrings automatically.

The old update_readme_snippets.py is replaced with sync_snippets.py, a superset that handles README.v2.md, docs/**/*.md, and src/**/*.py docstrings. It adds region extraction (# region / # endregion markers) so a single companion file can supply multiple snippets. For docstrings specifically, <!-- snippet-source #RegionName --> markers derive the companion path automatically from the target file's location (src/mcp/foo.pyexamples/snippets/docstrings/mcp/foo.py), avoiding line-length violations from embedding full paths.

42 code examples across the public API surface (MCPServer, Client, ClientSession, Context, ResponseRouter, task support, OAuth providers, etc.) are extracted into 19 companion files under examples/snippets/docstrings/mcp/, mirroring the source tree. Each example is wrapped in a named function with typed parameters, so pyright and ruff check them on every CI run — catching signature changes, renamed parameters, and moved imports at CI time rather than when a user copies a broken example.

Conventions for the snippet system (region naming, function-parameter pattern, # type: ignore prohibition, editing workflow) are documented in CLAUDE.md.


@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

@Kludex

Copy link
Copy Markdown
Member

@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

I said something like: "the examples/snippets are horribly lengthy, and complex". But yeah, I think ideally we want to have what would be an example as part of the docs.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

I said something like: "the examples/snippets are horribly lengthy, and complex".

Ah, I see. Agreed. I am working on getting more focused examples in place (e.g., without setup boilerplate).

But yeah, I think ideally we want to have what would be an example as part of the docs.

Agreed that they should be part of the docs, as in "embedded in the docs". Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

The way we've done it for the TypeScript SDK is to have, e.g., a examples/client/src/clientGuide.examples.ts file that is linted / type checked / etc, and to inject regions of that file into docs/client.md, which is what the user sees.

I slightly lean toward the way it's done the TypeScript SDK, but I don't have a strong preference. Which do you prefer?

@Kludex

Copy link
Copy Markdown
Member

Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

It's okay to live elsewhere, but for the perfect setup, that code should be tested.


Any approach is fine. Making sure that code is tested is the requirement here.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

@maxisbey

Copy link
Copy Markdown
Contributor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

Having the code tested would be nice, but that is a lot of overhead. Type checking and linting IMO is probably good enough at least to start with.

Comment threadREADME.v2.md Outdated
```
<!-- /snippet-source -->

_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_

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.

we should delete all these, or maybe have them as comments in the markdown. Not sure how helpful a link to the snippet actually is in the markdown since the code block contains the entire source anyway

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Makes sense. The snippet-source comment already contains the path (e.g., <!-- snippet-source examples/snippets/servers/basic_resource.py -->), so I've removed the links.

@Kludex

Copy link
Copy Markdown
Member

If we are making the examples simpler, then it's a good opportunity to test them.

I mean, the perfect world would be to add tests for that, so examples are tested and they actually work - given that in the past we got a lot of PRs/issues with example issues.

@Kludex

Copy link
Copy Markdown
Member

Otherwise, lint/type checker in them is fine.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Otherwise, lint/type checker in them is fine.

Since the examples in this PR are all in examples/snippets/docstrings/, they are all linted and type-checked. 👍

@Kludex@maxisbey Are there any further concerns? Is this okay to merge?

The new script is a superset of the old one. It continues to handle the
existing `<!-- snippet-source -->` markers in `README.v2.md`, and adds
support for syncing code snippets into Python docstrings and markdown
docs under `docs/`.
New capabilities beyond the old script:
- Region extraction from example files using `# region` / `# endregion`
markers, so a single example file can provide multiple snippets
- All source paths resolve relative to the repository root
- Scans `src/**/*.py` and `docs/**/*.md` in addition to the README
- Caches file contents and extracted regions for efficiency
The marker format uses HTML comments (`<!-- snippet-source -->` /
`<!-- /snippet-source -->`), which are invisible when rendered by
`mkdocstrings` and do not interfere with `pymdownx.superfences` code
fence parsing.
Add support for `<!-- snippet-source #region_name -->` markers that omit
the companion file path. The path is derived from the target file's
location using the mapping `src/X` → `examples/snippets/docstrings/X`.
This eliminates line-length violations on marker lines in docstrings,
since the full companion path no longer needs to be embedded in every
marker. The full-path form continues to work for non-`src/` targets like
markdown files.
Move inline code examples from docstrings in `src/mcp/` into standalone
companion files at `examples/snippets/docstrings/mcp/`, mirroring the
source tree structure. The `scripts/sync_snippets.py` script keeps the
docstring content in sync with the companion files via
`<!-- snippet-source #RegionName -->` markers.
This ensures all docstring examples are checked by pyright and ruff,
catching type errors and style drift that would otherwise go unnoticed
in raw docstring text. The pattern follows the TypeScript SDK's approach
of one companion file per source file, with each example in a named
function whose parameters supply typed context.
19 companion files cover 42 code examples across the public API surface:
`MCPServer`, `Client`, `ClientSession`, `Context`, `ResponseRouter`,
`ServerTaskContext`, `ExperimentalTaskHandlers`,
`ClientCredentialsOAuthProvider`, `PrivateKeyJWTOAuthProvider`,
`SignedJWTParameters`, and others.
All source markers use path-less form (`#RegionName`) — the companion
path is derived automatically from the target file location. Region
names follow `ClassName_methodName_variant` without abbreviation.
Pyright execution environment for the companion files suppresses only
"unused artifact" diagnostics inherent to example code
(`reportUnusedFunction`, `reportUnusedVariable`, `reportAbstractUsage`,
`reportUnusedClass`, `reportPrivateUsage`). All actual type-checking
rules remain enabled.
Add a "Docstring Code Examples" section covering the companion file
system: directory layout, `<!-- snippet-source #RegionName -->` markers,
`ClassName_methodName_variant` naming, the function-parameter pattern
for typed dependencies, and the prohibition on type-suppression comments
inside regions.
`sync_snippets.py` also syncs snippet-source markers in `docs/**/*.md`
and `README.v2.md`, not just `src/` docstrings. Add a short section
after "Docstring Code Examples" noting that these files use explicit
paths (path-less `#Region` markers are only supported in `src/` files).
The previous documentation had two flat sections where the docstring
section contained all the detail and the markdown section referred to it
vaguely. Reorganize into a `## Code Snippet System` intro covering
shared concepts (marker format, region extraction, naming conventions,
function wrappers, typed params, `# type: ignore` prohibition, pyright
workflow) with `### Markdown Code Examples` and
`### Docstring Code Examples` subsections covering only what is unique
to each target type.
The links to snippet source files are redundant since the code blocks
already contain the entire source. Removes all 33 occurrences.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanhefner@Kludex@maxisbey
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Type-check docstring code examples via companion files and unified sync script - #2119

Open
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script
Open

Type-check docstring code examples via companion files and unified sync script#2119
jonathanhefner wants to merge 7 commits into
modelcontextprotocol:mainfrom
jonathanhefner:sync-snippets-script

Conversation

@jonathanhefner

Copy link
Copy Markdown
Member

Docstring code examples in src/mcp/ were previously raw text — invisible to pyright and ruff, so type errors and style drift went unnoticed. This PR introduces a system for keeping those examples in standalone, type-checked companion files that are synced back into the docstrings automatically.

The old update_readme_snippets.py is replaced with sync_snippets.py, a superset that handles README.v2.md, docs/**/*.md, and src/**/*.py docstrings. It adds region extraction (# region / # endregion markers) so a single companion file can supply multiple snippets. For docstrings specifically, <!-- snippet-source #RegionName --> markers derive the companion path automatically from the target file's location (src/mcp/foo.pyexamples/snippets/docstrings/mcp/foo.py), avoiding line-length violations from embedding full paths.

42 code examples across the public API surface (MCPServer, Client, ClientSession, Context, ResponseRouter, task support, OAuth providers, etc.) are extracted into 19 companion files under examples/snippets/docstrings/mcp/, mirroring the source tree. Each example is wrapped in a named function with typed parameters, so pyright and ruff check them on every CI run — catching signature changes, renamed parameters, and moved imports at CI time rather than when a user copies a broken example.

Conventions for the snippet system (region naming, function-parameter pattern, # type: ignore prohibition, editing workflow) are documented in CLAUDE.md.


@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

@Kludex

Copy link
Copy Markdown
Member

@Kludex, I was told you were thinking about moving examples/snippets/ to docs/snippets/. Would you prefer that docstring snippets live in docs/snippets/docstrings/? (Or anywhere else other than examples/snippets/docstrings/?)

I said something like: "the examples/snippets are horribly lengthy, and complex". But yeah, I think ideally we want to have what would be an example as part of the docs.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

I said something like: "the examples/snippets are horribly lengthy, and complex".

Ah, I see. Agreed. I am working on getting more focused examples in place (e.g., without setup boilerplate).

But yeah, I think ideally we want to have what would be an example as part of the docs.

Agreed that they should be part of the docs, as in "embedded in the docs". Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

The way we've done it for the TypeScript SDK is to have, e.g., a examples/client/src/clientGuide.examples.ts file that is linted / type checked / etc, and to inject regions of that file into docs/client.md, which is what the user sees.

I slightly lean toward the way it's done the TypeScript SDK, but I don't have a strong preference. Which do you prefer?

@Kludex

Copy link
Copy Markdown
Member

Do you feel like the underlying code should also live in docs/? Or is it okay for the underlying code to live in examples/ and regions of it be injected into docs/*.md files?

It's okay to live elsewhere, but for the perfect setup, that code should be tested.


Any approach is fine. Making sure that code is tested is the requirement here.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

@maxisbey

Copy link
Copy Markdown
Contributor

Any approach is fine. Making sure that code is tested is the requirement here.

My plan was to ensure the code is type checked, linted, and formatted. Actual tests would add a lot of overhead to the process (setup code, mocks, assertions, etc.).

Are you okay with simply type checking? Do any of the existing examples have test coverage?

Having the code tested would be nice, but that is a lot of overhead. Type checking and linting IMO is probably good enough at least to start with.

Comment threadREADME.v2.md Outdated
```
<!-- /snippet-source -->

_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_

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.

we should delete all these, or maybe have them as comments in the markdown. Not sure how helpful a link to the snippet actually is in the markdown since the code block contains the entire source anyway

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Makes sense. The snippet-source comment already contains the path (e.g., <!-- snippet-source examples/snippets/servers/basic_resource.py -->), so I've removed the links.

@Kludex

Copy link
Copy Markdown
Member

If we are making the examples simpler, then it's a good opportunity to test them.

I mean, the perfect world would be to add tests for that, so examples are tested and they actually work - given that in the past we got a lot of PRs/issues with example issues.

@Kludex

Copy link
Copy Markdown
Member

Otherwise, lint/type checker in them is fine.

@jonathanhefner

Copy link
Copy Markdown
MemberAuthor

Otherwise, lint/type checker in them is fine.

Since the examples in this PR are all in examples/snippets/docstrings/, they are all linted and type-checked. 👍

@Kludex@maxisbey Are there any further concerns? Is this okay to merge?

The new script is a superset of the old one. It continues to handle the
existing `<!-- snippet-source -->` markers in `README.v2.md`, and adds
support for syncing code snippets into Python docstrings and markdown
docs under `docs/`.
New capabilities beyond the old script:
- Region extraction from example files using `# region` / `# endregion`
markers, so a single example file can provide multiple snippets
- All source paths resolve relative to the repository root
- Scans `src/**/*.py` and `docs/**/*.md` in addition to the README
- Caches file contents and extracted regions for efficiency
The marker format uses HTML comments (`<!-- snippet-source -->` /
`<!-- /snippet-source -->`), which are invisible when rendered by
`mkdocstrings` and do not interfere with `pymdownx.superfences` code
fence parsing.
Add support for `<!-- snippet-source #region_name -->` markers that omit
the companion file path. The path is derived from the target file's
location using the mapping `src/X` → `examples/snippets/docstrings/X`.
This eliminates line-length violations on marker lines in docstrings,
since the full companion path no longer needs to be embedded in every
marker. The full-path form continues to work for non-`src/` targets like
markdown files.
Move inline code examples from docstrings in `src/mcp/` into standalone
companion files at `examples/snippets/docstrings/mcp/`, mirroring the
source tree structure. The `scripts/sync_snippets.py` script keeps the
docstring content in sync with the companion files via
`<!-- snippet-source #RegionName -->` markers.
This ensures all docstring examples are checked by pyright and ruff,
catching type errors and style drift that would otherwise go unnoticed
in raw docstring text. The pattern follows the TypeScript SDK's approach
of one companion file per source file, with each example in a named
function whose parameters supply typed context.
19 companion files cover 42 code examples across the public API surface:
`MCPServer`, `Client`, `ClientSession`, `Context`, `ResponseRouter`,
`ServerTaskContext`, `ExperimentalTaskHandlers`,
`ClientCredentialsOAuthProvider`, `PrivateKeyJWTOAuthProvider`,
`SignedJWTParameters`, and others.
All source markers use path-less form (`#RegionName`) — the companion
path is derived automatically from the target file location. Region
names follow `ClassName_methodName_variant` without abbreviation.
Pyright execution environment for the companion files suppresses only
"unused artifact" diagnostics inherent to example code
(`reportUnusedFunction`, `reportUnusedVariable`, `reportAbstractUsage`,
`reportUnusedClass`, `reportPrivateUsage`). All actual type-checking
rules remain enabled.
Add a "Docstring Code Examples" section covering the companion file
system: directory layout, `<!-- snippet-source #RegionName -->` markers,
`ClassName_methodName_variant` naming, the function-parameter pattern
for typed dependencies, and the prohibition on type-suppression comments
inside regions.
`sync_snippets.py` also syncs snippet-source markers in `docs/**/*.md`
and `README.v2.md`, not just `src/` docstrings. Add a short section
after "Docstring Code Examples" noting that these files use explicit
paths (path-less `#Region` markers are only supported in `src/` files).
The previous documentation had two flat sections where the docstring
section contained all the detail and the markdown section referred to it
vaguely. Reorganize into a `## Code Snippet System` intro covering
shared concepts (marker format, region extraction, naming conventions,
function wrappers, typed params, `# type: ignore` prohibition, pyright
workflow) with `### Markdown Code Examples` and
`### Docstring Code Examples` subsections covering only what is unique
to each target type.
The links to snippet source files are redundant since the code blocks
already contain the entire source. Removes all 33 occurrences.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jonathanhefner@Kludex@maxisbey