- search honors the optional query substring filter (PRJ-07)
- search excludes both Sub andPub ops per ADR-041/ADR-068; dead match
arms removed (PRJ-08)
- batch returns {"results": [...]} with {isError, output|error} items;
tool description states the shape (PRJ-09)
- structuredContent is always an object: non-object outputs wrapped as
{"result": <output>} (PRJ-10)
- argument errors are CallError values (retryable always present);
non-string operation no longer reports 'missing required field'
(PRJ-13)
Verified: cargo test --all-features, cargo test, clippy -D warnings,
fmt --check
4.5 KiB
4.5 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| review-001-mcp-tool-fidelity | MCP tool-gateway runtime fidelity (PRJ-07, PRJ-08, PRJ-09, PRJ-10, PRJ-13) | completed |
|
narrow | low | component | implementation |
|
Description
Review 001 MCP projection findings in src/adapters/to_mcp.rs (the
schema-ACL half of the MCP story is review-001-schema-internal-visibility;
this task covers the rest of the tool surface):
- PRJ-07: the
searchtool advertises an optional substringqueryfilter butcall_tooldropsargumentsentirely (:382) — an LLM passing{"query": "fs"}gets the full unfiltered listing (context waste/overflow in big registries). Honor the filter. - PRJ-08:
searchexcludes onlySub, notPub(:268-274), contradicting ADR-068 ("excludes both"). A discovered Pub op can never be invoked via thecalltool — the advertised discovery surface is a lie for the whole Pub class. (The"subscription"/"Sub"match arms are dead —op_type_stronly emits lowercase.) - PRJ-09: batch item shape
{"isError", "output"|"error"}contradicts the tool description ("each shaped like acallresult") — fix the description or the shape. - PRJ-10:
structuredContentpasses output through verbatim, so string/array/null outputs produce non-objectstructuredContent(strict MCP clients may reject; batch returns a top-level array). Wrap or document. - PRJ-13: hand-rolled argument errors omit
retryable(required by the OpenAPI error schemas, always present onCallError), and a non-stringoperationreports the misleading "missing required field". Build argument errors in theCallErrorwire shape.
Acceptance Criteria
searchrespects aqueryargument (test);Pubops excluded from results (test)- Batch item doc matches the emitted shape (or shape changed to match — one way or the other, tested)
- Non-object outputs wrapped into objects or documented as an exception; batch shape consistent
- MCP argument errors carry
retryableand truthful messages cargo test --all-featurespasses
References
- docs/reviews/001-initial-implementation-review.md (Part F, PRJ-07..PRJ-10, PRJ-13)
- docs/architecture/decisions/041-mcp-tool-gateway-pattern.md
- docs/architecture/decisions/068-gateway-publish-endpoint.md
Notes
Agent fills during implementation. Depends on the visibility task because both rework the
schematool into_mcp.rs.
Summary
All five findings fixed in src/adapters/to_mcp.rs:
- PRJ-07:
call_toolextracts the optionalqueryargument andhandle_searchfilters the listing by substring match on the operation name (after the visibility/ACL filter — the query narrows what the caller is allowed to see, never widens it). - PRJ-08: exclusion now covers both
"sub"and"pub"(ADR-068 §1 and ADR-041 §2); the dead"subscription"/"Sub"match arms are removed. Asearch_excludes_pub_opstest asserts the Pub op is invisible to MCP discovery. - PRJ-09: shape decided over doc —
batchnow returns{"results": [...]}where each entry is{"isError": bool, "output": ...}on success or{"isError": true, "error": <CallError>}on failure; the tool description states exactly that (multiple dispatch-path failures in one batch let the other items run to completion, so the old "shaped like acallresult" description was the wrong side to keep). - PRJ-10: module doc documents the object guarantee: object outputs
pass through verbatim, non-object outputs are wrapped as
{"result": <output>}(object_result), applied consistently tocall'sstructuredContentand to batch itemoutput— so everystructuredContentis a JSON object and batch is never a top-level array. - PRJ-13: all argument errors (
call,batch,schema, and the batch per-item errors) areCallErrorvalues serialized through the samecall_error_to_structured_errorpath, soretryableis always present.parse_call_argumentsnow distinguishes a missingoperation("missing required field") from a non-string one ("must be a string, got ").
Tests: search_honors_query_substring_filter,
search_excludes_pub_ops, call_wraps_non_object_output_into_object_ structured_content, call_argument_errors_carry_retryable_and_truthy_ messages, batch_returns_object_with_result_entries (retryable +
INVALID_INPUT per-item check); existing tests updated to the new
shapes.