Skip to content

Commit 8aed28f

Browse files
committed
Resolve merge conflicts
2 parents e409cae + e23b8df commit 8aed28f

4 files changed

Lines changed: 64 additions & 14 deletions

File tree

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

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,41 @@ client:
4646
# client support for the token-exchange + JWT bearer flow.
4747
- auth/enterprise-managed-authorization
4848

49-
# The `active` suite (30 scenarios / 42 assertions) is fully green against
50-
# mcp-everything-server. Draft-suite entries are added when the workflow
51-
# gains a `--suite draft` step.
52-
server: []
49+
server:
50+
# --- Draft-spec scenarios (in `--suite draft`; the `active` suite is green) ---
51+
# SEP-2575 (stateless HTTP / _meta envelope): server has no stateless mode,
52+
# _meta-derived capabilities, error-code mappings, or server/discover yet.
53+
- server-stateless
54+
# SEP-2322 (multi-round-trip requests / IncompleteResult): not implemented;
55+
# most scenarios currently fail early with "Missing session ID" because
56+
# mcp-everything-server only runs in stateful mode.
57+
- input-required-result-basic-elicitation
58+
- input-required-result-basic-sampling
59+
- input-required-result-basic-list-roots
60+
- input-required-result-request-state
61+
- input-required-result-multiple-input-requests
62+
- input-required-result-multi-round
63+
- input-required-result-non-tool-request
64+
- input-required-result-result-type
65+
- input-required-result-tampered-state
66+
- input-required-result-capability-check
67+
# SEP-2549 (caching): no ttlMs/cacheScope support; scenario also hits the
68+
# stateful-mode "Missing session ID" error.
69+
- caching
70+
# SEP-2243 (HTTP header standardization): -32001 HeaderMismatch handling and
71+
# case-insensitive/whitespace-trimmed header validation not implemented.
72+
- http-header-validation
73+
- http-custom-header-server-validation
74+
# WARNING-only entries: these scenarios emit no FAILURE checks, only SHOULD-level
75+
# WARNINGs, but the expected-failures evaluator counts WARNINGs as failures.
76+
# SEP-2164: server returns -32600 (not -32602) and omits error.data.uri.
77+
- sep-2164-resource-not-found
78+
# SEP-2322 SHOULD-level behaviours (re-request missing inputResponses, ignore
79+
# unrecognized inputResponses keys).
80+
- input-required-result-missing-input-response
81+
- input-required-result-ignore-extra-params
82+
# Intentionally NOT baselined (2 of 19 draft scenarios): the SEP-2322
83+
# negative-case scenarios input-required-result-unsupported-methods and
84+
# input-required-result-validate-input pass today only because the stateful
85+
# server's -32600 "Missing session ID" satisfies their assertions. They will
86+
# start failing for real once stateless mode lands; add them then.

.github/workflows/conformance.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ jobs:
3838
./.github/actions/conformance/run-server.sh
3939
--suite active
4040
--expected-failures ./.github/actions/conformance/expected-failures.yml
41+
- name: Run server conformance (draft suite)
42+
run: >-
43+
./.github/actions/conformance/run-server.sh
44+
--suite draft
45+
--expected-failures ./.github/actions/conformance/expected-failures.yml
4146
4247
client-conformance:
4348
runs-on: ubuntu-latest

tests/interaction/transports/test_stdio.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,10 @@ async def test_tool_call_and_notification_round_trip_over_a_stdio_subprocess(
6161
# post-print kill can no longer silently lose the data file -- see _stdio_server.main). The
6262
# production 2s default is too tight for the unwind+save tail on loaded Windows runners
6363
# (measured in-situ p99 of the whole test is ~7s); a kill before the print fails the stderr
64-
# assertion below loudly rather than tripping the coverage gate. Not under test.
65-
monkeypatch.setattr(stdio, "PROCESS_TERMINATION_TIMEOUT", 10.0)
64+
# assertion below loudly rather than tripping the coverage gate. The 20s grace covers even a
65+
# badly starved runner (a >10s stall has been seen once in CI) and costs nothing when the
66+
# child exits promptly. Not under test.
67+
monkeypatch.setattr(stdio, "PROCESS_TERMINATION_TIMEOUT", 20.0)
6668

6769
received: list[LoggingMessageNotificationParams] = []
6870

@@ -85,8 +87,8 @@ async def collect(params: LoggingMessageNotificationParams) -> None:
8587
errlog=errlog,
8688
)
8789

88-
# Must exceed session time plus the patched PROCESS_TERMINATION_TIMEOUT (10s).
89-
with anyio.fail_after(20):
90+
# Must exceed session time plus the patched PROCESS_TERMINATION_TIMEOUT (20s).
91+
with anyio.fail_after(30):
9092
async with Client(transport, logging_callback=collect) as client:
9193
assert client.initialize_result.server_info.name == "stdio-echo"
9294
result = await client.call_tool("echo", {"text": "across\nprocesses"})

tests/issues/test_1363_race_condition_streamable_http.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from contextlib import asynccontextmanager
2222

2323
import anyio
24+
import anyio.to_thread
2425
import httpx
2526
import pytest
2627
from starlette.applications import Starlette
@@ -68,6 +69,7 @@ def __init__(self, app: Starlette):
6869
super().__init__(daemon=True)
6970
self.app = app
7071
self._stop_event = threading.Event()
72+
self._ready_event = threading.Event()
7173

7274
def run(self) -> None:
7375
"""Run the lifespan in a new event loop."""
@@ -78,12 +80,19 @@ async def run_lifespan():
7880
lifespan_context = getattr(self.app.router, "lifespan_context", None)
7981
assert lifespan_context is not None # Tests always create apps with lifespan
8082
async with lifespan_context(self.app):
83+
# Only signal readiness once lifespan startup has completed, i.e. the
84+
# session manager's task group exists and requests can be handled.
85+
self._ready_event.set()
8186
# Wait until stop is requested
8287
while not self._stop_event.is_set():
8388
await anyio.sleep(0.1)
8489

8590
anyio.run(run_lifespan)
8691

92+
def wait_ready(self, timeout: float = 5.0) -> None:
93+
"""Block until the lifespan has started; call from a worker thread, not the event loop."""
94+
assert self._ready_event.wait(timeout), "server thread did not start its lifespan in time"
95+
8796
def stop(self) -> None:
8897
"""Signal the thread to stop."""
8998
self._stop_event.set()
@@ -132,8 +141,8 @@ async def test_race_condition_invalid_accept_headers(caplog: pytest.LogCaptureFi
132141
server_thread.start()
133142

134143
try:
135-
# Give the server thread a moment to start
136-
await anyio.sleep(0.1)
144+
# Wait for the server thread to enter the lifespan before sending requests
145+
await anyio.to_thread.run_sync(server_thread.wait_ready)
137146

138147
# Suppress WARNING logs (expected validation errors) and capture ERROR logs
139148
with caplog.at_level(logging.ERROR):
@@ -203,8 +212,8 @@ async def test_race_condition_invalid_content_type(caplog: pytest.LogCaptureFixt
203212
server_thread.start()
204213

205214
try:
206-
# Give the server thread a moment to start
207-
await anyio.sleep(0.1)
215+
# Wait for the server thread to enter the lifespan before sending requests
216+
await anyio.to_thread.run_sync(server_thread.wait_ready)
208217

209218
# Suppress WARNING logs (expected validation errors) and capture ERROR logs
210219
with caplog.at_level(logging.ERROR):
@@ -243,8 +252,8 @@ async def test_race_condition_message_router_async_for(caplog: pytest.LogCapture
243252
server_thread.start()
244253

245254
try:
246-
# Give the server thread a moment to start
247-
await anyio.sleep(0.1)
255+
# Wait for the server thread to enter the lifespan before sending requests
256+
await anyio.to_thread.run_sync(server_thread.wait_ready)
248257

249258
# Suppress WARNING logs (expected validation errors) and capture ERROR logs
250259
with caplog.at_level(logging.ERROR):

0 commit comments

Comments
 (0)