Skip to content

Require the signed envelope and document where to get one - #1

Merged
GChief117 merged 1 commit into
mainfrom
fix/signed-envelope-schema
Sep 16, 2026
Merged

GChief117 merged 1 commit into
mainfrom
fix/signed-envelope-schema

Conversation

@GChief117

Copy link
Copy Markdown
Contributor

The defect

The MCP canary reached tool discovery and then failed on the only tool call, HTTP 400.

The free route POST /v1/demo/verify accepts bare claims and works, so the landing page, the playground and the published Postman example all teach that shape. The paid POST /v1/verify requires the signed envelope returned by POST /v1/mandates.

The tool schema was z.record(z.string(), z.unknown()) — it accepted the bare shape and forwarded a request that could not succeed. The developer saw "mandate.mandate" must be the claims object, an internal field path with no route to a signed mandate.

This is on the only surface with verified external discovery: the Glama listing advertises this package, so it is the most likely first contact a real developer has with the product.

The fix

  • Schema requires {mandate, signature}, so the tool refuses locally with a message naming the real cause instead of forwarding a doomed request.
  • Tool description names POST /v1/mandates as the source of the envelope and notes bare claims belong to the keyless demo route.
  • README gains the missing first step as a copyable walkthrough, names the HTTP 400 and explains it, and states that a deny or requires_approval is a correct result, not a failure.

Why not have the tool mint the envelope itself

It would consume two metered units per verification without the caller knowing, and turn a verification-only tool into one that creates durable authority. The server's own instructions say it never issues or revokes mandates. That property is worth more than the convenience.

Tests

Three existing fixtures passed only because the old schema accepted anything; they now carry a structurally real envelope. A new regression suite asserts the bare shape is refused, an envelope without a signature is refused, an empty signature is refused, the real /v1/mandates response passes unchanged, and passthrough preserves extra fields.

28/28 pass.

Verified against production

POST /v1/mandates  -> 201  keys: mandate, requestId, signature
verify_action via the built MCP server with that envelope
                   -> 200  decision: requires_approval
                      violation: Actions above 25000 minor units need a human approval token.

That is the correct decision for the fixture: 30000 requested against an approvalRequiredAboveMinor of 25000.

Version bumped to 0.1.1 in package.json, server.json and the README install commands.

🤖 Generated with Claude Code

The MCP canary reached tool discovery and then failed on the only tool call with
HTTP 400. Root cause: the free route POST /v1/demo/verify accepts bare claims and
works, so the landing page, the playground and the published Postman example all
teach that shape, while the paid POST /v1/verify requires the signed envelope
returned by POST /v1/mandates.

The tool schema was z.record(z.string(), z.unknown()), which accepted the bare
shape and forwarded a request that could not succeed. The developer saw
"mandate.mandate" must be the claims object — an internal field path with no
route to a signed mandate.

The schema now requires {mandate, signature}, so the tool refuses locally with a
message naming the real cause. The tool description says the argument is the
envelope returned by POST /v1/mandates and that bare claims belong to the keyless
demo route. The README gains the missing first step as a copyable walkthrough,
with the HTTP 400 named and explained, and states that a deny or
requires_approval is a correct result rather than a failure.

Three existing fixtures passed only because the old schema accepted anything;
they now carry a structurally real envelope. A regression suite asserts the bare
shape is refused and that the real POST /v1/mandates response passes through
unchanged with its extra fields preserved.

Verified end to end against production: POST /v1/mandates returns 201 with
mandate, signature and requestId; passing that envelope to verify_action through
the built server returns decision requires_approval with the expected violation.
@GChief117
GChief117 merged commit 40a403e into main Sep 16, 2026
1 check passed
@GChief117
GChief117 deleted the fix/signed-envelope-schema branch September 16, 2026 03:10
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