Skip to content

Commit 0291a91

Browse files
committed
fix: split mixed read write mcp tools
1 parent e9ab4bf commit 0291a91

164 files changed

Lines changed: 1572 additions & 1197 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.ci/publish_chart.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#!/usr/bin/env bash
2-
# Copyright 2024 StreamNative
2+
# Copyright 2026 StreamNative
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
66
# You may obtain a copy of the License at
77
#
8-
# http://www.apache.org/licenses/LICENSE-2.0
8+
# http://www.apache.org/licenses/LICENSE-2.0
99
#
1010
# Unless required by applicable law or agreed to in writing, software
1111
# distributed under the License is distributed on an "AS IS" BASIS,

.ci/release.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#!/usr/bin/env bash
2-
# Copyright 2024 StreamNative
2+
# Copyright 2026 StreamNative
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
66
# You may obtain a copy of the License at
77
#
8-
# http://www.apache.org/licenses/LICENSE-2.0
8+
# http://www.apache.org/licenses/LICENSE-2.0
99
#
1010
# Unless required by applicable law or agreed to in writing, software
1111
# distributed under the License is distributed on an "AS IS" BASIS,

.licenserc.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,9 @@ header:
3636
- '**/*.yml'
3737
- 'Makefile'
3838
- '.gitignore'
39+
- 'Dockerfile.goreleaser'
40+
- '**/.gitkeep'
41+
- 'charts/snmcp/e2e/test-secret.key'
42+
- 'charts/snmcp/templates/NOTES.txt'
3943

4044
comment: on-failure

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2025 StreamNative
1+
# Copyright 2026 StreamNative
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
1516
# Multi-stage build for multi-platform support
1617
FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS builder
1718

PLAN.md

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ Reference implementation checked:
3030

3131
## Current findings
3232

33+
Current follow-up focus: previous read/write split only separated tool names and operation enums in some builders. It still leaves mixed mode descriptions and write-only schema fields visible on read tools. Examples: `pkg/mcp/builders/kafka/topics.go` and `pkg/mcp/builders/pulsar/namespace.go`; same class can exist in other split builders. Connector review can still treat this as a mixed surface because `tools/list` exposes write verbs/examples/parameters through read tools.
34+
3335
Static `mcp.NewTool(...)` definitions found under `pkg/`: 36 tool definitions plus dynamic Pulsar Functions-as-Tools.
3436

3537
Current gaps:
@@ -39,6 +41,7 @@ Current gaps:
3941
- Only `sncloud_resources_apply` and `sncloud_resources_delete` currently set `WithToolAnnotation`; `apply` sets title only.
4042
- Dynamic Pulsar Functions-as-Tools in `pkg/mcp/pftools/manager.go` create tools without title/read-only/destructive annotations.
4143
- Many admin tools multiplex read and write operations through one `operation` parameter. Claude review criteria says mixed read/write catch-all tools can be rejected even if description documents safe/unsafe operations.
44+
- Some already-split tools still have mixed descriptions and schemas. Mode-specific enum is not enough; read tools must not expose write operations, examples, or write-only parameters.
4245

4346
## Proposed design
4447

@@ -48,7 +51,7 @@ Follow `mcp-auth0-proxy` pattern:
4851

4952
- split mixed tools into separate read and write tool names
5053
- keep shared internal implementation where practical
51-
- make operation enum mode-specific, so tool schema itself prevents mixed use
54+
- make operation enum, description, examples, and parameters mode-specific, so tool schema itself prevents mixed use
5255
- keep read-only runtime mode simple: register only read tools
5356
- in read-write runtime mode: register read tools and write tools as separate entries
5457
- do not expose legacy mixed tools in Claude-submitted surface
@@ -71,8 +74,8 @@ Pure write/side-effect tools can keep current names if description and annotatio
7174

7275
Compatibility policy:
7376

74-
- Recommended for Claude readiness: remove mixed legacy tool registration from default surface.
75-
- If backward compatibility is required, add opt-in legacy registration behind a feature/config flag and keep it disabled for connector submission.
77+
- Remove mixed legacy tool registration from default surface.
78+
- Do not add opt-in legacy aliases or compatibility flags for old mixed tool names.
7679
- Do not keep mixed legacy tools visible in submitted connector, even with destructive annotation.
7780

7881
### Shared helper APIs
@@ -101,6 +104,16 @@ Build functions should accept mode:
101104
- `validateOperation(mode, operation)`
102105
- `isWriteOperation(operation)`
103106

107+
Mode-specific tool builders should also split:
108+
109+
- `toolDesc`
110+
- `resourceDesc` when resource meanings differ by mode
111+
- `operationDesc`
112+
- `operationEnum`
113+
- parameter set (`mcp.WithString`, `mcp.WithNumber`, `mcp.WithObject`, etc.)
114+
115+
Read tools must not expose write-only fields. Write tools should not expose read-only-only fields unless a write operation genuinely needs them.
116+
104117
## Split inventory
105118

106119
### Kafka builders
@@ -394,18 +407,22 @@ Plan:
394407
- Add local read/write mode helpers in builders with mixed operations.
395408
- Add reusable operation validation helpers where a builder already has operation maps.
396409

397-
### Phase 2: split Kafka tools
410+
### Phase 2: split Kafka tools completely
398411

399-
- Update Kafka builders to build mode-specific tools.
412+
- Update all Kafka builders to build mode-specific tools.
413+
- Ensure read/write tools have mode-specific descriptions, examples, operation enums, and parameter schemas.
400414
- Read-only config returns only read tools.
401415
- Read-write config returns read + write tools, except pure write tools remain write-only.
416+
- Remove old mixed tool surface; no compatibility alias.
402417
- Update wrapper tests/docs.
403418

404-
### Phase 3: split Pulsar tools
419+
### Phase 3: split Pulsar tools completely
405420

406-
- Update Pulsar builders to build mode-specific tools.
421+
- Update all Pulsar builders to build mode-specific tools.
422+
- Ensure read/write tools have mode-specific descriptions, examples, operation enums, and parameter schemas.
407423
- Preserve existing read-only behavior by not registering write tools in read-only config.
408424
- Ensure mode-specific operation enums and validation errors.
425+
- Remove old mixed tool surface; no compatibility alias.
409426
- Add/extend parity tests for operation coverage.
410427

411428
### Phase 4: StreamNative Cloud/static tool annotations
@@ -419,19 +436,17 @@ Plan:
419436
- Add annotations to Functions-as-Tools.
420437
- Validate read-only exposure behavior.
421438

422-
### Phase 6: docs and compatibility
439+
### Phase 6: runtime-visible docs
423440

424-
Update runtime-visible docs:
441+
Update runtime-visible docs together with schema changes:
425442

426443
- `README.md` feature/tool examples if names change.
427444
- `docs/tools/*.md` matching renamed/split tools.
445+
- Split docs into explicit read/write sections where a family has both tool modes.
446+
- Ensure read docs do not mention write-only operations or parameters.
447+
- Ensure write docs do not rely on old mixed tool names.
428448
- Any design notes under `agents/` if tool surface changes are architectural.
429449

430-
Compatibility decision needed before implementation:
431-
432-
- Preferred: breaking but review-safe tool surface; remove mixed tool names.
433-
- Alternative: temporary alias support hidden behind explicit opt-in flag, disabled by default and not used for Claude submission.
434-
435450
## Tests / compliance guard
436451

437452
Add focused tests:
@@ -444,13 +459,17 @@ Add focused tests:
444459
- read tools: `ReadOnlyHint=true`, `DestructiveHint=false`
445460
- write tools: `DestructiveHint=true`, `ReadOnlyHint=false`
446461
- read-only config returns no write tools
462+
- read tools do not expose known write-only parameters
463+
- read tool descriptions do not mention known write-only operations, examples, or destructive verbs for that family
464+
- write tool schemas do not expose read-only-only parameters unless genuinely shared
447465
- StreamNative Cloud/context/log/resource tools have valid annotations.
448466
- PFTools dynamic tool creation has valid annotation.
449467
- Operation validation rejects read operations on write tools and write operations on read tools.
450468

451-
Optional static test:
469+
Static guard:
452470

453471
- Build all feature sets and assert no `operation` enum contains both read and write verbs in one tool.
472+
- For split tool families, assert mode-specific schema/description purity with family-specific allow/deny lists.
454473

455474
## Risks
456475

@@ -460,12 +479,12 @@ Optional static test:
460479
- Some current tools may have read-only-mode logic embedded in handlers; after split, registration and handler validation must both enforce mode to prevent write leakage.
461480
- `mcp-go` default annotations are unsafe for compliance because title empty and destructive default true.
462481

463-
## Questions to confirm
482+
## Confirmed decisions
464483

465-
1. Can we remove legacy mixed tool names from default registration, accepting breaking tool-name changes for Claude readiness?
466-
2. Should we add an opt-in legacy compatibility flag, disabled by default, or avoid compatibility layer entirely?
467-
3. For consume tools, should we conservatively classify as destructive, or implement a true non-mutating read variant first?
468-
4. Should session-only context changes (`sncloud_context_use_cluster/reset`) be marked destructive for Claude safety?
484+
- Fix all current mixed read/write surfaces, not only `kafka/topics.go` and `pulsar/namespace.go`.
485+
- Do not preserve old mixed tool names or old mixed builder/schema patterns.
486+
- Runtime-visible docs must be updated with read/write split and must avoid mixed read/write wording.
487+
- Conservative safety annotations are acceptable for ambiguous side-effect tools unless implementation proves true read-only behavior.
469488

470489
## Recommended validation
471490

charts/snmcp/e2e/test-tokens.env

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,16 @@
1+
# Copyright 2026 StreamNative
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
ADMIN_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjQxMDI0NDQ4MDAsImlhdCI6MTcwMDAwMDAwMCwic3ViIjoiYWRtaW4ifQ.fvMIzcCv16QvecEd8rJS6GZaJP_FeFw-XndtfRMfZyc
216
TEST_USER_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjQxMDI0NDQ4MDAsImlhdCI6MTcwMDAwMDAwMCwic3ViIjoidGVzdC11c2VyIn0.gv49qzkZrtc-6aXMGxSGFpRLk_C3pnFI4SprgewhN54

charts/snmcp/templates/_helpers.tpl

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
{{/*
2-
Copyright 2025 StreamNative
3-
SPDX-License-Identifier: Apache-2.0
2+
Copyright 2026 StreamNative
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
415
*/}}
516

617
{{/*

cmd/snmcp-e2e/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2025 StreamNative
1+
// Copyright 2026 StreamNative
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2026 StreamNative
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
class EchoFunction(object):
216
def process(self, input, context):
317
return input

cmd/streamnative-mcp-server/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2025 StreamNative
1+
// Copyright 2026 StreamNative
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.

0 commit comments

Comments
 (0)