feat(authorization): send the RFC 8707 resource parameter - #466
Open
tylerklose wants to merge 1 commit into
Open
feat(authorization): send the RFC 8707 resource parameter#466tylerklose wants to merge 1 commit into
resource parameter#466tylerklose wants to merge 1 commit into
Conversation
The runner is the MCP client in the `authorization` direction, and the spec requires clients to send `resource` in both the authorization request and the token request. It sent neither. Adds `--resource <uri>` and a matching `resource` field on AuthorizationServerOptionsSchema, so `--file` supplies it too. The value must be an absolute URI with no fragment. The parameter is only sent when set, so existing runs are unchanged. No new check IDs: in this direction the runner is the client, so a check that it sent `resource` could never fail. The existing grant checks now reach a path they couldn't before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tylerklose
added a commit
to tylerklose/hitch-rails
that referenced
this pull request
Aug 21, 2026
Validating an upstream branch that would make our patch unnecessary means running the harness against a working tree instead of the pinned clone plus reviewed patch. There was no seam for that, so the choice was reimplement the fixture, TLS, browser operator and credential canaries, or don't check. HITCH_CONFORMANCE_LOCAL_RUNNER stages a working tree by rsync — not a clone, so uncommitted edits are what gets exercised — and skips the patch step. Unset by default; CI never sets it. Evidence produced this way stamps its version and commit as "unpinned-local-checkout" so it can never be read as pinned conformance evidence. This is what proved modelcontextprotocol/conformance#466 works against a real authorization server: the public-client grant passes end to end, which it could not before, because Hitch rejects a missing resource indicator at both the authorization and token endpoints. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018JmnbitJ3Gx4kRUhbMjktc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #465.
The runner is the MCP client in the
authorizationdirection. The spec requiresclients to send
resourcein both the authorization request and the tokenrequest. It sent neither.
Changes
src/index.ts—--resource <uri>on theauthorizationcommand.src/schemas.ts—resourceonAuthorizationServerOptionsSchema, so--filesupplies it too.authorization-code-grant.ts— sendsresourcein the authorization requestand the token request when it's set.
The value must be an absolute URI with no fragment — the spec's own two invalid
examples are
mcp.example.com(no scheme) andhttps://mcp.example.com#fragment.Two conditionals, one per request. It's only sent when the flag or file field is
present, so existing runs are unchanged.
No new check IDs
Deliberate. Here the runner is the client, so a check for "the runner sent
resource" is the harness grading its own homework — it can never fail. URIvalidation happens in the schema, before scenarios run, so a check for that can't
fail either.
None is needed. The existing grant checks now reach a path they couldn't before:
an AS that mishandles
resourcefails them, where before it was never asked.Tests
Six cases added (
npm test: 530 passing).Scenario:
resourceappears in both the authorization URL and the token body when setunconditional
resourcemakes the existing grantcheck fail, and passes when the parameter is absent
Schema:
Revert the two conditionals and the first and third fail.
Validated against a real authorization server
Run against hitch-rails, my own Rails MCP server and its own authorization
server. It requires
resourceat both endpoints, and rejects atoken exchange whose
resourcedoesn't match the one recorded at authorizationtime. The public-client grant passes end to end — it couldn't have before this
change, because the parameter never arrived.
The confidential-client path wasn't exercised:
selectTokenAuthMethodreturnsnonewhenever an AS advertisesnone, even with a client secret supplied, sothe runner shows up as a public client against a client registered for
client_secret_basic. Unrelated to this change; worth raising separately.Open question
See the issue: a run without
--resourcestays silent about the requirement.Whether it should fail instead, or report untestable at WARNING per #248, is your
call.
Checklist
npm run buildpassesnpm testpasses (530)