Skip to content

test(aspnetcore): cover RequireAuthorization() on the MCP endpoint across session modes - #1870

Open
ump45nose wants to merge 1 commit into
modelcontextprotocol:mainfrom
ump45nose:contrib/8e3d5317b8c2
Open

test(aspnetcore): cover RequireAuthorization() on the MCP endpoint across session modes#1870
ump45nose wants to merge 1 commit into
modelcontextprotocol:mainfrom
ump45nose:contrib/8e3d5317b8c2

Conversation

@ump45nose

Copy link
Copy Markdown

Summary

Adds end-to-end coverage for protecting the MCP endpoint itself with RequireAuthorization().

AuthorizeAttributeTests already covers tool-level [Authorize]: the request reaches the MCP handler and the tool collection is filtered per user. The endpoint-level challenge has different requirements and had no coverage — it must happen before the handler runs, it must hold for every request in an established session, and it must work in each session mode without making the OAuth protected-resource metadata document unreachable.

New file: tests/ModelContextProtocol.AspNetCore.Tests/MapMcpAuthorizationTests.cs

  • Initialize_WithoutCredentials_IsChallenged — the initial initialize POST is rejected with 401 in Stateful, StatefulForInitializeClients, and Stateless.
  • Initialize_WithCredentials_Succeeds — 200, and a session id is minted in the session-based modes but not in Stateless (which keeps the endpoint free of server state).
  • StatefulSession_FollowUpRequests_RequireCredentials — an authorized initialize followed by an authorized tools/list on the same session works, while the same Mcp-Session-Id sent without credentials is rejected with 401. The session id identifies a session; it must not authenticate the caller.
  • ResourceMetadata_RemainsReachable_WhileTheMcpEndpointIsChallenged — with MapMcp("/mcp").RequireAuthorization() and the SDK's McpAuthenticationHandler configured, GET /.well-known/oauth-protected-resource/mcp is served without credentials, and the 401 challenge advertises resource_metadata="…/.well-known/oauth-protected-resource/mcp" so a client can still discover the authorization server from the challenge alone. The endpoint is mounted at /mcp here because that is the deployment shape where the metadata document mirrors the resource path.

The authentication scheme is a test-only header-based handler, so the challenged and authorized paths are both exercised without standing up a token issuer.

No product code changes.

Verification

dotnet build tests/ModelContextProtocol.AspNetCore.Tests succeeds for net10.0, net9.0, and net8.0 with 0 warnings.

dotnet test -c Release -f net10.0 (SDK 10.0.101) on this branch:

  • ModelContextProtocol.AspNetCore.Tests: 602 passed, 55 skipped, 0 failed
  • ModelContextProtocol.Tests: 2359 passed, 5 skipped, 0 failed
  • MapMcpAuthorizationTests on its own: 8 passed, 0 failed

Only the .NET 10 runtime is installed on my machine, so the net8.0/net9.0 legs are compile-verified rather than executed here. ModelContextProtocol.Analyzers.Tests targets net9.0 only and is unaffected by this change.

Built and tested locally with -p:NuGetAudit=false: Microsoft.Build.Tasks.Git 8.0.0 raises NU1902 on this repository today, which reproduces on unmodified main and is unrelated to this change.

Related to #1785, where endpoint-level RequireAuthorization() combined with session mode was the configuration under investigation.

AI assistance disclosure: AI was used to discover this opportunity and draft the change or text. The submission was checked against the prepared artifact and recorded verification evidence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant