Skip to content

refactor: Extract shared toolResult helper to reduce MCP handler boilerplate #51

@electather

Description

@electather

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions