feat: surface downstream tool metadata through the catalog (#27)#38
Merged
Conversation
domain.Tool carried only Ref, Description, and InputSchema, so the edge's tools/list dropped a downstream tool's outputSchema, title, annotations, and icons — outputSchema matters for structured-output tools (clients validate results against it), and title/annotations/icons drive client display. Widen the tool model and thread the fields end to end: registry.ToolInfo → aggregate.Tool → domain.Tool → edge mcp.Tool The extra fields ride as opaque json.RawMessage through the middle layers, so domain stays free of MCP SDK types (consistent with how InputSchema is already carried). The SDK's typed values are produced only at the boundaries: the registry reduces the SDK's reported tool to raw JSON (toolInfo), and the edge reconstructs the SDK's typed Annotations/Icons and passes OutputSchema through its any-typed field (toMCPTool). Absent metadata stays nil at both ends, so an unset field is omitted on the wire rather than serialized as null. The new fields are display/validation metadata only; the tools/call path is unchanged. Tests cover each layer: the registry mapping (including absent-field handling), aggregate carry-through, the app catalog/toListing path, and an end-to-end edge test asserting a client receives all four fields over tools/list. Widening Tool past gocritic's copy thresholds also turned several range-by-value loops into index-based access. Closes #27 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
domain.Toolcarried onlyRef,Description, andInputSchema, so the edge'stools/list(handleList) dropped a downstream tool'soutputSchema,title,annotations, andicons(issue #27).outputSchemamatters for structured-output tools (clients validate structured results against it);title/annotations/iconsdrive client display and hinting.This widens the tool model and threads the fields end to end:
Design: opaque in the middle, typed at the boundaries
The extra fields ride as opaque
json.RawMessagethrough the middle layers, sodomainstays free of MCP SDK types — consistent with howInputSchemais already carried, and preserving the domain-leaf invariant. The SDK's typed values are produced only at the two transport boundaries:registry.toolInfo) reduces the SDK's reported*mcp.Toolto raw JSON. Typed-nil values (a nil*ToolAnnotations, an empty[]Icon) are guarded so an absent field staysnilrather than marshaling to"null".edge.toMCPTool) reconstructs the SDK's typedAnnotations/Iconsfrom the raw JSON and passesOutputSchemathrough the SDK'sany-typed field. Each optional field is set only when present, so an unset field is omitted on the wire rather than serialized asnull.The new fields are display/validation metadata only — the
tools/callpath is unchanged.Testing
TDD, one failing test per layer first, then threaded through:
toolinfo_test.go): the SDK→ToolInfomapping carries all fields and round-trips annotations/icons; a separate test asserts absent metadata staysnil.Buildcarries the four fieldsaggregate.Tool→domain.Tool.catalog_test.go): metadata flows throughtoListing→Buildinto the cached catalog.server_test.go): end-to-end — an in-process MCP client receivestitle,annotations(readOnlyHint/title),icons, andoutputSchemaovertools/list.Widening
Toolpast gocritic's copy thresholds also turned several pre-existing range-by-value loops (domain.Catalog.Lookup,aggregatepaging,policy.Filter/Sync) into index-based access.make verify: build, vet,-racetests, coverage 95.0% (gate 80%),golangci-lintv2.12.2 0 issues,govulncheckclean.Closes #27
🤖 Generated with Claude Code