You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Update v2 plan: reflect implemented features and add missing features 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
@@ -101,27 +101,31 @@ This plan is intentionally high-level on API details. An agent with access to th
101
101
102
102
The MCP server uses the **same internal API client** the CLI uses (`Config.GetAPIClient()`), not shelling out to CLI subprocesses. One auth story (`hookdeck login` or a CI API key); no subprocess management or stdout parsing. Tool calls use the same project/workspace context as the CLI. The agent can list and switch projects via the `projects` tool (action: `use`).
103
103
104
-
**Authentication:** Inherited from the CLI. If auth is missing, every tool returns a clear error: `"Not authenticated. Run hookdeck login to authenticate."` No tool succeeds silently with missing credentials.
104
+
**Authentication:** Two paths, both zero-config for the agent:
105
+
106
+
1.**Pre-authenticated (typical):** User has already run `hookdeck login`. The MCP server inherits the CLI's API key and project context. All resource tools work immediately.
107
+
2.**In-band login (unauthenticated start):** If the CLI has no API key, the server registers a `hookdeck_login` tool that initiates browser-based device auth (polls for completion, persists credentials, then removes itself via `notifications/tools/list_changed`). All other tools return: `"Not authenticated. Please call the hookdeck_login tool to authenticate with Hookdeck."` until login completes. No tool succeeds silently with missing credentials.
105
108
106
109
**Suggested implementation order:**
107
110
1. MCP server skeleton and transport setup — the `initialize` handshake is handled automatically by the SDK, not something to implement as a tool; validate with `tools/list`
108
-
2.`projects` tool (sets project context for all subsequent calls)
11.`help` tool (stub early; enrich once other tools exist so responses can reference what's available)
117
121
118
122
Layer 1 and 2 tests can follow each slice. `projects` first because project context is required for all subsequent calls to be meaningful.
119
123
120
124
---
121
125
122
-
## 2. Tool surface area (11 tools)
126
+
## 2. Tool surface area (12 tools)
123
127
124
-
LLM tool-calling accuracy degrades above 30-50 tools. Phase 1 ships **11 tools** — 10 investigation and operational tools plus a catch-all guidance tool. All use the **compound pattern**: a single tool name with an `action` parameter. This keeps the selection surface small while preserving per-tool capability.
128
+
LLM tool-calling accuracy degrades above 30-50 tools. Phase 1 ships **12 tools** — 10 investigation and operational tools, a catch-all guidance tool, and a conditional login tool. All resource tools use the **compound pattern**: a single tool name with an `action` parameter. This keeps the selection surface small while preserving per-tool capability.
125
129
126
130
The compound pattern is a testable bet. If agents consistently fail to specify an action or confuse action-specific parameters, the fallback is to expand compound tools into single-action tools (e.g. `connections_list`, `connections_get`, `connections_pause`). Layer 3 behavioral testing validates this early.
127
131
@@ -134,12 +138,13 @@ The compound pattern is a testable bet. If agents consistently fail to specify a
134
138
|`sources`|`list`, `get`| Source details, URLs (e.g. "what's the URL I gave to Stripe?") |
`list` returns inbound requests with filters: `source_id`, `rejected`, `ingested_at` (range), `headers`, `body`, `path`, `parsed_query`, `bulk_retry_id`; plus `order_by`, `dir`, `limit`, `next`, `prev`. `get` takes `request_id` and returns full request details including the raw inbound body and headers. Useful for "did the provider even send this?" vs. "why did delivery fail?"
197
+
`list` returns inbound requests with filters: `source_id`, `status`, `rejection_cause`, `verified`; plus `limit`, `next`, `prev`. `get` takes `request_id` and returns full request details including headers and parsed body. `raw_body` returns the unparsed inbound payload for a request — useful when the parsed body loses fidelity or you need the exact bytes. `events` lists the events generated from a request (the fan-out after routing). `ignored_events` lists events that were received but not routed (e.g. filtered by rules). Together these answer "did the provider send this?" and "what happened to it after ingestion?"
193
198
194
-
CLI reference: `hookdeck gateway request list/get`. API: GET `/requests`, GET `/requests/{id}`.
199
+
CLI reference: `hookdeck gateway request list/get`. API: GET `/requests`, GET `/requests/{id}`, GET `/requests/{id}/raw_body`, GET `/requests/{id}/events`, GET `/requests/{id}/ignored_events`.
`get` takes `event_id` and returns event details including parsed body and headers. `raw_body` returns the unparsed event payload — same pattern as `requests``raw_body`, useful when the parsed body loses fidelity.
201
208
202
-
`get` takes `event_id` and returns event details including body and headers. **Enrichment decision:**Whether `get`additionally fetches the latest attempt's request/response inline (to avoid requiring agents to call `attempts`separately) is an implementation decision for the Phase 1 build. Enriching is better UX; deferring keeps the tool simpler. Decide during build based on the complexity of the additional API call.
209
+
**Enrichment decision (resolved):**`get`returns the event as-is from the API without inlining the latest attempt. The simpler approach was chosen — agents call `attempts`(action: `list`, filtered by `event_id`) when they need delivery details. This keeps the tool straightforward and avoids coupling event retrieval to attempt data.
203
210
204
-
CLI reference: `hookdeck gateway event list/get`. API: GET `/events`, GET `/events/{id}`.
211
+
CLI reference: `hookdeck gateway event list/get`. API: GET `/events`, GET `/events/{id}`, GET `/events/{id}/raw_body`.
CLI reference: `hookdeck gateway metrics events/requests/attempts`. API: GET `/metrics/events`, GET `/metrics/requests`, GET `/metrics/attempts`, GET `/metrics/transformations`.
231
238
232
-
### 2.12 Tool detail: `help`
239
+
### 2.12 Tool detail: `login`
240
+
241
+
Action: none (single-action tool, no `action` parameter)
242
+
243
+
**Conditional registration:** Only added to the tool list when the MCP server starts without an API key (`client.APIKey == ""`). After successful login, the tool is removed via `mcpServer.RemoveTools("hookdeck_login")`, which sends `notifications/tools/list_changed` to clients that support dynamic tool updates.
244
+
245
+
**Flow:** Calls `StartLogin()` to initiate browser-based device auth → returns the browser URL for the user to open → polls `WaitForAPIKey()` at 2-second intervals (up to ~4 minutes) → on success, persists credentials to the CLI profile, updates the shared client's `APIKey` and `ProjectID`, and removes itself from the tool list. On timeout, returns the browser URL again so the user can retry.
246
+
247
+
This tool bridges the gap between "user installed the CLI but hasn't logged in yet" and "all MCP tools require auth." Without it, an agent encountering the auth error would have no way to resolve the situation within the MCP session.
248
+
249
+
### 2.13 Tool detail: `help`
233
250
234
251
Action: `topic` (string parameter)
235
252
@@ -241,7 +258,7 @@ The catch-all entry point when no other tool fits the request. Two behaviors:
241
258
242
259
The `help` tool generates the signal that tells us what Phase 2 should be. Calls to `help`, and the topics passed to it, are the primary feedback mechanism for understanding unmet needs.
243
260
244
-
**Server-level description:** Set a clear MCP server description so clients display it correctly: "Hookdeck MCP — investigation and operational tools for querying event data, inspecting delivery attempts, checking pipeline health, and performing lightweight operational actions (pause, unpause, retry). For setup, scaffolding, and development workflows, use skills + CLI: `npx skills add hookdeck`."
261
+
**Server-level description:** Set a clear MCP server description so clients display it correctly: "Hookdeck MCP — investigation and operational tools for querying event data, inspecting delivery attempts, checking pipeline health, and performing lightweight operational actions (pause, unpause). For setup, scaffolding, and development workflows, use skills + CLI: `npx skills add hookdeck`."
245
262
246
263
---
247
264
@@ -251,13 +268,14 @@ Every tool call returns a **clear, actionable error message** the agent can reas
251
268
252
269
| Failure | Tool response |
253
270
|---------|--------------|
254
-
| Auth missing |`"Not authenticated. Run hookdeck login to authenticate."`|
255
-
| No project selected |`"No project selected. Use projects (action: use) to set the active project, or run hookdeck login."`|
256
-
| Resource not found |`"Connection web_G79G7nNUYWTa not found. Use connections (action: list) to see available connections."`|
257
-
| API 400 bad request | Surface the API error message verbatim with context: `"Invalid filter parameter 'statuss'. Valid values for status: SCHEDULED, QUEUED, HOLD, SUCCESSFUL, FAILED, CANCELLED."`|
258
-
| Rate limit (429) |`"Rate limited. Retry after {N} seconds."` (Surface API Retry-After value when present.) |
259
-
| Write tool not available | Do not return a generic "method not allowed." Return: `"Creating/updating resources isn't available through the MCP. Use the CLI with agent skills: npx skills add hookdeck."`|
260
-
| API 5xx |`"Hookdeck API returned an error ({status}). This may be transient — try again in a moment."`|
271
+
| Auth missing |`"Not authenticated. Please call the hookdeck_login tool to authenticate with Hookdeck."` (When `hookdeck_login` is available, the agent can resolve this in-band.) |
272
+
| Auth failed (401) |`"Authentication failed. Check your API key."`|
273
+
| Resource not found (404) |`"Resource not found: {API message}"`|
274
+
| Validation error (422) | API error message passed through verbatim. |
275
+
| Rate limit (429) |`"Rate limited. Retry after a brief pause."`|
276
+
| API 5xx |`"Hookdeck API error: {API message}"`|
277
+
278
+
**Note:** The error translation layer (`TranslateAPIError`) maps `*hookdeck.APIError` status codes to these messages. Non-API errors are returned unchanged.
261
279
262
280
**Rate limiting:** Rely on the API's 429 responses. Surface the `Retry-After` header to the agent. No client-side rate limiting or queuing in Phase 1.
263
281
@@ -298,6 +316,84 @@ Use **MCP Inspector** (`npx @modelcontextprotocol/inspector`) for manual validat
298
316
299
317
---
300
318
319
+
---
320
+
321
+
## 7. Missing features for consideration
322
+
323
+
The following items are specified in the plan but not yet implemented, or are gaps discovered during implementation. Each is listed with context to help decide whether to implement now (Phase 1), defer to Phase 2, or skip.
324
+
325
+
### 7.1 Help tool: skills + CLI redirect for action-oriented requests
326
+
327
+
**Plan reference:** Section 2.13 — when someone asks about create/update/delete/listen/scaffold, help should return guidance like *"Creating and managing connections isn't available through the MCP — that's handled by the Hookdeck CLI with agent skills."*
328
+
329
+
**Current state:** The help tool only returns tool reference documentation. If you ask about a topic that doesn't match a tool name, it returns an error saying the topic parameter expects a tool name. There is no natural-language routing and no skills/CLI redirect.
330
+
331
+
**Impact:** This is the primary mechanism for bridging MCP users to write operations. Without it, agents hitting the boundary of what's available get a dead-end error instead of actionable guidance. The plan also identifies `help` call topics as the feedback signal for Phase 2 priorities.
332
+
333
+
**Effort:** Medium — needs a category-matching layer (keyword or pattern-based) and a set of redirect response templates.
334
+
335
+
### 7.2 Server-level description
336
+
337
+
**Plan reference:** Section 2.13 — set a description so MCP clients display context about the server's purpose.
338
+
339
+
**Current state:** The server only sets `Name: "hookdeck-gateway"` and `Version`. No description field.
340
+
341
+
**Impact:** Low-medium. Clients like Claude Desktop show the server description to help users understand what's available. Without it, users see just the name.
342
+
343
+
**Effort:** Trivial — one field on `mcpsdk.Implementation` or server options.
344
+
345
+
### 7.3 Structured logging via slog
346
+
347
+
**Plan reference:** Section 4 — structured logging to stderr via `slog`, INFO/WARN/ERROR levels, `--verbose` flag for DEBUG.
348
+
349
+
**Current state:** No logging in the MCP server code at all.
350
+
351
+
**Impact:** Medium for debugging and support. Without it, diagnosing issues in production or during development requires adding ad-hoc prints. The `--verbose` flag is particularly useful for MCP Inspector workflows.
352
+
353
+
**Effort:** Medium — add slog setup in `NewServer`, pass logger through to handlers, add `--verbose` flag to the `hookdeck gateway mcp` command.
354
+
355
+
### 7.4 "No project selected" validation
356
+
357
+
**Plan reference:** Section 3 error table — *"No project selected. Use projects (action: use) to set the active project."*
358
+
359
+
**Current state:** Tools call the API without checking if `client.ProjectID` is set. The API may return confusing errors or default project data.
360
+
361
+
**Impact:** Medium. Without this guard, agents get opaque API errors when project context is missing instead of clear guidance to call `projects (action: use)`.
362
+
363
+
**Effort:** Low — add a `requireProject()` check similar to `requireAuth()`, call it from each tool handler.
364
+
365
+
### 7.5 Projects tool: `organization_name` + `project_name` resolution and `persist_scope`
366
+
367
+
**Plan reference:** Section 2.2 — resolve project by org + name, optional `persist_scope` (global vs local).
368
+
369
+
**Current state:** Only supports `project_id` for the `use` action.
370
+
371
+
**Impact:** Low-medium. Agents can work around this by calling `list` first to find the ID. `persist_scope` is mostly relevant for multi-directory workflows.
372
+
373
+
**Effort:** Low for name resolution (lookup from list results). Low for `persist_scope` (maps to existing `UseProject` vs `UseProjectLocal`).
374
+
375
+
### 7.6 Richer error messages for not-found and bad-request
376
+
377
+
**Plan reference:** Section 3 — *"Connection web_G79G7nNUYWTa not found. Use connections (action: list) to see available connections."* and *"Invalid filter parameter 'statuss'. Valid values for status: ..."*
378
+
379
+
**Current state:** Not-found returns `"Resource not found: {API message}"`. Validation errors pass through the API message verbatim. Neither includes next-step guidance (e.g. suggesting the `list` action).
380
+
381
+
**Impact:** Low-medium. The current errors are functional but not as agent-friendly. Adding "try X instead" guidance helps agents self-correct.
382
+
383
+
**Effort:** Low — enhance `TranslateAPIError` to include tool-aware suggestions for 404 and 422.
384
+
385
+
### 7.7 Rate limit: surface `Retry-After` header value
0 commit comments