Skip to content

feat(auth): implement MCP auth tool-level scopes validation#3049

Merged
duwenxin99 merged 12 commits into
mainfrom
tool-auth
May 13, 2026
Merged

feat(auth): implement MCP auth tool-level scopes validation#3049
duwenxin99 merged 12 commits into
mainfrom
tool-auth

Conversation

@duwenxin99

Copy link
Copy Markdown
Contributor

No description provided.

@duwenxin99 duwenxin99 requested review from a team as code owners April 13, 2026 22:46
@duwenxin99 duwenxin99 changed the base branch from main to feat/refactor-tool-interface April 13, 2026 22:47

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request implements tool-level scope authorization for the Model Context Protocol (MCP), enabling granular access control for database tools. The changes include updating the Tool interface, adding scopesRequired configuration to all supported database tools, and integrating scope verification logic into the MCP request handler. Feedback focuses on resolving critical field shadowing in Serverless Spark configurations and eliminating redundant global scope registries in favor of the new interface methods. Additionally, improvements were suggested for more robust scope string parsing and ensuring proper header value escaping using the %q verb.

I am having trouble creating individual review comments. Click here to see my feedback.

internal/tools/serverlessspark/serverlesssparkcreatepysparkbatch/serverlesssparkcreatepysparkbatch.go (46-49)

high

The ScopesRequired field is already present in the embedded createbatch.Config struct. Adding it again here shadows the base field. When the YAML is decoded, the outer field will be populated while the inner one (used by the embedded tool logic) will remain empty, effectively breaking scope enforcement for this tool.

	createbatch.Config
}

internal/tools/serverlessspark/serverlesssparkcreatesparkbatch/serverlesssparkcreatesparkbatch.go (46-49)

high

The ScopesRequired field is already present in the embedded createbatch.Config struct. Adding it again here shadows the base field, which will cause the tool to ignore configured scopes.

	createbatch.Config
}

internal/server/config.go (319-332)

medium

This manual parsing of scopesRequired and its storage in a global map is redundant. The field is already automatically unmarshaled into the tool's Config struct by the factory (as seen in the changes to individual tool files). Since the Tool interface now includes a GetScopesRequired() method, it is better to rely on the tool instance itself to provide its required scopes.

To maintain consistency with authRequired, you can simply ensure the field is initialized if missing.

	// Ensure scopesRequired is initialized if not present
	if _, ok := r["scopesRequired"]; !ok {
		r["scopesRequired"] = []string{}
	}

internal/server/mcp.go (585)

medium

The error_description value should be properly escaped to ensure the header remains valid if the error message contains double quotes. Using the %q verb in fmt.Sprintf will automatically handle quoting and escaping of the string.

					w.Header().Set("WWW-Authenticate", fmt.Sprintf("Bearer error=\"insufficient_scope\", scope=\"%s\", resource_metadata=\"%s\", error_description=%q", strings.Join(mcpErr.ScopesRequired, " "), s.toolboxUrl+"/.well-known/oauth-protected-resource", mcpErr.Message))

internal/server/mcp/v20251125/method.go (213)

medium

Instead of using the global tools.GetToolScopes map, use the GetScopesRequired() method from the Tool interface. This makes the tool implementation self-contained and avoids the need for a global registry of scopes.

	toolScopes := tool.GetScopesRequired()

internal/server/mcp/v20251125/method.go (226)

medium

Using strings.Fields is more robust than strings.Split with a single space, as it correctly handles multiple spaces and returns an empty slice for empty strings, avoiding potential issues with empty string elements in the resulting slice.

		tokenScopes := strings.Fields(scopeClaim)

internal/tools/tools.go (38-48)

medium

The toolScopes map and its associated getter/setter functions are redundant now that the Tool interface includes the GetScopesRequired() method and the scopes are being unmarshaled directly into the tool configurations.

@duwenxin99 duwenxin99 changed the title feat: implement MCP tool-level scopes and auth challenge feat(auth): implement MCP auth tool-level scopes validation Apr 14, 2026
@duwenxin99 duwenxin99 force-pushed the feat/refactor-tool-interface branch from 2aed062 to b024609 Compare May 7, 2026 23:31
Comment thread internal/auth/generic/generic.go

@averikitsch averikitsch left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See question about issuer

Base automatically changed from feat/refactor-tool-interface to main May 8, 2026 19:30
@duwenxin99

Copy link
Copy Markdown
Contributor Author

/gemini-review

@duwenxin99 duwenxin99 enabled auto-merge (squash) May 12, 2026 17:57
@duwenxin99 duwenxin99 disabled auto-merge May 12, 2026 17:58
@duwenxin99 duwenxin99 enabled auto-merge (squash) May 13, 2026 16:47
@duwenxin99 duwenxin99 merged commit c528985 into main May 13, 2026
26 checks passed
@duwenxin99 duwenxin99 deleted the tool-auth branch May 13, 2026 17:07
@github-actions

Copy link
Copy Markdown
Contributor

🧨 Preview deployments removed.

Cloudflare Pages environments for pr-3049 have been deleted.

github-actions Bot pushed a commit to Jaleel-zhu/genai-toolbox that referenced this pull request May 13, 2026
github-actions Bot pushed a commit to renovate-bot/googleapis-_-genai-toolbox that referenced this pull request May 13, 2026
pavankrishna13 pushed a commit to pavankrishna13/genai-toolbox that referenced this pull request May 19, 2026
Yuan325 added a commit that referenced this pull request May 21, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.3.0](v1.2.0...v1.3.0)
(2026-05-21)


### Features

* **auth:** Implement MCP auth tool-level scopes validation
([#3049](#3049))
([c528985](c528985))
* **looker:** Propagate client IP from incoming MCP requests to
downstream SDK calls
([#3253](#3253))
([75da6c2](75da6c2))
* Setup SQLCommenter and allow client metadata
([#3064](#3064))
([9f1f9b3](9f1f9b3))
* **tool/cloudsqladmin:** Add `cloud-sql-admin-execute-sql-many` and
`cloud-sql-admin-sql-many`
([#3083](#3083))
([ef300a8](ef300a8))


### Bug Fixes

* **auth/generic:** Fix generic auth expiration field and integration
with `authRequired`
([#3251](#3251))
([f4d16c0](f4d16c0))
* Enforce toolset/promptset boundary on tools/call and prompts/get
([#3036](#3036))
([c739b80](c739b80))
* **tools/http:** Prevent path traversal and base path scope escape
([#3218](#3218))
([80a6602](80a6602))
* **tools/looker:** Return a 401 error to MCP client when Looker returns
a 401 ([#3233](#3233))
([4f409a3](4f409a3))
* **tools/looker:** Strip wrapping quotes from filter values for
unquoted parameters
([#3273](#3273))
([1e3de96](1e3de96))
* **tools:** Initialize query result slices to empty array
([#3250](#3250))
([60ddf48](60ddf48))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
github-actions Bot pushed a commit that referenced this pull request May 21, 2026
🤖 I have created a release *beep* *boop*
---

##
[1.3.0](v1.2.0...v1.3.0)
(2026-05-21)

### Features

* **auth:** Implement MCP auth tool-level scopes validation
([#3049](#3049))
([c528985](c528985))
* **looker:** Propagate client IP from incoming MCP requests to
downstream SDK calls
([#3253](#3253))
([75da6c2](75da6c2))
* Setup SQLCommenter and allow client metadata
([#3064](#3064))
([9f1f9b3](9f1f9b3))
* **tool/cloudsqladmin:** Add `cloud-sql-admin-execute-sql-many` and
`cloud-sql-admin-sql-many`
([#3083](#3083))
([ef300a8](ef300a8))

### Bug Fixes

* **auth/generic:** Fix generic auth expiration field and integration
with `authRequired`
([#3251](#3251))
([f4d16c0](f4d16c0))
* Enforce toolset/promptset boundary on tools/call and prompts/get
([#3036](#3036))
([c739b80](c739b80))
* **tools/http:** Prevent path traversal and base path scope escape
([#3218](#3218))
([80a6602](80a6602))
* **tools/looker:** Return a 401 error to MCP client when Looker returns
a 401 ([#3233](#3233))
([4f409a3](4f409a3))
* **tools/looker:** Strip wrapping quotes from filter values for
unquoted parameters
([#3273](#3273))
([1e3de96](1e3de96))
* **tools:** Initialize query result slices to empty array
([#3250](#3250))
([60ddf48](60ddf48))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> b001006
github-actions Bot pushed a commit to renovate-bot/googleapis-_-genai-toolbox that referenced this pull request May 21, 2026
🤖 I have created a release *beep* *boop*
---

##
[1.3.0](googleapis/mcp-toolbox@v1.2.0...v1.3.0)
(2026-05-21)

### Features

* **auth:** Implement MCP auth tool-level scopes validation
([googleapis#3049](googleapis#3049))
([c528985](googleapis@c528985))
* **looker:** Propagate client IP from incoming MCP requests to
downstream SDK calls
([googleapis#3253](googleapis#3253))
([75da6c2](googleapis@75da6c2))
* Setup SQLCommenter and allow client metadata
([googleapis#3064](googleapis#3064))
([9f1f9b3](googleapis@9f1f9b3))
* **tool/cloudsqladmin:** Add `cloud-sql-admin-execute-sql-many` and
`cloud-sql-admin-sql-many`
([googleapis#3083](googleapis#3083))
([ef300a8](googleapis@ef300a8))

### Bug Fixes

* **auth/generic:** Fix generic auth expiration field and integration
with `authRequired`
([googleapis#3251](googleapis#3251))
([f4d16c0](googleapis@f4d16c0))
* Enforce toolset/promptset boundary on tools/call and prompts/get
([googleapis#3036](googleapis#3036))
([c739b80](googleapis@c739b80))
* **tools/http:** Prevent path traversal and base path scope escape
([googleapis#3218](googleapis#3218))
([80a6602](googleapis@80a6602))
* **tools/looker:** Return a 401 error to MCP client when Looker returns
a 401 ([googleapis#3233](googleapis#3233))
([4f409a3](googleapis@4f409a3))
* **tools/looker:** Strip wrapping quotes from filter values for
unquoted parameters
([googleapis#3273](googleapis#3273))
([1e3de96](googleapis@1e3de96))
* **tools:** Initialize query result slices to empty array
([googleapis#3250](googleapis#3250))
([60ddf48](googleapis@60ddf48))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> b001006
github-actions Bot pushed a commit to rodineyw/mcp-toolbox that referenced this pull request May 21, 2026
🤖 I have created a release *beep* *boop*
---

##
[1.3.0](googleapis/mcp-toolbox@v1.2.0...v1.3.0)
(2026-05-21)

### Features

* **auth:** Implement MCP auth tool-level scopes validation
([googleapis#3049](googleapis#3049))
([c528985](googleapis@c528985))
* **looker:** Propagate client IP from incoming MCP requests to
downstream SDK calls
([googleapis#3253](googleapis#3253))
([75da6c2](googleapis@75da6c2))
* Setup SQLCommenter and allow client metadata
([googleapis#3064](googleapis#3064))
([9f1f9b3](googleapis@9f1f9b3))
* **tool/cloudsqladmin:** Add `cloud-sql-admin-execute-sql-many` and
`cloud-sql-admin-sql-many`
([googleapis#3083](googleapis#3083))
([ef300a8](googleapis@ef300a8))

### Bug Fixes

* **auth/generic:** Fix generic auth expiration field and integration
with `authRequired`
([googleapis#3251](googleapis#3251))
([f4d16c0](googleapis@f4d16c0))
* Enforce toolset/promptset boundary on tools/call and prompts/get
([googleapis#3036](googleapis#3036))
([c739b80](googleapis@c739b80))
* **tools/http:** Prevent path traversal and base path scope escape
([googleapis#3218](googleapis#3218))
([80a6602](googleapis@80a6602))
* **tools/looker:** Return a 401 error to MCP client when Looker returns
a 401 ([googleapis#3233](googleapis#3233))
([4f409a3](googleapis@4f409a3))
* **tools/looker:** Strip wrapping quotes from filter values for
unquoted parameters
([googleapis#3273](googleapis#3273))
([1e3de96](googleapis@1e3de96))
* **tools:** Initialize query result slices to empty array
([googleapis#3250](googleapis#3250))
([60ddf48](googleapis@60ddf48))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> b001006
github-actions Bot pushed a commit to Jaleel-zhu/genai-toolbox that referenced this pull request May 21, 2026
🤖 I have created a release *beep* *boop*
---

##
[1.3.0](googleapis/mcp-toolbox@v1.2.0...v1.3.0)
(2026-05-21)

### Features

* **auth:** Implement MCP auth tool-level scopes validation
([googleapis#3049](googleapis#3049))
([c528985](googleapis@c528985))
* **looker:** Propagate client IP from incoming MCP requests to
downstream SDK calls
([googleapis#3253](googleapis#3253))
([75da6c2](googleapis@75da6c2))
* Setup SQLCommenter and allow client metadata
([googleapis#3064](googleapis#3064))
([9f1f9b3](googleapis@9f1f9b3))
* **tool/cloudsqladmin:** Add `cloud-sql-admin-execute-sql-many` and
`cloud-sql-admin-sql-many`
([googleapis#3083](googleapis#3083))
([ef300a8](googleapis@ef300a8))

### Bug Fixes

* **auth/generic:** Fix generic auth expiration field and integration
with `authRequired`
([googleapis#3251](googleapis#3251))
([f4d16c0](googleapis@f4d16c0))
* Enforce toolset/promptset boundary on tools/call and prompts/get
([googleapis#3036](googleapis#3036))
([c739b80](googleapis@c739b80))
* **tools/http:** Prevent path traversal and base path scope escape
([googleapis#3218](googleapis#3218))
([80a6602](googleapis@80a6602))
* **tools/looker:** Return a 401 error to MCP client when Looker returns
a 401 ([googleapis#3233](googleapis#3233))
([4f409a3](googleapis@4f409a3))
* **tools/looker:** Strip wrapping quotes from filter values for
unquoted parameters
([googleapis#3273](googleapis#3273))
([1e3de96](googleapis@1e3de96))
* **tools:** Initialize query result slices to empty array
([googleapis#3250](googleapis#3250))
([60ddf48](googleapis@60ddf48))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> b001006
github-actions Bot pushed a commit to pepe57/genai-toolbox that referenced this pull request May 22, 2026
🤖 I have created a release *beep* *boop*
---

##
[1.3.0](googleapis/mcp-toolbox@v1.2.0...v1.3.0)
(2026-05-21)

### Features

* **auth:** Implement MCP auth tool-level scopes validation
([googleapis#3049](googleapis#3049))
([c528985](googleapis@c528985))
* **looker:** Propagate client IP from incoming MCP requests to
downstream SDK calls
([googleapis#3253](googleapis#3253))
([75da6c2](googleapis@75da6c2))
* Setup SQLCommenter and allow client metadata
([googleapis#3064](googleapis#3064))
([9f1f9b3](googleapis@9f1f9b3))
* **tool/cloudsqladmin:** Add `cloud-sql-admin-execute-sql-many` and
`cloud-sql-admin-sql-many`
([googleapis#3083](googleapis#3083))
([ef300a8](googleapis@ef300a8))

### Bug Fixes

* **auth/generic:** Fix generic auth expiration field and integration
with `authRequired`
([googleapis#3251](googleapis#3251))
([f4d16c0](googleapis@f4d16c0))
* Enforce toolset/promptset boundary on tools/call and prompts/get
([googleapis#3036](googleapis#3036))
([c739b80](googleapis@c739b80))
* **tools/http:** Prevent path traversal and base path scope escape
([googleapis#3218](googleapis#3218))
([80a6602](googleapis@80a6602))
* **tools/looker:** Return a 401 error to MCP client when Looker returns
a 401 ([googleapis#3233](googleapis#3233))
([4f409a3](googleapis@4f409a3))
* **tools/looker:** Strip wrapping quotes from filter values for
unquoted parameters
([googleapis#3273](googleapis#3273))
([1e3de96](googleapis@1e3de96))
* **tools:** Initialize query result slices to empty array
([googleapis#3250](googleapis#3250))
([60ddf48](googleapis@60ddf48))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> b001006
github-actions Bot pushed a commit to CrazyForks/genai-toolbox that referenced this pull request May 22, 2026
🤖 I have created a release *beep* *boop*
---

##
[1.3.0](googleapis/mcp-toolbox@v1.2.0...v1.3.0)
(2026-05-21)

### Features

* **auth:** Implement MCP auth tool-level scopes validation
([googleapis#3049](googleapis#3049))
([c528985](googleapis@c528985))
* **looker:** Propagate client IP from incoming MCP requests to
downstream SDK calls
([googleapis#3253](googleapis#3253))
([75da6c2](googleapis@75da6c2))
* Setup SQLCommenter and allow client metadata
([googleapis#3064](googleapis#3064))
([9f1f9b3](googleapis@9f1f9b3))
* **tool/cloudsqladmin:** Add `cloud-sql-admin-execute-sql-many` and
`cloud-sql-admin-sql-many`
([googleapis#3083](googleapis#3083))
([ef300a8](googleapis@ef300a8))

### Bug Fixes

* **auth/generic:** Fix generic auth expiration field and integration
with `authRequired`
([googleapis#3251](googleapis#3251))
([f4d16c0](googleapis@f4d16c0))
* Enforce toolset/promptset boundary on tools/call and prompts/get
([googleapis#3036](googleapis#3036))
([c739b80](googleapis@c739b80))
* **tools/http:** Prevent path traversal and base path scope escape
([googleapis#3218](googleapis#3218))
([80a6602](googleapis@80a6602))
* **tools/looker:** Return a 401 error to MCP client when Looker returns
a 401 ([googleapis#3233](googleapis#3233))
([4f409a3](googleapis@4f409a3))
* **tools/looker:** Strip wrapping quotes from filter values for
unquoted parameters
([googleapis#3273](googleapis#3273))
([1e3de96](googleapis@1e3de96))
* **tools:** Initialize query result slices to empty array
([googleapis#3250](googleapis#3250))
([60ddf48](googleapis@60ddf48))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> b001006
github-actions Bot pushed a commit to bhardwajRahul/genai-toolbox that referenced this pull request May 23, 2026
🤖 I have created a release *beep* *boop*
---

##
[1.3.0](googleapis/mcp-toolbox@v1.2.0...v1.3.0)
(2026-05-21)

### Features

* **auth:** Implement MCP auth tool-level scopes validation
([googleapis#3049](googleapis#3049))
([c528985](googleapis@c528985))
* **looker:** Propagate client IP from incoming MCP requests to
downstream SDK calls
([googleapis#3253](googleapis#3253))
([75da6c2](googleapis@75da6c2))
* Setup SQLCommenter and allow client metadata
([googleapis#3064](googleapis#3064))
([9f1f9b3](googleapis@9f1f9b3))
* **tool/cloudsqladmin:** Add `cloud-sql-admin-execute-sql-many` and
`cloud-sql-admin-sql-many`
([googleapis#3083](googleapis#3083))
([ef300a8](googleapis@ef300a8))

### Bug Fixes

* **auth/generic:** Fix generic auth expiration field and integration
with `authRequired`
([googleapis#3251](googleapis#3251))
([f4d16c0](googleapis@f4d16c0))
* Enforce toolset/promptset boundary on tools/call and prompts/get
([googleapis#3036](googleapis#3036))
([c739b80](googleapis@c739b80))
* **tools/http:** Prevent path traversal and base path scope escape
([googleapis#3218](googleapis#3218))
([80a6602](googleapis@80a6602))
* **tools/looker:** Return a 401 error to MCP client when Looker returns
a 401 ([googleapis#3233](googleapis#3233))
([4f409a3](googleapis@4f409a3))
* **tools/looker:** Strip wrapping quotes from filter values for
unquoted parameters
([googleapis#3273](googleapis#3273))
([1e3de96](googleapis@1e3de96))
* **tools:** Initialize query result slices to empty array
([googleapis#3250](googleapis#3250))
([60ddf48](googleapis@60ddf48))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> b001006
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.

3 participants