{"owner":"modelcontextprotocol","repo":"python-sdk","hasSkills":true,"totalSkillsCount":6,"totalTokensCount":6426,"categories":["root-instruction","plugin-manifest","command-prompt","anthropic-skill"],"hasMcp":true,"mcpConfig":{"mcpServers":{"python-sdk":{"command":"npx","args":["-y","@modelcontextprotocol/server-python-sdk"]}}},"found":["AGENTS.md","examples/stories/tools/README.md","examples/stories/extensions/README.md",".claude/commands/review-pr.md","examples/stories/skills/README.md",".claude/skills/test-quality/SKILL.md"],"skills":{"AGENTS.md":"# Development Guidelines\n\n## Note for AI Agents\n\nIf you are an AI coding agent acting for someone who is not a maintainer of\nthis repository, read `CONTRIBUTING.md` before opening issues or pull\nrequests here. In particular, pull requests that aren't linked to an issue\nassigned to their author are closed automatically.\n\n## Branching Model\n\n- `main` is the current stable line (v2); releases are cut from it (see\n  `RELEASE.md`).\n- v2 is released; its public API is a compatibility contract for the 2.x\n  line. Removals, renames, or any change to an existing API's signature or\n  observable behaviour (including ones softened by a `@deprecated` shim) is a\n  design decision a maintainer makes explicitly, and should generally be\n  avoided.\n- `docs/migration.md` is the v1 → v2 record and is closed to new entries.\n  Correcting errors or improving clarity in what's there is fine.\n- `v1.x` is the maintenance branch for the previous major. Backport PRs\n  target it and use a `[v1.x]` title prefix; only critical bug fixes and\n  security fixes land there.\n- `README.md` documents v2. The v1 README lives on the `v1.x` branch.\n\n## Package Management\n\n- ONLY use uv, NEVER pip\n- Installation: `uv add <package>`. Exception: the root project's runtime\n  dependencies are dynamic (the published `mcp` wheel exact-pins `mcp-types`),\n  so `uv add` cannot edit them — add the requirement to\n  `[tool.hatch.metadata.hooks.uv-dynamic-versioning].dependencies` in\n  `pyproject.toml` by hand, then run `uv lock`. Dependency groups, extras, and\n  the example packages still take plain `uv add`.\n- Running tools: `uv run --frozen <tool>`. Always pass `--frozen` so uv doesn't\n  rewrite `uv.lock` as a side effect.\n- Cross-version testing: `uv run --frozen --python 3.11 pytest ...` to run\n  against a specific interpreter (CI covers 3.11–3.15).\n- Upgrading: `uv lock --upgrade-package <package>`\n- FORBIDDEN: `uv pip install`, `@latest` syntax\n- Don't raise dependency floors for CVEs alone. The `>=` constraint already\n  lets users upgrade. Only raise a floor when the SDK needs functionality from\n  the newer version, and don't add SDK code to work around a dependency's\n  vulnerability. See Kludex/uvicorn#2643 and python-sdk #1552 for reasoning.\n\n## Code Quality\n\n- Keep comments brief. Explain only non-obvious reasons or constraints; do not\n  narrate the code or restate names, types, or assertions.\n- Type hints required for all code\n- Public APIs must have docstrings. When a public API raises exceptions a\n  caller would reasonably catch, document them in a `Raises:` section. Don't\n  list exceptions from argument validation or programmer error.\n- `src/mcp/__init__.py` defines the public API surface via `__all__`. Adding a\n  symbol there is a deliberate API decision, not a convenience re-export.\n- IMPORTANT: All imports go at the top of the file — inline imports hide\n  dependencies and obscure circular-import bugs. Only exception: when a\n  top-level import genuinely can't work (lazy-loading optional deps, or\n  tests that re-import a module).\n- Always pass `encoding=` to text-mode `open()`, `Path.read_text()`/`write_text()`,\n  `tempfile` and `subprocess` text pipes — normally `\"utf-8\"`, or `\"locale\"` when the\n  platform encoding is genuinely intended; the default is the process locale, not UTF-8.\n  CI and `scripts/test` run pytest with `PYTHONWARNDEFAULTENCODING=1` (PEP 597), which\n  makes any omission an error under the `error` filter.\n\n## Testing\n\n- When writing or reviewing tests, conform to `.claude/skills/test-quality/SKILL.md`\n  — it defines the bar for naming, abstraction level, assertions, and determinism.\n- Framework: `uv run --frozen pytest`\n- Async testing: use anyio, not asyncio\n- Do not use `Test` prefixed classes — write plain top-level `test_*` functions.\n  Legacy files still contain `Test*` classes; do NOT follow that pattern for new\n  tests even when adding to such a file.\n- IMPORTANT: Tests should be fast and deterministic. Prefer in-memory async execution;\n  reach for threads only when necessary, and subprocesses only as a last resort.\n- For end-to-end behavior, an in-memory `Client(server)` is usually the\n  cleanest approach (see `tests/client/test_client.py` for the canonical\n  pattern). For narrower changes, testing the function directly is fine. Use\n  judgment.\n- Test files mirror the source tree: `src/mcp/client/stdio.py` →\n  `tests/client/test_stdio.py`. Add tests to the existing file for that module.\n- Avoid `anyio.sleep()` with a fixed duration to wait for async operations. Instead:\n  - Use `anyio.Event` — set it in the callback/handler, `await event.wait()` in the test\n  - For stream messages, use `await stream.receive()` instead of `sleep()` + `receive_nowait()`\n  - Exception: `sleep()` is appropriate when testing time-based features (e.g., timeouts)\n- Wrap indefinite waits (`event.wait()`, `stream.receive()`) in `anyio.fail_after(5)` to prevent hangs\n- Pytest is configured with `filterwarnings = [\"error\"]`, so warnings fail\n  tests. Don't silence warnings from your own code; fix the underlying cause.\n  Scoped `ignore::` entries for upstream libraries are acceptable in\n  `pyproject.toml` with a comment explaining why.\n- New features from the 2026-07-28 spec must have a matching test in the\n  [conformance suite](https://github.com/modelcontextprotocol/conformance)\n  that passes against this SDK (CI runs it via\n  `.github/workflows/conformance.yml`). If no matching test exists, stop and\n  tell the user so they can raise an issue on the conformance repo.\n\n### Coverage\n\nCI requires 100% (`fail_under = 100`, `branch = true`).\n\n- Full check: `./scripts/test` (~23s). Runs coverage + `strict-no-cover` on the\n  default Python. Not identical to CI: CI runs 3.11–3.15 × {ubuntu, windows}\n  × {locked, lowest-direct}, and some branch-coverage quirks only surface on\n  specific matrix entries.\n- Targeted check while iterating (~4s, deterministic):\n\n  ```bash\n  uv run --frozen coverage erase\n  uv run --frozen coverage run -m pytest tests/path/test_foo.py\n  uv run --frozen coverage combine\n  uv run --frozen coverage report --include='src/mcp/path/foo.py' --fail-under=0\n  # UV_FROZEN=1 propagates --frozen to the uv subprocess strict-no-cover spawns\n  UV_FROZEN=1 uv run --frozen strict-no-cover\n  ```\n\n  Partial runs can't hit 100% (coverage tracks `tests/` too), so `--fail-under=0`\n  and `--include` scope the report. `strict-no-cover` has no false positives on\n  partial runs — if your new test executes a line marked `# pragma: no cover`,\n  even a single-file run catches it.\n\nAvoid adding new `# pragma: no cover`, `# type: ignore`, or `# noqa` comments.\nIn tests, use `assert isinstance(x, T)` to narrow types instead of\n`# type: ignore`. In library code (`src/`), a `# pragma: no cover` needs very\ngood reasoning — it usually means a test is missing. Audit before pushing:\n\n```bash\ngit diff origin/main... | grep -E '^\\+.*(pragma|type: ignore|noqa)'\n```\n\nWhat the existing pragmas mean:\n\n- `# pragma: no cover` — line is never executed. CI's `strict-no-cover` (skipped\n  on Windows runners) fails if it IS executed. When your test starts covering\n  such a line, remove the pragma.\n- `# pragma: lax no cover` — excluded from coverage but not checked by\n  `strict-no-cover`. Use for lines covered on some platforms/versions but not\n  others.\n- `# pragma: no branch` — excludes branch arcs only. coverage.py misreports the\n  `->exit` arc for nested `async with` on Python 3.11+ (worse on 3.14/Windows).\n\n## Documentation\n\nWhen a change affects public API or user-visible behaviour, update the relevant\npage(s) under `docs/` in the same PR. Docs are organised by the `nav:` sections\nin `mkdocs.yml` (Get started, Servers, Inside your handler, Running your server,\nClients, Advanced), not by the on-disk directory names. Find the page covering\nthe feature you touched in `mkdocs.yml` rather than adding a new one.\n\n## Formatting & Type Checking\n\n- Format: `uv run --frozen ruff format .`\n- Lint: `uv run --frozen ruff check . --fix`\n- Type check: `uv run --frozen pyright`\n- Pre-commit runs all of the above plus markdownlint, a `uv.lock` consistency\n  check, and README checks — see `.pre-commit-config.yaml`\n\n## Exception Handling\n\n- **Always use `logger.exception()` instead of `logger.error()` when catching exceptions**\n  - Don't include the exception in the message: `logger.exception(\"Failed\")` not `logger.exception(f\"Failed: {e}\")`\n- **Catch specific exceptions** where possible:\n  - File ops: `except (OSError, PermissionError):`\n  - JSON: `except json.JSONDecodeError:`\n  - Network: `except (ConnectionError, TimeoutError):`\n- **FORBIDDEN** `except Exception:` - unless in top-level handlers\n","examples/stories/tools/README.md":"# tools\n\n**Start here.** Register tools with `@mcp.tool()`; the SDK infers the JSON\ninput schema from type hints, the output schema from the return annotation, and\nreturns `structuredContent` alongside text. `ToolAnnotations` carries\nbehavioural hints (`readOnlyHint`, `idempotentHint`) the host can show to\nusers. The client lists tools, inspects schemas + annotations, calls both, and\nasserts structured output.\n\n## Run it\n\n```bash\n# stdio (default — the client spawns the server as a subprocess)\nuv run python -m stories.tools.client\n\n# HTTP — the client self-hosts the server on a free port, runs, then tears it down\nuv run python -m stories.tools.client --http\n# same, against the lowlevel-API server variant\nuv run python -m stories.tools.client --http --server server_lowlevel\n```\n\n## What to look at\n\n- `server.py` `calc` — `Literal[...]` and `BaseModel` in the signature become\n  the tool's `inputSchema` / `outputSchema` with zero hand-written JSON.\n- `server.py` `echo` — `structured_output=False` opts out of schema inference\n  for a plain text-only tool.\n- `server_lowlevel.py` — the same wire contract built by hand: this is what\n  `MCPServer` generates for you.\n\n## Spec\n\n[Tools — server features](https://modelcontextprotocol.io/specification/2025-11-25/server/tools)\n\n## See also\n\n`schema_validators/` (every input-schema source: pydantic / TypedDict /\ndataclass / dict), `error_handling/` (`is_error` vs protocol error),\n`streaming/` (progress mid-call).\n","examples/stories/extensions/README.md":"# extensions\n\nWriting your own extension (SEP-2133): one identifier bundles a settings entry\nunder `ServerCapabilities.extensions`, a contributed tool, and a vendor request\nmethod gated on the client declaring the extension back.\n\n## Run it\n\n```bash\n# stdio (default — the client spawns the server as a subprocess)\nuv run python -m stories.extensions.client\n\n# HTTP — the client self-hosts the server on a free port, runs, then tears it down\nuv run python -m stories.extensions.client --http\n```\n\n## What to look at\n\n- `server.py` `class Catalog(Extension)` — the whole extension: `settings()`\n  becomes the advertised capability entry, `tools()` contributes a regular tool,\n  `methods()` registers a vendor verb. The extension never holds the server; it\n  declares contributions and `MCPServer(extensions=[...])` consumes them.\n- `server.py` `require_client_extension(ctx, EXTENSION_ID)` — the vendor method\n  rejects clients that did not declare the extension with `-32021` (missing\n  required client capability) and a machine-readable `requiredCapabilities`\n  payload.\n- `client.py` `Client(target, extensions=[advertise(EXTENSION_ID)])` — the client-side\n  half of the negotiation; on 2026-07-28 it travels in the per-request `_meta`\n  envelope.\n- `client.py` `client.session.send_request(...)` — vendor methods have no\n  `Client`-level helper; the session escape hatch sends them.\n\n## Spec\n\n[SEP-2133 — extensions capability](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2133)\n· [Capabilities — `_meta` key grammar](https://modelcontextprotocol.io/specification/draft/basic/index)\n\n## See also\n\n`apps/` (the built-in MCP Apps extension) · `custom_methods/` (the same verb\nregistered on the lowlevel `Server` by hand, without an extension).\n",".claude/commands/review-pr.md":"Review the pull request: $ARGUMENTS\n\nFollow these steps carefully. Use the `gh` CLI for all GitHub interactions.\n\n## Step 1: Resolve the PR\n\nParse `$ARGUMENTS` to determine the PR. It can be:\n\n- A full URL like `https://github.com/owner/repo/pull/123`\n- A `owner/repo#123` reference\n- A bare number like `123` (use the current repo)\n- A description — search for it with `gh pr list --search \"<description>\" --limit 5` and pick the best match\n\nOnce resolved, fetch the PR metadata:\n\n```bash\ngh pr view <PR> --json number,title,body,author,state,baseRefName,headRefName,url,labels,milestone,additions,deletions,changedFiles,createdAt,updatedAt,mergedAt,reviewDecision,reviews,assignees\n```\n\n## Step 2: Gather the diff\n\nGet the full diff of the PR:\n\n```bash\ngh pr diff <PR>\n```\n\nIf the diff is very large (>3000 lines), focus on the most important files first and summarize the rest.\n\n## Step 3: Collect PR discussion context\n\nFetch all comments and review threads:\n\n```bash\ngh api repos/{owner}/{repo}/pulls/{number}/comments --paginate\ngh api repos/{owner}/{repo}/issues/{number}/comments --paginate\ngh api repos/{owner}/{repo}/pulls/{number}/reviews --paginate\n```\n\nPay attention to:\n\n- Reviewer feedback and requested changes\n- Author responses and explanations\n- Any unresolved conversations\n- Approval or rejection status\n\n## Step 4: Find and read linked issues\n\nLook for issue references in:\n\n- The PR body (patterns like `#123`, `fixes #123`, `closes #123`, `resolves #123`)\n- The PR branch name (patterns like `issue-123`, `fix/123`)\n- Commit messages\n\nFor each linked issue, fetch its content:\n\n```bash\ngh issue view <number> --json title,body,comments,labels,state\n```\n\nRead through issue comments to understand the original problem, user reports, and any discussed solutions.\n\n## Step 5: Analyze and validate\n\nWith all context gathered, analyze the PR critically:\n\n1. **Intent alignment**: Does the code change actually solve the problem described in the PR and/or linked issues?\n2. **Completeness**: Are there aspects of the issue or requested feature that the PR doesn't address?\n3. **Scope**: Does the PR include changes unrelated to the stated goal? Are there unnecessary modifications?\n4. **Correctness**: Based on the diff, are there obvious bugs, edge cases, or logic errors?\n5. **Testing**: Does the PR include tests? Are they meaningful and do they cover the important cases?\n6. **Breaking changes**: Could this PR break existing functionality or APIs?\n7. **Unresolved feedback**: Are there reviewer comments that haven't been addressed?\n\n## Step 6: Produce the review summary\n\nPresent the summary in this format:\n\n---\n\n### PR Review: `<title>` (<url>)\n\n**Author:** <author> | **Status:** <state> | **Review decision:** <decision>\n**Base:** `<base>` ← `<head>` | **Changed files:** <n> | **+<additions> / -<deletions>**\n\n#### Problem\n\n<1-3 sentences describing what problem this PR is trying to solve, based on the PR description and linked issues>\n\n#### Solution\n\n<1-3 sentences describing the approach taken in the code>\n\n#### Key changes\n\n<Bulleted list of the most important changes, grouped by theme. Include file paths.>\n\n#### Linked issues\n\n<List of linked issues with their title, state, and a one-line summary of the discussion>\n\n#### Discussion highlights\n\n<Summary of important comments from reviewers and the author. Flag any unresolved threads.>\n\n#### Concerns\n\n<List any issues found during validation: bugs, missing tests, scope creep, unaddressed feedback, etc. If none, say \"No concerns found.\">\n\n#### Verdict\n\n<One of: APPROVE / REQUEST CHANGES / NEEDS DISCUSSION, with a brief justification>\n\n#### Suggested action\n\n<Clear recommendation for the reviewer: what to approve, what to push back on, what to ask about>\n\n---\n","examples/stories/skills/README.md":"# skills\n\nSEP-2640 skills: a server exposes a `skill://index.json` directory resource and\n`@skill` / `@skillDir` registrations that a host can read to bootstrap\nagent-level instructions. The story will list skills and read one.\n\n**Status: not yet implemented** ([#2896](https://github.com/modelcontextprotocol/python-sdk/issues/2896)).\nThe `extensions` capability map is not yet surfaced on `MCPServer`, so a server\ncannot advertise the skills extension.\n\n## Spec\n\n[SEP-2640 — skills](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2640)\n· [SEP-2133 — extensions capability](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2133)\n",".claude/skills/test-quality/SKILL.md":"---\nname: test-quality\ndescription: Test quality bar for this repo. Read when writing, reviewing, or designing tests — covers naming, abstraction level, assertions, determinism, and the process for agent-driven test work.\n---\n\n# Test & code quality guide\n\nWhat \"best practice for new work\" means in this repo. Each rule carries its recorded reasoning\nwhere one exists; a rule with no stated why is a convention — follow it anyway.\n\n## Naming & shape\n\n- **Test names are behaviour sentences** stating the observable outcome, not the feature being\n  poked: `test_elicit_form_decline_returns_no_content`, never `test_elicit_form_decline`.\n- Plain top-level `test_*` functions; no `Test` classes (legacy files have them — don't copy).\n- **Docstrings: 1–2 sentences of behaviour, honest about provenance** — spec-mandated,\n  SDK-defined, or pinning a known gap? Say which: provenance is the triage key when the test\n  later fails. A pinned-gap assertion breaking usually means a change *fixed* the gap; a\n  spec-mandated assertion breaking means a regression.\n- Define things in dependency order; nothing forward-references. For client↔server tests:\n  handlers → server construction → client setup → act → assert — the test reads in the order\n  the conversation happens.\n- Inline the server (or equivalent setup) in the test, so the whole observable behaviour fits\n  on one screen. Lift to a file-level fixture only when several tests in *that file* genuinely\n  share it; never share across files.\n- A big multi-step test is fine when the property is irreducibly multi-step (e.g. resumability).\n  Split when a failure wouldn't tell you which claim broke — not for shortness. Compensate with\n  a numbered \"Steps:\" docstring so a reader sees the choreography before the body.\n\n## Level of abstraction\n\n- **Drive through the highest-level public API that can observe the property.** Hand-built wire\n  requests are brittle and don't prove the user-facing contract; tests that stay above the\n  internals keep working when the internals change. Drop to raw HTTP only when the assertion is\n  about something the high-level API *cannot* observe (status codes, headers, wire framing).\n- **Scripting a peer over raw streams is a last resort**, reserved for behaviour the typed API\n  cannot *produce* (malformed input, an impossible peer response). First ask what it would take\n  for the public API to express it — often a small helper suffices. Every such test's docstring\n  states why the public API couldn't do it.\n- **In-memory / in-process first.** HTTP-, SSE-, and auth-shaped behaviour can all be driven\n  through an in-process ASGI transport; threads only when necessary, subprocesses only when the\n  process boundary is itself the thing under test. In-process isn't just faster — it surfaces\n  bugs (a real stream leak was found this way) that subprocess indirection masks.\n- **Tests read like real user code**: no aliasing shims in conftest, no walls of suppressions,\n  no private imports unless that is genuinely the documented way to do the thing.\n- The assertion must prove the round trip — no side-channel state. What the server saw comes\n  back through the protocol, or via a closure-captured list asserted after the call. Handlers\n  assert their dispatch identity first (`assert params.name == \"add\"`), proving the request\n  that arrived is the request the test sent.\n\n## Assertions\n\n- **Transformations** (input → output the SDK produced) → full-object `snapshot(...)` equality,\n  so an added or dropped field fails. Regenerate with `--inline-snapshot=fix` so intentional\n  changes arrive as a reviewable diff; never hand-edit snapshot literals.\n- **Pass-through values** (opaque tokens, `_meta`, cursors) → identity against the same\n  variable you sent. A snapshot of a pass-through value only \"matches\" because a human checked\n  two literals correspond — it proves nothing.\n- **Errors** → `pytest.raises` + `.code` against the named constant; snapshot SDK-authored\n  messages; never `match=` on message text. Third-party text (pydantic, jsonschema) → stable\n  prefix only — never pin text that changes with a dependency upgrade — with a comment saying so.\n\n## Determinism\n\n- **No sleeps, ever.** A sleep guesses at timing instead of waiting on the condition, so it\n  either flakes or pads the run — sleeps head the list of the older test code's failure modes.\n  Coordinate with `anyio.Event` so the wait ends exactly when the condition holds (that\n  discipline is why 529 e2e tests run in ~10 s). Sole exception: tests *of* time-based\n  features, with a comment.\n- Bound every indefinite wait with `anyio.fail_after(5)`. **5 is the standard** — widening it\n  needs an articulable reason; \"10 to be safe\" is covering up a flake, not fixing one, and\n  unexplained widenings propagate (one agent used 10 and every later one copied it).\n- **Never assert wall-clock time, even with huge margins.** `elapsed < 0.9` on a ~0.01 s\n  operation — a 90× margin — was still rejected in review. `fail_after` bounding a hang is the\n  only timing primitive allowed.\n- **Concurrency tests must prove genuine interleaving.** Without barriers the scheduler is free\n  to serialize — \"a\" can start, finish, and return before \"b\" even begins — so two `start_soon`\n  calls prove nothing. Gate with events so all parties are mid-flight before any proceeds, emit\n  interleaved, then assert the demux.\n- **Don't over-synchronize either.** When delivery ordering is guaranteed (notifications\n  emitted during a request you're awaiting, over a single ordered in-memory stream), a plain\n  collected list asserted after the call is correct; events are for messages not tied to an\n  awaited operation. Verify the ordering guarantee actually holds for your transport first.\n- Async tests use anyio, not asyncio.\n\n## Behaviour philosophy\n\n- **Pin current behaviour; never xfail.** A green suite asserting what actually happens is a\n  regression bar for any refactor; an xfail proves nothing about it. Where current behaviour\n  falls short of spec, pin the divergent output and record the gap as data — a tracking issue,\n  with the docstring naming the known gap (suites with a requirements manifest record it as a\n  divergence entry). Not hidden, not skipped.\n- **Hollow-proof check**: before claiming a test covers a behaviour, re-read the claim and ask\n  \"which assertion proves *this*?\" A passing test near a behaviour is not proof of it — a full\n  review of the e2e suite found two such cases even under this discipline.\n\n## Hygiene\n\n- No new `# pragma`, `# type: ignore`, `# noqa` by default — restructure first; a suppression\n  usually means a test or a type is missing. The narrow sanctioned escape hatches (and the\n  audit to run before pushing) are in AGENTS.md. In tests, narrow types with `assert\n  isinstance`; never `Any`/`object` when a real type exists.\n- **Warnings raised during tests are findings, not noise** (the repo runs\n  `filterwarnings = error`). Fix the cause; if the fix can't land in the same change, scope the\n  suppression to the one fixture that needs it and track the real fix explicitly.\n- Registered-but-never-invoked handler bodies are `raise NotImplementedError`, so they cannot\n  silently become load-bearing.\n- Comments live next to the line they explain, not in docstrings; single backticks for code\n  refs; match the surrounding comment density (one-liners next to one-liners). No\n  `from __future__ import annotations` (py311+ repo).\n- Test work doesn't change `src/` as a side effect — the one mechanical exception is deleting a\n  pragma a new test now covers. If a test can't be written without a library change, raise it\n  as a finding or defer the test; don't quietly edit `src/`.\n\n## Process (for agent-driven work)\n\n- **Small chunks.** ≤10 tests per human-reviewed batch; when fanning out to multiple agents,\n  ≤5 per agent. Review quality scales inversely with batch size: the observed shortcuts\n  (over-stacked tests, a timing assertion, wrong abstraction level) all surfaced in one\n  oversized 27-test batch.\n- **Design → review → implement, as separate steps.** The design deliverable is not just the\n  plan — it's the judgement calls (abstraction level, deferrals, contested assertions) stated\n  explicitly, so the reviewer vetoes them before implementation rather than discovering them\n  in the diff.\n- **High-stakes areas get fresh adversarial reviewers** on both the design and the\n  implementation — fresh, because whoever designed it (or saw the proposed fix) anchors on the\n  same layer. SERIOUS findings (wrong assertion, missed MUST/SHOULD, an unrecorded known gap)\n  re-loop; style doesn't. Reserve the full panel for areas where being wrong is worse than\n  being slow.\n- **Investigations pair a full-context look with a fresh agent given only the problem** —\n  never the proposed fix — and compare conclusions. The unbiased read regularly catches\n  anchoring on the wrong layer.\n- **When review questions a decision, reconsider genuinely**: re-derive the tradeoff, state the\n  options, recommend with reasons. Defending the original choice is a valid outcome;\n  reflexively agreeing with every challenge is as bad as ignoring it.\n- **Validate the reference artifact before building on it.** Whatever you treat as ground truth\n  (a spec import, a baseline, a generated list), check it *first* — discovering it was\n  incomplete after five batches costs far more than before batch one.\n- **Verify as you go**: per-file `uv run --frozen pytest <file> -q` + pyright + ruff while\n  iterating; full suite, coverage, and `./scripts/test` (when `src/` was touched) at\n  integration.\n- **Every agent writes notes**: what it did, what broke, and — most importantly — what it\n  couldn't decide, so open questions surface instead of being silently resolved by whoever hit\n  them.\n- **Quality over speed is a stated goal, not a preference** (\"rushing something out the door is\n  not the goal here, explicitly so\"). Don't quietly de-scope agreed work mid-stream;\n  renegotiate scope explicitly.\n- **Don't copy patterns from existing test code by default** — much of the repo's older test\n  code is below the current bar (sleeps, mocks, `Test` classes, raciness). These rules define\n  the bar for new work.\n"},"files":{"AGENTS.md":"# Development Guidelines\n\n## Note for AI Agents\n\nIf you are an AI coding agent acting for someone who is not a maintainer of\nthis repository, read `CONTRIBUTING.md` before opening issues or pull\nrequests here. In particular, pull requests that aren't linked to an issue\nassigned to their author are closed automatically.\n\n## Branching Model\n\n- `main` is the current stable line (v2); releases are cut from it (see\n  `RELEASE.md`).\n- v2 is released; its public API is a compatibility contract for the 2.x\n  line. Removals, renames, or any change to an existing API's signature or\n  observable behaviour (including ones softened by a `@deprecated` shim) is a\n  design decision a maintainer makes explicitly, and should generally be\n  avoided.\n- `docs/migration.md` is the v1 → v2 record and is closed to new entries.\n  Correcting errors or improving clarity in what's there is fine.\n- `v1.x` is the maintenance branch for the previous major. Backport PRs\n  target it and use a `[v1.x]` title prefix; only critical bug fixes and\n  security fixes land there.\n- `README.md` documents v2. The v1 README lives on the `v1.x` branch.\n\n## Package Management\n\n- ONLY use uv, NEVER pip\n- Installation: `uv add <package>`. Exception: the root project's runtime\n  dependencies are dynamic (the published `mcp` wheel exact-pins `mcp-types`),\n  so `uv add` cannot edit them — add the requirement to\n  `[tool.hatch.metadata.hooks.uv-dynamic-versioning].dependencies` in\n  `pyproject.toml` by hand, then run `uv lock`. Dependency groups, extras, and\n  the example packages still take plain `uv add`.\n- Running tools: `uv run --frozen <tool>`. Always pass `--frozen` so uv doesn't\n  rewrite `uv.lock` as a side effect.\n- Cross-version testing: `uv run --frozen --python 3.11 pytest ...` to run\n  against a specific interpreter (CI covers 3.11–3.15).\n- Upgrading: `uv lock --upgrade-package <package>`\n- FORBIDDEN: `uv pip install`, `@latest` syntax\n- Don't raise dependency floors for CVEs alone. The `>=` constraint already\n  lets users upgrade. Only raise a floor when the SDK needs functionality from\n  the newer version, and don't add SDK code to work around a dependency's\n  vulnerability. See Kludex/uvicorn#2643 and python-sdk #1552 for reasoning.\n\n## Code Quality\n\n- Keep comments brief. Explain only non-obvious reasons or constraints; do not\n  narrate the code or restate names, types, or assertions.\n- Type hints required for all code\n- Public APIs must have docstrings. When a public API raises exceptions a\n  caller would reasonably catch, document them in a `Raises:` section. Don't\n  list exceptions from argument validation or programmer error.\n- `src/mcp/__init__.py` defines the public API surface via `__all__`. Adding a\n  symbol there is a deliberate API decision, not a convenience re-export.\n- IMPORTANT: All imports go at the top of the file — inline imports hide\n  dependencies and obscure circular-import bugs. Only exception: when a\n  top-level import genuinely can't work (lazy-loading optional deps, or\n  tests that re-import a module).\n- Always pass `encoding=` to text-mode `open()`, `Path.read_text()`/`write_text()`,\n  `tempfile` and `subprocess` text pipes — normally `\"utf-8\"`, or `\"locale\"` when the\n  platform encoding is genuinely intended; the default is the process locale, not UTF-8.\n  CI and `scripts/test` run pytest with `PYTHONWARNDEFAULTENCODING=1` (PEP 597), which\n  makes any omission an error under the `error` filter.\n\n## Testing\n\n- When writing or reviewing tests, conform to `.claude/skills/test-quality/SKILL.md`\n  — it defines the bar for naming, abstraction level, assertions, and determinism.\n- Framework: `uv run --frozen pytest`\n- Async testing: use anyio, not asyncio\n- Do not use `Test` prefixed classes — write plain top-level `test_*` functions.\n  Legacy files still contain `Test*` classes; do NOT follow that pattern for new\n  tests even when adding to such a file.\n- IMPORTANT: Tests should be fast and deterministic. Prefer in-memory async execution;\n  reach for threads only when necessary, and subprocesses only as a last resort.\n- For end-to-end behavior, an in-memory `Client(server)` is usually the\n  cleanest approach (see `tests/client/test_client.py` for the canonical\n  pattern). For narrower changes, testing the function directly is fine. Use\n  judgment.\n- Test files mirror the source tree: `src/mcp/client/stdio.py` →\n  `tests/client/test_stdio.py`. Add tests to the existing file for that module.\n- Avoid `anyio.sleep()` with a fixed duration to wait for async operations. Instead:\n  - Use `anyio.Event` — set it in the callback/handler, `await event.wait()` in the test\n  - For stream messages, use `await stream.receive()` instead of `sleep()` + `receive_nowait()`\n  - Exception: `sleep()` is appropriate when testing time-based features (e.g., timeouts)\n- Wrap indefinite waits (`event.wait()`, `stream.receive()`) in `anyio.fail_after(5)` to prevent hangs\n- Pytest is configured with `filterwarnings = [\"error\"]`, so warnings fail\n  tests. Don't silence warnings from your own code; fix the underlying cause.\n  Scoped `ignore::` entries for upstream libraries are acceptable in\n  `pyproject.toml` with a comment explaining why.\n- New features from the 2026-07-28 spec must have a matching test in the\n  [conformance suite](https://github.com/modelcontextprotocol/conformance)\n  that passes against this SDK (CI runs it via\n  `.github/workflows/conformance.yml`). If no matching test exists, stop and\n  tell the user so they can raise an issue on the conformance repo.\n\n### Coverage\n\nCI requires 100% (`fail_under = 100`, `branch = true`).\n\n- Full check: `./scripts/test` (~23s). Runs coverage + `strict-no-cover` on the\n  default Python. Not identical to CI: CI runs 3.11–3.15 × {ubuntu, windows}\n  × {locked, lowest-direct}, and some branch-coverage quirks only surface on\n  specific matrix entries.\n- Targeted check while iterating (~4s, deterministic):\n\n  ```bash\n  uv run --frozen coverage erase\n  uv run --frozen coverage run -m pytest tests/path/test_foo.py\n  uv run --frozen coverage combine\n  uv run --frozen coverage report --include='src/mcp/path/foo.py' --fail-under=0\n  # UV_FROZEN=1 propagates --frozen to the uv subprocess strict-no-cover spawns\n  UV_FROZEN=1 uv run --frozen strict-no-cover\n  ```\n\n  Partial runs can't hit 100% (coverage tracks `tests/` too), so `--fail-under=0`\n  and `--include` scope the report. `strict-no-cover` has no false positives on\n  partial runs — if your new test executes a line marked `# pragma: no cover`,\n  even a single-file run catches it.\n\nAvoid adding new `# pragma: no cover`, `# type: ignore`, or `# noqa` comments.\nIn tests, use `assert isinstance(x, T)` to narrow types instead of\n`# type: ignore`. In library code (`src/`), a `# pragma: no cover` needs very\ngood reasoning — it usually means a test is missing. Audit before pushing:\n\n```bash\ngit diff origin/main... | grep -E '^\\+.*(pragma|type: ignore|noqa)'\n```\n\nWhat the existing pragmas mean:\n\n- `# pragma: no cover` — line is never executed. CI's `strict-no-cover` (skipped\n  on Windows runners) fails if it IS executed. When your test starts covering\n  such a line, remove the pragma.\n- `# pragma: lax no cover` — excluded from coverage but not checked by\n  `strict-no-cover`. Use for lines covered on some platforms/versions but not\n  others.\n- `# pragma: no branch` — excludes branch arcs only. coverage.py misreports the\n  `->exit` arc for nested `async with` on Python 3.11+ (worse on 3.14/Windows).\n\n## Documentation\n\nWhen a change affects public API or user-visible behaviour, update the relevant\npage(s) under `docs/` in the same PR. Docs are organised by the `nav:` sections\nin `mkdocs.yml` (Get started, Servers, Inside your handler, Running your server,\nClients, Advanced), not by the on-disk directory names. Find the page covering\nthe feature you touched in `mkdocs.yml` rather than adding a new one.\n\n## Formatting & Type Checking\n\n- Format: `uv run --frozen ruff format .`\n- Lint: `uv run --frozen ruff check . --fix`\n- Type check: `uv run --frozen pyright`\n- Pre-commit runs all of the above plus markdownlint, a `uv.lock` consistency\n  check, and README checks — see `.pre-commit-config.yaml`\n\n## Exception Handling\n\n- **Always use `logger.exception()` instead of `logger.error()` when catching exceptions**\n  - Don't include the exception in the message: `logger.exception(\"Failed\")` not `logger.exception(f\"Failed: {e}\")`\n- **Catch specific exceptions** where possible:\n  - File ops: `except (OSError, PermissionError):`\n  - JSON: `except json.JSONDecodeError:`\n  - Network: `except (ConnectionError, TimeoutError):`\n- **FORBIDDEN** `except Exception:` - unless in top-level handlers\n","examples/stories/tools/README.md":"# tools\n\n**Start here.** Register tools with `@mcp.tool()`; the SDK infers the JSON\ninput schema from type hints, the output schema from the return annotation, and\nreturns `structuredContent` alongside text. `ToolAnnotations` carries\nbehavioural hints (`readOnlyHint`, `idempotentHint`) the host can show to\nusers. The client lists tools, inspects schemas + annotations, calls both, and\nasserts structured output.\n\n## Run it\n\n```bash\n# stdio (default — the client spawns the server as a subprocess)\nuv run python -m stories.tools.client\n\n# HTTP — the client self-hosts the server on a free port, runs, then tears it down\nuv run python -m stories.tools.client --http\n# same, against the lowlevel-API server variant\nuv run python -m stories.tools.client --http --server server_lowlevel\n```\n\n## What to look at\n\n- `server.py` `calc` — `Literal[...]` and `BaseModel` in the signature become\n  the tool's `inputSchema` / `outputSchema` with zero hand-written JSON.\n- `server.py` `echo` — `structured_output=False` opts out of schema inference\n  for a plain text-only tool.\n- `server_lowlevel.py` — the same wire contract built by hand: this is what\n  `MCPServer` generates for you.\n\n## Spec\n\n[Tools — server features](https://modelcontextprotocol.io/specification/2025-11-25/server/tools)\n\n## See also\n\n`schema_validators/` (every input-schema source: pydantic / TypedDict /\ndataclass / dict), `error_handling/` (`is_error` vs protocol error),\n`streaming/` (progress mid-call).\n","examples/stories/extensions/README.md":"# extensions\n\nWriting your own extension (SEP-2133): one identifier bundles a settings entry\nunder `ServerCapabilities.extensions`, a contributed tool, and a vendor request\nmethod gated on the client declaring the extension back.\n\n## Run it\n\n```bash\n# stdio (default — the client spawns the server as a subprocess)\nuv run python -m stories.extensions.client\n\n# HTTP — the client self-hosts the server on a free port, runs, then tears it down\nuv run python -m stories.extensions.client --http\n```\n\n## What to look at\n\n- `server.py` `class Catalog(Extension)` — the whole extension: `settings()`\n  becomes the advertised capability entry, `tools()` contributes a regular tool,\n  `methods()` registers a vendor verb. The extension never holds the server; it\n  declares contributions and `MCPServer(extensions=[...])` consumes them.\n- `server.py` `require_client_extension(ctx, EXTENSION_ID)` — the vendor method\n  rejects clients that did not declare the extension with `-32021` (missing\n  required client capability) and a machine-readable `requiredCapabilities`\n  payload.\n- `client.py` `Client(target, extensions=[advertise(EXTENSION_ID)])` — the client-side\n  half of the negotiation; on 2026-07-28 it travels in the per-request `_meta`\n  envelope.\n- `client.py` `client.session.send_request(...)` — vendor methods have no\n  `Client`-level helper; the session escape hatch sends them.\n\n## Spec\n\n[SEP-2133 — extensions capability](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2133)\n· [Capabilities — `_meta` key grammar](https://modelcontextprotocol.io/specification/draft/basic/index)\n\n## See also\n\n`apps/` (the built-in MCP Apps extension) · `custom_methods/` (the same verb\nregistered on the lowlevel `Server` by hand, without an extension).\n",".claude/commands/review-pr.md":"Review the pull request: $ARGUMENTS\n\nFollow these steps carefully. Use the `gh` CLI for all GitHub interactions.\n\n## Step 1: Resolve the PR\n\nParse `$ARGUMENTS` to determine the PR. It can be:\n\n- A full URL like `https://github.com/owner/repo/pull/123`\n- A `owner/repo#123` reference\n- A bare number like `123` (use the current repo)\n- A description — search for it with `gh pr list --search \"<description>\" --limit 5` and pick the best match\n\nOnce resolved, fetch the PR metadata:\n\n```bash\ngh pr view <PR> --json number,title,body,author,state,baseRefName,headRefName,url,labels,milestone,additions,deletions,changedFiles,createdAt,updatedAt,mergedAt,reviewDecision,reviews,assignees\n```\n\n## Step 2: Gather the diff\n\nGet the full diff of the PR:\n\n```bash\ngh pr diff <PR>\n```\n\nIf the diff is very large (>3000 lines), focus on the most important files first and summarize the rest.\n\n## Step 3: Collect PR discussion context\n\nFetch all comments and review threads:\n\n```bash\ngh api repos/{owner}/{repo}/pulls/{number}/comments --paginate\ngh api repos/{owner}/{repo}/issues/{number}/comments --paginate\ngh api repos/{owner}/{repo}/pulls/{number}/reviews --paginate\n```\n\nPay attention to:\n\n- Reviewer feedback and requested changes\n- Author responses and explanations\n- Any unresolved conversations\n- Approval or rejection status\n\n## Step 4: Find and read linked issues\n\nLook for issue references in:\n\n- The PR body (patterns like `#123`, `fixes #123`, `closes #123`, `resolves #123`)\n- The PR branch name (patterns like `issue-123`, `fix/123`)\n- Commit messages\n\nFor each linked issue, fetch its content:\n\n```bash\ngh issue view <number> --json title,body,comments,labels,state\n```\n\nRead through issue comments to understand the original problem, user reports, and any discussed solutions.\n\n## Step 5: Analyze and validate\n\nWith all context gathered, analyze the PR critically:\n\n1. **Intent alignment**: Does the code change actually solve the problem described in the PR and/or linked issues?\n2. **Completeness**: Are there aspects of the issue or requested feature that the PR doesn't address?\n3. **Scope**: Does the PR include changes unrelated to the stated goal? Are there unnecessary modifications?\n4. **Correctness**: Based on the diff, are there obvious bugs, edge cases, or logic errors?\n5. **Testing**: Does the PR include tests? Are they meaningful and do they cover the important cases?\n6. **Breaking changes**: Could this PR break existing functionality or APIs?\n7. **Unresolved feedback**: Are there reviewer comments that haven't been addressed?\n\n## Step 6: Produce the review summary\n\nPresent the summary in this format:\n\n---\n\n### PR Review: `<title>` (<url>)\n\n**Author:** <author> | **Status:** <state> | **Review decision:** <decision>\n**Base:** `<base>` ← `<head>` | **Changed files:** <n> | **+<additions> / -<deletions>**\n\n#### Problem\n\n<1-3 sentences describing what problem this PR is trying to solve, based on the PR description and linked issues>\n\n#### Solution\n\n<1-3 sentences describing the approach taken in the code>\n\n#### Key changes\n\n<Bulleted list of the most important changes, grouped by theme. Include file paths.>\n\n#### Linked issues\n\n<List of linked issues with their title, state, and a one-line summary of the discussion>\n\n#### Discussion highlights\n\n<Summary of important comments from reviewers and the author. Flag any unresolved threads.>\n\n#### Concerns\n\n<List any issues found during validation: bugs, missing tests, scope creep, unaddressed feedback, etc. If none, say \"No concerns found.\">\n\n#### Verdict\n\n<One of: APPROVE / REQUEST CHANGES / NEEDS DISCUSSION, with a brief justification>\n\n#### Suggested action\n\n<Clear recommendation for the reviewer: what to approve, what to push back on, what to ask about>\n\n---\n","examples/stories/skills/README.md":"# skills\n\nSEP-2640 skills: a server exposes a `skill://index.json` directory resource and\n`@skill` / `@skillDir` registrations that a host can read to bootstrap\nagent-level instructions. The story will list skills and read one.\n\n**Status: not yet implemented** ([#2896](https://github.com/modelcontextprotocol/python-sdk/issues/2896)).\nThe `extensions` capability map is not yet surfaced on `MCPServer`, so a server\ncannot advertise the skills extension.\n\n## Spec\n\n[SEP-2640 — skills](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2640)\n· [SEP-2133 — extensions capability](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2133)\n",".claude/skills/test-quality/SKILL.md":"---\nname: test-quality\ndescription: Test quality bar for this repo. Read when writing, reviewing, or designing tests — covers naming, abstraction level, assertions, determinism, and the process for agent-driven test work.\n---\n\n# Test & code quality guide\n\nWhat \"best practice for new work\" means in this repo. Each rule carries its recorded reasoning\nwhere one exists; a rule with no stated why is a convention — follow it anyway.\n\n## Naming & shape\n\n- **Test names are behaviour sentences** stating the observable outcome, not the feature being\n  poked: `test_elicit_form_decline_returns_no_content`, never `test_elicit_form_decline`.\n- Plain top-level `test_*` functions; no `Test` classes (legacy files have them — don't copy).\n- **Docstrings: 1–2 sentences of behaviour, honest about provenance** — spec-mandated,\n  SDK-defined, or pinning a known gap? Say which: provenance is the triage key when the test\n  later fails. A pinned-gap assertion breaking usually means a change *fixed* the gap; a\n  spec-mandated assertion breaking means a regression.\n- Define things in dependency order; nothing forward-references. For client↔server tests:\n  handlers → server construction → client setup → act → assert — the test reads in the order\n  the conversation happens.\n- Inline the server (or equivalent setup) in the test, so the whole observable behaviour fits\n  on one screen. Lift to a file-level fixture only when several tests in *that file* genuinely\n  share it; never share across files.\n- A big multi-step test is fine when the property is irreducibly multi-step (e.g. resumability).\n  Split when a failure wouldn't tell you which claim broke — not for shortness. Compensate with\n  a numbered \"Steps:\" docstring so a reader sees the choreography before the body.\n\n## Level of abstraction\n\n- **Drive through the highest-level public API that can observe the property.** Hand-built wire\n  requests are brittle and don't prove the user-facing contract; tests that stay above the\n  internals keep working when the internals change. Drop to raw HTTP only when the assertion is\n  about something the high-level API *cannot* observe (status codes, headers, wire framing).\n- **Scripting a peer over raw streams is a last resort**, reserved for behaviour the typed API\n  cannot *produce* (malformed input, an impossible peer response). First ask what it would take\n  for the public API to express it — often a small helper suffices. Every such test's docstring\n  states why the public API couldn't do it.\n- **In-memory / in-process first.** HTTP-, SSE-, and auth-shaped behaviour can all be driven\n  through an in-process ASGI transport; threads only when necessary, subprocesses only when the\n  process boundary is itself the thing under test. In-process isn't just faster — it surfaces\n  bugs (a real stream leak was found this way) that subprocess indirection masks.\n- **Tests read like real user code**: no aliasing shims in conftest, no walls of suppressions,\n  no private imports unless that is genuinely the documented way to do the thing.\n- The assertion must prove the round trip — no side-channel state. What the server saw comes\n  back through the protocol, or via a closure-captured list asserted after the call. Handlers\n  assert their dispatch identity first (`assert params.name == \"add\"`), proving the request\n  that arrived is the request the test sent.\n\n## Assertions\n\n- **Transformations** (input → output the SDK produced) → full-object `snapshot(...)` equality,\n  so an added or dropped field fails. Regenerate with `--inline-snapshot=fix` so intentional\n  changes arrive as a reviewable diff; never hand-edit snapshot literals.\n- **Pass-through values** (opaque tokens, `_meta`, cursors) → identity against the same\n  variable you sent. A snapshot of a pass-through value only \"matches\" because a human checked\n  two literals correspond — it proves nothing.\n- **Errors** → `pytest.raises` + `.code` against the named constant; snapshot SDK-authored\n  messages; never `match=` on message text. Third-party text (pydantic, jsonschema) → stable\n  prefix only — never pin text that changes with a dependency upgrade — with a comment saying so.\n\n## Determinism\n\n- **No sleeps, ever.** A sleep guesses at timing instead of waiting on the condition, so it\n  either flakes or pads the run — sleeps head the list of the older test code's failure modes.\n  Coordinate with `anyio.Event` so the wait ends exactly when the condition holds (that\n  discipline is why 529 e2e tests run in ~10 s). Sole exception: tests *of* time-based\n  features, with a comment.\n- Bound every indefinite wait with `anyio.fail_after(5)`. **5 is the standard** — widening it\n  needs an articulable reason; \"10 to be safe\" is covering up a flake, not fixing one, and\n  unexplained widenings propagate (one agent used 10 and every later one copied it).\n- **Never assert wall-clock time, even with huge margins.** `elapsed < 0.9` on a ~0.01 s\n  operation — a 90× margin — was still rejected in review. `fail_after` bounding a hang is the\n  only timing primitive allowed.\n- **Concurrency tests must prove genuine interleaving.** Without barriers the scheduler is free\n  to serialize — \"a\" can start, finish, and return before \"b\" even begins — so two `start_soon`\n  calls prove nothing. Gate with events so all parties are mid-flight before any proceeds, emit\n  interleaved, then assert the demux.\n- **Don't over-synchronize either.** When delivery ordering is guaranteed (notifications\n  emitted during a request you're awaiting, over a single ordered in-memory stream), a plain\n  collected list asserted after the call is correct; events are for messages not tied to an\n  awaited operation. Verify the ordering guarantee actually holds for your transport first.\n- Async tests use anyio, not asyncio.\n\n## Behaviour philosophy\n\n- **Pin current behaviour; never xfail.** A green suite asserting what actually happens is a\n  regression bar for any refactor; an xfail proves nothing about it. Where current behaviour\n  falls short of spec, pin the divergent output and record the gap as data — a tracking issue,\n  with the docstring naming the known gap (suites with a requirements manifest record it as a\n  divergence entry). Not hidden, not skipped.\n- **Hollow-proof check**: before claiming a test covers a behaviour, re-read the claim and ask\n  \"which assertion proves *this*?\" A passing test near a behaviour is not proof of it — a full\n  review of the e2e suite found two such cases even under this discipline.\n\n## Hygiene\n\n- No new `# pragma`, `# type: ignore`, `# noqa` by default — restructure first; a suppression\n  usually means a test or a type is missing. The narrow sanctioned escape hatches (and the\n  audit to run before pushing) are in AGENTS.md. In tests, narrow types with `assert\n  isinstance`; never `Any`/`object` when a real type exists.\n- **Warnings raised during tests are findings, not noise** (the repo runs\n  `filterwarnings = error`). Fix the cause; if the fix can't land in the same change, scope the\n  suppression to the one fixture that needs it and track the real fix explicitly.\n- Registered-but-never-invoked handler bodies are `raise NotImplementedError`, so they cannot\n  silently become load-bearing.\n- Comments live next to the line they explain, not in docstrings; single backticks for code\n  refs; match the surrounding comment density (one-liners next to one-liners). No\n  `from __future__ import annotations` (py311+ repo).\n- Test work doesn't change `src/` as a side effect — the one mechanical exception is deleting a\n  pragma a new test now covers. If a test can't be written without a library change, raise it\n  as a finding or defer the test; don't quietly edit `src/`.\n\n## Process (for agent-driven work)\n\n- **Small chunks.** ≤10 tests per human-reviewed batch; when fanning out to multiple agents,\n  ≤5 per agent. Review quality scales inversely with batch size: the observed shortcuts\n  (over-stacked tests, a timing assertion, wrong abstraction level) all surfaced in one\n  oversized 27-test batch.\n- **Design → review → implement, as separate steps.** The design deliverable is not just the\n  plan — it's the judgement calls (abstraction level, deferrals, contested assertions) stated\n  explicitly, so the reviewer vetoes them before implementation rather than discovering them\n  in the diff.\n- **High-stakes areas get fresh adversarial reviewers** on both the design and the\n  implementation — fresh, because whoever designed it (or saw the proposed fix) anchors on the\n  same layer. SERIOUS findings (wrong assertion, missed MUST/SHOULD, an unrecorded known gap)\n  re-loop; style doesn't. Reserve the full panel for areas where being wrong is worse than\n  being slow.\n- **Investigations pair a full-context look with a fresh agent given only the problem** —\n  never the proposed fix — and compare conclusions. The unbiased read regularly catches\n  anchoring on the wrong layer.\n- **When review questions a decision, reconsider genuinely**: re-derive the tradeoff, state the\n  options, recommend with reasons. Defending the original choice is a valid outcome;\n  reflexively agreeing with every challenge is as bad as ignoring it.\n- **Validate the reference artifact before building on it.** Whatever you treat as ground truth\n  (a spec import, a baseline, a generated list), check it *first* — discovering it was\n  incomplete after five batches costs far more than before batch one.\n- **Verify as you go**: per-file `uv run --frozen pytest <file> -q` + pyright + ruff while\n  iterating; full suite, coverage, and `./scripts/test` (when `src/` was touched) at\n  integration.\n- **Every agent writes notes**: what it did, what broke, and — most importantly — what it\n  couldn't decide, so open questions surface instead of being silently resolved by whoever hit\n  them.\n- **Quality over speed is a stated goal, not a preference** (\"rushing something out the door is\n  not the goal here, explicitly so\"). Don't quietly de-scope agreed work mid-stream;\n  renegotiate scope explicitly.\n- **Don't copy patterns from existing test code by default** — much of the repo's older test\n  code is below the current bar (sleeps, mocks, `Test` classes, raciness). These rules define\n  the bar for new work.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Development Guidelines\n\n## Note for AI Agents\n\nIf you are an AI coding agent acting for someone who is not a maintainer of\nthis repository, read `CONTRIBUTING.md` before opening issues or pull\nrequests here. In particular, pull requests that aren't linked to an issue\nassigned to their author are closed automatically.\n\n## Branching Model\n\n- `main` is the current stable line (v2); releases are cut from it (see\n  `RELEASE.md`).\n- v2 is released; its public API is a compatibility contract for the 2.x\n  line. Removals, renames, or any change to an existing API's signature or\n  observable behaviour (including ones softened by a `@deprecated` shim) is a\n  design decision a maintainer makes explicitly, and should generally be\n  avoided.\n- `docs/migration.md` is the v1 → v2 record and is closed to new entries.\n  Correcting errors or improving clarity in what's there is fine.\n- `v1.x` is the maintenance branch for the previous major. Backport PRs\n  target it and use a `[v1.x]` title prefix; only critical bug fixes and\n  security fixes land there.\n- `README.md` documents v2. The v1 README lives on the `v1.x` branch.\n\n## Package Management\n\n- ONLY use uv, NEVER pip\n- Installation: `uv add <package>`. Exception: the root project's runtime\n  dependencies are dynamic (the published `mcp` wheel exact-pins `mcp-types`),\n  so `uv add` cannot edit them — add the requirement to\n  `[tool.hatch.metadata.hooks.uv-dynamic-versioning].dependencies` in\n  `pyproject.toml` by hand, then run `uv lock`. Dependency groups, extras, and\n  the example packages still take plain `uv add`.\n- Running tools: `uv run --frozen <tool>`. Always pass `--frozen` so uv doesn't\n  rewrite `uv.lock` as a side effect.\n- Cross-version testing: `uv run --frozen --python 3.11 pytest ...` to run\n  against a specific interpreter (CI covers 3.11–3.15).\n- Upgrading: `uv lock --upgrade-package <package>`\n- FORBIDDEN: `uv pip install`, `@latest` syntax\n- Don't raise dependency floors for CVEs alone. The `>=` constraint already\n  lets users upgrade. Only raise a floor when the SDK needs functionality from\n  the newer version, and don't add SDK code to work around a dependency's\n  vulnerability. See Kludex/uvicorn#2643 and python-sdk #1552 for reasoning.\n\n## Code Quality\n\n- Keep comments brief. Explain only non-obvious reasons or constraints; do not\n  narrate the code or restate names, types, or assertions.\n- Type hints required for all code\n- Public APIs must have docstrings. When a public API raises exceptions a\n  caller would reasonably catch, document them in a `Raises:` section. Don't\n  list exceptions from argument validation or programmer error.\n- `src/mcp/__init__.py` defines the public API surface via `__all__`. Adding a\n  symbol there is a deliberate API decision, not a convenience re-export.\n- IMPORTANT: All imports go at the top of the file — inline imports hide\n  dependencies and obscure circular-import bugs. Only exception: when a\n  top-level import genuinely can't work (lazy-loading optional deps, or\n  tests that re-import a module).\n- Always pass `encoding=` to text-mode `open()`, `Path.read_text()`/`write_text()`,\n  `tempfile` and `subprocess` text pipes — normally `\"utf-8\"`, or `\"locale\"` when the\n  platform encoding is genuinely intended; the default is the process locale, not UTF-8.\n  CI and `scripts/test` run pytest with `PYTHONWARNDEFAULTENCODING=1` (PEP 597), which\n  makes any omission an error under the `error` filter.\n\n## Testing\n\n- When writing or reviewing tests, conform to `.claude/skills/test-quality/SKILL.md`\n  — it defines the bar for naming, abstraction level, assertions, and determinism.\n- Framework: `uv run --frozen pytest`\n- Async testing: use anyio, not asyncio\n- Do not use `Test` prefixed classes — write plain top-level `test_*` functions.\n  Legacy files still contain `Test*` classes; do NOT follow that pattern for new\n  tests even when adding to such a file.\n- IMPORTANT: Tests should be fast and deterministic. Prefer in-memory async execution;\n  reach for threads only when necessary, and subprocesses only as a last resort.\n- For end-to-end behavior, an in-memory `Client(server)` is usually the\n  cleanest approach (see `tests/client/test_client.py` for the canonical\n  pattern). For narrower changes, testing the function directly is fine. Use\n  judgment.\n- Test files mirror the source tree: `src/mcp/client/stdio.py` →\n  `tests/client/test_stdio.py`. Add tests to the existing file for that module.\n- Avoid `anyio.sleep()` with a fixed duration to wait for async operations. Instead:\n  - Use `anyio.Event` — set it in the callback/handler, `await event.wait()` in the test\n  - For stream messages, use `await stream.receive()` instead of `sleep()` + `receive_nowait()`\n  - Exception: `sleep()` is appropriate when testing time-based features (e.g., timeouts)\n- Wrap indefinite waits (`event.wait()`, `stream.receive()`) in `anyio.fail_after(5)` to prevent hangs\n- Pytest is configured with `filterwarnings = [\"error\"]`, so warnings fail\n  tests. Don't silence warnings from your own code; fix the underlying cause.\n  Scoped `ignore::` entries for upstream libraries are acceptable in\n  `pyproject.toml` with a comment explaining why.\n- New features from the 2026-07-28 spec must have a matching test in the\n  [conformance suite](https://github.com/modelcontextprotocol/conformance)\n  that passes against this SDK (CI runs it via\n  `.github/workflows/conformance.yml`). If no matching test exists, stop and\n  tell the user so they can raise an issue on the conformance repo.\n\n### Coverage\n\nCI requires 100% (`fail_under = 100`, `branch = true`).\n\n- Full check: `./scripts/test` (~23s). Runs coverage + `strict-no-cover` on the\n  default Python. Not identical to CI: CI runs 3.11–3.15 × {ubuntu, windows}\n  × {locked, lowest-direct}, and some branch-coverage quirks only surface on\n  specific matrix entries.\n- Targeted check while iterating (~4s, deterministic):\n\n  ```bash\n  uv run --frozen coverage erase\n  uv run --frozen coverage run -m pytest tests/path/test_foo.py\n  uv run --frozen coverage combine\n  uv run --frozen coverage report --include='src/mcp/path/foo.py' --fail-under=0\n  # UV_FROZEN=1 propagates --frozen to the uv subprocess strict-no-cover spawns\n  UV_FROZEN=1 uv run --frozen strict-no-cover\n  ```\n\n  Partial runs can't hit 100% (coverage tracks `tests/` too), so `--fail-under=0`\n  and `--include` scope the report. `strict-no-cover` has no false positives on\n  partial runs — if your new test executes a line marked `# pragma: no cover`,\n  even a single-file run catches it.\n\nAvoid adding new `# pragma: no cover`, `# type: ignore`, or `# noqa` comments.\nIn tests, use `assert isinstance(x, T)` to narrow types instead of\n`# type: ignore`. In library code (`src/`), a `# pragma: no cover` needs very\ngood reasoning — it usually means a test is missing. Audit before pushing:\n\n```bash\ngit diff origin/main... | grep -E '^\\+.*(pragma|type: ignore|noqa)'\n```\n\nWhat the existing pragmas mean:\n\n- `# pragma: no cover` — line is never executed. CI's `strict-no-cover` (skipped\n  on Windows runners) fails if it IS executed. When your test starts covering\n  such a line, remove the pragma.\n- `# pragma: lax no cover` — excluded from coverage but not checked by\n  `strict-no-cover`. Use for lines covered on some platforms/versions but not\n  others.\n- `# pragma: no branch` — excludes branch arcs only. coverage.py misreports the\n  `->exit` arc for nested `async with` on Python 3.11+ (worse on 3.14/Windows).\n\n## Documentation\n\nWhen a change affects public API or user-visible behaviour, update the relevant\npage(s) under `docs/` in the same PR. Docs are organised by the `nav:` sections\nin `mkdocs.yml` (Get started, Servers, Inside your handler, Running your server,\nClients, Advanced), not by the on-disk directory names. Find the page covering\nthe feature you touched in `mkdocs.yml` rather than adding a new one.\n\n## Formatting & Type Checking\n\n- Format: `uv run --frozen ruff format .`\n- Lint: `uv run --frozen ruff check . --fix`\n- Type check: `uv run --frozen pyright`\n- Pre-commit runs all of the above plus markdownlint, a `uv.lock` consistency\n  check, and README checks — see `.pre-commit-config.yaml`\n\n## Exception Handling\n\n- **Always use `logger.exception()` instead of `logger.error()` when catching exceptions**\n  - Don't include the exception in the message: `logger.exception(\"Failed\")` not `logger.exception(f\"Failed: {e}\")`\n- **Catch specific exceptions** where possible:\n  - File ops: `except (OSError, PermissionError):`\n  - JSON: `except json.JSONDecodeError:`\n  - Network: `except (ConnectionError, TimeoutError):`\n- **FORBIDDEN** `except Exception:` - unless in top-level handlers\n","isInternal":false,"tokens":2210,"sizeBytes":8714},{"name":"SKILL.md","path":".claude/skills/test-quality/SKILL.md","rawUrl":"https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/HEAD/.claude/skills/test-quality/SKILL.md","title":"test-quality","category":"anthropic-skill","format":"markdown","content":"---\nname: test-quality\ndescription: Test quality bar for this repo. Read when writing, reviewing, or designing tests — covers naming, abstraction level, assertions, determinism, and the process for agent-driven test work.\n---\n\n# Test & code quality guide\n\nWhat \"best practice for new work\" means in this repo. Each rule carries its recorded reasoning\nwhere one exists; a rule with no stated why is a convention — follow it anyway.\n\n## Naming & shape\n\n- **Test names are behaviour sentences** stating the observable outcome, not the feature being\n  poked: `test_elicit_form_decline_returns_no_content`, never `test_elicit_form_decline`.\n- Plain top-level `test_*` functions; no `Test` classes (legacy files have them — don't copy).\n- **Docstrings: 1–2 sentences of behaviour, honest about provenance** — spec-mandated,\n  SDK-defined, or pinning a known gap? Say which: provenance is the triage key when the test\n  later fails. A pinned-gap assertion breaking usually means a change *fixed* the gap; a\n  spec-mandated assertion breaking means a regression.\n- Define things in dependency order; nothing forward-references. For client↔server tests:\n  handlers → server construction → client setup → act → assert — the test reads in the order\n  the conversation happens.\n- Inline the server (or equivalent setup) in the test, so the whole observable behaviour fits\n  on one screen. Lift to a file-level fixture only when several tests in *that file* genuinely\n  share it; never share across files.\n- A big multi-step test is fine when the property is irreducibly multi-step (e.g. resumability).\n  Split when a failure wouldn't tell you which claim broke — not for shortness. Compensate with\n  a numbered \"Steps:\" docstring so a reader sees the choreography before the body.\n\n## Level of abstraction\n\n- **Drive through the highest-level public API that can observe the property.** Hand-built wire\n  requests are brittle and don't prove the user-facing contract; tests that stay above the\n  internals keep working when the internals change. Drop to raw HTTP only when the assertion is\n  about something the high-level API *cannot* observe (status codes, headers, wire framing).\n- **Scripting a peer over raw streams is a last resort**, reserved for behaviour the typed API\n  cannot *produce* (malformed input, an impossible peer response). First ask what it would take\n  for the public API to express it — often a small helper suffices. Every such test's docstring\n  states why the public API couldn't do it.\n- **In-memory / in-process first.** HTTP-, SSE-, and auth-shaped behaviour can all be driven\n  through an in-process ASGI transport; threads only when necessary, subprocesses only when the\n  process boundary is itself the thing under test. In-process isn't just faster — it surfaces\n  bugs (a real stream leak was found this way) that subprocess indirection masks.\n- **Tests read like real user code**: no aliasing shims in conftest, no walls of suppressions,\n  no private imports unless that is genuinely the documented way to do the thing.\n- The assertion must prove the round trip — no side-channel state. What the server saw comes\n  back through the protocol, or via a closure-captured list asserted after the call. Handlers\n  assert their dispatch identity first (`assert params.name == \"add\"`), proving the request\n  that arrived is the request the test sent.\n\n## Assertions\n\n- **Transformations** (input → output the SDK produced) → full-object `snapshot(...)` equality,\n  so an added or dropped field fails. Regenerate with `--inline-snapshot=fix` so intentional\n  changes arrive as a reviewable diff; never hand-edit snapshot literals.\n- **Pass-through values** (opaque tokens, `_meta`, cursors) → identity against the same\n  variable you sent. A snapshot of a pass-through value only \"matches\" because a human checked\n  two literals correspond — it proves nothing.\n- **Errors** → `pytest.raises` + `.code` against the named constant; snapshot SDK-authored\n  messages; never `match=` on message text. Third-party text (pydantic, jsonschema) → stable\n  prefix only — never pin text that changes with a dependency upgrade — with a comment saying so.\n\n## Determinism\n\n- **No sleeps, ever.** A sleep guesses at timing instead of waiting on the condition, so it\n  either flakes or pads the run — sleeps head the list of the older test code's failure modes.\n  Coordinate with `anyio.Event` so the wait ends exactly when the condition holds (that\n  discipline is why 529 e2e tests run in ~10 s). Sole exception: tests *of* time-based\n  features, with a comment.\n- Bound every indefinite wait with `anyio.fail_after(5)`. **5 is the standard** — widening it\n  needs an articulable reason; \"10 to be safe\" is covering up a flake, not fixing one, and\n  unexplained widenings propagate (one agent used 10 and every later one copied it).\n- **Never assert wall-clock time, even with huge margins.** `elapsed < 0.9` on a ~0.01 s\n  operation — a 90× margin — was still rejected in review. `fail_after` bounding a hang is the\n  only timing primitive allowed.\n- **Concurrency tests must prove genuine interleaving.** Without barriers the scheduler is free\n  to serialize — \"a\" can start, finish, and return before \"b\" even begins — so two `start_soon`\n  calls prove nothing. Gate with events so all parties are mid-flight before any proceeds, emit\n  interleaved, then assert the demux.\n- **Don't over-synchronize either.** When delivery ordering is guaranteed (notifications\n  emitted during a request you're awaiting, over a single ordered in-memory stream), a plain\n  collected list asserted after the call is correct; events are for messages not tied to an\n  awaited operation. Verify the ordering guarantee actually holds for your transport first.\n- Async tests use anyio, not asyncio.\n\n## Behaviour philosophy\n\n- **Pin current behaviour; never xfail.** A green suite asserting what actually happens is a\n  regression bar for any refactor; an xfail proves nothing about it. Where current behaviour\n  falls short of spec, pin the divergent output and record the gap as data — a tracking issue,\n  with the docstring naming the known gap (suites with a requirements manifest record it as a\n  divergence entry). Not hidden, not skipped.\n- **Hollow-proof check**: before claiming a test covers a behaviour, re-read the claim and ask\n  \"which assertion proves *this*?\" A passing test near a behaviour is not proof of it — a full\n  review of the e2e suite found two such cases even under this discipline.\n\n## Hygiene\n\n- No new `# pragma`, `# type: ignore`, `# noqa` by default — restructure first; a suppression\n  usually means a test or a type is missing. The narrow sanctioned escape hatches (and the\n  audit to run before pushing) are in AGENTS.md. In tests, narrow types with `assert\n  isinstance`; never `Any`/`object` when a real type exists.\n- **Warnings raised during tests are findings, not noise** (the repo runs\n  `filterwarnings = error`). Fix the cause; if the fix can't land in the same change, scope the\n  suppression to the one fixture that needs it and track the real fix explicitly.\n- Registered-but-never-invoked handler bodies are `raise NotImplementedError`, so they cannot\n  silently become load-bearing.\n- Comments live next to the line they explain, not in docstrings; single backticks for code\n  refs; match the surrounding comment density (one-liners next to one-liners). No\n  `from __future__ import annotations` (py311+ repo).\n- Test work doesn't change `src/` as a side effect — the one mechanical exception is deleting a\n  pragma a new test now covers. If a test can't be written without a library change, raise it\n  as a finding or defer the test; don't quietly edit `src/`.\n\n## Process (for agent-driven work)\n\n- **Small chunks.** ≤10 tests per human-reviewed batch; when fanning out to multiple agents,\n  ≤5 per agent. Review quality scales inversely with batch size: the observed shortcuts\n  (over-stacked tests, a timing assertion, wrong abstraction level) all surfaced in one\n  oversized 27-test batch.\n- **Design → review → implement, as separate steps.** The design deliverable is not just the\n  plan — it's the judgement calls (abstraction level, deferrals, contested assertions) stated\n  explicitly, so the reviewer vetoes them before implementation rather than discovering them\n  in the diff.\n- **High-stakes areas get fresh adversarial reviewers** on both the design and the\n  implementation — fresh, because whoever designed it (or saw the proposed fix) anchors on the\n  same layer. SERIOUS findings (wrong assertion, missed MUST/SHOULD, an unrecorded known gap)\n  re-loop; style doesn't. Reserve the full panel for areas where being wrong is worse than\n  being slow.\n- **Investigations pair a full-context look with a fresh agent given only the problem** —\n  never the proposed fix — and compare conclusions. The unbiased read regularly catches\n  anchoring on the wrong layer.\n- **When review questions a decision, reconsider genuinely**: re-derive the tradeoff, state the\n  options, recommend with reasons. Defending the original choice is a valid outcome;\n  reflexively agreeing with every challenge is as bad as ignoring it.\n- **Validate the reference artifact before building on it.** Whatever you treat as ground truth\n  (a spec import, a baseline, a generated list), check it *first* — discovering it was\n  incomplete after five batches costs far more than before batch one.\n- **Verify as you go**: per-file `uv run --frozen pytest <file> -q` + pyright + ruff while\n  iterating; full suite, coverage, and `./scripts/test` (when `src/` was touched) at\n  integration.\n- **Every agent writes notes**: what it did, what broke, and — most importantly — what it\n  couldn't decide, so open questions surface instead of being silently resolved by whoever hit\n  them.\n- **Quality over speed is a stated goal, not a preference** (\"rushing something out the door is\n  not the goal here, explicitly so\"). Don't quietly de-scope agreed work mid-stream;\n  renegotiate scope explicitly.\n- **Don't copy patterns from existing test code by default** — much of the repo's older test\n  code is below the current bar (sleeps, mocks, `Test` classes, raciness). These rules define\n  the bar for new work.\n","frontmatter":{"name":"test-quality","description":"Test quality bar for this repo. Read when writing, reviewing, or designing tests — covers naming, abstraction level, assertions, determinism, and the process for agent-driven test work."},"isInternal":false,"tokens":2366,"sizeBytes":10314},{"name":"README.md","path":"examples/stories/skills/README.md","rawUrl":"https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/HEAD/examples/stories/skills/README.md","title":"Skills Skill","category":"anthropic-skill","format":"markdown","content":"# skills\n\nSEP-2640 skills: a server exposes a `skill://index.json` directory resource and\n`@skill` / `@skillDir` registrations that a host can read to bootstrap\nagent-level instructions. The story will list skills and read one.\n\n**Status: not yet implemented** ([#2896](https://github.com/modelcontextprotocol/python-sdk/issues/2896)).\nThe `extensions` capability map is not yet surfaced on `MCPServer`, so a server\ncannot advertise the skills extension.\n\n## Spec\n\n[SEP-2640 — skills](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2640)\n· [SEP-2133 — extensions capability](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2133)\n","isInternal":false,"tokens":158,"sizeBytes":675},{"name":"README.md","path":"examples/stories/extensions/README.md","rawUrl":"https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/HEAD/examples/stories/extensions/README.md","title":"extensions Documentation","category":"plugin-manifest","format":"markdown","content":"# extensions\n\nWriting your own extension (SEP-2133): one identifier bundles a settings entry\nunder `ServerCapabilities.extensions`, a contributed tool, and a vendor request\nmethod gated on the client declaring the extension back.\n\n## Run it\n\n```bash\n# stdio (default — the client spawns the server as a subprocess)\nuv run python -m stories.extensions.client\n\n# HTTP — the client self-hosts the server on a free port, runs, then tears it down\nuv run python -m stories.extensions.client --http\n```\n\n## What to look at\n\n- `server.py` `class Catalog(Extension)` — the whole extension: `settings()`\n  becomes the advertised capability entry, `tools()` contributes a regular tool,\n  `methods()` registers a vendor verb. The extension never holds the server; it\n  declares contributions and `MCPServer(extensions=[...])` consumes them.\n- `server.py` `require_client_extension(ctx, EXTENSION_ID)` — the vendor method\n  rejects clients that did not declare the extension with `-32021` (missing\n  required client capability) and a machine-readable `requiredCapabilities`\n  payload.\n- `client.py` `Client(target, extensions=[advertise(EXTENSION_ID)])` — the client-side\n  half of the negotiation; on 2026-07-28 it travels in the per-request `_meta`\n  envelope.\n- `client.py` `client.session.send_request(...)` — vendor methods have no\n  `Client`-level helper; the session escape hatch sends them.\n\n## Spec\n\n[SEP-2133 — extensions capability](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2133)\n· [Capabilities — `_meta` key grammar](https://modelcontextprotocol.io/specification/draft/basic/index)\n\n## See also\n\n`apps/` (the built-in MCP Apps extension) · `custom_methods/` (the same verb\nregistered on the lowlevel `Server` by hand, without an extension).\n","isInternal":false,"tokens":415,"sizeBytes":1786},{"name":"README.md","path":"examples/stories/tools/README.md","rawUrl":"https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/HEAD/examples/stories/tools/README.md","title":"tools Documentation","category":"plugin-manifest","format":"markdown","content":"# tools\n\n**Start here.** Register tools with `@mcp.tool()`; the SDK infers the JSON\ninput schema from type hints, the output schema from the return annotation, and\nreturns `structuredContent` alongside text. `ToolAnnotations` carries\nbehavioural hints (`readOnlyHint`, `idempotentHint`) the host can show to\nusers. The client lists tools, inspects schemas + annotations, calls both, and\nasserts structured output.\n\n## Run it\n\n```bash\n# stdio (default — the client spawns the server as a subprocess)\nuv run python -m stories.tools.client\n\n# HTTP — the client self-hosts the server on a free port, runs, then tears it down\nuv run python -m stories.tools.client --http\n# same, against the lowlevel-API server variant\nuv run python -m stories.tools.client --http --server server_lowlevel\n```\n\n## What to look at\n\n- `server.py` `calc` — `Literal[...]` and `BaseModel` in the signature become\n  the tool's `inputSchema` / `outputSchema` with zero hand-written JSON.\n- `server.py` `echo` — `structured_output=False` opts out of schema inference\n  for a plain text-only tool.\n- `server_lowlevel.py` — the same wire contract built by hand: this is what\n  `MCPServer` generates for you.\n\n## Spec\n\n[Tools — server features](https://modelcontextprotocol.io/specification/2025-11-25/server/tools)\n\n## See also\n\n`schema_validators/` (every input-schema source: pydantic / TypedDict /\ndataclass / dict), `error_handling/` (`is_error` vs protocol error),\n`streaming/` (progress mid-call).\n","isInternal":false,"tokens":376,"sizeBytes":1485},{"name":"review-pr.md","path":".claude/commands/review-pr.md","rawUrl":"https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/HEAD/.claude/commands/review-pr.md","title":"Command: /review-pr","category":"command-prompt","format":"markdown","content":"Review the pull request: $ARGUMENTS\n\nFollow these steps carefully. Use the `gh` CLI for all GitHub interactions.\n\n## Step 1: Resolve the PR\n\nParse `$ARGUMENTS` to determine the PR. It can be:\n\n- A full URL like `https://github.com/owner/repo/pull/123`\n- A `owner/repo#123` reference\n- A bare number like `123` (use the current repo)\n- A description — search for it with `gh pr list --search \"<description>\" --limit 5` and pick the best match\n\nOnce resolved, fetch the PR metadata:\n\n```bash\ngh pr view <PR> --json number,title,body,author,state,baseRefName,headRefName,url,labels,milestone,additions,deletions,changedFiles,createdAt,updatedAt,mergedAt,reviewDecision,reviews,assignees\n```\n\n## Step 2: Gather the diff\n\nGet the full diff of the PR:\n\n```bash\ngh pr diff <PR>\n```\n\nIf the diff is very large (>3000 lines), focus on the most important files first and summarize the rest.\n\n## Step 3: Collect PR discussion context\n\nFetch all comments and review threads:\n\n```bash\ngh api repos/{owner}/{repo}/pulls/{number}/comments --paginate\ngh api repos/{owner}/{repo}/issues/{number}/comments --paginate\ngh api repos/{owner}/{repo}/pulls/{number}/reviews --paginate\n```\n\nPay attention to:\n\n- Reviewer feedback and requested changes\n- Author responses and explanations\n- Any unresolved conversations\n- Approval or rejection status\n\n## Step 4: Find and read linked issues\n\nLook for issue references in:\n\n- The PR body (patterns like `#123`, `fixes #123`, `closes #123`, `resolves #123`)\n- The PR branch name (patterns like `issue-123`, `fix/123`)\n- Commit messages\n\nFor each linked issue, fetch its content:\n\n```bash\ngh issue view <number> --json title,body,comments,labels,state\n```\n\nRead through issue comments to understand the original problem, user reports, and any discussed solutions.\n\n## Step 5: Analyze and validate\n\nWith all context gathered, analyze the PR critically:\n\n1. **Intent alignment**: Does the code change actually solve the problem described in the PR and/or linked issues?\n2. **Completeness**: Are there aspects of the issue or requested feature that the PR doesn't address?\n3. **Scope**: Does the PR include changes unrelated to the stated goal? Are there unnecessary modifications?\n4. **Correctness**: Based on the diff, are there obvious bugs, edge cases, or logic errors?\n5. **Testing**: Does the PR include tests? Are they meaningful and do they cover the important cases?\n6. **Breaking changes**: Could this PR break existing functionality or APIs?\n7. **Unresolved feedback**: Are there reviewer comments that haven't been addressed?\n\n## Step 6: Produce the review summary\n\nPresent the summary in this format:\n\n---\n\n### PR Review: `<title>` (<url>)\n\n**Author:** <author> | **Status:** <state> | **Review decision:** <decision>\n**Base:** `<base>` ← `<head>` | **Changed files:** <n> | **+<additions> / -<deletions>**\n\n#### Problem\n\n<1-3 sentences describing what problem this PR is trying to solve, based on the PR description and linked issues>\n\n#### Solution\n\n<1-3 sentences describing the approach taken in the code>\n\n#### Key changes\n\n<Bulleted list of the most important changes, grouped by theme. Include file paths.>\n\n#### Linked issues\n\n<List of linked issues with their title, state, and a one-line summary of the discussion>\n\n#### Discussion highlights\n\n<Summary of important comments from reviewers and the author. Flag any unresolved threads.>\n\n#### Concerns\n\n<List any issues found during validation: bugs, missing tests, scope creep, unaddressed feedback, etc. If none, say \"No concerns found.\">\n\n#### Verdict\n\n<One of: APPROVE / REQUEST CHANGES / NEEDS DISCUSSION, with a brief justification>\n\n#### Suggested action\n\n<Clear recommendation for the reviewer: what to approve, what to push back on, what to ask about>\n\n---\n","isInternal":false,"tokens":901,"sizeBytes":3760}],"systemPromptSnippet":"<yakaai_skills repo=\"modelcontextprotocol/python-sdk\">\n<!-- File: AGENTS.md (Tokens: ~2210 | Category: root-instruction) -->\n# Development Guidelines\n\n## Note for AI Agents\n\nIf you are an AI coding agent acting for someone who is not a maintainer of\nthis repository, read `CONTRIBUTING.md` before opening issues or pull\nrequests here. In particular, pull requests that aren't linked to an issue\nassigned to their author are closed automatically.\n\n## Branching Model\n\n- `main` is the current stable line (v2); releases are cut from it (see\n  `RELEASE.md`).\n- v2 is released; its public API is a compatibility contract for the 2.x\n  line. Removals, renames, or any change to an existing API's signature or\n  observable behaviour (including ones softened by a `@deprecated` shim) is a\n  design decision a maintainer makes explicitly, and should generally be\n  avoided.\n- `docs/migration.md` is the v1 → v2 record and is closed to new entries.\n  Correcting errors or improving clarity in what's there is fine.\n- `v1.x` is the maintenance branch for the previous major. Backport PRs\n  target it and use a `[v1.x]` title prefix; only critical bug fixes and\n  security fixes land there.\n- `README.md` documents v2. The v1 README lives on the `v1.x` branch.\n\n## Package Management\n\n- ONLY use uv, NEVER pip\n- Installation: `uv add <package>`. Exception: the root project's runtime\n  dependencies are dynamic (the published `mcp` wheel exact-pins `mcp-types`),\n  so `uv add` cannot edit them — add the requirement to\n  `[tool.hatch.metadata.hooks.uv-dynamic-versioning].dependencies` in\n  `pyproject.toml` by hand, then run `uv lock`. Dependency groups, extras, and\n  the example packages still take plain `uv add`.\n- Running tools: `uv run --frozen <tool>`. Always pass `--frozen` so uv doesn't\n  rewrite `uv.lock` as a side effect.\n- Cross-version testing: `uv run --frozen --python 3.11 pytest ...` to run\n  against a specific interpreter (CI covers 3.11–3.15).\n- Upgrading: `uv lock --upgrade-package <package>`\n- FORBIDDEN: `uv pip install`, `@latest` syntax\n- Don't raise dependency floors for CVEs alone. The `>=` constraint already\n  lets users upgrade. Only raise a floor when the SDK needs functionality from\n  the newer version, and don't add SDK code to work around a dependency's\n  vulnerability. See Kludex/uvicorn#2643 and python-sdk #1552 for reasoning.\n\n## Code Quality\n\n- Keep comments brief. Explain only non-obvious reasons or constraints; do not\n  narrate the code or restate names, types, or assertions.\n- Type hints required for all code\n- Public APIs must have docstrings. When a public API raises exceptions a\n  caller would reasonably catch, document them in a `Raises:` section. Don't\n  list exceptions from argument validation or programmer error.\n- `src/mcp/__init__.py` defines the public API surface via `__all__`. Adding a\n  symbol there is a deliberate API decision, not a convenience re-export.\n- IMPORTANT: All imports go at the top of the file — inline imports hide\n  dependencies and obscure circular-import bugs. Only exception: when a\n  top-level import genuinely can't work (lazy-loading optional deps, or\n  tests that re-import a module).\n- Always pass `encoding=` to text-mode `open()`, `Path.read_text()`/`write_text()`,\n  `tempfile` and `subprocess` text pipes — normally `\"utf-8\"`, or `\"locale\"` when the\n  platform encoding is genuinely intended; the default is the process locale, not UTF-8.\n  CI and `scripts/test` run pytest with `PYTHONWARNDEFAULTENCODING=1` (PEP 597), which\n  makes any omission an error under the `error` filter.\n\n## Testing\n\n- When writing or reviewing tests, conform to `.claude/skills/test-quality/SKILL.md`\n  — it defines the bar for naming, abstraction level, assertions, and determinism.\n- Framework: `uv run --frozen pytest`\n- Async testing: use anyio, not asyncio\n- Do not use `Test` prefixed classes — write plain top-level `test_*` functions.\n  Legacy files still contain `Test*` classes; do NOT follow that pattern for new\n  tests even when adding to such a file.\n- IMPORTANT: Tests should be fast and deterministic. Prefer in-memory async execution;\n  reach for threads only when necessary, and subprocesses only as a last resort.\n- For end-to-end behavior, an in-memory `Client(server)` is usually the\n  cleanest approach (see `tests/client/test_client.py` for the canonical\n  pattern). For narrower changes, testing the function directly is fine. Use\n  judgment.\n- Test files mirror the source tree: `src/mcp/client/stdio.py` →\n  `tests/client/test_stdio.py`. Add tests to the existing file for that module.\n- Avoid `anyio.sleep()` with a fixed duration to wait for async operations. Instead:\n  - Use `anyio.Event` — set it in the callback/handler, `await event.wait()` in the test\n  - For stream messages, use `await stream.receive()` instead of `sleep()` + `receive_nowait()`\n  - Exception: `sleep()` is appropriate when testing time-based features (e.g., timeouts)\n- Wrap indefinite waits (`event.wait()`, `stream.receive()`) in `anyio.fail_after(5)` to prevent hangs\n- Pytest is configured with `filterwarnings = [\"error\"]`, so warnings fail\n  tests. Don't silence warnings from your own code; fix the underlying cause.\n  Scoped `ignore::` entries for upstream libraries are acceptable in\n  `pyproject.toml` with a comment explaining why.\n- New features from the 2026-07-28 spec must have a matching test in the\n  [conformance suite](https://github.com/modelcontextprotocol/conformance)\n  that passes against this SDK (CI runs it via\n  `.github/workflows/conformance.yml`). If no matching test exists, stop and\n  tell the user so they can raise an issue on the conformance repo.\n\n### Coverage\n\nCI requires 100% (`fail_under = 100`, `branch = true`).\n\n- Full check: `./scripts/test` (~23s). Runs coverage + `strict-no-cover` on the\n  default Python. Not identical to CI: CI runs 3.11–3.15 × {ubuntu, windows}\n  × {locked, lowest-direct}, and some branch-coverage quirks only surface on\n  specific matrix entries.\n- Targeted check while iterating (~4s, deterministic):\n\n  ```bash\n  uv run --frozen coverage erase\n  uv run --frozen coverage run -m pytest tests/path/test_foo.py\n  uv run --frozen coverage combine\n  uv run --frozen coverage report --include='src/mcp/path/foo.py' --fail-under=0\n  # UV_FROZEN=1 propagates --frozen to the uv subprocess strict-no-cover spawns\n  UV_FROZEN=1 uv run --frozen strict-no-cover\n  ```\n\n  Partial runs can't hit 100% (coverage tracks `tests/` too), so `--fail-under=0`\n  and `--include` scope the report. `strict-no-cover` has no false positives on\n  partial runs — if your new test executes a line marked `# pragma: no cover`,\n  even a single-file run catches it.\n\nAvoid adding new `# pragma: no cover`, `# type: ignore`, or `# noqa` comments.\nIn tests, use `assert isinstance(x, T)` to narrow types instead of\n`# type: ignore`. In library code (`src/`), a `# pragma: no cover` needs very\ngood reasoning — it usually means a test is missing. Audit before pushing:\n\n```bash\ngit diff origin/main... | grep -E '^\\+.*(pragma|type: ignore|noqa)'\n```\n\nWhat the existing pragmas mean:\n\n- `# pragma: no cover` — line is never executed. CI's `strict-no-cover` (skipped\n  on Windows runners) fails if it IS executed. When your test starts covering\n  such a line, remove the pragma.\n- `# pragma: lax no cover` — excluded from coverage but not checked by\n  `strict-no-cover`. Use for lines covered on some platforms/versions but not\n  others.\n- `# pragma: no branch` — excludes branch arcs only. coverage.py misreports the\n  `->exit` arc for nested `async with` on Python 3.11+ (worse on 3.14/Windows).\n\n## Documentation\n\nWhen a change affects public API or user-visible behaviour, update the relevant\npage(s) under `docs/` in the same PR. Docs are organised by the `nav:` sections\nin `mkdocs.yml` (Get started, Servers, Inside your handler, Running your server,\nClients, Advanced), not by the on-disk directory names. Find the page covering\nthe feature you touched in `mkdocs.yml` rather than adding a new one.\n\n## Formatting & Type Checking\n\n- Format: `uv run --frozen ruff format .`\n- Lint: `uv run --frozen ruff check . --fix`\n- Type check: `uv run --frozen pyright`\n- Pre-commit runs all of the above plus markdownlint, a `uv.lock` consistency\n  check, and README checks — see `.pre-commit-config.yaml`\n\n## Exception Handling\n\n- **Always use `logger.exception()` instead of `logger.error()` when catching exceptions**\n  - Don't include the exception in the message: `logger.exception(\"Failed\")` not `logger.exception(f\"Failed: {e}\")`\n- **Catch specific exceptions** where possible:\n  - File ops: `except (OSError, PermissionError):`\n  - JSON: `except json.JSONDecodeError:`\n  - Network: `except (ConnectionError, TimeoutError):`\n- **FORBIDDEN** `except Exception:` - unless in top-level handlers\n\n<!-- File: .claude/skills/test-quality/SKILL.md (Tokens: ~2366 | Category: anthropic-skill) -->\n---\nname: test-quality\ndescription: Test quality bar for this repo. Read when writing, reviewing, or designing tests — covers naming, abstraction level, assertions, determinism, and the process for agent-driven test work.\n---\n\n# Test & code quality guide\n\nWhat \"best practice for new work\" means in this repo. Each rule carries its recorded reasoning\nwhere one exists; a rule with no stated why is a convention — follow it anyway.\n\n## Naming & shape\n\n- **Test names are behaviour sentences** stating the observable outcome, not the feature being\n  poked: `test_elicit_form_decline_returns_no_content`, never `test_elicit_form_decline`.\n- Plain top-level `test_*` functions; no `Test` classes (legacy files have them — don't copy).\n- **Docstrings: 1–2 sentences of behaviour, honest about provenance** — spec-mandated,\n  SDK-defined, or pinning a known gap? Say which: provenance is the triage key when the test\n  later fails. A pinned-gap assertion breaking usually means a change *fixed* the gap; a\n  spec-mandated assertion breaking means a regression.\n- Define things in dependency order; nothing forward-references. For client↔server tests:\n  handlers → server construction → client setup → act → assert — the test reads in the order\n  the conversation happens.\n- Inline the server (or equivalent setup) in the test, so the whole observable behaviour fits\n  on one screen. Lift to a file-level fixture only when several tests in *that file* genuinely\n  share it; never share across files.\n- A big multi-step test is fine when the property is irreducibly multi-step (e.g. resumability).\n  Split when a failure wouldn't tell you which claim broke — not for shortness. Compensate with\n  a numbered \"Steps:\" docstring so a reader sees the choreography before the body.\n\n## Level of abstraction\n\n- **Drive through the highest-level public API that can observe the property.** Hand-built wire\n  requests are brittle and don't prove the user-facing contract; tests that stay above the\n  internals keep working when the internals change. Drop to raw HTTP only when the assertion is\n  about something the high-level API *cannot* observe (status codes, headers, wire framing).\n- **Scripting a peer over raw streams is a last resort**, reserved for behaviour the typed API\n  cannot *produce* (malformed input, an impossible peer response). First ask what it would take\n  for the public API to express it — often a small helper suffices. Every such test's docstring\n  states why the public API couldn't do it.\n- **In-memory / in-process first.** HTTP-, SSE-, and auth-shaped behaviour can all be driven\n  through an in-process ASGI transport; threads only when necessary, subprocesses only when the\n  process boundary is itself the thing under test. In-process isn't just faster — it surfaces\n  bugs (a real stream leak was found this way) that subprocess indirection masks.\n- **Tests read like real user code**: no aliasing shims in conftest, no walls of suppressions,\n  no private imports unless that is genuinely the documented way to do the thing.\n- The assertion must prove the round trip — no side-channel state. What the server saw comes\n  back through the protocol, or via a closure-captured list asserted after the call. Handlers\n  assert their dispatch identity first (`assert params.name == \"add\"`), proving the request\n  that arrived is the request the test sent.\n\n## Assertions\n\n- **Transformations** (input → output the SDK produced) → full-object `snapshot(...)` equality,\n  so an added or dropped field fails. Regenerate with `--inline-snapshot=fix` so intentional\n  changes arrive as a reviewable diff; never hand-edit snapshot literals.\n- **Pass-through values** (opaque tokens, `_meta`, cursors) → identity against the same\n  variable you sent. A snapshot of a pass-through value only \"matches\" because a human checked\n  two literals correspond — it proves nothing.\n- **Errors** → `pytest.raises` + `.code` against the named constant; snapshot SDK-authored\n  messages; never `match=` on message text. Third-party text (pydantic, jsonschema) → stable\n  prefix only — never pin text that changes with a dependency upgrade — with a comment saying so.\n\n## Determinism\n\n- **No sleeps, ever.** A sleep guesses at timing instead of waiting on the condition, so it\n  either flakes or pads the run — sleeps head the list of the older test code's failure modes.\n  Coordinate with `anyio.Event` so the wait ends exactly when the condition holds (that\n  discipline is why 529 e2e tests run in ~10 s). Sole exception: tests *of* time-based\n  features, with a comment.\n- Bound every indefinite wait with `anyio.fail_after(5)`. **5 is the standard** — widening it\n  needs an articulable reason; \"10 to be safe\" is covering up a flake, not fixing one, and\n  unexplained widenings propagate (one agent used 10 and every later one copied it).\n- **Never assert wall-clock time, even with huge margins.** `elapsed < 0.9` on a ~0.01 s\n  operation — a 90× margin — was still rejected in review. `fail_after` bounding a hang is the\n  only timing primitive allowed.\n- **Concurrency tests must prove genuine interleaving.** Without barriers the scheduler is free\n  to serialize — \"a\" can start, finish, and return before \"b\" even begins — so two `start_soon`\n  calls prove nothing. Gate with events so all parties are mid-flight before any proceeds, emit\n  interleaved, then assert the demux.\n- **Don't over-synchronize either.** When delivery ordering is guaranteed (notifications\n  emitted during a request you're awaiting, over a single ordered in-memory stream), a plain\n  collected list asserted after the call is correct; events are for messages not tied to an\n  awaited operation. Verify the ordering guarantee actually holds for your transport first.\n- Async tests use anyio, not asyncio.\n\n## Behaviour philosophy\n\n- **Pin current behaviour; never xfail.** A green suite asserting what actually happens is a\n  regression bar for any refactor; an xfail proves nothing about it. Where current behaviour\n  falls short of spec, pin the divergent output and record the gap as data — a tracking issue,\n  with the docstring naming the known gap (suites with a requirements manifest record it as a\n  divergence entry). Not hidden, not skipped.\n- **Hollow-proof check**: before claiming a test covers a behaviour, re-read the claim and ask\n  \"which assertion proves *this*?\" A passing test near a behaviour is not proof of it — a full\n  review of the e2e suite found two such cases even under this discipline.\n\n## Hygiene\n\n- No new `# pragma`, `# type: ignore`, `# noqa` by default — restructure first; a suppression\n  usually means a test or a type is missing. The narrow sanctioned escape hatches (and the\n  audit to run before pushing) are in AGENTS.md. In tests, narrow types with `assert\n  isinstance`; never `Any`/`object` when a real type exists.\n- **Warnings raised during tests are findings, not noise** (the repo runs\n  `filterwarnings = error`). Fix the cause; if the fix can't land in the same change, scope the\n  suppression to the one fixture that needs it and track the real fix explicitly.\n- Registered-but-never-invoked handler bodies are `raise NotImplementedError`, so they cannot\n  silently become load-bearing.\n- Comments live next to the line they explain, not in docstrings; single backticks for code\n  refs; match the surrounding comment density (one-liners next to one-liners). No\n  `from __future__ import annotations` (py311+ repo).\n- Test work doesn't change `src/` as a side effect — the one mechanical exception is deleting a\n  pragma a new test now covers. If a test can't be written without a library change, raise it\n  as a finding or defer the test; don't quietly edit `src/`.\n\n## Process (for agent-driven work)\n\n- **Small chunks.** ≤10 tests per human-reviewed batch; when fanning out to multiple agents,\n  ≤5 per agent. Review quality scales inversely with batch size: the observed shortcuts\n  (over-stacked tests, a timing assertion, wrong abstraction level) all surfaced in one\n  oversized 27-test batch.\n- **Design → review → implement, as separate steps.** The design deliverable is not just the\n  plan — it's the judgement calls (abstraction level, deferrals, contested assertions) stated\n  explicitly, so the reviewer vetoes them before implementation rather than discovering them\n  in the diff.\n- **High-stakes areas get fresh adversarial reviewers** on both the design and the\n  implementation — fresh, because whoever designed it (or saw the proposed fix) anchors on the\n  same layer. SERIOUS findings (wrong assertion, missed MUST/SHOULD, an unrecorded known gap)\n  re-loop; style doesn't. Reserve the full panel for areas where being wrong is worse than\n  being slow.\n- **Investigations pair a full-context look with a fresh agent given only the problem** —\n  never the proposed fix — and compare conclusions. The unbiased read regularly catches\n  anchoring on the wrong layer.\n- **When review questions a decision, reconsider genuinely**: re-derive the tradeoff, state the\n  options, recommend with reasons. Defending the original choice is a valid outcome;\n  reflexively agreeing with every challenge is as bad as ignoring it.\n- **Validate the reference artifact before building on it.** Whatever you treat as ground truth\n  (a spec import, a baseline, a generated list), check it *first* — discovering it was\n  incomplete after five batches costs far more than before batch one.\n- **Verify as you go**: per-file `uv run --frozen pytest <file> -q` + pyright + ruff while\n  iterating; full suite, coverage, and `./scripts/test` (when `src/` was touched) at\n  integration.\n- **Every agent writes notes**: what it did, what broke, and — most importantly — what it\n  couldn't decide, so open questions surface instead of being silently resolved by whoever hit\n  them.\n- **Quality over speed is a stated goal, not a preference** (\"rushing something out the door is\n  not the goal here, explicitly so\"). Don't quietly de-scope agreed work mid-stream;\n  renegotiate scope explicitly.\n- **Don't copy patterns from existing test code by default** — much of the repo's older test\n  code is below the current bar (sleeps, mocks, `Test` classes, raciness). These rules define\n  the bar for new work.\n\n<!-- File: examples/stories/skills/README.md (Tokens: ~158 | Category: anthropic-skill) -->\n# skills\n\nSEP-2640 skills: a server exposes a `skill://index.json` directory resource and\n`@skill` / `@skillDir` registrations that a host can read to bootstrap\nagent-level instructions. The story will list skills and read one.\n\n**Status: not yet implemented** ([#2896](https://github.com/modelcontextprotocol/python-sdk/issues/2896)).\nThe `extensions` capability map is not yet surfaced on `MCPServer`, so a server\ncannot advertise the skills extension.\n\n## Spec\n\n[SEP-2640 — skills](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2640)\n· [SEP-2133 — extensions capability](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2133)\n\n<!-- File: examples/stories/extensions/README.md (Tokens: ~415 | Category: plugin-manifest) -->\n# extensions\n\nWriting your own extension (SEP-2133): one identifier bundles a settings entry\nunder `ServerCapabilities.extensions`, a contributed tool, and a vendor request\nmethod gated on the client declaring the extension back.\n\n## Run it\n\n```bash\n# stdio (default — the client spawns the server as a subprocess)\nuv run python -m stories.extensions.client\n\n# HTTP — the client self-hosts the server on a free port, runs, then tears it down\nuv run python -m stories.extensions.client --http\n```\n\n## What to look at\n\n- `server.py` `class Catalog(Extension)` — the whole extension: `settings()`\n  becomes the advertised capability entry, `tools()` contributes a regular tool,\n  `methods()` registers a vendor verb. The extension never holds the server; it\n  declares contributions and `MCPServer(extensions=[...])` consumes them.\n- `server.py` `require_client_extension(ctx, EXTENSION_ID)` — the vendor method\n  rejects clients that did not declare the extension with `-32021` (missing\n  required client capability) and a machine-readable `requiredCapabilities`\n  payload.\n- `client.py` `Client(target, extensions=[advertise(EXTENSION_ID)])` — the client-side\n  half of the negotiation; on 2026-07-28 it travels in the per-request `_meta`\n  envelope.\n- `client.py` `client.session.send_request(...)` — vendor methods have no\n  `Client`-level helper; the session escape hatch sends them.\n\n## Spec\n\n[SEP-2133 — extensions capability](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/2133)\n· [Capabilities — `_meta` key grammar](https://modelcontextprotocol.io/specification/draft/basic/index)\n\n## See also\n\n`apps/` (the built-in MCP Apps extension) · `custom_methods/` (the same verb\nregistered on the lowlevel `Server` by hand, without an extension).\n\n<!-- File: examples/stories/tools/README.md (Tokens: ~376 | Category: plugin-manifest) -->\n# tools\n\n**Start here.** Register tools with `@mcp.tool()`; the SDK infers the JSON\ninput schema from type hints, the output schema from the return annotation, and\nreturns `structuredContent` alongside text. `ToolAnnotations` carries\nbehavioural hints (`readOnlyHint`, `idempotentHint`) the host can show to\nusers. The client lists tools, inspects schemas + annotations, calls both, and\nasserts structured output.\n\n## Run it\n\n```bash\n# stdio (default — the client spawns the server as a subprocess)\nuv run python -m stories.tools.client\n\n# HTTP — the client self-hosts the server on a free port, runs, then tears it down\nuv run python -m stories.tools.client --http\n# same, against the lowlevel-API server variant\nuv run python -m stories.tools.client --http --server server_lowlevel\n```\n\n## What to look at\n\n- `server.py` `calc` — `Literal[...]` and `BaseModel` in the signature become\n  the tool's `inputSchema` / `outputSchema` with zero hand-written JSON.\n- `server.py` `echo` — `structured_output=False` opts out of schema inference\n  for a plain text-only tool.\n- `server_lowlevel.py` — the same wire contract built by hand: this is what\n  `MCPServer` generates for you.\n\n## Spec\n\n[Tools — server features](https://modelcontextprotocol.io/specification/2025-11-25/server/tools)\n\n## See also\n\n`schema_validators/` (every input-schema source: pydantic / TypedDict /\ndataclass / dict), `error_handling/` (`is_error` vs protocol error),\n`streaming/` (progress mid-call).\n\n<!-- File: .claude/commands/review-pr.md (Tokens: ~901 | Category: command-prompt) -->\nReview the pull request: $ARGUMENTS\n\nFollow these steps carefully. Use the `gh` CLI for all GitHub interactions.\n\n## Step 1: Resolve the PR\n\nParse `$ARGUMENTS` to determine the PR. It can be:\n\n- A full URL like `https://github.com/owner/repo/pull/123`\n- A `owner/repo#123` reference\n- A bare number like `123` (use the current repo)\n- A description — search for it with `gh pr list --search \"<description>\" --limit 5` and pick the best match\n\nOnce resolved, fetch the PR metadata:\n\n```bash\ngh pr view <PR> --json number,title,body,author,state,baseRefName,headRefName,url,labels,milestone,additions,deletions,changedFiles,createdAt,updatedAt,mergedAt,reviewDecision,reviews,assignees\n```\n\n## Step 2: Gather the diff\n\nGet the full diff of the PR:\n\n```bash\ngh pr diff <PR>\n```\n\nIf the diff is very large (>3000 lines), focus on the most important files first and summarize the rest.\n\n## Step 3: Collect PR discussion context\n\nFetch all comments and review threads:\n\n```bash\ngh api repos/{owner}/{repo}/pulls/{number}/comments --paginate\ngh api repos/{owner}/{repo}/issues/{number}/comments --paginate\ngh api repos/{owner}/{repo}/pulls/{number}/reviews --paginate\n```\n\nPay attention to:\n\n- Reviewer feedback and requested changes\n- Author responses and explanations\n- Any unresolved conversations\n- Approval or rejection status\n\n## Step 4: Find and read linked issues\n\nLook for issue references in:\n\n- The PR body (patterns like `#123`, `fixes #123`, `closes #123`, `resolves #123`)\n- The PR branch name (patterns like `issue-123`, `fix/123`)\n- Commit messages\n\nFor each linked issue, fetch its content:\n\n```bash\ngh issue view <number> --json title,body,comments,labels,state\n```\n\nRead through issue comments to understand the original problem, user reports, and any discussed solutions.\n\n## Step 5: Analyze and validate\n\nWith all context gathered, analyze the PR critically:\n\n1. **Intent alignment**: Does the code change actually solve the problem described in the PR and/or linked issues?\n2. **Completeness**: Are there aspects of the issue or requested feature that the PR doesn't address?\n3. **Scope**: Does the PR include changes unrelated to the stated goal? Are there unnecessary modifications?\n4. **Correctness**: Based on the diff, are there obvious bugs, edge cases, or logic errors?\n5. **Testing**: Does the PR include tests? Are they meaningful and do they cover the important cases?\n6. **Breaking changes**: Could this PR break existing functionality or APIs?\n7. **Unresolved feedback**: Are there reviewer comments that haven't been addressed?\n\n## Step 6: Produce the review summary\n\nPresent the summary in this format:\n\n---\n\n### PR Review: `<title>` (<url>)\n\n**Author:** <author> | **Status:** <state> | **Review decision:** <decision>\n**Base:** `<base>` ← `<head>` | **Changed files:** <n> | **+<additions> / -<deletions>**\n\n#### Problem\n\n<1-3 sentences describing what problem this PR is trying to solve, based on the PR description and linked issues>\n\n#### Solution\n\n<1-3 sentences describing the approach taken in the code>\n\n#### Key changes\n\n<Bulleted list of the most important changes, grouped by theme. Include file paths.>\n\n#### Linked issues\n\n<List of linked issues with their title, state, and a one-line summary of the discussion>\n\n#### Discussion highlights\n\n<Summary of important comments from reviewers and the author. Flag any unresolved threads.>\n\n#### Concerns\n\n<List any issues found during validation: bugs, missing tests, scope creep, unaddressed feedback, etc. If none, say \"No concerns found.\">\n\n#### Verdict\n\n<One of: APPROVE / REQUEST CHANGES / NEEDS DISCUSSION, with a brief justification>\n\n#### Suggested action\n\n<Clear recommendation for the reviewer: what to approve, what to push back on, what to ask about>\n\n---\n</yakaai_skills>"}