Skip to content

feat(gateway): add MCP server with 11 tools, issues CLI, and metrics consolidation#231

Draft
leggetter wants to merge 44 commits intomainfrom
claude/hookdeck-gateway-mcp-Xe6WQ
Draft

feat(gateway): add MCP server with 11 tools, issues CLI, and metrics consolidation#231
leggetter wants to merge 44 commits intomainfrom
claude/hookdeck-gateway-mcp-Xe6WQ

Conversation

@leggetter
Copy link
Collaborator

Summary

Adds an MCP (Model Context Protocol) server to hookdeck gateway that exposes Hookdeck's API as 11 LLM-callable tools, along with prerequisite CLI backfills. See plans/hookdeck_mcp_detailed_implementation_plan.md for the full plan.

MCP Server (hookdeck gateway mcp)

  • 11 tools: hookdeck_help, list_events, get_event, list_requests, get_request, list_event_delivery_attempts, list_connections, list_sources, list_destinations, list_transformations, hookdeck_login
  • Stdio JSON-RPC transport compatible with Claude Desktop, Cursor, and other MCP clients
  • Structured error translation (HTTP status → MCP error codes)
  • Input validation with required field enforcement
  • In-band browser-based authentication via hookdeck_login tool
  • Project listing and switching via list_connections (workspace context)

Issues CLI Backfill (Phase 1, Part 1)

  • New hookdeck gateway issue subcommand with list, get, count, update, dismiss
  • Acceptance test coverage

Metrics CLI Consolidation (Phase 1, Part 2)

  • Consolidated 7 metrics subcommands down to 4 resource-aligned ones (events, issues, requests, pending)
  • --measures flag with per-resource validation
  • Expanded acceptance tests

Status

Part Description Status
1 Issues CLI Backfill Complete
2 Metrics CLI Consolidation Complete
3 MCP Server Skeleton Complete
4 MCP Tool Implementations Complete
5 Integration Testing & Polish Not complete

claude and others added 30 commits March 5, 2026 13:34
Comprehensive implementation plan mapping all 11 MCP tools to existing
CLI codebase with exact file paths, API client methods, request/response
types, and MCP input schemas. Identifies gaps (issues API client missing)
and surfaces 9 questions covering functionality unknowns, plan
ambiguities, and implementation risks.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
…d OpenAPI spec

- Expand Section 1.2.9 (Issues) with full OpenAPI-derived schema, API client
  code, CLI commands, and MCP tool design
- Rewrite Section 1.2.10 (Metrics) with 7→4 subcommand consolidation and
  CLI-layer routing logic
- Update Section 1.3 (File Structure) with all new/modified/removed files
- Replace resolved Q1-Q3 in Section 2 with updated open questions
- Add OpenAPI spec (2025-07-01) to plans/ for reference

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Adds a checklist at the top of the plan document breaking Phase 1 into
5 parts: Issues CLI backfill, Metrics consolidation, MCP server skeleton,
MCP tool implementations, and integration testing. Each part lists every
file/task as a checkbox so progress can be tracked across commits.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Add full Issues API client and CLI commands:
- pkg/hookdeck/issues.go: Issue types, enums, and 5 API client methods
  (ListIssues, GetIssue, UpdateIssue, DismissIssue, CountIssues)
- pkg/cmd/issue.go: Issue group command (issue/issues aliases)
- pkg/cmd/issue_list.go: List with filters (type, status, trigger, pagination)
- pkg/cmd/issue_get.go: Get single issue by ID
- pkg/cmd/issue_update.go: Update issue status (with validation)
- pkg/cmd/issue_dismiss.go: Dismiss issue (DELETE, with confirmation)
- pkg/cmd/issue_count.go: Count issues with filters
- Register via addIssueCmdTo() in gateway.go
- Mark Part 1 complete in plan progress tracker

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Covers all 5 issue subcommands:
- Help: verifies all subcommands listed, plural alias works
- List: basic, type/status/limit/order-by filters, JSON output
- Count: basic, type filter, status filter
- Get/Update/Dismiss: argument validation (missing ID, missing status, invalid status)
- Workflow: list → get → update on a real issue (skips if none exist)

Follows the same patterns as metrics_test.go and event_test.go.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
- Single issue_test.go (was issue_0_test, issue_dismiss, issue_resolve)
- Skip 18 tests that use createConnectionWithFailingTransformationAndIssue
  (flaky due to backend timing); 7 stable tests run (help + validation)
- Helpers: createConnectionWithFailingTransformationAndIssue, dismissIssue, Issue type

Made-with: Cursor
Parts 1-3 now include acceptance test tasks, and Part 5 separates
CLI acceptance testing from MCP integration testing.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Part 2 now explicitly covers verifying --measures/--dimensions on
requests, attempts, and transformations, plus comprehensive acceptance
test updates for the full consolidation from 7 to 4 subcommands.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Fold queue-depth, pending, and events-by-issue into the events subcommand
with smart routing based on --measures and --dimensions flags:
- queue_depth/max_depth/max_age measures → QueryQueueDepth API
- pending measure with --granularity → QueryEventsPendingTimeseries API
- issue_id dimension or --issue-id → QueryEventsByIssue API
- All other combinations → QueryEventMetrics API (default)

Remove metrics_pending.go, metrics_queue_depth.go, metrics_events_by_issue.go.
Update acceptance tests to cover consolidated routing and verify
--measures/--dimensions on all 4 subcommands.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
…xpand acceptance tests

- Help: user-facing copy for metrics and events (no 'consolidate'); document
  --issue-id required for per-issue in Long and flag help
- Pending timeseries: send measures=count to API (routing keeps --measures pending)
- Events-by-issue: require --issue-id when routing; clear error and help text
- Tests: TestMetricsHelp asserts --start/--end; remove NotContains for old subcommands
- Tests: TestMetricsEventsPerIssueRequiresIssueID (client-side validation)
- Tests: requests/attempts/transformations — output JSON, granularity, one filter each;
  transformations missing start/end validation

Made-with: Cursor
…lation

- Add github.com/modelcontextprotocol/go-sdk v1.4.0 dependency
- Create pkg/gateway/mcp/ package: server.go (MCP server init + stdio
  transport), tools.go (11 tool definitions with placeholder handlers),
  errors.go (API error → MCP error translation), response.go (JSON/text/
  error result helpers)
- Create pkg/cmd/mcp.go: `hookdeck gateway mcp` Cobra command that
  validates auth, gets API client, and starts the MCP stdio server
- Register MCP subcommand in pkg/cmd/gateway.go
- Add acceptance tests: TestMCPHelp, TestGatewayHelpListsMCP

The skeleton compiles, registers all 11 tools (placeholder implementations),
and will respond to MCP initialize requests over stdio. Part 4 will fill in
the real tool handler implementations.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
The MCP go-sdk requires a non-nil input schema with type "object" for
every tool (AddTool panics otherwise). Use a shared emptyObjectSchema
so the server starts and responds to initialize/tools/list/tools/call.

Made-with: Cursor
Parts 1-3 are complete. Add status summary table, note the
InputSchema fix, and mark Part 4 (tool implementations) as next.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Replace placeholder handlers with real implementations that call the
Hookdeck API. Each tool parses JSON arguments, maps parameters to API
query params, and returns structured JSON results.

Tools implemented:
- hookdeck_projects: list/use (session-scoped project switching)
- hookdeck_connections: list/get/pause/unpause
- hookdeck_sources: list/get
- hookdeck_destinations: list/get
- hookdeck_transformations: list/get
- hookdeck_requests: list/get/raw_body/events/ignored_events/retry
- hookdeck_events: list/get/raw_body/retry/cancel/mute
- hookdeck_attempts: list/get
- hookdeck_issues: list/get/update/dismiss
- hookdeck_metrics: events/requests/attempts/transformations
- hookdeck_help: overview and per-tool detailed help

Also adds proper JSON Schema input definitions for all tools and a
shared input parsing helper (input.go) for typed argument extraction.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Document the hookdeck_login tool for in-band browser-based authentication
when the CLI is not yet logged in. The MCP server always starts (never
crashes on missing auth), registers all resource tools upfront, and adds
a hookdeck_login tool when unauthenticated. Resource tools return isError
until login completes. After login, hookdeck_login is removed via
tools/list_changed notification.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
When the CLI is not authenticated, the MCP server now starts
successfully (never crashes) and registers a hookdeck_login tool
alongside all resource tools. Resource tools return isError until
login completes. The login tool initiates browser-based device auth,
polls for completion, saves credentials, and removes itself via
tools/list_changed once authenticated.

Changes:
- New auth.go: requireAuth() helper for auth-gating
- New tool_login.go: hookdeck_login handler using StartLogin/WaitForAPIKey
- server.go: accepts *config.Config, conditionally registers login tool
- mcp.go: removed ValidateAPIKey gate, passes config to NewServer
- All 10 resource tool handlers: added requireAuth() check

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
- Mark 'measures' as required in hookdeck_metrics JSON schema so LLM
  clients know to include it (was causing confusing 422 errors)
- Add server-side validation for measures in buildMetricsParams
- Improve hookdeck_help error when topic doesn't match a tool name:
  now lists all available tools instead of a bare "unknown tool" message

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
The hookdeck_login tool deliberately only supports browser-based device
auth. For CI/headless environments, pass --api-key in the MCP server
config. Both paths tested and verified against live API.

Also updates Part 4 status to COMPLETE with accurate action lists.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
20 tests covering server initialization, tool listing, help tool,
auth guard, error translation, mock API tool calls, error scenarios
(404, 422, 429), and input validation. Uses MCP SDK InMemoryTransport
for end-to-end client-server testing.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
94 tests (up from 20) covering all 12 tools and all 36 actions:

- sources: list, get (success + missing ID + API errors 404/422/429)
- destinations: list, get (success + missing ID + unknown action)
- connections: list, get, pause, unpause (success + missing ID + disabled filter)
- transformations: list, get (success + missing ID)
- attempts: list, get (success + missing ID)
- events: list, get, raw_body, retry, cancel, mute (success + missing ID +
  truncation + connection_id→webhook_id mapping)
- requests: list, get, raw_body, events, ignored_events, retry (success +
  missing ID + truncation + connection_ids + verified filter)
- issues: list, get, update, dismiss (success + missing ID + missing status)
- projects: list, use (success + missing project_id + not found)
- metrics: events (4 routing paths: default, queue_depth, pending_timeseries,
  by_issue), requests, attempts, transformations (missing start/end/measures)
- login: already-authenticated early return
- help: overview, specific topic, short name, unknown topic
- auth guard: all 10 resource tools reject unauthenticated
- input parsing: accessors, empty args, invalid JSON
- error translation: 401, 404, 422, 429, 500, non-API

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
…inciple

Per RFC #228, the MCP server should be read-focused for investigation
workflows. Remove write actions that were added beyond the RFC scope:
- events: remove retry, cancel, mute actions
- requests: remove retry action
- issues: remove update, dismiss actions

Connection pause/unpause are retained as they are explicitly scoped in
the RFC as "lightweight flow-control actions".

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
…nd README

Update all MCP tool descriptions to accurately reflect read-only
investigation capabilities per MCP best practices:
- Replace generic "Manage" with specific verbs (inspect, query, list)
- Add contextual detail about what each tool returns and when to use it
- Describe the webhook data model (requests → events → attempts)

Expand README MCP section with:
- Available tools table showing all 11 tools
- Claude Desktop configuration alongside Cursor
- Seven example prompts demonstrating investigation workflows

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
…guage

Hookdeck is HTTP in, HTTP out — webhook events are one type of event
trigger. Update tool descriptions and README to reflect this:
- "webhook sources" → "inbound sources"
- "webhook delivery destinations" → "delivery destinations"
- "webhook payloads" → "event payloads"
- "webhook connections" → "connections"
- "webhook traffic" → "event traffic"
- Use "webhook events" only where specifically about webhooks

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
claude and others added 14 commits March 10, 2026 10:33
… plan

- AGENTS.md: add pointer to test/acceptance/README.md for API key setup
- Plan: mark all Part 5 checklist items complete with test references

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Introduced a new document detailing the Hookdeck MCP build-out plan v2, focusing on the investigation and operations layer. The plan outlines the goals, scope, and phases of implementation, including success criteria and an end-to-end example of a production investigation workflow. This document serves as a guide for implementers and PMs, ensuring clarity on the MCP's capabilities and limitations.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
… section

Updates the plan to match the actual implementation:
- Add hookdeck_login tool (in-band browser auth, conditional registration, self-removing)
- Add raw_body action to events and requests tools
- Add events and ignored_events actions to requests tool
- Update tool count from 11 to 12
- Update auth section to describe both pre-auth and in-band login paths
- Resolve events enrichment decision (chose simpler path)
- Fix server description mentioning retry (out of scope for Phase 1)
- Update error handling table to match actual TranslateAPIError implementation

Adds Section 7 "Missing features for consideration" covering 7 gaps:
- Help tool skills+CLI redirect, server description, slog logging,
  project selection validation, projects name resolution, richer errors,
  and Retry-After header surfacing.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Keep Claude Code project notes local-only so branch configuration
doesn't get committed to the repository.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
… errors

Covers gaps identified in test review:
- Server name/version via InitializeResult
- Help topics for all 11 tools (full and short name forms)
- Help overview lists all tools and handles empty ProjectID
- Unknown topic error includes available tools list
- Error translation for 401, 409, 429, 500, 502, 503 across different tools
- Cross-tool error scenarios (destinations 500, connections 401,
  issues 422, attempts 429)

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
…mediately

Previously, handleLogin blocked for up to 4 minutes while polling for
the user to complete browser auth. The browser URL was only returned
in the tool result after polling finished, meaning the user never saw
it — they just saw a spinner with no way to authenticate.

Now the handler returns the browser URL immediately and polls in a
background goroutine. Subsequent calls to hookdeck_login report
"in progress" (with the URL) or the final result. Once auth completes,
the background goroutine updates the shared client and removes the
login tool.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Outlines the design for making Hookdeck-CLI-Telemetry header useful:
adding source (cli/mcp), invocation_id for grouping multi-call commands,
and mcp_client identification. Covers both the internal client and SDK
client paths, with a WithTelemetry() clone approach for MCP concurrency.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Adds plan for persistent telemetry disable in config.toml (top-level setting,
not per-profile) with precedence: env var > config > default enabled. Includes
CI/CD detection strategy that tags CI traffic as source="ci" rather than
auto-disabling, preserving analytics visibility while enabling server-side
filtering.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
source (cli/mcp) describes the interface; environment (interactive/ci)
describes the runtime context. These are independent axes that enable
cross-tabulation (e.g. "MCP tool calls from CI"). Previously CI was
overloading the source field which would have lost that information.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Renamed PLAN.md to plans/cli_mcp_telemetry_instrumentation_plan.md.
Consolidated duplicate file change entries, added key source files
reference table for implementer orientation.

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
- Moved PLAN.md to plans/cli_mcp_telemetry_instrumentation_plan.md
- Reordered so all phases (1-6) are contiguous under Implementation
- Promoted CI detection to Phase 6 (was nested under Phase 5)
- Moved File Change Summary, Risks, Key Source Files, Testing after phases
- Added CI-specific test cases to Testing Strategy

https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants