feat(migrate): convert toolset to group kind during migration - #3704
Conversation
…ews (#3488) ## Description First slice of the toolsets→groups evolution. Introduces `internal/group` as the unified source of truth for a named collection of **tools and prompts**, without changing any existing behavior yet.
## Description
The MCP route is `/{toolsetName}`, so `promptsetName` was always empty
and `GetPromptset("")` returned every prompt regardless of which group
the client connected to. This fixes `prompts/list` (and `prompts/get`)
to scope prompts to the connected group by resolving the group from the
URL name and serving its derived promptset. `tools/list` is unchanged —
tools were already scoped by the toolset name.
### Old vs new response
Given two groups `docs` (prompt `summarize`) and `i18n` (prompt
`translate`), connected to `/mcp/docs`:
**`prompts/list`** request:
```json
{ "jsonrpc": "2.0", "id": 1, "method": "prompts/list" }
```
Old (bug — returns every prompt on the server):
```json
{ "jsonrpc": "2.0", "id": 1, "result": { "prompts": [
{ "name": "summarize", "description": "Summarize a document" },
{ "name": "translate", "description": "Translate text" }
] } }
```
New (scoped to the `docs` group):
```json
{ "jsonrpc": "2.0", "id": 1, "result": { "prompts": [
{ "name": "summarize", "description": "Summarize a document" }
] } }
```
**`prompts/get`** for a prompt in another group (`translate`, which
belongs to `i18n`):
Old (bug — succeeds, since the default all-prompts set was used):
```json
{ "jsonrpc": "2.0", "id": 2, "result": { "description": "Translate text", "messages": [ ... ] } }
```
New (correctly rejected):
```json
{ "jsonrpc": "2.0", "id": 2, "error": {
"code": -32602,
"message": "invalid prompt name: prompt with name \"translate\" does not exist"
} }
```
Stacked on #3575
---------
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
## Description
Adds two Toolbox methods for group introspection, implemented across all
five MCP protocol versions (v20241105, v20250326, v20250618, v20251125,
vdraft).
- **`groups/list`** — returns named groups (name + description). The
default nameless group is omitted and results are sorted by name.
- **`groups/get`** — returns a named group's tools and prompts. Unknown
names return `-32602` (INVALID_PARAMS); the default group is reachable
via an empty name.
### `groups/list`
Request:
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "groups/list"
}
```
Response:
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"groups": [
{ "name": "set_one" },
{ "name": "set_two" }
]
}
}
```
### `groups/get`
Request:
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "groups/get",
"params": { "name": "set_two" }
}
```
Response:
```json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"name": "set_two",
"tools": [
{
"name": "tool_b",
"description": "Tool B does B.",
"inputSchema": { "type": "object", "properties": {}, "required": [] }
},
{
"name": "tool_a",
"description": "Tool A does A.",
"inputSchema": { "type": "object", "properties": {}, "required": [] }
}
],
"prompts": []
}
}
```
Unknown group:
```json
{
"jsonrpc": "2.0",
"id": 3,
"method": "groups/get",
"params": { "name": "nope" }
}
```
```json
{
"jsonrpc": "2.0",
"id": 3,
"error": {
"code": -32602,
"message": "invalid group name: group with name \"nope\" does not exist"
}
}
```
Stacked on #3576
---------
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
Stacked on #3575 --------- Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
# Conflicts: # cmd/internal/config.go # cmd/internal/invoke/command.go # cmd/internal/skills/command.go # cmd/root.go # internal/server/api.go # internal/server/common_test.go # internal/server/config.go # internal/server/mcp.go # internal/server/mcp/mcp.go # internal/server/mcp/v20241105/method.go # internal/server/mcp/v20241105/method_test.go # internal/server/mcp/v20250326/method.go # internal/server/mcp/v20250326/method_test.go # internal/server/mcp/v20250618/method.go # internal/server/mcp/v20250618/method_test.go # internal/server/mcp/v20251125/method.go # internal/server/mcp/v20251125/method_test.go # internal/server/mcp/vdraft/method.go # internal/server/mcp/vdraft/method_test.go # internal/server/mcp_test.go # internal/server/primitives/primitives.go # internal/server/primitives/primitives_test.go # internal/server/server.go # internal/server/server_test.go # internal/tools/cloudgda/cloudgda_test.go
…ip (#3629) Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
## Description Reinstates the `(!present || rawName == nil)` guard in `UnmarshalResourceConfig` that was accidentally dropped during the merge of the groups stack into `feat/groups`. Without the guard, a config like: ```yaml kind: group name: 123 ``` would silently default to the empty (default) group instead of returning a parse error. Deeven Seru flagged this in the review of #3575. The fix ensures non-string name values (`name: 123`, `name: true`) are rejected with `"missing 'name' field or it is not a string"`, while legitimately absent or null names are still accepted as the default group. Adds regression tests to `TestParseConfigGroupNameValidation` covering all four cases.
## Description Follow-up to #3575 Previously only `kind: group` rejected duplicate names. Every other resource kind — `source`, `authService`, `tool`, `toolset`, `embeddingModel`, and `prompt` silently kept the *last* declaration when a name was reused within a config, so a duplicated resource would be dropped with no error. This makes duplicate detection uniform: `UnmarshalResourceConfig` now returns `"<kind> %q declared more than once"` for any repeated name, matching the behavior already in place for groups. Stacked on top of #3575 Fixed #3648 --------- Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
## Description Follow-up to #3583, adding the telemetry that was deferred out of the introspection PR to keep it focused. This mirrors the existing `prompts/get` instrumentation for `groups/get` across all five MCP version packages (`v20241105`, `v20250326`, `v20250618`, `v20251125`, `vdraft`) --------- Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
## Description Stacked on top of #3605. The prompts coverage check in #3605 fails at **69.2%** (needs **80%**). Investigating why turned up the real cause: the `prompts.Promptset` layer is **dead code**. Groups are the source of truth for prompt scoping. `prompts/list` and `prompts/get` resolve entirely from `group.Group` (`GenerateListPromptsResult` and `group.ContainsPrompt`). `PrimitiveManager.GetPromptset` — the only caller of `prompts.Promptset.Initialize` — has no production caller itself, so `Promptset` / `PromptsetConfig` / `PromptsetManifest` and `GetPromptset` are never used. Rather than add tests for unreachable code to satisfy the gate, this PR removes the orphaned layer: - `internal/prompts/promptsets.go` (+ its unit test) - `PrimitiveManager.GetPromptset` - the promptset scaffolding in `testutils.SetUpResources` and the two server tests Dropping the uncovered promptset statements brings `./internal/prompts/...` coverage to **84.0%**, clearing the gate with no new tests. **Groups still contain prompts** — this only removes the unused parallel view; `group.Group.PromptNames` / `ContainsPrompt` and the MCP prompt handlers are unchanged.
## Description Stacked on top of #3641. Companion cleanup to the promptset removal. `PrimitiveManager.GetToolset` is the toolset twin of the `GetPromptset` dead code removed in #3641 — and it is equally orphaned. Groups are the source of truth for named collections. The REST `/toolset/{name}` path renders directly from `group.Group.ToolsetManifest`, and MCP tool listing resolves from `group.Group.ToolNames` / `ContainsTool`. Nothing in production calls `GetToolset`, so the "materialize a `tools.Toolset` view from the group on demand" helper is never reached. This PR removes the orphaned method and its now-dangling test assertions.
# Conflicts: # internal/server/mcp/vdraft/method_test.go # internal/server/server.go
…gated extension release (#3670) ## Description Makes `groups/list` / `groups/get` unreachable in `feat/groups` so groups ships as Part A only (scoping). These methods must be gated behind the `com.google.cloud/toolbox` extension; shipping them reachable now and gating later would be a breaking change. Removes only the `case GROUPS_LIST` / `case GROUPS_GET` dispatch arms in `ProcessMethod` across all 5 MCP versions (methods now return `METHOD_NOT_FOUND`). All other Part B code — types, handlers, manifests, telemetry, tests — is retained and still unit-tested. Re-enabling later = re-add the arms alongside the gate. Also trims the docs describing these methods.
The migrate command now rewrites toolsets to groups for both nested and already-flat inputs. The conversion is opt-in via a ConvertConfig flag so the runtime parse path leaves toolsets untouched.
There was a problem hiding this comment.
Code Review
This pull request introduces support for migrating toolsets to groups during configuration migration. It updates the ConvertConfig function to accept a migrateToolset boolean flag, which, when enabled, rewrites both nested and flat toolset configurations to the group kind. The migrate command has been updated to pass true for this flag, and comprehensive unit and integration tests have been added to verify the migration behavior. There are no review comments, so I have no additional feedback to provide.
Add a migrate subcommand entry to the CLI reference and a migration note to the groups doc pointing users to toolbox migrate.
The runtime already folds every kind: toolset into a group config, so gating the rewrite behind a flag only preserved two ways the toolset path was looser: unknown fields were silently dropped, and a toolset/group name clash warned instead of erroring. Both now behave like groups. A toolset has no description of its own -- UnmarshalYAMLToolsetConfig keeps only the tools list -- so a description on one is dropped on conversion rather than promoted, which would otherwise publish a description for a collection that never declared one.
Both collections carry a description, but a kind: toolset has no description field -- UnmarshalYAMLToolsetConfig keeps only the tools list -- so the text was parsed and silently discarded. Declaring them as kind: group makes the descriptions reach clients.
A description written on a nested map-form toolset bypassed the strip and was promoted onto the resulting group. Drop it on that path too, warn on both, and stop mutating the caller's MapSlice while rewriting the kind. Correct the docs that claimed toolsets keep working unchanged: they are now parsed as groups, so descriptions are dropped, unknown fields are rejected, and a toolset/group name clash is a duplicate-name error.
The rewrite lived in two places — the nested switch and a flat-only helper — so the two spellings could drift, and they did. Flatten first and emit kind: toolset as before, then rewrite to group on every doc once it is flat. transformDocs and processValue return to their original form, leaving the shared nested-to-flat path untouched by this change.
The multi-kind nested cases already assert that toolsets emit as groups alongside every other kind, and the description-drop cases already cover the plain rewrite. Fold the two end-to-end migrate tests into one that exercises all three toolset spellings. Also drop the cli.md migrate reference: it documents flags and behavior that predate this change.
|
Hi @Yuan325 The previous version rewrote the toolset kind in two places: once for nested input, once for already-flat docs. I realised it makes more sense to have two sequential passes instead of one forked pass: transformDocs flattens nested input exactly as before and still emits kind: toolset, then migrateToolsetKind rewrites the kind on every doc once it's flat. Both shapes converge on a single function. This seems to have made the code changes simpler and more robust. Let me know what you think! |
Yuan325
left a comment
There was a problem hiding this comment.
LGTM, feel free to merge after resolving the comments :)
Index name alongside kind and description in the pass that already runs, rewrite the kind through kindIndex instead of a second loop, and drop mapSliceString and warnDescriptionDropped, which each had a single caller. The copy of the input doc is kept, now as slices.Clone: ConvertConfig passes the slice it is still ranging over, so deleting the description in place would shift a zeroed element under that loop.
|
🧨 Preview deployments removed. Cloudflare Pages environments for |
…#3704) ## Description Parsing a toolset as a group is stricter than the old toolset path, so three behaviors change: - A `description` on a toolset is **dropped** with a warning: a toolset has no description of its own, so promoting one would publish a description the collection never declared. Use `kind: group` to keep it. - Unknown fields are **rejected** at startup rather than silently ignored. - A `kind: toolset` and `kind: group` sharing a name is a **duplicate-name error**; it used to warn and let the group win. Docs under `configuration/groups/` and `configuration/toolsets/` said toolsets need "no migration", and now list these three changes. Stacked on #3764, which converts the two cloud-storage toolsets carrying descriptions so those descriptions apply rather than being dropped by the rule above. --------- Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> 0adeaa5
…googleapis#3704) ## Description Parsing a toolset as a group is stricter than the old toolset path, so three behaviors change: - A `description` on a toolset is **dropped** with a warning: a toolset has no description of its own, so promoting one would publish a description the collection never declared. Use `kind: group` to keep it. - Unknown fields are **rejected** at startup rather than silently ignored. - A `kind: toolset` and `kind: group` sharing a name is a **duplicate-name error**; it used to warn and let the group win. Docs under `configuration/groups/` and `configuration/toolsets/` said toolsets need "no migration", and now list these three changes. Stacked on googleapis#3764, which converts the two cloud-storage toolsets carrying descriptions so those descriptions apply rather than being dropped by the rule above. --------- Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> 0adeaa5
…googleapis#3704) ## Description Parsing a toolset as a group is stricter than the old toolset path, so three behaviors change: - A `description` on a toolset is **dropped** with a warning: a toolset has no description of its own, so promoting one would publish a description the collection never declared. Use `kind: group` to keep it. - Unknown fields are **rejected** at startup rather than silently ignored. - A `kind: toolset` and `kind: group` sharing a name is a **duplicate-name error**; it used to warn and let the group win. Docs under `configuration/groups/` and `configuration/toolsets/` said toolsets need "no migration", and now list these three changes. Stacked on googleapis#3764, which converts the two cloud-storage toolsets carrying descriptions so those descriptions apply rather than being dropped by the rule above. --------- Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> 0adeaa5
🤖 I have created a release *beep* *boop* --- ## [1.9.0](v1.8.0...v1.9.0) (2026-08-14) ### Features * **groups:** Add ttlMs and cacheScope customization to config ([#3805](#3805)) ([a5d4947](a5d4947)) * **migrate:** Convert toolset to group kind during migration ([#3704](#3704)) ([0adeaa5](0adeaa5)) * **server/mcp:** Introduce generic client extension registry ([#3723](#3723)) ([016245c](016245c)) * **skill:** Add review-prs skill for mcp-toolbox ([#3743](#3743)) ([5b7bacc](5b7bacc)) * **source/bigquery:** Add apiEndpoint field to override BigQuery API host ([#3437](#3437)) ([4da1600](4da1600)) * **source/databaseinsights:** Add databaseinsights source ([#3461](#3461)) ([3b9615d](3b9615d)) * **sources/spanner:** Rename execute_sql_dql to execute_sql_readonly ([#3776](#3776)) ([cf5a0c8](cf5a0c8)) * **tools/bigtable:** Add admin lifecycle and listing tools ([#3596](#3596)) ([801d589](801d589)) * **tools/bigtable:** Bigtable-list-schemas MCP tool ([#3683](#3683)) ([9228c61](9228c61)) * **tools/databaseinsights:** Add Advanced Query Insights tools for AlloyDB ([#3722](#3722)) ([74d18ae](74d18ae)) * **tools/looker:** Add additional tools to allow dashboards to be modified, and their layouts altered. ([#3597](#3597)) ([b2b80fb](b2b80fb)) * **tools:** Add cloud-sql-connect-gce for pg, mysql, mssql ([#3740](#3740)) ([ca58fa4](ca58fa4)) ### Bug Fixes * **auth/mcp:** Derive PRM URL from Toolbox URL ([#3765](#3765)) ([aa30842](aa30842)) * **config:** Ignore environment variables in YAML comments ([#3807](#3807)) ([79aa732](79aa732)), refs [#3793](#3793) * **mcp:** Return Tool execution error for invalid input param ([#3799](#3799)) ([8120197](8120197)) * **prebuilt/cloud-storage:** Declare tool collections as groups ([#3764](#3764)) ([7d468be](7d468be)) * **server/mcp:** Disallow client overriding URL bound parameters ([#3798](#3798)) ([f15a9c7](f15a9c7)) * **server:** Avoid a nil-flusher panic in the SSE handler ([#3520](#3520)) ([947f42f](947f42f)) * **tools/bigquery:** Keep the provider error classification in bigquery-execute-sql ([#3738](#3738)) ([42570b8](42570b8)) * **tools/looker:** Scope the filters quoting rule to values in query description ([#3788](#3788)) ([78eb0b8](78eb0b8)) * **util:** Convert exponent-form JSON numbers in ConvertNumbers ([#3730](#3730)) ([e9713ee](e9713ee)) --- 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>
🤖 I have created a release *beep* *boop* --- ## [1.9.0](v1.8.0...v1.9.0) (2026-08-14) ### Features * **groups:** Add ttlMs and cacheScope customization to config ([#3805](#3805)) ([a5d4947](a5d4947)) * **migrate:** Convert toolset to group kind during migration ([#3704](#3704)) ([0adeaa5](0adeaa5)) * **server/mcp:** Introduce generic client extension registry ([#3723](#3723)) ([016245c](016245c)) * **skill:** Add review-prs skill for mcp-toolbox ([#3743](#3743)) ([5b7bacc](5b7bacc)) * **source/bigquery:** Add apiEndpoint field to override BigQuery API host ([#3437](#3437)) ([4da1600](4da1600)) * **source/databaseinsights:** Add databaseinsights source ([#3461](#3461)) ([3b9615d](3b9615d)) * **sources/spanner:** Rename execute_sql_dql to execute_sql_readonly ([#3776](#3776)) ([cf5a0c8](cf5a0c8)) * **tools/bigtable:** Add admin lifecycle and listing tools ([#3596](#3596)) ([801d589](801d589)) * **tools/bigtable:** Bigtable-list-schemas MCP tool ([#3683](#3683)) ([9228c61](9228c61)) * **tools/databaseinsights:** Add Advanced Query Insights tools for AlloyDB ([#3722](#3722)) ([74d18ae](74d18ae)) * **tools/looker:** Add additional tools to allow dashboards to be modified, and their layouts altered. ([#3597](#3597)) ([b2b80fb](b2b80fb)) * **tools:** Add cloud-sql-connect-gce for pg, mysql, mssql ([#3740](#3740)) ([ca58fa4](ca58fa4)) ### Bug Fixes * **auth/mcp:** Derive PRM URL from Toolbox URL ([#3765](#3765)) ([aa30842](aa30842)) * **config:** Ignore environment variables in YAML comments ([#3807](#3807)) ([79aa732](79aa732)), refs [#3793](#3793) * **mcp:** Return Tool execution error for invalid input param ([#3799](#3799)) ([8120197](8120197)) * **prebuilt/cloud-storage:** Declare tool collections as groups ([#3764](#3764)) ([7d468be](7d468be)) * **server/mcp:** Disallow client overriding URL bound parameters ([#3798](#3798)) ([f15a9c7](f15a9c7)) * **server:** Avoid a nil-flusher panic in the SSE handler ([#3520](#3520)) ([947f42f](947f42f)) * **tools/bigquery:** Keep the provider error classification in bigquery-execute-sql ([#3738](#3738)) ([42570b8](42570b8)) * **tools/looker:** Scope the filters quoting rule to values in query description ([#3788](#3788)) ([78eb0b8](78eb0b8)) * **util:** Convert exponent-form JSON numbers in ConvertNumbers ([#3730](#3730)) ([e9713ee](e9713ee)) --- 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> 5de8f13
🤖 I have created a release *beep* *boop* --- ## [1.9.0](googleapis/mcp-toolbox@v1.8.0...v1.9.0) (2026-08-14) ### Features * **groups:** Add ttlMs and cacheScope customization to config ([googleapis#3805](googleapis#3805)) ([a5d4947](googleapis@a5d4947)) * **migrate:** Convert toolset to group kind during migration ([googleapis#3704](googleapis#3704)) ([0adeaa5](googleapis@0adeaa5)) * **server/mcp:** Introduce generic client extension registry ([googleapis#3723](googleapis#3723)) ([016245c](googleapis@016245c)) * **skill:** Add review-prs skill for mcp-toolbox ([googleapis#3743](googleapis#3743)) ([5b7bacc](googleapis@5b7bacc)) * **source/bigquery:** Add apiEndpoint field to override BigQuery API host ([googleapis#3437](googleapis#3437)) ([4da1600](googleapis@4da1600)) * **source/databaseinsights:** Add databaseinsights source ([googleapis#3461](googleapis#3461)) ([3b9615d](googleapis@3b9615d)) * **sources/spanner:** Rename execute_sql_dql to execute_sql_readonly ([googleapis#3776](googleapis#3776)) ([cf5a0c8](googleapis@cf5a0c8)) * **tools/bigtable:** Add admin lifecycle and listing tools ([googleapis#3596](googleapis#3596)) ([801d589](googleapis@801d589)) * **tools/bigtable:** Bigtable-list-schemas MCP tool ([googleapis#3683](googleapis#3683)) ([9228c61](googleapis@9228c61)) * **tools/databaseinsights:** Add Advanced Query Insights tools for AlloyDB ([googleapis#3722](googleapis#3722)) ([74d18ae](googleapis@74d18ae)) * **tools/looker:** Add additional tools to allow dashboards to be modified, and their layouts altered. ([googleapis#3597](googleapis#3597)) ([b2b80fb](googleapis@b2b80fb)) * **tools:** Add cloud-sql-connect-gce for pg, mysql, mssql ([googleapis#3740](googleapis#3740)) ([ca58fa4](googleapis@ca58fa4)) ### Bug Fixes * **auth/mcp:** Derive PRM URL from Toolbox URL ([googleapis#3765](googleapis#3765)) ([aa30842](googleapis@aa30842)) * **config:** Ignore environment variables in YAML comments ([googleapis#3807](googleapis#3807)) ([79aa732](googleapis@79aa732)), refs [googleapis#3793](googleapis#3793) * **mcp:** Return Tool execution error for invalid input param ([googleapis#3799](googleapis#3799)) ([8120197](googleapis@8120197)) * **prebuilt/cloud-storage:** Declare tool collections as groups ([googleapis#3764](googleapis#3764)) ([7d468be](googleapis@7d468be)) * **server/mcp:** Disallow client overriding URL bound parameters ([googleapis#3798](googleapis#3798)) ([f15a9c7](googleapis@f15a9c7)) * **server:** Avoid a nil-flusher panic in the SSE handler ([googleapis#3520](googleapis#3520)) ([947f42f](googleapis@947f42f)) * **tools/bigquery:** Keep the provider error classification in bigquery-execute-sql ([googleapis#3738](googleapis#3738)) ([42570b8](googleapis@42570b8)) * **tools/looker:** Scope the filters quoting rule to values in query description ([googleapis#3788](googleapis#3788)) ([78eb0b8](googleapis@78eb0b8)) * **util:** Convert exponent-form JSON numbers in ConvertNumbers ([googleapis#3730](googleapis#3730)) ([e9713ee](googleapis@e9713ee)) --- 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> 5de8f13
🤖 I have created a release *beep* *boop* --- ## [1.9.0](googleapis/mcp-toolbox@v1.8.0...v1.9.0) (2026-08-14) ### Features * **groups:** Add ttlMs and cacheScope customization to config ([googleapis#3805](googleapis#3805)) ([a5d4947](googleapis@a5d4947)) * **migrate:** Convert toolset to group kind during migration ([googleapis#3704](googleapis#3704)) ([0adeaa5](googleapis@0adeaa5)) * **server/mcp:** Introduce generic client extension registry ([googleapis#3723](googleapis#3723)) ([016245c](googleapis@016245c)) * **skill:** Add review-prs skill for mcp-toolbox ([googleapis#3743](googleapis#3743)) ([5b7bacc](googleapis@5b7bacc)) * **source/bigquery:** Add apiEndpoint field to override BigQuery API host ([googleapis#3437](googleapis#3437)) ([4da1600](googleapis@4da1600)) * **source/databaseinsights:** Add databaseinsights source ([googleapis#3461](googleapis#3461)) ([3b9615d](googleapis@3b9615d)) * **sources/spanner:** Rename execute_sql_dql to execute_sql_readonly ([googleapis#3776](googleapis#3776)) ([cf5a0c8](googleapis@cf5a0c8)) * **tools/bigtable:** Add admin lifecycle and listing tools ([googleapis#3596](googleapis#3596)) ([801d589](googleapis@801d589)) * **tools/bigtable:** Bigtable-list-schemas MCP tool ([googleapis#3683](googleapis#3683)) ([9228c61](googleapis@9228c61)) * **tools/databaseinsights:** Add Advanced Query Insights tools for AlloyDB ([googleapis#3722](googleapis#3722)) ([74d18ae](googleapis@74d18ae)) * **tools/looker:** Add additional tools to allow dashboards to be modified, and their layouts altered. ([googleapis#3597](googleapis#3597)) ([b2b80fb](googleapis@b2b80fb)) * **tools:** Add cloud-sql-connect-gce for pg, mysql, mssql ([googleapis#3740](googleapis#3740)) ([ca58fa4](googleapis@ca58fa4)) ### Bug Fixes * **auth/mcp:** Derive PRM URL from Toolbox URL ([googleapis#3765](googleapis#3765)) ([aa30842](googleapis@aa30842)) * **config:** Ignore environment variables in YAML comments ([googleapis#3807](googleapis#3807)) ([79aa732](googleapis@79aa732)), refs [googleapis#3793](googleapis#3793) * **mcp:** Return Tool execution error for invalid input param ([googleapis#3799](googleapis#3799)) ([8120197](googleapis@8120197)) * **prebuilt/cloud-storage:** Declare tool collections as groups ([googleapis#3764](googleapis#3764)) ([7d468be](googleapis@7d468be)) * **server/mcp:** Disallow client overriding URL bound parameters ([googleapis#3798](googleapis#3798)) ([f15a9c7](googleapis@f15a9c7)) * **server:** Avoid a nil-flusher panic in the SSE handler ([googleapis#3520](googleapis#3520)) ([947f42f](googleapis@947f42f)) * **tools/bigquery:** Keep the provider error classification in bigquery-execute-sql ([googleapis#3738](googleapis#3738)) ([42570b8](googleapis@42570b8)) * **tools/looker:** Scope the filters quoting rule to values in query description ([googleapis#3788](googleapis#3788)) ([78eb0b8](googleapis@78eb0b8)) * **util:** Convert exponent-form JSON numbers in ConvertNumbers ([googleapis#3730](googleapis#3730)) ([e9713ee](googleapis@e9713ee)) --- 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> 5de8f13
🤖 I have created a release *beep* *boop* --- ## [1.9.0](googleapis/mcp-toolbox@v1.8.0...v1.9.0) (2026-08-14) ### Features * **groups:** Add ttlMs and cacheScope customization to config ([googleapis#3805](googleapis#3805)) ([a5d4947](googleapis@a5d4947)) * **migrate:** Convert toolset to group kind during migration ([googleapis#3704](googleapis#3704)) ([0adeaa5](googleapis@0adeaa5)) * **server/mcp:** Introduce generic client extension registry ([googleapis#3723](googleapis#3723)) ([016245c](googleapis@016245c)) * **skill:** Add review-prs skill for mcp-toolbox ([googleapis#3743](googleapis#3743)) ([5b7bacc](googleapis@5b7bacc)) * **source/bigquery:** Add apiEndpoint field to override BigQuery API host ([googleapis#3437](googleapis#3437)) ([4da1600](googleapis@4da1600)) * **source/databaseinsights:** Add databaseinsights source ([googleapis#3461](googleapis#3461)) ([3b9615d](googleapis@3b9615d)) * **sources/spanner:** Rename execute_sql_dql to execute_sql_readonly ([googleapis#3776](googleapis#3776)) ([cf5a0c8](googleapis@cf5a0c8)) * **tools/bigtable:** Add admin lifecycle and listing tools ([googleapis#3596](googleapis#3596)) ([801d589](googleapis@801d589)) * **tools/bigtable:** Bigtable-list-schemas MCP tool ([googleapis#3683](googleapis#3683)) ([9228c61](googleapis@9228c61)) * **tools/databaseinsights:** Add Advanced Query Insights tools for AlloyDB ([googleapis#3722](googleapis#3722)) ([74d18ae](googleapis@74d18ae)) * **tools/looker:** Add additional tools to allow dashboards to be modified, and their layouts altered. ([googleapis#3597](googleapis#3597)) ([b2b80fb](googleapis@b2b80fb)) * **tools:** Add cloud-sql-connect-gce for pg, mysql, mssql ([googleapis#3740](googleapis#3740)) ([ca58fa4](googleapis@ca58fa4)) ### Bug Fixes * **auth/mcp:** Derive PRM URL from Toolbox URL ([googleapis#3765](googleapis#3765)) ([aa30842](googleapis@aa30842)) * **config:** Ignore environment variables in YAML comments ([googleapis#3807](googleapis#3807)) ([79aa732](googleapis@79aa732)), refs [googleapis#3793](googleapis#3793) * **mcp:** Return Tool execution error for invalid input param ([googleapis#3799](googleapis#3799)) ([8120197](googleapis@8120197)) * **prebuilt/cloud-storage:** Declare tool collections as groups ([googleapis#3764](googleapis#3764)) ([7d468be](googleapis@7d468be)) * **server/mcp:** Disallow client overriding URL bound parameters ([googleapis#3798](googleapis#3798)) ([f15a9c7](googleapis@f15a9c7)) * **server:** Avoid a nil-flusher panic in the SSE handler ([googleapis#3520](googleapis#3520)) ([947f42f](googleapis@947f42f)) * **tools/bigquery:** Keep the provider error classification in bigquery-execute-sql ([googleapis#3738](googleapis#3738)) ([42570b8](googleapis@42570b8)) * **tools/looker:** Scope the filters quoting rule to values in query description ([googleapis#3788](googleapis#3788)) ([78eb0b8](googleapis@78eb0b8)) * **util:** Convert exponent-form JSON numbers in ConvertNumbers ([googleapis#3730](googleapis#3730)) ([e9713ee](googleapis@e9713ee)) --- 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> 5de8f13
Description
Parsing a toolset as a group is stricter than the old toolset path, so three behaviors change:
descriptionon a toolset is dropped with a warning: a toolset has no description of its own, so promoting one would publish a description the collection never declared. Usekind: groupto keep it.kind: toolsetandkind: groupsharing a name is a duplicate-name error; it used to warn and let the group win.Docs under
configuration/groups/andconfiguration/toolsets/said toolsets need "no migration", and now list these three changes.Stacked on #3764, which converts the two cloud-storage toolsets carrying descriptions so those descriptions apply rather than being dropped by the rule above.