Skip to content

fix: #2105 add example values to MCP workflow-call OpenAPI 200 schemas - #2275

Open
tenk-earn wants to merge 1 commit into
KeeperHub:stagingfrom
tenk-earn:fix/issue-2105-openapi-mcp-call-examples
Open

fix: #2105 add example values to MCP workflow-call OpenAPI 200 schemas#2275
tenk-earn wants to merge 1 commit into
KeeperHub:stagingfrom
tenk-earn:fix/issue-2105-openapi-mcp-call-examples

Conversation

@tenk-earn

Copy link
Copy Markdown

Closes #2105.

Adds a static example on both hardcoded /api/mcp/workflows/{slug}/call 200-response schemas in buildPathEntry:

  • write-type: { type: "calldata", to, data, value } matching handleWriteWorkflow / PaymentDeliverable in app/api/mcp/workflows/[slug]/call/route.ts
  • read-type: { executionId, status: "running" } matching the fire-and-forget timeout fallback documented on createAndStartExecution

data: "0xa9059cbb" is the public ERC-20 transfer(address,uint256) selector (first 4 bytes of keccak256 of that signature). value: "0" is a string because the schema types value as string (wei). to is the all-zero-but-one address so the example is a 20-byte hex string without pointing at a live contract.

No runtime behaviour change. Unit test pins both examples.

Hackathon note: KeeperHub Agent Economy OSS bounty track; author tenk-earn. Not a cash claim.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

About the build check on this pull request

This pull request comes from a fork, so GitHub does not pass it the credentials build normally uses for our image registry cache and staging build configuration. The build still runs and still compiles the image, so a red build here is real; it just takes longer than on team branches.

Every workflow run on a pull request from a fork also waits for a maintainer to approve it, so checks can sit at "awaiting approval" for a while after each push. Nothing is needed from you for either of these.

@suisuss suisuss left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Welcome, and thanks for this - the contributing guide is in CONTRIBUTING.md, and ISSUES.md covers when a change needs an issue first.

What this changes

app/api/openapi/route.ts gains a static example on each of the two hardcoded 200-response schemas in buildPathEntry - the write branch's calldata shape and the read branch's executionId/status shape. One unit test pins both. No runtime path is touched.

Does it match the description

Matches, including the choices it makes - the description says outright that the read example is the timeout fallback and that to is deliberately not a live contract.

Scope also matches #2105, whose plan asks for exactly this: a static example on both hardcoded schemas.

Blocking

  • app/api/openapi/route.ts:290 - "exec_example_000000000000000000000001" is not a shape this system mints. workflowExecutions.id defaults to generateId() (lib/db/schema.ts:674-676), which is customAlphabet("0123456789abcdefghijklmnopqrstuvwxyz", 21) - a 21-character lowercase nanoid with no prefix and no underscores. -> An SDK generator infers a Stripe-style prefixed id and writes a startsWith("exec_") check that rejects every real execution id; a caller using the literal against the feedback route passes validation and fails at the row lookup with "not found" rather than a format error. -> Use a 21-character lowercase-alphanumeric literal, and consider pattern: "^[0-9a-z]{21}$" on the property so the format is stated rather than implied.

  • app/api/openapi/route.ts:269-270 - the calldata example cannot be broadcast. data is the bare 4-byte transfer(address,uint256) selector, but the field carries iface.encodeFunctionData(...) output (lib/mcp/calldata.ts:194), which is the selector plus 64 bytes of ABI-encoded arguments - never 4 bytes. to carries the workflow's contractAddress (:216), and 0x...0001 is the ecrecover precompile. -> The write endpoint's entire contract is "here is calldata for you to sign and broadcast"; a client or test fixture templated on this example builds a transaction to a precompile with a truncated selector. -> Selector plus a 32-byte padded recipient and a 32-byte padded amount, and an ordinary contract-shaped address. value: "0" is correct as it stands - calldata.ts:216 and :322 both emit wei as a decimal string.

Mechanical - actionable as-is

  • app/api/openapi/route.ts:267, 289 - the document declares openapi: "3.1.0", and the file's one pre-existing sample (ERROR_SCHEMA.error:88) uses the 2020-12 plural examples. The singular example is deprecated inside Schema Objects in 3.1, so the file now carries both spellings and a strict renderer ignores the new one. examples: [...] matches what is already there.

With the team

  • Whether the read branch's 200 should model the response union rather than illustrate one arm of it. buildCallCompletionResponse returns success with output and feedback, error, or running on a 25s timeout (lib/payments/x402/execution-wait.ts:227-249), and the schema declares only const: "running" - so the document's own x-guidance at :419 tells readers to expect status: "success" with output while the schema says otherwise. I'm weighing a oneOf over the three arms with the example on the success arm against leaving the schema alone and pointing the example at success - the first is more correct and outside what #2105 accepted, the second is one literal. The schema being wrong predates you, and #2105's plan inherited it, so this is not a miss on your part. I'll come back with a verdict shortly.

Verdict

Changes requested - both new literals misdescribe the fields they illustrate, which is the one thing an example has to get right.

The two examples sit in mutually exclusive branches and have no shared state, so the write half can land while the read half waits on the question above; the single test asserting both is the only thing coupling them.

@suisuss suisuss added changes-requested Triage: reviewed, changes needed from the contributor decision-needed Blocked on a maintainer decision, not on the contributor labels Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changes-requested Triage: reviewed, changes needed from the contributor decision-needed Blocked on a maintainer decision, not on the contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenAPI: MCP workflow-call 200-response schemas carry no example values

2 participants