feat: add committee & committee-member search/fetch tools (ARCH-329)#8
Conversation
Add three new MCP tools for committee operations: - search_committees: queries the LFX query service with type=committee, supports name typeahead, optional project_uid filter, and pagination. - get_committee: fetches CommitteeBase and CommitteeSettings (settings are omitted gracefully when the caller lacks permissions). - get_committee_member: fetches a single committee member by committee UID and member UID. Wire up lfx-v2-committee-service v0.2.19 HTTP client in lfxv2.Clients alongside the existing project and query service clients. Committee tools share the same CommitteeConfig/SetCommitteeConfig pattern as project tools and reuse the token exchange client. Default enabled tools list extended to include all five tools: search_projects, get_project, search_committees, get_committee, get_committee_member. 🤖 Generated with [GitHub Copilot](https://github.com/features/copilot) (via Zed) Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
Add search_committee_members MCP tool that queries the LFX query service with type=committee_member and a committee_uid:<uid> tag filter. Members are indexed with this tag by the committee service, so it is the correct way to scope a member search to a specific committee. Supports optional name typeahead and pagination. committee_uid is a required parameter. Adds the tool to the default enabled list. 🤖 Generated with [GitHub Copilot](https://github.com/features/copilot) (via Zed) Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
The query service Parent parameter requires a typed reference in the form "<type>:<id>" (validated by regexp ^[a-zA-Z]+:[a-zA-Z0-9_-]+$). Passing a bare UUID causes a 400 BadRequest. Also update the project_uid arg description to clarify it takes a plain UID (the tool handles the prefix internally). 🤖 Generated with [GitHub Copilot](https://github.com/features/copilot) (via Zed) Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
🤖 Generated with [GitHub Copilot](https://github.com/features/copilot) (via Zed) Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
There was a problem hiding this comment.
Pull request overview
Adds MCP tools for discovering and fetching LFX committees and committee members, backed by the existing LFX v2 client infrastructure and new lfx-v2-committee-service SDK wiring.
Changes:
- Introduces new committee-related MCP tools:
search_committees,get_committee,get_committee_member,search_committee_members. - Extends the LFX v2 client wrapper to initialize a committee service client.
- Updates server wiring to configure/register the new tools and enables them by default.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/tools/committee.go | Implements and registers the 4 new committee/committee-member MCP tools. |
| internal/lfxv2/client.go | Adds Clients.Committee and wires up the committee-service HTTP client. |
| cmd/lfx-mcp-server/main.go | Configures committee tools, registers them, and expands default enabled tools list. |
| go.mod | Adds lfx-v2-committee-service dependency and makes query-service a direct dependency. |
| go.sum | Updates module sums for added/updated dependencies. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if err != nil { | ||
| logger.Error("failed to create LFX v2 clients", "error", err) | ||
| return &mcp.CallToolResult{ | ||
| Content: []mcp.Content{ |
There was a problem hiding this comment.
lfxv2.ErrorMessage is referenced here, but there is no ErrorMessage helper defined in the internal/lfxv2 package in this repo (only client.go and token_exchange.go). This will not compile unless the helper is added or these calls are replaced (e.g., with err.Error() or another existing formatter).
| Content: []mcp.Content{ | |
| &mcp.TextContent{Text: fmt.Sprintf("Error: failed to connect to LFX API: %s", err.Error())}, |
|
|
||
| pageSize := args.PageSize | ||
| if pageSize <= 0 { | ||
| pageSize = 10 | ||
| } | ||
|
|
||
| resourceType := committeeResourceType | ||
| payload := &querysvc.QueryResourcesPayload{ | ||
| Version: "1", | ||
| Type: &resourceType, | ||
| PageSize: pageSize, |
There was a problem hiding this comment.
The page_size schema says "max 100", but the implementation only defaults when <= 0 and does not clamp values above 100. This can lead to unexpected API errors or overly large responses; consider capping pageSize to 100 (or returning a validation error) when the caller provides a larger value.
|
|
||
| // Settings may be unavailable due to insufficient permissions; treat that | ||
| // as a partial result rather than a hard failure so callers still get the | ||
| // base data they are authorised to see. | ||
| var committeeSettings *committeeservice.CommitteeSettingsWithReadonlyAttributes | ||
| settingsResult, err := clients.Committee.GetCommitteeSettings(ctx, &committeeservice.GetCommitteeSettingsPayload{ | ||
| UID: &args.UID, | ||
| }) | ||
| if err != nil { | ||
| logger.Warn("getting privileged committee settings failed, returning base only", "error", lfxv2.ErrorMessage(err), "uid", args.UID) |
There was a problem hiding this comment.
This treats any error from GetCommitteeSettings as a permissions issue and returns base-only results, which can hide real failures (timeouts, 5xx, misconfig) and also diverges from the intent described in the comment/PR text. Consider only suppressing known authz errors (e.g., 401/403) and returning an error (or including a settings error field) for other failures.
|
|
||
| pageSize := args.PageSize | ||
| if pageSize <= 0 { | ||
| pageSize = 10 | ||
| } | ||
|
|
||
| resourceType := committeeMemberResourceType | ||
| // Members are tagged with committee_uid:<uid> by the committee service indexer. | ||
| committeeTag := fmt.Sprintf("committee_uid:%s", args.CommitteeUID) | ||
| payload := &querysvc.QueryResourcesPayload{ | ||
| Version: "1", | ||
| Type: &resourceType, | ||
| Tags: []string{committeeTag}, | ||
| PageSize: pageSize, | ||
| Sort: "name_asc", |
There was a problem hiding this comment.
Same as search_committees: the page_size schema advertises a max of 100, but values above 100 are currently passed through unmodified. Consider clamping or validating pageSize before calling the query service.
Summary
Adds committee and committee member search/fetch MCP tools using the
lfx-v2-committee-serviceandlfx-v2-query-serviceGoa SDKs.New Tools
search_committees— queries the query service withtype=committee; supports optional name typeahead,project_uidfilter (formatted asproject:<uid>for the Parent field), and pagination.get_committee— fetchesCommitteeBaseandCommitteeSettings; settings are omitted gracefully if the caller lacks permissions.get_committee_member— fetches a single member by committee UID and member UID.search_committee_members— queries the query service withtype=committee_memberand acommittee_uid:<uid>tag filter (the tag format the committee service uses when indexing members); supports optional name typeahead and pagination.committee_uidis required.Changes
internal/tools/committee.go— new file with all four tools following the same config/registration pattern asproject.go.internal/lfxv2/client.go— addsCommittee *committeeservice.ClienttoClientsand wires up thelfx-v2-committee-servicev0.2.19 HTTP client.cmd/lfx-mcp-server/main.go— callsSetCommitteeConfigalongsideSetProjectConfig, registers all four tools, extends the default enabled tools list.go.mod/go.sum— addsgithub.com/linuxfoundation/lfx-v2-committee-service v0.2.19.Jira
ARCH-329