Skip to content

Add webhook notifications and an MCP server#9

Merged
vingrad merged 1 commit into
mainfrom
feat/webhooks-and-mcp-server
Jun 10, 2026
Merged

Add webhook notifications and an MCP server#9
vingrad merged 1 commit into
mainfrom
feat/webhooks-and-mcp-server

Conversation

@vingrad

@vingrad vingrad commented Jun 10, 2026

Copy link
Copy Markdown
Owner

What

Two integration surfaces for the engine:

Webhook event notifications — the service layer emits domain events (goal.created, plan.created, signal.received, replan.completed, outcome.recorded, goal.status_changed) behind a Notifier interface (nop by default, mirroring Metrics). internal/webhook delivers them best-effort: buffered async queue, retries with exponential backoff + jitter, HMAC-SHA256 X-DDE-Signature, graceful drain, dde_webhook_deliveries_total{event,result} metric. Enabled by DDE_WEBHOOK_URL; off by default.

MCP serverinternal/mcp exposes the use-cases as 10 MCP tools via the official modelcontextprotocol/go-sdk, over two transports:

  • dde mcp (stdio) for Claude Code/Desktop and agent runtimes; logs on stderr, stdout is JSON-RPC only
  • streamable HTTP at /mcp on the API server, sharing the live service with REST

Tool error messages mirror the REST status mapping. Plan-version outputs are untyped because provenance carries raw source payloads (json.RawMessage), which schema inference mistypes.

Notable changes

  • buildService extracted in cmd/dde — serve and mcp share storage/engine/webhook/queue wiring and shutdown ordering (replan drain → webhook drain → repo close)
  • per-request timeout middleware now wraps only REST/ops routes; server WriteTimeout removed so long-lived MCP streams survive
  • new config keys DDE_WEBHOOK_{URL,SECRET,TIMEOUT,RETRIES,EVENTS}
  • docs: docs/mcp.md (new), webhooks section in docs/api.md, README updates

Testing

  • go test ./... -race green across all packages; golangci-lint 0 issues
  • new tests: event emission (internal/app/notify_test.go), dispatcher behaviour incl. retries/HMAC/overflow/drain (internal/webhook), MCP client round-trips over in-memory transports (internal/mcp), /mcp mount + timeout scoping (internal/api)
  • verified live: webhook deliveries with valid signatures from a running serve; MCP stdio handshake; MCP-over-HTTP session seeing REST-created goals

Webhooks: the service layer now emits domain events (goal.created,
plan.created, signal.received, replan.completed, outcome.recorded,
goal.status_changed) behind a Notifier interface, nop by default like
Metrics. internal/webhook delivers them best-effort: buffered async
queue, retries with exponential backoff and jitter, HMAC-SHA256
signature header, graceful drain on shutdown, and a
dde_webhook_deliveries_total counter. Configured via DDE_WEBHOOK_*;
disabled when no URL is set.

MCP: internal/mcp exposes the use-cases as Model Context Protocol tools
(evaluate, create_goal, generate_plan, submit_signal, record_outcome,
and the read/lifecycle tools) over two transports: a new "dde mcp"
stdio command and a streamable HTTP endpoint at /mcp on the API server,
sharing the live service. Tool errors mirror the REST status mapping.
Plan-version outputs are untyped because provenance carries raw source
payloads (json.RawMessage), which schema inference would mistype.

The per-request timeout middleware now wraps only the REST and
operational routes, and the connection write deadline is removed, so
long-lived MCP streams are not severed. Service wiring shared by serve
and mcp is extracted into buildService.
@vingrad vingrad merged commit 5eb7337 into main Jun 10, 2026
3 checks passed
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.

1 participant