Skip to content

Commit a9cff4e

Browse files
Merge branch 'main' into fix/streamable-http-401-unauthorized
2 parents 9fd1882 + 14aa889 commit a9cff4e

7 files changed

Lines changed: 109 additions & 58 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Expected failures at the 2025-11-25 wire, read by the `--suite all
2+
# --spec-version 2025-11-25` server and client legs: every scenario the pinned
3+
# harness marks applicable at 2025-11-25, run over the stateful handshake.
4+
#
5+
# That selection is a superset of the frozen 2025-11-25 requirement set (`npx
6+
# $CONFORMANCE_PKG list --requirements 2025-11-25`), so an entry here for a
7+
# scenario in that set means `conformance tier-check` scores the SDK below 100%
8+
# for 2025-11-25 even though CI is green; link the tracking issue next to any
9+
# such entry.
10+
#
11+
# Kept separate from expected-failures.yml even though the bare `--suite all`
12+
# legs currently run these same scenarios at 2025-11-25 too: the harness's
13+
# default wire is due to move (modelcontextprotocol/conformance#426) and this
14+
# file must keep meaning 2025-11-25. Until then a failure here also needs an
15+
# entry there. The file is passed even while empty: run-client.sh keys its solo
16+
# re-verification off the harness's baseline output.
17+
#
18+
# Baseline established against the harness pinned via CONFORMANCE_PKG in
19+
# .github/workflows/conformance.yml. New conformance releases are adopted by
20+
# deliberately bumping that pin and reconciling all three expected-failures
21+
# files in the same change. Entries MUST be removed as they start passing (the
22+
# runner fails on stale entries).
23+
24+
client: []
25+
26+
server: []

.github/actions/conformance/expected-failures.2026-07-28.yml

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
1-
# Expected failures for the carried-forward 2026-07-28 legs
2-
# (`--suite all --spec-version 2026-07-28` for both server and client).
1+
# Expected failures at the 2026-07-28 wire, read by the `--suite all
2+
# --spec-version 2026-07-28` server and client legs: every scenario the pinned
3+
# harness marks applicable at 2026-07-28, run stateless with per-request _meta.
4+
#
5+
# That selection is a superset of the frozen 2026-07-28 requirement set (`npx
6+
# $CONFORMANCE_PKG list --requirements 2026-07-28`), so an entry here for a
7+
# scenario in that set means `conformance tier-check` scores the SDK below 100%
8+
# for 2026-07-28 even though CI is green; link the tracking issue next to any
9+
# such entry.
310
#
411
# This baseline is separate from expected-failures.yml because entries are
5-
# keyed by scenario name only: a scenario that passes at its default version
6-
# in the 2025 legs but fails when forced to 2026-07-28 (or vice versa) cannot
7-
# be expressed in a shared file (the passing leg would flag the entry as
8-
# stale). Like expected-failures.yml, this single file covers both
9-
# directions: the client 2026 leg reads the `client:` section and the server
10-
# 2026 leg reads the `server:` section. Both burn down independently of the
11-
# 2025 legs.
12+
# keyed by scenario name only: a scenario that passes at the harness default
13+
# wire in the bare `--suite all` legs but fails when forced to 2026-07-28 (or
14+
# vice versa) cannot be expressed in a shared file. Where the bare legs already
15+
# default a scenario to 2026-07-28, a failure here also needs an entry there.
1216
#
1317
# Baseline established against the harness pinned via CONFORMANCE_PKG in
1418
# .github/workflows/conformance.yml. New conformance releases are adopted by
15-
# deliberately bumping that pin and reconciling both this file and
16-
# expected-failures.yml in the same change.
19+
# deliberately bumping that pin and reconciling all three expected-failures
20+
# files in the same change.
1721
#
1822
# Entries are grouped by what unblocks them. As each gap closes the
1923
# corresponding scenarios start passing and MUST be removed from this list

.github/actions/conformance/expected-failures.yml

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
# Conformance scenarios not yet passing against the Python SDK on main.
2-
# CI exits 0 if only these fail, exits 1 on unexpected failures or stale entries.
1+
# Conformance scenarios not yet passing against the Python SDK on main, read by
2+
# the bare `--suite all` server and client legs (every scenario shipped with the
3+
# pinned harness, each at the harness's default wire for it). CI exits 0 if only
4+
# these fail, exits 1 on unexpected failures or stale entries.
5+
#
6+
# The wire-pinned legs read expected-failures.2025-11-25.yml and
7+
# expected-failures.2026-07-28.yml instead; see the header of
8+
# .github/workflows/conformance.yml for the leg layout.
39
#
410
# Baseline established against the harness pinned via CONFORMANCE_PKG in
511
# .github/workflows/conformance.yml. New conformance releases are adopted by
6-
# deliberately bumping that pin and reconciling both this file and
7-
# expected-failures.2026-07-28.yml in the same change.
12+
# deliberately bumping that pin and reconciling all three expected-failures
13+
# files in the same change.
814
#
915
# Entries are grouped by SEP. As each SEP lands in the SDK the corresponding
1016
# scenarios start passing and MUST be removed from this list (the runner fails
@@ -30,10 +36,9 @@ client:
3036

3137
server:
3238
# SEP-2663 (io.modelcontextprotocol/tasks): the SDK does not implement the
33-
# tasks extension yet. These extension-tagged scenarios are selected only by
34-
# the bare `--suite all` leg — extension scenarios never match a
35-
# --spec-version filter and the active/draft suites exclude them — so these
36-
# entries are inert for the other legs that read this file.
39+
# tasks extension yet. The bare `--suite all` leg is the only one that
40+
# reaches these extension-tagged scenarios (they never match a
41+
# --spec-version filter), so these entries live here only.
3742
#
3843
# `tasks-status-notifications` is intentionally NOT listed: the harness
3944
# skips it unconditionally (pending its rewrite against subscriptions/

.github/actions/conformance/run-client.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22
# Run a client conformance suite, re-verifying unexpected failures solo.
3-
# Concurrent suite runs on a 2-vCPU runner can push scenarios with real-time
3+
# Concurrent suite runs on a hosted runner can push scenarios with real-time
44
# waits past tolerance; solo, a real failure fails again while a contention
55
# artifact passes. Failures that only reproduce under concurrency are excused.
66
set -uo pipefail
@@ -101,4 +101,8 @@ if [ -n "$output_dir" ]; then
101101
printf '%s\n' "${scenarios[@]}" > "$output_dir/FLAKE_RESCUED"
102102
fi
103103
echo "All ${#scenarios[@]} unexpected failure(s) passed when re-run solo; the suite failures were parallel-run contention."
104+
# Surface the rescue on the run summary; the log line above and the
105+
# FLAKE_RESCUED marker in the uploaded results are otherwise easy to miss on a
106+
# green run.
107+
echo "::warning title=Conformance flake rescued::${scenarios[*]} failed under suite concurrency and passed solo${output_dir:+ (see ${output_dir}-solo and FLAKE_RESCUED in the uploaded results)}."
104108
exit 0

.github/workflows/conformance.yml

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,28 @@ permissions:
1515

1616
env:
1717
# Pinned conformance harness package spec (passed verbatim to `npx --yes`).
18-
# Bump deliberately and reconcile both
18+
# Bump deliberately and reconcile the three
1919
# .github/actions/conformance/expected-failures*.yml files in the same change.
2020
CONFORMANCE_PKG: "@modelcontextprotocol/conformance@0.2.0-alpha.11"
2121

22+
# Each job runs three `--suite all` legs, one per baseline file. The two
23+
# `--spec-version <rev>` legs run every scenario the pinned harness marks
24+
# applicable at that spec revision, at that revision's wire (stateful
25+
# handshake for 2025-11-25, stateless per-request _meta for 2026-07-28). Each
26+
# is a superset of the frozen requirement set that `conformance tier-check`
27+
# scores for that revision (`npx $CONFORMANCE_PKG list --requirements <rev>`
28+
# prints it), so an expected-failures.<rev>.yml entry for a scenario in that
29+
# set means tier-check reports the SDK below 100% for <rev>. The bare leg runs
30+
# every shipped scenario at whichever wire the harness defaults it to; it is
31+
# the only leg that reaches extension-tagged scenarios (tasks-*, auth/dpop*,
32+
# ...), which never match a --spec-version filter. For everything else it
33+
# overlaps one of the pinned legs, so a failure it also sees needs its own
34+
# expected-failures.yml entry besides the pinned file's.
35+
2236
jobs:
2337
server-conformance:
2438
runs-on: ubuntu-latest
39+
timeout-minutes: 15
2540
steps:
2641
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
2742
with:
@@ -34,45 +49,31 @@ jobs:
3449
with:
3550
node-version: 24
3651
- run: uv sync --frozen --all-extras --package mcp-everything-server
37-
- name: Run server conformance (active suite)
38-
run: >-
39-
./.github/actions/conformance/run-server.sh
40-
--suite active
41-
--expected-failures ./.github/actions/conformance/expected-failures.yml
42-
--output-dir conformance-results/server-active
43-
- name: Run server conformance (draft suite)
52+
- name: Run server conformance (all suite, 2025-11-25 wire)
4453
run: >-
4554
./.github/actions/conformance/run-server.sh
46-
--suite draft
47-
--expected-failures ./.github/actions/conformance/expected-failures.yml
48-
--output-dir conformance-results/server-draft
49-
- name: Run server conformance (2026-07-28 wire, all suite)
55+
--suite all
56+
--spec-version 2025-11-25
57+
--expected-failures ./.github/actions/conformance/expected-failures.2025-11-25.yml
58+
--output-dir conformance-results/server-2025-11-25
59+
- name: Run server conformance (all suite, 2026-07-28 wire)
5060
run: >-
5161
./.github/actions/conformance/run-server.sh
5262
--suite all
5363
--spec-version 2026-07-28
5464
--expected-failures ./.github/actions/conformance/expected-failures.2026-07-28.yml
5565
--output-dir conformance-results/server-2026-07-28
56-
- name: Run server conformance (all suite, extension scenarios)
57-
# A bare `--suite all` (no --spec-version) selects every scenario
58-
# shipped with the pinned harness — including the extension-tagged
59-
# tasks-* scenarios and pending-listed ones like server-sse-polling,
60-
# which no other leg reaches (extension scenarios never match a
61-
# --spec-version filter, and the pending list keeps them out of the
62-
# active suite). Running the full set keeps unimplemented surfaces
63-
# visible as baselined known failures in expected-failures.yml instead
64-
# of silent exclusions, and stays robust to scenarios moving between
65-
# harness suite lists across pin bumps. `--suite pending` would cover
66-
# the same union slightly faster; the full set is preferred for the
67-
# self-contained run and for parity with typescript-sdk's CI.
66+
- name: Run server conformance (all suite, default wire)
6867
run: >-
6968
./.github/actions/conformance/run-server.sh
7069
--suite all
7170
--expected-failures ./.github/actions/conformance/expected-failures.yml
7271
--output-dir conformance-results/server-all
7372
- name: Upload conformance results
7473
# The log has only summary counts; per-check data is in checks.json.
75-
if: failure()
74+
# always(), not !cancelled(): a timeout-minutes kill is a cancellation,
75+
# and that is when the partial results matter most.
76+
if: always()
7677
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
7778
with:
7879
name: server-conformance-results
@@ -81,6 +82,7 @@ jobs:
8182

8283
client-conformance:
8384
runs-on: ubuntu-latest
85+
timeout-minutes: 15
8486
steps:
8587
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
8688
with:
@@ -97,20 +99,21 @@ jobs:
9799
- run: uv sync --frozen --all-extras --package mcp --compile-bytecode
98100
- name: Pre-compile bytecode (editable sources)
99101
run: uv run --frozen python -m compileall -q src .github/actions/conformance
100-
- name: Run client conformance (all suite)
101-
# The harness runs all scenarios via unbounded Promise.all; with 40
102-
# scenarios on a 2-core runner the slowest one (sse-retry, which has a
103-
# real-time SSE reconnect wait) needs more than the 30s default budget.
104-
# `.venv/bin/python` (not `uv run`) avoids lockfile re-checks in ~40
105-
# concurrent spawns; run-client.sh re-runs unexpected failures solo.
102+
# The harness runs a leg's scenarios via unbounded Promise.all; under
103+
# that concurrency the slowest one (sse-retry, which has a real-time SSE
104+
# reconnect wait) needs more than the 30s default budget.
105+
# `.venv/bin/python` (not `uv run`) avoids lockfile re-checks in ~40
106+
# concurrent spawns; run-client.sh re-runs unexpected failures solo.
107+
- name: Run client conformance (all suite, 2025-11-25 wire)
106108
run: >-
107109
./.github/actions/conformance/run-client.sh
108110
--command '.venv/bin/python .github/actions/conformance/client.py'
109111
--suite all
110112
--timeout 60000
111-
--expected-failures ./.github/actions/conformance/expected-failures.yml
112-
--output-dir conformance-results/client-all
113-
- name: Run client conformance (2026-07-28 wire, all suite)
113+
--spec-version 2025-11-25
114+
--expected-failures ./.github/actions/conformance/expected-failures.2025-11-25.yml
115+
--output-dir conformance-results/client-2025-11-25
116+
- name: Run client conformance (all suite, 2026-07-28 wire)
114117
run: >-
115118
./.github/actions/conformance/run-client.sh
116119
--command '.venv/bin/python .github/actions/conformance/client.py'
@@ -119,10 +122,19 @@ jobs:
119122
--spec-version 2026-07-28
120123
--expected-failures ./.github/actions/conformance/expected-failures.2026-07-28.yml
121124
--output-dir conformance-results/client-2026-07-28
125+
- name: Run client conformance (all suite, default wire)
126+
run: >-
127+
./.github/actions/conformance/run-client.sh
128+
--command '.venv/bin/python .github/actions/conformance/client.py'
129+
--suite all
130+
--timeout 60000
131+
--expected-failures ./.github/actions/conformance/expected-failures.yml
132+
--output-dir conformance-results/client-all
122133
- name: Upload conformance results
123134
# The log has only summary counts; per-check data is in checks.json.
124-
# Also on FLAKE_RESCUED: rescued-flake evidence is otherwise discarded.
125-
if: failure() || hashFiles('conformance-results/**/FLAKE_RESCUED') != ''
135+
# always(), not !cancelled(): a timeout-minutes kill is a cancellation,
136+
# and that is when the partial results matter most.
137+
if: always()
126138
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
127139
with:
128140
name: client-conformance-results

tests/examples/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
STORIES_DIR = Path(stories.__file__).parent
3939
BASE_URL = "http://127.0.0.1:8000"
4040

41-
MANIFEST = tomllib.loads((STORIES_DIR / "manifest.toml").read_text())
41+
MANIFEST = tomllib.loads((STORIES_DIR / "manifest.toml").read_text(encoding="utf-8"))
4242
DEFAULTS: dict[str, Any] = MANIFEST["defaults"]
4343
STORIES: dict[str, dict[str, Any]] = MANIFEST["story"]
4444

tests/examples/test_story_shape.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
def _parse(path: Path) -> ast.Module:
2929
"""Parse ``path`` into an AST module."""
30-
return ast.parse(path.read_text(), filename=str(path))
30+
return ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
3131

3232

3333
def _resolve(node: ast.ImportFrom, package: str) -> str:

0 commit comments

Comments
 (0)