diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index f00ea9a6d..1c69e1ce7 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -91,7 +91,6 @@ jobs: --url http://127.0.0.1:8002/mcp \ --suite all \ --spec-version 2026-07-28 \ - --expected-failures conformance/expected-failures-2026-07-28.yaml \ -o conformance-results # Extension scenarios are excluded by the --spec-version filter and @@ -165,7 +164,6 @@ jobs: --command "$(pwd)/target/debug/conformance-client" \ --suite all \ --spec-version 2026-07-28 \ - --expected-failures conformance/expected-failures-2026-07-28.yaml \ -o conformance-client-results/draft - name: Run extension client suite (informational) diff --git a/conformance/expected-failures-2026-07-28.yaml b/conformance/expected-failures-2026-07-28.yaml deleted file mode 100644 index 29a166b76..000000000 --- a/conformance/expected-failures-2026-07-28.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Known failures for the pinned 2026-07-28 draft conformance suite -# (@modelcontextprotocol/conformance DRAFT_CONFORMANCE_VERSION). -# -# The full versioned-spec suites run in CI with `--expected-failures` pointing -# at this file. Extension scenarios are filtered out by `--spec-version` and -# tracked separately in `expected-failures-extensions.yaml`. -# -# Within the versioned-spec suites: -# - a scenario failing that is NOT listed here fails the build -# - a scenario listed here that starts passing also fails the build (stale entry), -# so remove it from this list when the underlying issue is fixed. -# -# When bumping DRAFT_CONFORMANCE_VERSION, diff -# `conformance list --spec-version 2026-07-28` and update #977. - -server: [] - -client: - # Client does not yet send MCP-Protocol-Version header pre-initialize as - # required by the 2026-07-28 stateless lifecycle. - # tracked in #1002 - - tools_call - # Auth feature gaps in the 2026-07-28 auth scenarios. - # tracked in #1002 - - auth/scope-step-up diff --git a/conformance/src/bin/client.rs b/conformance/src/bin/client.rs index 54ce7c284..0785e0675 100644 --- a/conformance/src/bin/client.rs +++ b/conformance/src/bin/client.rs @@ -189,6 +189,7 @@ impl ClientHandler for FullClientHandler { const CIMD_CLIENT_METADATA_URL: &str = "https://conformance-test.local/client-metadata.json"; const REDIRECT_URI: &str = "http://localhost:3000/callback"; +const SCOPE_STEP_UP_INITIAL_SCOPES: &[&str] = &["mcp:basic"]; const SCOPE_STEP_UP_ESCALATED_SCOPES: &[&str] = &["mcp:basic", "mcp:write"]; /// Perform the headless OAuth authorization-code flow. @@ -320,11 +321,10 @@ async fn run_auth_scope_step_up_client( server_url: &str, _ctx: &ConformanceContext, ) -> anyhow::Result<()> { - // First auth let mut oauth = OAuthState::new(server_url, None).await?; oauth .start_authorization_with_metadata_url( - &[], + SCOPE_STEP_UP_INITIAL_SCOPES, REDIRECT_URI, Some("conformance-client"), Some(CIMD_CLIENT_METADATA_URL), @@ -351,7 +351,9 @@ async fn run_auth_scope_step_up_client( StreamableHttpClientTransportConfig::with_uri(server_url), ); - let client = BasicClientHandler.serve(transport).await?; + let client = BasicClientHandler + .serve_with_lifecycle(transport, conformance_lifecycle()) + .await?; let tools = client.list_tools(Default::default()).await?; tracing::debug!("Listed {} tools", tools.tools.len()); @@ -398,10 +400,12 @@ async fn run_auth_scope_step_up_client( auth_client2, StreamableHttpClientTransportConfig::with_uri(server_url), ); - let client2 = BasicClientHandler.serve(transport2).await?; - let _ = client2 + let client2 = BasicClientHandler + .serve_with_lifecycle(transport2, conformance_lifecycle()) + .await?; + client2 .call_tool(call_tool_params(tool.name.clone(), args)) - .await; + .await?; client2.cancel().await.ok(); return Ok(()); } @@ -859,7 +863,7 @@ async fn run_basic_client(server_url: &str) -> anyhow::Result<()> { } async fn run_tools_call_client(server_url: &str, ctx: &ConformanceContext) -> anyhow::Result<()> { - run_tools_call_client_with_lifecycle(server_url, ctx, ClientLifecycleMode::Initialize).await + run_tools_call_client_with_lifecycle(server_url, ctx, conformance_lifecycle()).await } async fn run_discover_tools_call_client( @@ -930,7 +934,17 @@ fn conformance_protocol_version() -> ProtocolVersion { std::env::var("MCP_CONFORMANCE_PROTOCOL_VERSION") .ok() .and_then(|version| serde_json::from_value(Value::String(version)).ok()) - .unwrap_or(ProtocolVersion::V_2026_07_28) + .unwrap_or(ProtocolVersion::V_2025_11_25) +} + +fn conformance_lifecycle() -> ClientLifecycleMode { + if conformance_protocol_version().as_str() >= ProtocolVersion::V_2026_07_28.as_str() { + ClientLifecycleMode::Discover { + preferred_versions: preferred_protocol_versions(), + } + } else { + ClientLifecycleMode::Initialize + } } /// Preferred protocol versions for discover-lifecycle negotiation: the