feat(tools): add outputSchema and structuredContent via typed handler Out parameters#93
feat(tools): add outputSchema and structuredContent via typed handler Out parameters#93emsearcy wants to merge 4 commits into
Conversation
Correct committee endpoint path, fix parameter name from 'slug' to 'project_slug' in two sequence diagrams. Assisted-by: github-copilot:claude-sonnet-4.6 Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
Change tool handler signatures from the untyped ToolHandlerFor[In, any] form to concrete output types so the MCP Go SDK automatically generates Tool.OutputSchema and populates StructuredContent on every successful response. The existing TextContent fallback (pretty-printed JSON) is retained in the Content array so backward-compatible clients continue to receive a text response unchanged. Tools updated: - search_b2b_orgs → b2bOrgSearchResult - list_b2b_org_memberships → b2bOrgMembershipListResult - search_members → memberSearchResult - get_member_membership → *ProjectMembershipResponse - list_project_tiers → []membershipTierView - get_project_tier → membershipTierView - get_membership_key_contacts → []keyContactView - get_membership_key_contact → keyContactView - search_projects → projectSearchResult - get_project → projectGetResult - search_committees/search_groups → committeeSearchResult - get_committee/get_group → committeeGetResult - get_committee_member/get_group_member → *CommitteeMemberFullWithReadonlyAttributes - search_committee_members/search_group_members → committeeMemberSearchResult Inline anonymous structs that were only used as local variables are lifted to named package-level types to satisfy the type parameter constraint. Assisted-by: github-copilot:claude-sonnet-4.6 Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
Error returns in handleListProjectTiers were returning nil for the
[]membershipTierView Out parameter. Use []membershipTierView{} to
match the pattern used by all other handlers in the file, so the SDK
serializes [] instead of null in structuredContent on error paths.
Assisted-by: github-copilot:claude-sonnet-4.6
Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
There was a problem hiding this comment.
Pull request overview
This PR adds typed output parameters to selected MCP tool handlers so the SDK can generate outputSchema and populate structured responses while preserving existing text JSON content for backward compatibility.
Changes:
- Adds named result structs for project, committee, member, and B2B organization search/get responses.
- Updates read-only tool handlers from
anyoutputs to concrete typed outputs. - Adjusts a few member tool responses to return filtered view types consistently.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
internal/tools/project.go |
Adds typed structured outputs for project search and get tools. |
internal/tools/member.go |
Adds typed structured outputs for member, tier, and key contact tools. |
internal/tools/committee.go |
Adds typed structured outputs for committee/group search, get, and member tools. |
internal/tools/b2b_org.go |
Adds typed structured outputs for B2B org search and membership list tools. |
ARCHITECTURE.md |
Corrects documented parameter and endpoint examples. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| // handleListProjectTiers implements the list_project_tiers tool logic. | ||
| func handleListProjectTiers(ctx context.Context, req *mcp.CallToolRequest, args ListProjectTiersArgs) (*mcp.CallToolResult, any, error) { | ||
| func handleListProjectTiers(ctx context.Context, req *mcp.CallToolRequest, args ListProjectTiersArgs) (*mcp.CallToolResult, []membershipTierView, error) { |
There was a problem hiding this comment.
Fixed in 2fec443. Introduced membershipTierListResult{Tiers []membershipTierView} wrapper so the root is an object. The 2025-11-25 spec requires outputSchema to have type: "object" at the root and structuredContent to be a string-keyed map.
|
|
||
| // handleGetMembershipKeyContacts implements the get_membership_key_contacts tool logic. | ||
| func handleGetMembershipKeyContacts(ctx context.Context, req *mcp.CallToolRequest, args GetMembershipKeyContactsArgs) (*mcp.CallToolResult, any, error) { | ||
| func handleGetMembershipKeyContacts(ctx context.Context, req *mcp.CallToolRequest, args GetMembershipKeyContactsArgs) (*mcp.CallToolResult, []keyContactView, error) { |
There was a problem hiding this comment.
Fixed in 2fec443. Introduced keyContactListResult{Contacts []keyContactView} wrapper so the root is an object, same rationale as the tiers fix above.
The 2025-11-25 MCP spec requires outputSchema to have type "object" at
the root level, and structuredContent to be a string-keyed object map.
Returning a raw slice violates this constraint.
Introduce two wrapper types:
- membershipTierListResult{Tiers []membershipTierView} for list_project_tiers
- keyContactListResult{Contacts []keyContactView} for get_membership_key_contacts
Update both handlers to build and return the wrapper, and marshal the
wrapper for the TextContent fallback so all representations stay in sync.
Assisted-by: github-copilot:claude-sonnet-4.6
Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
Summary
Promotes tool handler signatures from untyped
ToolHandlerFor[In, any]to concrete output types so the MCP Go SDK automatically generatesTool.OutputSchemaand populatesStructuredContenton every successful response.The existing
TextContentfallback (pretty-printed JSON) is retained in theContentarray so backward-compatible clients continue to receive a text response unchanged.Tools Updated
search_b2b_orgsb2bOrgSearchResultlist_b2b_org_membershipsb2bOrgMembershipListResultsearch_membersmemberSearchResultget_member_membership*ProjectMembershipResponselist_project_tiersmembershipTierListResultget_project_tiermembershipTierViewget_membership_key_contactskeyContactListResultget_membership_key_contactkeyContactViewsearch_projectsprojectSearchResultget_projectprojectGetResultsearch_committees/search_groupscommitteeSearchResultget_committee/get_groupcommitteeGetResultget_committee_member/get_group_member*CommitteeMemberFullWithReadonlyAttributessearch_committee_members/search_group_memberscommitteeMemberSearchResultSkipped Tools
hello_world,user_info— no stable structured schemaquery_lfx_lens,query_lfx_semantic_layer— freeform text outputBehavioral Notes
get_project_tierandget_membership_key_contactnow marshal the filtered view type instead of the raw service response, aligning with the rest of the member tools and stripping internal fields.list_project_tiersandget_membership_key_contactswrap their slice results in an object type to conform to the 2025-11-25 spec requirement thatoutputSchemahavetype: "object"at the root.Known Client Caveats
outputSchemaintools/list. Validate separately.outputSchemacontaining$defs/$ref. Our schemas are flat structs so this likely does not apply, but should be confirmed in Dev.outputSchemais present. Validate that tool calls succeed, not just that tools appear in the list.structuredContentagainstoutputSchema; returns-32602on mismatch.Testing
make checkpasses./scripts/test_server.sh)Jira: LFXV2-1996
🤖 Generated with GitHub Copilot (via OpenCode)