with one click
with one click
| name | add-tool |
| description | Scaffold a new MCP tool with handler, registration, and test |
Add a new domain tool to the MCP server. Follow the established patterns:
Identify the right file in pkg/tools/domain/. Group related tools together (jobs.go, tests.go, component.go, payloads.go, pullrequests.go, search.go, releases.go, variants.go). Create a new file only if the tool doesn't fit an existing group.
Write the handler as a closure that captures the client interface:
func GetThingHandler(sippy client.Sippy) server.ToolHandlerFunc {
return func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// ...
}
}
Register the tool in the Register*Tools function in the same file. If creating a new file, add a new registration function and call it from pkg/server/server.go inside New().
Apply variant filtering if the tool queries jobs or tests:
vp := extractVariantParams(req)
filter.MergeInto(params, vp)
Use filter.MergeItemInto for non-variant filters (name, component, org, etc.):
filter.MergeItemInto(params, filter.Item{ColumnField: "name", OperatorValue: "contains", Value: name})
Resolve the release when it's optional:
release, err := tools.ResolveRelease(ctx, sippy, req.GetString("release", ""))
Write tests using newMockSippy() from testhelpers_test.go for canned responses. Use &capturingSippy{} directly to assert on parameters sent upstream.
Verify: Run go test ./pkg/tools/domain/... -v and go vet ./....
Probe the upstream Sippy API endpoint to confirm required parameters and response shape. Use curl or invoke the /sippy-api-explorer agent. Don't assume parameter names match the Sippy UI โ verify against the actual API.