Skip to content

feat: Add CLI telemetry instrumentation and remove deprecated SDK#233

Merged
leggetter merged 10 commits intoclaude/hookdeck-gateway-mcp-Xe6WQfrom
claude/add-cli-telemetry-NZ6a6
Mar 11, 2026
Merged

feat: Add CLI telemetry instrumentation and remove deprecated SDK#233
leggetter merged 10 commits intoclaude/hookdeck-gateway-mcp-Xe6WQfrom
claude/add-cli-telemetry-NZ6a6

Conversation

@leggetter
Copy link
Collaborator

@leggetter leggetter commented Mar 10, 2026

Summary

Adds anonymous telemetry instrumentation to the CLI and MCP server, and removes the deprecated hookdeck-go-sdk dependency — a prerequisite for the 2.0.0 release.

Telemetry Instrumentation

  • Process-wide telemetry singleton (CLITelemetry) populated during Cobra PersistentPreRun, attached as X-Hookdeck-CLI-Telemetry JSON header on every API request
  • Tracks: source (cli/mcp), environment (ci/interactive), command_path, invocation_id, device_name, generated_resource, mcp_client
  • hookdeck telemetry enable/disable subcommand for persistent opt-out via config file
  • HOOKDECK_CLI_TELEMETRY_OPTOUT env var for per-invocation opt-out
  • Two-layer opt-out safety net: per-client TelemetryDisabled field + singleton Disabled field, both checked in PerformRequest — ensures telemetry is never sent when disabled, even if a client is constructed directly without GetAPIClient()
  • MCP server detects client name from initialize params and includes it in telemetry

Deprecated SDK Removal (Breaking Change)

  • Removed hookdeck-go-sdk (github.com/hookdeck/hookdeck-go-sdk v0.7.0) — the SDK was pinned to API version 2024-03-01; all code now uses the direct hookdeck.Client targeting 2025-07-01
  • Migrated listen command: source.go, connection.go, listen.go, printer.go, proxy.go, TUI — all rewritten from SDK types to direct client types
  • Key type differences handled:
    • Field naming: IdID, UrlURL, SourceIdSourceID
    • List responses: []*Source with .Count[]Source with .Pagination
    • CLI path: Destination.CliPathDestination.Config["path"] with GetCLIPath()/SetCLIPath() helpers
  • Deleted files: pkg/hookdeck/sdkclient.go, pkg/config/sdkclient.go, pkg/login/validate.go
  • Consolidated all API client usage through config.GetAPIClient()

Other Changes

  • Acceptance test parallelization: split into 3 tagged slices for CI (run_parallel.sh)
  • Consolidated project.go and whoami.go to use GetAPIClient()
  • Login flows pass TelemetryDisabled to pre-auth clients

Breaking Changes

  • Removed hookdeck-go-sdk dependency — any downstream code relying on SDK types will need to use direct client types from pkg/hookdeck/
  • API version upgrade: 2024-03-012025-07-01 for all listen command operations
  • Destination CLI path access: destination.CliPathdestination.GetCLIPath() / destination.SetCLIPath()

Test Coverage

Automated

  • 30+ new unit tests: telemetry singleton (19), client telemetry header (11), initTelemetry (4), config flag (2)
  • MCP telemetry integration tests: 352-line test file covering client detection, header propagation, opt-out
  • Acceptance test parallelization: all 23 test files tagged for 3-slice CI

Manual Testing Recommended

  • hookdeck listen 3000 — TUI renders correctly (source URLs, IDs, CLI paths)
  • hookdeck listen 3000 --source new-source — new source/connection creation
  • hookdeck listen 3000 --output compact — compact output
  • hookdeck login / hookdeck login --cli-key — both login flows
  • hookdeck telemetry disable then any command — verify header absent
  • HOOKDECK_CLI_TELEMETRY_OPTOUT=1 hookdeck listen 3000 — verify header absent

Commits

Commit Description
eee24e5 Core telemetry: singleton, header injection, CI detection
388f914 End-to-end MCP telemetry integration tests
53ce91e hookdeck telemetry enable/disable subcommand
03dd341 Refactor enable/disable as positional args
267fe60 Singleton reset helpers and CLI telemetry unit tests
30517f2 Extract telemetry header to named constant
ccbd229 Remove hookdeck-go-sdk, migrate listen to direct API client
cae9770 Rename header to X-Hookdeck-CLI-Telemetry
29d8124 Parallelize acceptance tests into 3 CI slices
15af040 Consolidate API client usage, fix telemetry opt-out for direct clients

claude added 5 commits March 10, 2026 16:56
Extend the telemetry header with source, environment, command_path,
invocation_id, and mcp_client fields so the API server can distinguish
CLI from MCP requests and correlate multiple API calls to a single
command invocation.

Phase 1 - Telemetry struct & CLI wiring:
- Add Source, Environment, InvocationID, MCPClient fields to CLITelemetry
- Add NewInvocationID() generator (8 random bytes, hex-encoded)
- Add initTelemetry() helper called from root PersistentPreRun
- Fix Cobra PersistentPreRun chaining for connection command

Phase 2 - MCP per-request telemetry:
- Add Telemetry field + WithTelemetry() clone method on Client
- Update PerformRequest to use per-request telemetry when set
- Wrap MCP tool handlers to set per-invocation telemetry context
- Extract MCP client info from ServerSession.InitializeParams()

Phase 3 - SDK client:
- Works automatically: PersistentPreRun populates singleton before
  GetClient() bakes headers at construction time

Phase 5 - Config-based opt-out:
- Add TelemetryDisabled to Config, read from config.toml
- Update telemetryOptedOut() to accept config flag
- Thread TelemetryDisabled through API and SDK client construction

Phase 6 - CI detection:
- Add DetectEnvironment() checking CI, GITHUB_ACTIONS, GITLAB_CI,
  JENKINS_URL, CODEBUILD_BUILD_ID, BUILDKITE, TF_BUILD env vars
- Tag requests with environment: "ci" or "interactive"

https://claude.ai/code/session_01TQFynqFrXsP38LuYmdERYL
Add 6 integration tests that exercise the full pipeline:
MCP tool call → wrapWithTelemetry → HTTP request → mock API server,
verifying the Hookdeck-CLI-Telemetry header arrives with correct content.

Tests cover:
- Header sent with correct source/command_path/invocation_id/mcp_client
- Each tool call gets a unique invocation ID
- Command path reflects the action (hookdeck_sources/list vs /get)
- Telemetry disabled by config (TelemetryDisabled=true)
- Telemetry disabled by env var (HOOKDECK_CLI_TELEMETRY_OPTOUT=true)
- Multiple API calls within one tool invocation share the same ID

https://claude.ai/code/session_01TQFynqFrXsP38LuYmdERYL
Adds a telemetry subcommand with enable/disable actions so users can
toggle anonymous telemetry without manually editing config.toml.

https://claude.ai/code/session_01TQFynqFrXsP38LuYmdERYL
Instead of separate subcommands, `hookdeck telemetry enable` and
`hookdeck telemetry disable` now use a single command with a required
positional argument. Also adds telemetry section to the README.

https://claude.ai/code/session_01TQFynqFrXsP38LuYmdERYL
Add ResetTelemetryInstanceForTesting() and ResetAPIClientForTesting()
to enable isolated testing of the CLI telemetry path. Add tests that
verify the singleton reset → populate → HTTP request → header cycle,
singleton isolation between sequential commands, and initTelemetry
correctness including generated resource detection.

https://claude.ai/code/session_01TQFynqFrXsP38LuYmdERYL
@leggetter leggetter changed the base branch from main to claude/hookdeck-gateway-mcp-Xe6WQ March 10, 2026 19:22
@leggetter leggetter changed the title docs: add detailed MCP server implementation plan Add CLI telemetry instrumentation and telemetry command Mar 10, 2026
@leggetter leggetter changed the title Add CLI telemetry instrumentation and telemetry command feat: Add CLI telemetry instrumentation and telemetry command Mar 11, 2026
claude and others added 5 commits March 11, 2026 09:15
Add TelemetryHeaderName constant to avoid hardcoded header strings
across the codebase. Include a comment explaining why we omit the
"X-" prefix (deprecated by RFC 6648).

https://claude.ai/code/session_01TQFynqFrXsP38LuYmdERYL
The listen command was the only consumer of the hookdeck-go-sdk (pinned
to API version 2024-03-01). This migrates it to use the direct
hookdeck.Client which hits the current API version (2025-07-01) and
reads telemetry from the singleton on every request — fixing the gap
where the SDK client baked headers at creation time and never updated.

- Replace all hookdecksdk types with hookdeck types (Source, Connection,
  Destination) across listen/, proxy/, and tui/ packages
- Replace SDK client calls (Source.List, Connection.Create, etc.) with
  direct Client methods (ListSources, CreateConnection, etc.)
- Use Destination.GetCLIPath()/SetCLIPath() instead of direct CliPath field
- Delete pkg/hookdeck/sdkclient.go and pkg/config/sdkclient.go
- Remove github.com/hookdeck/hookdeck-go-sdk from go.mod

https://claude.ai/code/session_01TQFynqFrXsP38LuYmdERYL
* docs: generate REFERENCE.md in-place, remove REFERENCE.template.md

- Default input is REFERENCE.md; run with no args for in-place update
- Update README generator instructions and --check example
- Remove REFERENCE.template.md

Made-with: Cursor

* feat!: introduce Hookdeck config file and root --hookdeck-config flag

- Rename root-level --config to --hookdeck-config to avoid conflict with
  source/destination --config (JSON body) and --config-file (JSON path).
- Add HOOKDECK_CONFIG_FILE env var for config path; precedence is flag,
  then env, then .hookdeck/config.toml, then default location.
- Document env var and flag in README (precedence list and Global Flags).
- Update REFERENCE.md global options and acceptance tests.

Made-with: Cursor

* test: parallelize acceptance tests into three slices

- Add feature build tags to all automated acceptance test files so tests
  can be split across parallel runs (CI and local).
- CI: run three matrix jobs with tags split by estimated runtime; each job
  uses its own API key (HOOKDECK_CLI_TESTING_API_KEY, _2, _3).
- Local: run_parallel.sh runs three slices in parallel, writing to
  test/acceptance/logs/slice0.log, slice1.log, slice2.log; add logs/ to
  .gitignore.
- Helpers: support ACCEPTANCE_SLICE=2 and HOOKDECK_CLI_TESTING_API_KEY_3;
  per-slice config path and API key selection for isolated projects.
- Rebalance slices for ~5–5.5 min wall time (slice 0: connection/source/
  destination/gateway/etc.; slice 1: request, event; slice 2: attempt,
  metrics, issue, transformation).
- Document three-slice setup, tags, and run commands in test/acceptance/README.md.

Made-with: Cursor
Several places constructed hookdeck.Client directly, bypassing
GetAPIClient(). These clients didn't carry TelemetryDisabled from
config, so they'd send telemetry even when the user had opted out.

Two-layer fix:

1. Safety net: Add Disabled flag to the telemetry singleton. PerformRequest
   now checks both the per-client TelemetryDisabled and the singleton's
   Disabled flag, so even stray clients respect the config-level opt-out.

2. Consistency: Route as many callers as possible through GetAPIClient():
   - project.go: use config.GetAPIClient() instead of raw construction
   - whoami.go: use Config.GetAPIClient().ValidateAPIKey()
   - Login() validate path: use config.GetAPIClient().ValidateAPIKey()
   - proxy.go createSession: receive APIClient via proxy.Config
   - tui/model.go: receive APIClient via tui.Config
   - Remove login/validate.go (no longer called)

   For unauthenticated login clients (Login, GuestLogin, CILogin,
   InteractiveLogin, MCP tool_login), pass TelemetryDisabled from config.

https://claude.ai/code/session_01TQFynqFrXsP38LuYmdERYL
@leggetter leggetter changed the title feat: Add CLI telemetry instrumentation and telemetry command feat: Add CLI telemetry instrumentation and remove deprecated SDK Mar 11, 2026
@leggetter leggetter merged commit e3f7b26 into claude/hookdeck-gateway-mcp-Xe6WQ Mar 11, 2026
1 check passed
@leggetter leggetter deleted the claude/add-cli-telemetry-NZ6a6 branch March 11, 2026 15:09
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