Skip to content

fix: pass OAuth scopes to DCR and extract granted_scopes from token response#7571

Merged
jamadeo merged 8 commits intoblock:mainfrom
peschee:fix/oauth-granted-scopes
Mar 9, 2026
Merged

fix: pass OAuth scopes to DCR and extract granted_scopes from token response#7571
jamadeo merged 8 commits intoblock:mainfrom
peschee:fix/oauth-granted-scopes

Conversation

@peschee
Copy link
Contributor

@peschee peschee commented Feb 27, 2026

Summary

Two fixes for OAuth scope handling when connecting to MCP servers:

  • Pass scopes to DCR registration: When an MCP server returns WWW-Authenticate: Bearer scope="...", the scopes are parsed but never included in the Dynamic Client Registration (DCR) request. This patches rmcp via [patch.crates-io] to include a scope field in the DCR request per RFC 7591. Upstream PR: fix(auth): pass WWW-Authenticate scopes to DCR registration request modelcontextprotocol/rust-sdk#705
  • Extract granted_scopes from token response: Previously granted_scopes: vec![] was always saved. Now the actual scopes from the token response are extracted and stored in credentials.

Test plan

  • cargo check -p goose compiles without errors
  • Connect to an MCP server that returns scopes in WWW-Authenticate and verify the DCR registration request includes the scope field
  • Verify stored credentials contain the granted scopes after OAuth flow completes
  • Once upstream rmcp PR is merged and released, update to remove the [patch.crates-io] entry

@peschee peschee force-pushed the fix/oauth-granted-scopes branch 3 times, most recently from 56bbd66 to 0b621ea Compare February 27, 2026 17:02
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0b621ea3bc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Cargo.toml Outdated

[patch.crates-io]
v8 = { path = "vendor/v8" }
rmcp = { git = "https://github.com/peschee/rust-sdk.git", branch = "fix-dcr-scopes-v2" }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pin rmcp patch to a fixed commit

The new [patch.crates-io] entry tracks a mutable Git branch, so any lockfile refresh (cargo update, dependency bumps, or lockfile regeneration in CI) can pull different rmcp code than what was reviewed here. That makes builds non-reproducible and can silently reintroduce OAuth regressions or new behavior from later branch commits; use an immutable rev for this patch to keep the dependency stable.

Useful? React with 👍 / 👎.

@peschee peschee force-pushed the fix/oauth-granted-scopes branch from ba82a26 to eb8c7c5 Compare February 27, 2026 17:18
@jamadeo jamadeo self-assigned this Feb 28, 2026
Copy link
Collaborator

@jamadeo jamadeo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @peschee this looks good. Once your PR is merged into the rust SDK please update the Cargo.toml here and we can merge.

assert_eq!(std::fs::read_to_string(&path2).unwrap(), "second");
// Note: we intentionally don't assert file content here because
// parallel tests (render_output_truncates_*) share the same static
// temp file and can overwrite the content between our write and read.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, this appears to be a flaky test. Looks like removing this assert loses very little actual test usefulness, so this seems fine to me

@peschee peschee force-pushed the fix/oauth-granted-scopes branch from 472d024 to c6df961 Compare February 28, 2026 06:51
…esponse

Two fixes for OAuth scope handling in MCP server connections:

1. Patch rmcp to include scopes from WWW-Authenticate in the DCR
   registration request (see modelcontextprotocol/rust-sdk#705)

2. Extract granted_scopes from the token response instead of always
   saving an empty vec, so stored credentials accurately reflect
   what the authorization server granted.

Signed-off-by: Peter Siska <63866+peschee@users.noreply.github.com>
The test shares a static temp file path with parallel tests
(render_output_truncates_*), which can overwrite the file content
between the write and read_to_string calls. The path reuse assertion
is the important invariant and is protected by the Mutex.

Signed-off-by: Peter Siska <63866+peschee@users.noreply.github.com>
…nges

The fork was based on upstream main (19 commits ahead of v0.16.0),
which included `allow empty content in CallToolResult` and other
unreleased changes that broke goose tests. Rebased to v0.16.0 tag
with only the DCR scopes fix on top.

Signed-off-by: Peter Siska <63866+peschee@users.noreply.github.com>
…s construction

The StoredCredentials struct in rmcp does not have a token_received_at
field. Removing it fixes the compilation error that caused CI failures.

Signed-off-by: Peter Siska <63866+peschee@users.noreply.github.com>
Signed-off-by: Peter Siska <63866+peschee@users.noreply.github.com>
@peschee peschee force-pushed the fix/oauth-granted-scopes branch from c6df961 to bd9bdb4 Compare February 28, 2026 06:54
Signed-off-by: Peter Siska <63866+peschee@users.noreply.github.com>
@peschee peschee force-pushed the fix/oauth-granted-scopes branch from 1ebf362 to 2aaf14a Compare February 28, 2026 07:54
@peschee
Copy link
Contributor Author

peschee commented Mar 3, 2026

@jamadeo upstream has been merged

@jamadeo
Copy link
Collaborator

jamadeo commented Mar 5, 2026

thanks @peschee , once #7619 merges, we can remove the dependency override

@jamadeo jamadeo enabled auto-merge March 9, 2026 15:36
@jamadeo jamadeo added this pull request to the merge queue Mar 9, 2026
Merged via the queue into block:main with commit f740bb7 Mar 9, 2026
20 checks passed
wpfleger96 added a commit that referenced this pull request Mar 9, 2026
* origin/main: (21 commits)
  fix(ui-desktop): unify path resolution around GOOSE_PATH_ROOT (#7335)
  fix: pass OAuth scopes to DCR and extract granted_scopes from token response (#7571)
  fix: write to real file if config.yaml is symlink (#7669)
  fix: preserve pairings when stopping gateway (#7733)
  fix: reduce server log verbosity — skip session in instrument, defaul… (#7729)
  fix: provider test infrastructure (#7738)
  fix: sanitize streamable HTTP extension names derived from URLs (#7740)
  refactor: derive GooseMode string conversions with strum (#7706)
  docs: Add Spraay Batch Payments MCP Extension Tutorial (#7525)
  fix: flake.nix (#7224)
  delete goose web (#7696)
  Add @angiejones as CODEOWNER for documentation (#7711)
  Add MLflow integration guide (#7563)
  docs: LM Studio availability (#7698)
  feat: add Avian as an LLM provider (#7561)
  Adds `linux-mcp-server` to the goose registry (#6979)
  fix: add #[serde(default)] to description field on 4 ExtensionConfig variants (#7708)
  feat: combine TUI UX from alexhancock/tui-goodness with publishing config from jackamadeo/package-tui (#7683)
  chore: cleanup old sandbox (#7700)
  Correct windows artifact (#7699)
  ...
wpfleger96 added a commit that referenced this pull request Mar 9, 2026
* origin/main: (21 commits)
  fix(ui-desktop): unify path resolution around GOOSE_PATH_ROOT (#7335)
  fix: pass OAuth scopes to DCR and extract granted_scopes from token response (#7571)
  fix: write to real file if config.yaml is symlink (#7669)
  fix: preserve pairings when stopping gateway (#7733)
  fix: reduce server log verbosity — skip session in instrument, defaul… (#7729)
  fix: provider test infrastructure (#7738)
  fix: sanitize streamable HTTP extension names derived from URLs (#7740)
  refactor: derive GooseMode string conversions with strum (#7706)
  docs: Add Spraay Batch Payments MCP Extension Tutorial (#7525)
  fix: flake.nix (#7224)
  delete goose web (#7696)
  Add @angiejones as CODEOWNER for documentation (#7711)
  Add MLflow integration guide (#7563)
  docs: LM Studio availability (#7698)
  feat: add Avian as an LLM provider (#7561)
  Adds `linux-mcp-server` to the goose registry (#6979)
  fix: add #[serde(default)] to description field on 4 ExtensionConfig variants (#7708)
  feat: combine TUI UX from alexhancock/tui-goodness with publishing config from jackamadeo/package-tui (#7683)
  chore: cleanup old sandbox (#7700)
  Correct windows artifact (#7699)
  ...
wpfleger96 added a commit that referenced this pull request Mar 9, 2026
…e-issue

* origin/main:
  fix(ui-desktop): unify path resolution around GOOSE_PATH_ROOT (#7335)
  fix: pass OAuth scopes to DCR and extract granted_scopes from token response (#7571)
  fix: write to real file if config.yaml is symlink (#7669)
  fix: preserve pairings when stopping gateway (#7733)
  fix: reduce server log verbosity — skip session in instrument, defaul… (#7729)
  fix: provider test infrastructure (#7738)
  fix: sanitize streamable HTTP extension names derived from URLs (#7740)
  refactor: derive GooseMode string conversions with strum (#7706)
  docs: Add Spraay Batch Payments MCP Extension Tutorial (#7525)
  fix: flake.nix (#7224)
  delete goose web (#7696)
  Add @angiejones as CODEOWNER for documentation (#7711)
  Add MLflow integration guide (#7563)
  docs: LM Studio availability (#7698)
  feat: add Avian as an LLM provider (#7561)
  Adds `linux-mcp-server` to the goose registry (#6979)
  fix: add #[serde(default)] to description field on 4 ExtensionConfig variants (#7708)
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.

2 participants