-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Problem / motivation
Every MCP tool handler in cmd/mcp/tools_*.go follows the exact same 8-line pattern: extract params → create client → call API → check error → marshal JSON → return text result. This pattern is repeated ~30+ times across the codebase, making it tedious to add new tools and increasing the surface area for copy-paste bugs.
Proposed solution
Create a shared toolResult helper function in cmd/mcp/mcp.go (or a new cmd/mcp/helpers.go):
// toolResult converts an API response into an MCP tool result.
// On API error it returns a user-visible MCP error; on success it marshals to JSON.
func toolResult(label string, res interface{}, err error) (*mcp.CallToolResult, error) {
if err != nil {
return apiToolError(label+" failed", err)
}
b, err := json.Marshal(res)
if err != nil {
return nil, err
}
return mcp.NewToolResultText(string(b)), nil
}Then each handler's return becomes a one-liner:
// Before:
res, _, err := client.MoviesAPI.MovieMovieIdGet(callCtx, float32(movieId)).Execute()
if err != nil {
return apiToolError("MovieMovieIdGet failed", err)
}
b, err := json.Marshal(res)
if err != nil {
return nil, err
}
return mcp.NewToolResultText(string(b)), nil
// After:
res, _, err := client.MoviesAPI.MovieMovieIdGet(callCtx, float32(movieId)).Execute()
return toolResult("MovieMovieIdGet", res, err)Files affected: All cmd/mcp/tools_*.go files (~12 files, ~30 handlers).
Alternatives considered
- Use code generation — overkill for this pattern.
- Leave as-is — but every new tool requires copying the same 8 lines.
Additional context
This reduces ~200 lines of boilerplate and makes adding new MCP tools trivial. The status_system handler already uses mcp.NewToolResultJSON which is similar in spirit — this would standardise the approach for handlers that need the apiToolError path.