Skip to content

Add 'thv mcp call' for invoking MCP server tools#5389

Merged
JAORMX merged 1 commit into
mainfrom
add-mcp-call-subcommand
May 29, 2026
Merged

Add 'thv mcp call' for invoking MCP server tools#5389
JAORMX merged 1 commit into
mainfrom
add-mcp-call-subcommand

Conversation

@JAORMX
Copy link
Copy Markdown
Collaborator

@JAORMX JAORMX commented May 28, 2026

Summary

thv mcp list shows what an MCP server exposes but not how it behaves. This adds a sibling thv mcp call subcommand so an operator can open a session, invoke a named tool, and inspect the result without leaving the CLI — useful for ad-hoc debugging, registry verification, and shell pipelines.

  • Adds thv mcp call <tool-name> with --server (URL or workload name), --args '<json>', --args-file <path> (where - reads stdin), --ignore-tool-error, --format, --timeout, --transport.
  • New helper pkg/mcp/client.CallTool handles the Connect → CallTool → Close lifecycle.
  • Output: text by default (text content streamed to stdout; non-text payloads stubbed by type and size; StructuredContent pretty-printed); --format json emits the full CallToolResult.
  • Tool-level errors (CallToolResult.IsError=true) exit non-zero; --ignore-tool-error flips that. Transport / protocol failures always exit non-zero.
  • Renders all five 2025-11-25 MCP Content types (TextContent, ImageContent, AudioContent, ResourceLink, EmbeddedResource).

Type of change

  • New feature

Test plan

  • Unit tests (task test) — added TestReadToolArgs, TestFormatBinaryContent, TestFormatContentResourceLink covering the JSON-args validation helper and content rendering.
  • Linting (task lint-fix) — clean on touched files.
  • Manual testing (described below)

Live testing against running MCP servers:

  • thv mcp call fetch --server fetch --args '{"url":"https://example.com"}' → returns example.com content on stdout, exit 0.
  • thv mcp call get_vulnerability --server osv --args '{"id":"GHSA-jq35-85cj-fj4p"}' --format json → real OSV record (Docker /sys/devices/virtual/powercap advisory, all references and affected ranges correct).
  • thv mcp call query_vulnerability --server osv --args '{"package_name":"github.com/docker/docker","ecosystem":"Go","version":"24.0.0"}' → live OSV query, structured JSON, exit 0.
  • Stdin path (--args-file -), tool-error path (isError=true → exit 1 with content on stdout and Error: marker on stderr), --ignore-tool-error (same result, exit 0), non-object JSON rejection — all verified.

Does this introduce a user-facing change?

Yes. A new thv mcp call subcommand is added for invoking MCP tools. CLI documentation is regenerated at docs/cli/thv_mcp_call.md and the toolhive-cli-user skill is updated with the new command, examples, and flag reference.

Implementation plan

Approved implementation plan

Surface:

thv mcp call <tool-name> \
  --server <url-or-name>            # required
  [--args '<json>']                 # JSON object literal
  [--args-file <path>]              # file path; `-` reads stdin
  [--ignore-tool-error]             # exit 0 even when result.IsError=true
  [--format json|text]              # default text
  [--timeout 30s]
  [--transport auto|sse|streamable-http]

Decisions agreed before implementation:

  • Positional tool name (clearer than --tool).
  • --args and --args-file mutually exclusive. No flag → tool called with no arguments.
  • Parsed args must be a JSON object; top-level array/scalar rejected.
  • Default exit non-zero on IsError=true; --ignore-tool-error overrides.
  • Transport/protocol failures always exit non-zero.
  • Helper goes in pkg/mcp/client (Connect + CallTool + Close), CLI stays thin.
  • Text mode handles all five MCP Content types from the 2025-11-25 spec.

Special notes for reviewers

  • A panel review (Spec / Standards / Domain axes via specialist agents) was run before opening this PR. Ship-blockers — missing ResourceLink content type, stderr-redirect of tool output — were addressed. Mechanical fixes (dead-code pointer cases dropped, doc/code sync in CallTool, error-message style aligned to failed to <verb>: %w) were also applied.
  • The pkg/mcp/client.CallTool helper is intentionally kept as a thin wrapper for now. The existing thv mcp list subcommands do the same Connect → SDK call → Close shape inline; the asymmetry is acknowledged. Reviewers flagged a judgement call here — either keep the helper or inline it for symmetry with list. I'd like to revisit that decision when a third caller (e.g. mcp resource read, mcp prompt get) lands, since the right abstraction at that point is "scoped session", not "one-shot tool call". Open to inlining now if preferred.
  • No E2E test was added — none currently exist for thv mcp list either. Worth a follow-up that backfills both.

🤖 Generated with Claude Code

Listing tools via 'thv mcp list' showed what an MCP server exposes
but not how it behaves. Adding 'thv mcp call' lets the user open a
session, invoke a named tool, and inspect the result without leaving
the CLI -- useful for ad-hoc debugging, registry verification, and
shell pipelines.

The subcommand accepts a positional tool name, server URL or workload
name via --server, and JSON arguments via --args, --args-file, or
stdin (--args-file -). Output is rendered in text by default or as
the full CallToolResult in JSON. Tool-level errors exit non-zero by
default; --ignore-tool-error inverts that for pipelines that want to
inspect the result regardless.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the size/M Medium PR: 300-599 lines changed label May 28, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 28, 2026

Codecov Report

❌ Patch coverage is 0% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.77%. Comparing base (8fbc935) to head (b89fedb).

Files with missing lines Patch % Lines
pkg/mcp/client/call.go 0.00% 14 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5389      +/-   ##
==========================================
- Coverage   68.84%   68.77%   -0.08%     
==========================================
  Files         627      628       +1     
  Lines       63644    63658      +14     
==========================================
- Hits        43816    43780      -36     
- Misses      16574    16626      +52     
+ Partials     3254     3252       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@JAORMX JAORMX merged commit 6f63ac0 into main May 29, 2026
75 of 76 checks passed
@JAORMX JAORMX deleted the add-mcp-call-subcommand branch May 29, 2026 10:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Medium PR: 300-599 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants