fix(langgraph): stop concatenating getServerName()+getName() into connectorType#198
Conversation
…nectorType
LangGraphAdapter.mcpToolInterceptor() derived a single connectorType as
"{serverName}.{toolName}" because the MCP check-input/check-output wire
contract only had one identity field. The platform now accepts a
separate `tool` field alongside `connector_type` (epic #2905, #2904),
so thread server and tool identity through as two distinct fields
instead of collapsing them into one opaque string.
- MCPCheckInputRequest / MCPCheckOutputRequest gain an optional `tool`
field (sdk_only pending platform-spec sync, tracked in the wire-shape
baseline like `content_type` before it).
- AxonFlow.mcpCheckInput/mcpCheckOutput read "tool" out of the options
map and forward it on the wire.
- MCPInterceptorOptions gains a toolFn alongside connectorTypeFn.
- LangGraphAdapter.mcpToolInterceptor() now defaults connectorType to
MCPToolRequest::getServerName and tool to MCPToolRequest::getName,
in both the custom-options and default branches.
- Add runtime-e2e/mcp_server_tool_split/, run against a live agent:
proves the interceptor's split server+tool identity round-trips
through check-input/check-output, a direct mcpCheckInput call with an
explicit "tool" option is accepted, and the pre-#2909 two-argument
mcpCheckInput(connectorType, statement) overload still works
unchanged.
Refs #2909, epic #2905.
Signed-off-by: Gregory Zak <gzak@getaxonflow.com>
42d4af6 to
95cfad6
Compare
|
R3 review (master + independent hostile pass). Verdict: MERGEABLE with conditions. CI green; additive constructors preserve the public API; Jackson NON_NULL omission + two-field serialization pinned in MoreTypesTest; WireMock pins the wire body on both endpoints; adapter tests cover default/custom connectorTypeFn/custom toolFn. MEDIUM —
|
|
Delta note — semver classification (net-new, decision-forcing). This de-concatenation changes the wire value of Honest call: this warrants a MAJOR SDK bump (SDK semver is decoupled from the platform, so the platform stays on its own track). The (All prior-round findings on this PR are still open at the current head — no post-review commits landed.) |
Apply epic #2905 RULING 3 and mark the de-concatenation as a BREAKING change:
- RULING 3: DROP the Java-only MCPInterceptorOptions.toolFn. The tool identity
is always MCPToolRequest#getName(); connectorTypeFn remains the escape hatch
for the server/connector dimension only. A separate tool-identity override
let a caller write an arbitrary identity into the audit trail (integrity
foot-gun) and had no analog in the py/ts/go adapters. Removed the field,
getter, builder method, and constructor param; the shouldUseCustomToolFn
test is replaced with one asserting the tool name is always getName().
- Fix the MCPCheckOutputRequest.tool javadoc overclaim ("mirrored on
check-output" implied server-side consumption): check-output has NO tool
field on any released version (tracked by #2955). Also pin check-input Tool
consumption to v9.10.0+.
- Add the missing-server edge test: empty serverName -> connector_type=""
-> platform 400 -> fail-closed; wire body pinned.
- Changelog: move the entry to a new "Changed (BREAKING)" section, require a
major SDK bump, add the policy re-scope note, the missing-server edge, and
the platform-version pins; drop the stale "gains a toolFn" line.
Refs #2909, epic #2905.
Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
The prior commit's wire-shape validate run left a scripts/wire_shape/ __pycache__/*.pyc build artifact staged. Remove it and add __pycache__/ + *.pyc to .gitignore so it cannot recur. Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
…rver-tool-split Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> # Conflicts: # CHANGELOG.md
|
Follow-up commits (WS-DECONCAT): applied epic #2905 RULING 3 — DROPPED the Java-only |
|
Master independent R3: CLEAR-FOR-SET (code). Two-field split coherent with the other SDKs ( RULING 3 verified: no residual |
Bump pom.xml to 9.0.0 and finalize the tool-identity content under ## [9.0.0] - 2026-07-18 (banner + internal sweep intro dropped). Changelog scrubbed of internal issue/PR numbers and internal review terminology; minimum platform stated as versions (check-input tool = platform v9.10.0+, response-plane tool = platform v9.11.0+). Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
|
Release-ready follow-up: bumped the version to 9.0.0 and finalized the tool-identity content under a real |
|
Master re-R3 of the v9.0.0 finalize delta: CLEAR-FOR-SET. Version file 8.5.1 → 9.0.0; correct Keep-a-Changelog shape (empty Scrub also removed a leaked partner name (BukuWarung) from the public changelog, plus the enterprise/RULING refs. py#217 companion note: RULING-1 body rewrite confirmed on that PR. |
Summary
LangGraphAdapter.mcpToolInterceptor()derived a singleconnectorTypeas"{serverName}.{toolName}"because the MCPcheck-input/check-outputwire contract only had one identity field to put it in. The platform has since finalized a genuine two-field(server, tool)identity contract for that request (epic #2905, sub-issue #2904 — R3-approved, CI-green, schema finalized though not yet merged toaxonflow-enterprise): a new optionaltoolfield alongside the existingconnector_type.This PR threads server and tool identity through as two separate fields instead of collapsing them into one opaque string, in both branches of
mcpToolInterceptor(options)(default and caller-suppliedMCPInterceptorOptions).Changes
MCPCheckInputRequest/MCPCheckOutputRequest: add an optionaltoolfield (@JsonProperty("tool")), with new all-args constructors; existing constructors are preserved and defaulttooltonullfor backward compatibility.AxonFlow.mcpCheckInput/mcpCheckOutput: read a new"tool"key out of the existingoptionsmap and forward it on the wire alongsideconnectorType.MCPInterceptorOptions: adds atoolFn(Function<MCPToolRequest, String>) alongside the existingconnectorTypeFn, so callers can customize tool-name derivation independently of connector-type derivation.MCPToolInterceptor: now takes both aconnectorTypeFnand atoolFn; sendstoolin the options map passed tomcpCheckInput/mcpCheckOutputfor both the pre-check and post-check calls.LangGraphAdapter.mcpToolInterceptor(options): defaultconnectorTypeFnis nowMCPToolRequest::getServerName(wasserverName + "." + name), defaulttoolFnisMCPToolRequest::getName. Applied in both theoptions != nullandoptions == nullbranches — same root cause, same fix.tests/fixtures/wire-shape-baseline.json: regenerated viascripts/wire_shape/refresh.pyagainst the pinned OpenAPI spec commit. The newtoolfield shows up as expectedsdk_onlydrift onMCPCheckInputRequest/MCPCheckOutputRequest(same pattern as the pre-existingcontent_typefield), since the platform's spec pin predates #2904 merging intoaxonflow-enterprise. Once the platform spec shipstooland the pin is bumped, that baseline entry should be removed as part of the burndown.CHANGELOG.md:[Unreleased]entry.LangGraphAdapterTest(MCPToolInterceptorTests) to assertconnectorTypeandtoolare sent as separate values (not concatenated), plus a new case for a customtoolFn; addedtool-field coverage toMoreTypesTest(MCPCheckInputRequest/MCPCheckOutputRequest) andAxonFlowTest(wire-level assertions via WireMock thatconnector_typeandtoolare sent as distinct JSON fields).Not in scope
GovernedTool/GovernedTool.Builder.connectorTypeFnuses a single-tool-nameFunction<String, String>(no MCP server concept) — unrelated pattern, untouched.axonflow-docs/main-tree/docs/orchestration/wcp/langgraph-wrapper.mdmentionsmcp_tool_interceptor()(~line 454), but that's describing the Python SDK's snake_case equivalent, not this Java concatenation bug — spot-checked, no Java-specific staleness found. If the Python SDK has an analogous single-field concatenation issue, that would need its own follow-up inaxonflow-docs/axonflow-sdk-python, tracked separately.Refs #2909, epic #2905.
Test plan
./mvnw test— 1321 tests, 0 failures/errors./mvnw verify— BUILD SUCCESS (jacoco coverage gate passes)scripts/wire_shape/validate.pyrun locally against the pinned OpenAPI spec commit — passes with the regenerated baselineconnectorTypeandtoolare sent as two distinct values rather than a concatenated string, in both the default and custom-MCPInterceptorOptionsinterceptor paths