Skip to content

v3.0.0

Choose a tag to compare

@leggetter leggetter released this 24 Sep 11:55
· 60 commits to main since this release
c601293

Summary

v3.0.0 brings Outpost to the command line. hookdeck outpost manages tenants, destinations and
the events delivered to them, publishes events, inspects attempts, and reads topics, destination
types, metrics, config and deployment status, with hookdeck outpost mcp exposing the same surface
to an agent. Every Outpost command is marked [BETA] — flags and output may still change.

The Event Gateway MCP server can now change data. Every tool was read-only in v2.6.0; create,
update, delete, retry, cancel, mute and dismiss are all available behind --allow-write.

Adding those actions to the existing tool names would have meant anyone who had already allowed
hookdeck_connections for list and get silently gained delete as well — clients grant
permission per tool name and cannot match on arguments, so one name carrying both has to be allowed
or denied whole. Each resource splits into a _read half and a _write half instead, which makes
"allow all reads, prompt on anything that changes data" a single rule:
mcp__hookdeck-gateway__*_read.

The Event Gateway's own tools also move from the hookdeck_* prefix to gateway_*. Both renames
land together so you re-grant once.

If you have automation built against v2.x, the three breaking changes are the ones to check.

Breaking changes

  • Every MCP tool name changes. The Event Gateway's product tools take a gateway_ prefix, and
    each tool splits by what it does — hookdeck_connections becomes gateway_connections_read
    (list, get), gateway_connections_pause (pause, unpause) and gateway_connections_write (create,
    upsert, update, delete, enable, disable). Outpost splits the same way.

    Three tools keep the hookdeck_ prefix, because they are platform operations shared by both
    servers rather than one product's: hookdeck_login, and hookdeck_projects split into
    hookdeck_projects_read and hookdeck_projects_use.

    Per-tool grants and allowedTools entries need updating once; they do not survive a rename
    and MCP has no migration mechanism.

  • Arguments an action ignores are now refused. Every property is scoped to the actions that read
    it, so {"action": "get", "order_by": "created_at"} errors instead of silently dropping
    order_by. An ignored filter made a result look filtered when it was not. Declared enums are
    enforced for the same reason — they never were.

  • --hookdeck-config writes to the passed file location. It was honoured for reads and ignored
    for writes, so run from a directory that happens to contain .hookdeck/config.toml, the switch
    went to the local file while every later command carried on reading the file you passed — and so
    carried on reporting the old project:

    $ hookdeck --hookdeck-config ./mine.toml project use "Acme" "Staging"
    Successfully set active project to: Acme / Staging   # written to ./.hookdeck/config.toml
    $ hookdeck --hookdeck-config ./mine.toml whoami
    ... on project Production                            # ./mine.toml was never touched

    The flag now decides the file for reads and writes alike.
    (#424)

  • An unknown subcommand now exits 1. hookdeck gateway connection lst printed help and exited
    0, so a mistyped command in a script reported success. Applies to all 23 commands that exist only
    to hold subcommands — hookdeck project, hookdeck outpost tenant and the like. Running one of
    those on its own still prints its help and exits 0.

New features

  • Outpost support — hookdeck outpost … [BETA]. tenant, destination, destination-type,
    event, attempt, publish, topic, metrics, config and status.

    hookdeck outpost config set TOPICS=orders.created   # replaces the project's topic list
    hookdeck outpost status                             # repeat until it reports HEALTHY
    hookdeck outpost tenant upsert acme
    hookdeck outpost destination create --tenant-id acme --type webhook \
      --config url=https://acme.example.com/hooks --topics orders.created
    hookdeck outpost publish --tenant-id acme --topic orders.created --data '{"id":"ord_1"}' \
      --api-key $HOOKDECK_API_KEY

    A destination can subscribe only to topics configured on the project; a new project has none.
    A configuration change takes effect when hookdeck outpost status reports HEALTHY. publish
    requires a Project API key, passed with --api-key or read from HOOKDECK_API_KEY.

    Which fields a destination takes is decided by your Outpost instance, not by the CLI, so there is
    no flag per field: pass repeatable --config key=value and --credential key=value pairs
    instead, with --config a.b=c for a nested object and --config-file for anything too long for a
    flag. The CLI fetches each type's schema and rejects unknown keys and missing required fields
    before sending. destination create --type <type> --help lists that type's fields.
    (#346,
    #347)

  • hookdeck outpost mcp [BETA]. The commands above, exposed as MCP tools, split _read /
    _write and gated the same way as the Gateway server: read-only unless you pass --allow-write
    or set HOOKDECK_MCP_ALLOW_WRITE, with --read-only winning over both. The tenant token and
    portal actions are gated with the writes even though they only read, because both hand back a
    reusable credential. Publishing needs a separate key via --publish-api-key or
    HOOKDECK_OUTPOST_PUBLISH_API_KEY; without one the tool is not registered at all.

  • Gateway MCP write mode, behind --allow-write. create, upsert, update, delete, enable and
    disable on connections, sources and destinations; create, upsert, update and delete on
    transformations; retry, cancel and mute on events; retry on requests; update and dismiss on
    issues. pause/unpause stay ungated — read-only is the mode you investigate an incident in —
    and transformations run counts as a read because it creates no execution record and delivers
    nothing.

  • gateway_bulk_read and gateway_bulk_write. Bulk retry, cancel and replay. plan reports
    how many records an operation would touch without running it, and works without --allow-write —
    so you can check the scope of a bulk retry before enabling writes at all. Fifteen of the nineteen
    bulk endpoints were not reachable from the CLI or an agent before.

  • Events and requests split into plural search and singular by-id tools. hookdeck_events
    carried six actions and 25 parameters, and id was the only one more than one action used —
    retry, cancel and mute each needed just that, and were offered all 25. A request's events
    are now gateway_events_read with a request_id filter. Guessing wrong recovers: a singular tool
    asked to list names the plural tool, and an id of the wrong type is caught before the call.

  • Query filters the API documented but neither surface exposed. gateway requests list gains
    --search-term, --events-count, --ignored-count and --cli-events-count; gateway events list gains --search-term, --next-attempt-at-after and --next-attempt-at-before.
    --events-count 0 finds requests that produced no events, the usual explanation for a webhook
    that looks missing.

Fixes

MCP

  • Debug logs no longer persist credentials. Request redaction matched one field and responses
    were logged verbatim, so --log-level debug wrote webhook secrets, bearer tokens and the CLI key
    you receive when you sign in to disk. Redaction is now recursive, by field name, over requests and
    responses.

  • Filters sent as the wrong JSON type are no longer discarded. Models routinely send a boolean
    or a number as a string — verified: "false", limit: "5" — and the tools accepted only the
    declared type, so those filters were dropped without an error. A dropped filter reads as no
    filter, so the API returned everything and the answer came back looking filtered when it was not.

  • Argument values a tool cannot use are refused rather than dropped. {"measures": ["count", 5]} queried one measure and reported success.

  • hookdeck_connections accepted a disabled filter it could not honour — now
    gateway_connections_read. disabled: false set nothing and returned every connection as though
    filtered to the enabled ones. There is no enabled-only filter to send, so it is refused with that
    explanation instead.

  • hookdeck_metrics rejected the measures it had just been given — now
    gateway_metrics_read. It was the one tool not accepting the comma-separated form, so
    "measures": "count" was dropped and you were told measures is required.
    Correction: this fix is not in v3.0.0 or v3.0.1. See
    #440.

  • The connections tools no longer say "id or name is required" to callers who passed name.
    name is a declared property, but only id was read.

  • An abandoned re-authentication no longer signs you out. hookdeck_login with reauth: true
    deleted the stored credentials before opening the browser, so a closed laptop or a failed poll
    left you signed out everywhere with nothing to show for it.

  • The mcp --help example did not work. Copied verbatim it printed server is closing: EOF and
    exited 1. (#428)

CLI

  • hookdeck ci --help no longer prints your API key. --api-key took its default from
    HOOKDECK_API_KEY, and help output prints a flag's default — so with the variable exported your
    key was echoed into the terminal and into any log that captured it. tools/generate-reference
    reads the same defaults, so it could have written the key into the public REFERENCE.md.

  • A resource id can no longer retarget a request at a different resource. Ids were concatenated
    into URL paths, and resolving a path normalises .., so src_1/../../destinations/des_2
    addressed a different resource of a different type while the caller reported the id it was given.

  • gateway event retry, cancel and mute report the status the API returned. All three read
    the status code and ignored the body, but the API answers 200 to a no-op — so cancelling a
    delivered event printed cancelled while the event stayed SUCCESSFUL.

  • gateway request retry says how many events it produced, and fails when a retry aimed at a
    connection the request never went through creates none.

  • gateway issue dismiss says what it changed. Two QA passes reported "dismiss does not
    dismiss" after checking status. Nothing was broken — the API populates dismissed_at and leaves
    status alone — so the CLI now says that.

  • gateway connection update --rules '[]' clears a ruleset. An empty array was left out of the
    request entirely, so the command changed nothing and exited 0.

  • A 401 in a terminal no longer tells you to call an MCP tool. The hint was appended wherever
    the error was printed, including to readers with no way to call one.

  • A warning could corrupt --output json. Source validation warned on stdout when the OpenAPI
    spec fetch failed, so the warning landed ahead of the JSON. That fetch fails intermittently, so it
    broke scripts at random.


Full Changelog: v2.6.0...v3.0.0