ondc-mcp
OfficialClick on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ondc-mcpstart a new flow for seller onboarding"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ondc-mcp
A production MCP server boilerplate: stdio + Streamable HTTP, built on the MCP TypeScript SDK v2 against spec revision 2026-07-28.
The design goal is horizontal scalability. The 2026-07-28 transport is
stateless — no Mcp-Session-Id, no initialize handshake, no long-lived GET
stream — so any replica can answer any request behind a plain round-robin load
balancer. src/app.test.ts proves it: one instance lists the tools, a second
instance with no shared state executes the call.
npm install
cp .env.example .env
npm run dev # HTTP transport on :3000
npm run dev:stdio # stdio transport
npm run inspect # MCP Inspector against the stdio entrypoint
npm run typecheck && npm run lint && npm testLayout
src/
mcp/server.ts buildMcpServer(container, ctx) — THE factory, no transport
mcp/capabilities.ts one line per module
entrypoints/stdio.ts serveStdio(...) — only stdio binder
entrypoints/http.ts listen() — only file that binds a port
app.ts buildHttpApp(...) — Fastify host, no listen()
container.ts boot-once singletons + dependency health checks
config/env.ts zod env, parsed once, exits non-zero when invalid
plugins/ security · error-handler · auth · mcp
modules/catalog/ config-service client: builds, flows, mock configs
modules/session/ sessions, NP identity, role inversion
modules/flow/ the loop — derived state machine, start/proceed/await
modules/record/ exchanges, payloads and business data
modules/transport/ inbound receiver routes + outbound signed sender
modules/forms/ forms this mock hosts, and forms it has to fill
modules/health/ /health and /ready
lib/ errors · define-tool · logger · cache · mock-engine · events
test/harness.ts in-process client ↔ server (the app.inject() analogue)Related MCP server: mcp-apps-demo-engine
The one architectural idea
The SDK's central type is McpServerFactory = (ctx) => McpServer. Both
entrypoints consume it, so the scaffold has a direct analogue of buildApp():
buildMcpServer(container, ctx)registers every capability and binds no transport. Entrypoints own transports. Tests consume the factory directly.
Keep the factory cheap. Over HTTP it runs once per request — that is
what makes the transport stateless. Anything expensive (connection pools, HTTP
agents, caches) belongs in createContainer, built once at boot and closed
over. Get this wrong and you open a pool per request; the symptom is a capacity
cliff under load, not a failing test. So src/mcp/server.test.ts asserts the
factory performs no I/O across 100 constructions.
Layering
tool → service → repository, one-way, never skipped — the MCP analogue of
routes → controller → service → repository.
File | Role |
| Protocol edge. Schemas, annotations, result shaping. Knows MCP only. |
| Business logic.Imports nothing from the SDK. Throws |
| Data access. Interface + in-memory implementation. |
| zod schemas; |
A service never returns { content: [...] }; a tool never contains a business
rule. That is what lets one service back a tool, a resource, and later a REST
route.
MCP-specific conventions
These are the rules with no REST analogue. They are the substance of the scaffold.
1. Every tool declares both schemas
defineTool requires inputSchema and outputSchema — a tool missing
either will not typecheck. outputSchema drives structuredContent, which is
what makes a tool consumable by code rather than only by a model reading prose.
Handlers return typed domain data; the helper builds the envelope, so no tool
can return half of it.
defineTool({
name: "session_get",
title: "Get session",
description: "Fetch a session by id: the participant under test, the role …",
inputSchema: GetSessionInput,
outputSchema: GetSessionOutput,
annotations: { readOnlyHint: true, idempotentHint: true },
render: ({ session }) => renderSession(session),
handler: async ({ session_id }) => ({
session: await service.requireSession(session_id),
}),
});2. Two error channels — pick by who can fix it
Failure | Channel | Who acts |
Bad arguments, not found, conflict, upstream down |
| Themodel — it reads the failure and retries differently |
Auth failure, unknown method | JSON-RPC error | Theclient — the model cannot mint a token or invent a method |
Report a model-fixable failure as a protocol error and the model never learns the call failed; it sees a transport fault and retries the identical call.
Argument validation sits on the tool channel — which is also what the SDK
does for inputSchema violations it catches itself. session.tool.test.ts
pins that behaviour so the two layers stay consistent.
A protocol NACK is emphatically on the tool channel too: the participant rejecting a payload is the most informative result a compliance run produces, and the model has to read it.
Each AppError subclass declares its own channel; handleToolError routes it.
3. stdout belongs to the protocol
On stdio, stdout is the JSON-RPC channel. One stray console.log corrupts
the stream and surfaces as an unrelated-looking parse error in the client.
pino writes to stderr in every mode. There is no config that changes it.
no-consoleis an ESLint error — load-bearing here, not stylistic.src/entrypoints/stdio.test.tsspawns the real entrypoint and fails if a single non-protocol byte reaches stdout.
This also matches 2026-07-28, which deprecates the MCP logging capability in
favour of stderr (stdio) and OpenTelemetry (HTTP).
4. No module-level mutable state
The point of the stateless revision. Cross-request state goes to the injected
ServerEventBus — in-process by default; pass a Redis-backed implementation to
createMcpHandler({ bus }) when running more than one replica.
This server's own domain state (sessions, transactions, payloads) goes through
the CacheStore port in src/lib/cache/ instead. See
State persistence.
5. Cache hints are free throughput
Cacheable results (tools/list, prompts/list, resources/*,
server/discover) carry ttlMs / cacheScope. The SDK default is
ttlMs: 0, cacheScope: "private" — no caching at all. mcp/server.ts sets
them deliberately, and a test asserts tools/list really carries them. Treat an
unset hint as a decision you skipped.
6. Trace context is propagated
_meta carries W3C traceparent / tracestate / baggage (formalised for
MCP in 2026-07-28). defineTool lifts them into the per-call child logger, so
a tool call correlates with the rest of your traces. There is no separate
observability plugin: request logging is Fastify's own (pointed at the shared
stderr logger in app.ts), and the MCP-level context belongs where the call
is served.
7. Deprecated surface is avoided
roots, sampling, and the logging capability are all deprecated in
2026-07-28. Nothing here builds on them. Server→client requests are expressed
with inputRequired(...) instead.
Talking to the HTTP transport
A 2026-07-28 request is stricter than 2025. Three things are mandatory:
Accept: application/json, text/event-stream— both. The server picks per response whether to answer with JSON or upgrade to a stream; sending only JSON earns a406.A full
_metaenvelope on every request —protocolVersion,clientInfo,clientCapabilities. A missing key is a-32602naming it.Mcp-Method, plusMcp-Namefortools/call(SEP-2243) — and they must agree with the body. These exist so load balancers and rate limiters can route and meter on the operation without parsing JSON-RPC.
curl -sS localhost:3000/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-H 'mcp-method: tools/list' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientInfo":{"name":"curl","version":"1.0"},
"io.modelcontextprotocol/clientCapabilities":{}}}}'Clients still speaking 2025 keep working: plugins/mcp.ts sets
legacy: "stateless", so they are served per-request from the same factory.
Set legacy: "reject" to go modern-only.
Authorization
AUTH_MODE=jwt turns /mcp into an OAuth 2.1 Resource Server:
Unauthenticated calls get
401withWWW-Authenticate: Bearer ... resource_metadata="…".That URL serves an RFC 9728 document at
/.well-known/oauth-protected-resource/mcp, unauthenticated — it is how a client discovers which authorization server to use./healthand/readystay open so orchestrators can probe without a token.
Swap lib/token-verifier.ts for introspection or a vendor SDK; it is a
one-method interface.
Gotcha worth knowing: the SDK rejects any token whose
AuthInfo.expiresAtis unset — silently, as a plain401. Both shipped verifiers populate it from the JWTexpclaim.
env.ts refuses to boot with AUTH_MODE=none when NODE_ENV=production, so
an unauthenticated production deploy cannot happen by configuration alone.
State persistence
Sessions, transactions, stored payloads and business data live behind the
CacheStore port (src/lib/cache/). Two implementations ship:
| Store | Behaviour |
unset |
| Zero infrastructure. A restart wipes everything. |
|
| State survives restarts and is shared by replicas. |
Unset is the default so the server runs with nothing installed. In development
that has a sharp edge: npm run dev is tsx watch, so every file save
restarts the process and drops the session you were mid-flow in. Pointing at a
local Redis fixes that:
docker compose -f docker-compose.dev.yml up -d # redis:8-alpine, loopback only, appendonly
echo 'REDIS_URL=redis://127.0.0.1:6379' >> .env # .env is read by npm run dev
npm run devKeys are the workbench's own layout (session::{id}, {txn}::{sub}) under a
REDIS_KEY_PREFIX namespace, so one local Redis can serve several projects —
and setting the prefix empty writes the workbench's literal keys, should you
ever want to share a Redis with it.
Two deliberate choices worth knowing:
The flow catalog never goes to Redis.
FlowService.load()reads a ~330KB mock-runner config on everyflow_proceedand every inbound callback. It is derived data, TTL'd at 15 minutes and re-fetched transparently on a miss, so it stays in-process — one 330KB transfer per loop iteration, half of them inside the ACK window, would buy nothing.createContainersays so in place.A failed read throws, it does not return
undefined.undefinedmeans "no such session", and the model answers that by starting a new transaction against a real participant. An outage has to look like an outage.
Issue reporting
When a run gets stuck — a blocked step, a NACK in either direction, a send that
failed — the server records what happened, strips it of payload content, and
writes it to a local spool directory. If FEEDBACK_ENDPOINT_URL is set it also
uploads it. This is on by default; FEEDBACK_DISABLED=1 turns it off, and the
choice is logged once at boot along with where reports go.
FEEDBACK_DISABLED=1 npm run dev # off
FEEDBACK_SPOOL_DIR=/tmp/fb npm run dev # spool somewhere you can readWhat leaves is deliberately narrow. Payload leaf values are replaced by type
tokens ("<string:12>"), so key names, types and array lengths survive and no
value does; identifiers are HMAC-pseudonymised with a per-install salt; free
text — including the model's own account — is scrubbed for emails, phone
numbers, GPS pairs and the rest. The rule is default-deny: a field nobody
anticipated is redacted by omission rather than leaked by oversight.
src/test/pii-fixtures.ts is the canary, and feedback.redact.ts is where the
tests live.
Nothing about this depends on the model cooperating. Capture is deterministic
and the report ships with narration: null if it is never answered;
feedback_submit_report only adds the model's diagnosis on top. To see exactly
what would be sent, call feedback_list_reports with include_body: true, or
read the spool directory — it is the same JSON.
Testing
Layer | Mechanism |
Service | Plain unit test — no MCP involved |
Tool / resource / prompt |
|
HTTP |
|
stdio | Real subprocess, asserting stdout purity |
| One shared contract suite ( |
Redis is exercised two ways: a fake client in the default suite, and a real
server behind an opt-in gate — RUN_REDIS_TESTS=1 npm test -- redis-cache-store,
which needs docker-compose.dev.yml up. Each run namespaces its keys and cleans
up with SCAN, never FLUSHDB, because the Redis it finds may not be its own.
Scaffold-level guarantees under test: the factory does no I/O; stdout carries
only protocol bytes; /ready returns 503 when a dependency is down; cache
hints are emitted; DNS-rebinding protection rejects bad Host/Origin; the 401
challenge is discoverable; a second instance serves a call the first never saw.
Adding a module
src/modules/<name>/with*.schema.ts,*.service.ts,*.tool.ts—session/is the smallest complete example.Write schemas first — everything else derives from them.
Keep the service free of SDK imports.
Add one line to
src/mcp/capabilities.ts.
Both transports pick it up automatically.
Notes on versions
The SDK is pinned to exact
2.0.0-beta.5, deliberately. v2 is in beta and the API is still settling.@modelcontextprotocol/fastifypublishes alatesttag that lags its siblings, so a caret range silently mixes versions.npm run sdk:checksurfaces the GA bump.SDK types are confined to
mcp/,entrypoints/,plugins/mcp.ts,lib/define-tool.tsandlib/errors.ts. Services and repositories import nothing from the SDK, so a v2 API change has a small blast radius.TypeScript is pinned to 6.0.3, not 7.x:
typescript-eslintsupports<6.1.0, and a supported dependency graph beats a forced install.types: ["node"]is required either way — TS 6 no longer auto-includes@types/*and the SDK's.d.mtsreferencesBuffer.@modelcontextprotocol/nodepeer-depends onhonoeven under Fastify. It is a transitive requirement of the adapter, not a stray dependency.
Available Tools
21 toolscatalog_describe_flowDescribe a flowARead-onlyIdempotent
The full ordered sequence of one flow. Every step is tagged with an actor: 'mock' means this server must produce it, 'np' means it must arrive from the participant under test. Also lists the inputs each step needs and any parallel or unsolicited steps.
| Name | Required | Description | Default |
|---|---|---|---|
| flow_id | Yes | Flow identifier, as listed by catalog_list_flows. | |
| session_id | Yes | Session returned by session_create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| tags | Yes | |
| flow_id | Yes | |
| sequence | Yes | The ordered main sequence. |
| mock_role | Yes | The role this session's mock plays. |
| step_count | Yes | |
| description | Yes | |
| extra_sequence | Yes | Parallel or unsolicited steps, if any. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only and idempotent behavior. The description adds valuable context beyond annotations by explaining the meaning of actor tags ('mock' vs 'np'), listing inputs per step, and mentioning parallel/unsolicited steps. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, immediately states the core purpose, and then adds only meaningful specifics. No redundant phrases or unnecessary detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only describe tool with an output schema, the description sufficiently covers the content of the response: sequence, actor semantics, inputs, parallel/unsolicited steps. The highlights and annotations fill any remaining context gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for both parameters; each has a clear description. The tool description doesn't need to add parameter details, and doesn't, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'The full ordered sequence of one flow' with specific detail about actor tags, inputs, and parallel/unsolicited steps. This distinguishes it from siblings like flow_get_status (status only) and catalog_list_flows (list of flows).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool: when a complete, step-by-step breakdown of a flow is needed. It doesn't explicitly name alternatives or provide exclusion criteria, but the clear contextual detail makes the use case evident. Slight improvement would be explicitly pointing to alternatives for status-only checks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
catalog_list_buildsList available buildsARead-onlyIdempotent
List every domain, version and use-case published by the ONDC config-service. Call this before session_create when the exact domain code, version or use-case name is uncertain — use-case names are case- and space-sensitive and must match exactly.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | Restrict the catalog to one domain code, e.g. ONDC:FIS12. Omit for all. |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | Number of domains returned. |
| builds | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and openWorldHint, so safety and side-effect behavior are covered. The description adds valuable behavioral context by warning that 'use-case names are case- and space-sensitive and must match exactly,' which is important for downstream session creation. This goes beyond the annotations, though it doesn't describe output volume or pagination.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences: the first states the purpose, the second gives actionable usage guidance. Every word earns its place, and the key information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a simple listing tool with one optional parameter, strong annotations, and an output schema. The description covers what it does, when to use it, and the critical exact-match caveat. All necessary context for invocation is present, making it complete for the agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema already fully describes the one parameter 'domain' with a clear explanation and example. The description adds no parameter-specific semantics beyond what the schema provides, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'List every domain, version and use-case published by the ONDC config-service.' This unambiguously defines what the tool does and implicitly distinguishes it from sibling catalog tools like catalog_list_flows by focusing on 'builds' (domain/version/use-case) rather than flows.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance: 'Call this before session_create when the exact domain code, version or use-case name is uncertain.' It also explains the case/space sensitivity. However, it does not explicitly mention when not to use it or name alternative tools, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
catalog_list_flowsList flows for a sessionARead-onlyIdempotent
List every flow published for the session's build, with the number of steps this server must produce versus the number expected from the participant under test. Use catalog_describe_flow for the full sequence.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Session returned by session_create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| build | Yes | |
| flows | Yes | |
| total | Yes | |
| mock_role | Yes | |
| session_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, and idempotentHint. The description adds useful context beyond those: it details what the list contains (server vs. participant step expectations) and scopes it to the session's build. That is helpful behavioral context without contradicting the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the action and resource, and every clause adds value. The pointer to the sibling tool replaces additional explanation, so it is both concise and structured well.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple (1 parameter, output schema exists). The description states what the list contains (flows with step counts) and directs to a sibling for the full sequence. Given the output schema covers return structure, nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the only parameter session_id is fully described in the schema. The tool description doesn't add extra meaning about the parameter beyond mentioning 'session's build,' which is already implied. Baseline 3 is appropriate because the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('List'), names the resource ('flows published for the session's build'), and specifies the exact data returned (number of steps for this server vs. expected from the participant). It clearly distinguishes from the sibling catalog_describe_flow, so purpose is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly points to catalog_describe_flow as the alternative for the full sequence, implying this tool is for the summarized list with step counts. This gives clear when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
catalog_load_flow_configLoad a flow's mock configAIdempotent
Fetch and cache the mock-runner configuration for a flow — the per-step generation, validation, requirement and save-data logic the workbench uses to drive it. Returns a summary of what each step carries; the configuration itself is held server-side under the returned cache_key for later execution, because it is far too large to read directly.
| Name | Required | Description | Default |
|---|---|---|---|
| flow_id | Yes | Flow whose mock-runner config should be loaded. | |
| session_id | Yes | Session returned by session_create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | Config identity as published by the config-service. |
| steps | Yes | |
| flow_id | Yes | |
| cache_key | Yes | Server-side handle for the cached config, for later execution. |
| step_count | Yes | |
| total_bytes | Yes | Size of the whole config held server-side. |
| helper_lib_bytes | Yes | Size of the shared helper library carried by the config. |
| validation_lib_bytes | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (idempotent, not read-only, not destructive), the description discloses that the tool caches the configuration server-side and returns a cache_key because the config is 'far too large to read directly.' This adds useful behavioral context about side effects and storage that annotations do not capture.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the primary action and resource, and each clause earns its place. It efficiently explains what the tool does, what it returns, and why the caching design exists.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the purpose, the caching behavior, the return value (summary + cache_key), and the rationale. An output schema exists to document the exact return shape, so the description is complete for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides full descriptions for both parameters (flow_id and session_id) at 100% coverage. The description does not add parameter-specific meaning beyond the schema, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific action ('Fetch and cache') and a distinct resource ('mock-runner configuration for a flow'), and elaborates on what the configuration contains (per-step generation, validation, requirement, save-data logic). This clearly distinguishes it from sibling tools like flow_start or flow_get_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool is used before executing a flow (it 'drives' the flow and the config is cached 'for later execution'), but it does not explicitly state when to use this tool vs alternatives or any exclusions. No sibling tool is mentioned, leaving usage guidance largely implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
feedback_list_reportsList issue reports for this sessionARead-onlyIdempotent
Every incident this session has opened, with its derived state and whether it still needs your account. Pass include_body: true to see the fully-redacted report exactly as it would be uploaded — that is the honest answer to a user asking what is being sent about them.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| session_id | Yes | ||
| include_body | No | Render each incident as the fully-redacted report that would be uploaded. This is how you answer 'what are you sending about me?'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| sharing | Yes | Where these go, in one sentence, so it can be repeated to the user. |
| incidents | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true, and the description adds valuable behavioral context: the 'derived state', whether the item 'still needs your account', and the fact that include_body renders the fully-redacted report exactly as it would be uploaded. This is honest and beyond what annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no filler. The first sentence states the core function; the second explains a key parameter and its purpose. Front-loaded and efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and three straightforward parameters, the description covers the essential behavior (list reports, include_body variant). It is complete enough for the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 33% (only include_body has a description), so the description compensates by elaborating on include_body: passing it shows the fully-redacted report, framed as 'the honest answer' for user transparency. limit and session_id are not discussed, but they are self-explanatory and typical.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists every incident report opened in this session, including derived state and whether action is still needed. This goes beyond the title by specifying the exact scope (session) and output content, and it is clearly differentiable from siblings like feedback_submit_report.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage context: when you need to see all incidents for the session, and specifically for answering a user's privacy question ('what is being sent about them?'). It does not explicitly name alternatives or exclusions, but the context is clear enough for selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
feedback_submit_reportReport what went wrongA
Record your account of an incident this session opened — you will see one as an ISSUE_OPEN event on a tool result. Call it AFTER you have tried to resolve the problem, so you can say how it turned out; report it whether or not you succeeded, because a failure you could not rescue is the more useful of the two. tooling_gap is the most valuable field: it is what changes the tools you are given next time. Do not paste payload values into any field — name the JSONPath instead; values are stripped either way.
| Name | Required | Description | Default |
|---|---|---|---|
| outcome | Yes | ||
| attempted | No | What you tried, in order, including what did not work. | |
| diagnosis | Yes | What you concluded was actually wrong. | |
| session_id | Yes | ||
| incident_id | Yes | From the ISSUE_OPEN event, or from feedback_list_reports. | |
| tooling_gap | No | What would have let you resolve this faster. | |
| suspected_cause | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| state | Yes | The **derived** state. If it disagrees with your `outcome`, the report keeps both — that disagreement is itself a finding. |
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| message | Yes | |
| accepted | Yes | |
| incident_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations, the description reveals that 'values are stripped either way' and that the tooling_gap field 'changes the tools you are given next time'. These behavioral details are not exposed by the annotations (which only cover read-only, open-world, idempotency, and destructiveness) and add meaningful context for the agent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is composed of five concise, purposeful sentences, each adding distinct value: what it does, when to call, why failures are useful, the key field, and the JSONPath rule. No fluff or repetition; the structure is efficient and front-loaded with the core purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a submit-report tool with a rich schema, output schema, and annotations, the description covers the essential context: the trigger (ISSUE_OPEN event), timing, desired content, and a crucial formatting rule. It does not need to repeat return-value details since the output schema exists. The guidance is complete for an agent to use the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds significant meaning for tooling_gap calling it 'the most valuable field' and explaining its effect. It also instructs to reference JSONPath instead of pasting values, which applies to all parameters. Schema descriptions cover most fields, but this extra guidance goes beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Record your account of an incident this session opened'. It specifies the resource (an incident report) and the action (record/submit). It also distinguishes from sibling feedback_list_reports by focusing on submission rather than listing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance: 'Call it AFTER you have tried to resolve the problem' and explains that it should be called whether or not the attempt succeeded. It does not explicitly name alternatives or exclusion cases, but the context is clear enough for an agent to decide when to invoke it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
flow_awaitWait for the participantARead-only
Block until something happens, then report it. Two scopes: Name a flow_id (or transaction_id) and it waits on that one run, returning as soon as the participant calls back — pass the seq from your last call as after_seq so nothing is seen twice. When the participant sends the flow's first action this is where you learn the transaction_id, because it was theirs to choose. Name neither and it waits on the whole session: any callback on any run, a step auto-advance sent, a refused call, a form submitted. That is the one to use when you have nothing to do — it needs no seq bookkeeping, and it comes back with runs telling you where every flow stands. Narrow what wakes it with kinds / flow_ids; anything filtered out is still reported, it just does not end the wait. timed_out: true means nothing happened yet — call again. Always prefer this over polling flow_get_status.
| Name | Required | Description | Default |
|---|---|---|---|
| kinds | No | Session scope only. Wake only for these kinds. Everything else that happens is still reported in `events` — it just does not end the wait, so nothing is ever lost by filtering. | |
| flow_id | No | The flow started with flow_start. Works before the transaction id exists, so prefer it. | |
| flow_ids | No | Session scope only. Wake only for these flows. Same rule as `kinds`: other flows' events are delivered, they just do not end the wait. | |
| after_seq | No | Run scope only. Only report events newer than this — use the `seq` from the last flow_get_status or flow_await so nothing is seen twice. Ignored in session scope, which tracks delivery for you. | |
| session_id | Yes | Session returned by session_create. | |
| timeout_ms | No | How long to block. Capped server-side; defaults to the cap. | |
| transaction_id | No | A specific transaction. Only known once the flow's first action has crossed the wire. |
Output Schema
| Name | Required | Description |
|---|---|---|
| seq | Yes | Run scope: the run's latest event number, to pass back as after_seq. Session scope: the journal seq delivered through, which is tracked for you and needs passing nowhere. |
| next | No | What the loop needs now the wait is over. Run scope only — a session wait covers several runs, so it answers with `runs` instead. |
| runs | No | Session scope only: where every run in this session stands, so you can pick which to drive next. |
| event | No | |
| scope | Yes | 'run' — you named a flow or transaction, and this reports that one. 'session' — you named neither, and this reports the whole session. |
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| timed_out | Yes | True when nothing arrived. Call again to keep waiting. |
| transaction_id | Yes | The run's transaction id. When the participant sent the flow's first action, this wait is where you learn it — it was theirs to choose. Always null in session scope, which names no single run. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint and openWorldHint annotations, the description discloses blocking semantics, timeout behavior (timed_out: true means nothing happened, call again), seq bookkeeping to avoid duplicates, and that filtered events are still delivered but do not end the wait. This significantly enriches behavioral understanding without contradicting annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with a clear lead sentence, bolded scope separation, and no redundant content. It is dense but every sentence adds operational value, covering scopes, filtering, seq, timeout, and preference over polling. It remains focused despite its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (multiple scopes, filtering, seq semantics, timeout), the description covers all necessary usage aspects. It mentions key return concepts like runs and timed_out, and with the output schema available, it does not need to detail every return field. This is complete for effective use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
While the schema already has 100% parameter description coverage, the tool description adds cross-parameter semantics: after_seq is used to avoid duplicates in run scope and ignored in session scope, kinds/flow_ids filter only wake conditions but not reporting, and transaction_id is learned when the first action arrives. This goes beyond simple field definitions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Block until something happens, then report it.' It distinguishes two scopes (named flow/transaction vs. whole session) and contrasts with sibling flow_get_status by instructing 'Always prefer this over polling flow_get_status.' This provides a specific verb, resource, and behavior that sets it apart.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly tells when to use which scope: name a flow_id to wait on that run, name neither to wait on the whole session and 'use when you have nothing to do.' It also says to prefer this over flow_get_status, and explains filtering with kinds/flow_ids and re-calling on timed_out. This is comprehensive guidance with clear alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
flow_get_statusGet flow statusARead-onlyIdempotent
Where a run has got to: every step with its status and who owes it, any exchanges that arrived off-sequence, and what the loop needs next. State is derived from the recorded exchanges on every call, so this is always current. Name the run by flow_id (or transaction_id once it has one). Read it whenever you lose track; next says exactly which tool to call.
| Name | Required | Description | Default |
|---|---|---|---|
| flow_id | No | The flow started with flow_start. Works before the transaction id exists, so prefer it. | |
| session_id | Yes | Session returned by session_create. | |
| transaction_id | No | A specific transaction. Only known once the flow's first action has crossed the wire. |
Output Schema
| Name | Required | Description |
|---|---|---|
| seq | Yes | Latest event number. Pass it to flow_await as after_seq. |
| next | Yes | What the loop needs next, without doing it. |
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| attempt | Yes | Which try of this flow the run is on. 1 unless restarted. |
| flow_id | Yes | |
| sequence | Yes | The main sequence, in order. |
| abandoned | No | Set when reading an attempt that flow_restart wrote off. Its record is kept as evidence but it cannot be advanced; the run has moved on. |
| attention | No | Why auto-advance stopped, if it did. |
| mock_role | Yes | |
| extra_steps | Yes | Side-channel steps — unsolicited updates and their replies. |
| flow_status | Yes | |
| missed_steps | Yes | Exchanges that did not fit the flow. Compliance findings. |
| transaction_id | Yes | Null while the flow's first action has not yet crossed. |
| reference_data_keys | Yes | Form steps with a resolved artefact waiting in business data. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as read-only and idempotent. The description adds meaningful behavior: "State is derived from the recorded exchanges on every call, so this is always current," and reveals that the response includes a `next` action recommendation. This goes beyond the safe-read hint without contradicting it.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three densely packed sentences, front-loaded with the core purpose. No filler words; every sentence adds a unique piece of information (what it reports, why it's current, how to address it, when to use it).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the rich annotations (read-only, idempotent) and presence of an output schema, the description covers the what, when, how-to-call, and expected outcomes (statuses, off-sequence exchanges, next action). There are no significant gaps for an agent to invoke this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds extra guidance on parameter selection: "Name the run by flow_id (or transaction_id once it has one)" and clarifies that session_id is the required context. This supplements the schema's own field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a vivid, specific explanation: "Where a run has got to: every step with its status and who owes it, any exchanges that arrived off-sequence, and what the loop needs next." It clearly names the resource (a flow run) and distinctively positions it against sibling tools like flow_proceed and flow_await.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a clear usage cue: "Read it whenever you lose track; `next` says exactly which tool to call." It also advises which identifier to use (flow_id vs transaction_id). It stops short of explicitly listing exclusions or alternatives, but the context is strongly differentiated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
flow_proceedAdvance the flowA
The loop driver. Takes the next step this mock owns, checks its preconditions, generates its payload from the flow's own mock config, and POSTs it to the participant — then records both the payload and whatever the step saved for later steps. If the step needs values it comes back INPUT_REQUIRED with the declarations; call again with inputs. If the next move is the participant's it comes back WAITING; call flow_await. Pass dry_run: true to generate and inspect a payload without sending it, or trigger_extra to fire a named side-channel step. When a step is blocked because the flow's own config generates a non-compliant payload, payload_overrides patches the offending fields so the run can continue instead of being abandoned. Sending the flow's first action is what mints its transaction_id, which the answer then reports.
| Name | Required | Description | Default |
|---|---|---|---|
| inputs | No | Values for a step reported as INPUT_REQUIRED, as a **flat** object: it becomes `sessionData.user_inputs` verbatim and the step's generator reads the declared field names off the top of it. Do not nest them under the declaration's name — `inputs_required.fields` lists the keys to send, and `inputs_required.example` shows the shape. For a manual step pass {id: '<step_key>'} — naming it is what triggers it. | |
| dry_run | No | Generate and record the payload but do not send it, so it can be inspected first. Nothing reaches the participant. Combines with `payload_overrides` to check a patch before it goes out. | |
| flow_id | No | The flow started with flow_start. Works before the transaction id exists, so prefer it. | |
| session_id | Yes | Session returned by session_create. | |
| trigger_extra | No | Fire a named side-channel step from the flow's extra sequence instead of advancing the main sequence. Only steps this mock owns can be fired. | |
| transaction_id | No | A specific transaction. Only known once the flow's first action has crossed the wire. | |
| payload_overrides | No | Patch the generated payload before it is validated and sent: a map of JSONPath to replacement value, e.g. {"$.context.bpp_uri": "https://np.example.com/seller"}. This is the escape hatch for a **flow config that is itself wrong** — a step whose generator emits a non-compliant field cannot otherwise be got past, and abandoning the run costs the participant its compliance report. Not a validation bypass: the gate still runs on the patched payload, so an override that does not fix the finding still blocks. Paths must be concrete (no wildcards, filters or `..`), `$.context.transaction_id` is refused, and they apply to this call only — a chained step never inherits them. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ack | No | How the participant answered a SENT step. |
| action | No | Its protocol action or form type. |
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| reason | No | Machine-readable cause of a block. |
| details | No | Everything known about the block — requirement codes, errors. |
| message | Yes | |
| outcome | Yes | |
| ack_body | No | The participant's synchronous response, verbatim. |
| form_url | No | Where the form lives, for whichever side has to open it. |
| step_key | No | The step this outcome is about. |
| form_role | No | 'fill' — the participant hosts the form and this mock must submit it. 'host' — this mock serves the form and the participant must submit it. |
| overrides | No | Paths patched by `payload_overrides` before this payload was validated and sent. Present only when a step was patched, which makes it not a clean step: the participant was tested against a payload this flow's own config did not produce, and the compliance report says so. |
| payload_id | No | Handle for the payload produced. Read it with record_get_payload. |
| validation | No | How the generated payload judged against the spec. Present whenever a payload was produced, including one that was blocked or drafted rather than sent. `status: "unavailable"` means it went unchecked — the payload was still sent, because refusing to act on our own outage would strand the run. |
| http_status | No | |
| input_problems | No | Why the supplied `inputs` were refused. Present only when values were sent and did not match — nothing was generated or sent, so fixing them and calling again costs the run nothing. |
| transaction_id | No | This flow run's transaction id. Absent until the flow's first action crosses the wire — it belongs to whoever sends that action, so when the participant moves first it is theirs to choose and unknowable until their call lands. Address the run by flow_id until then. |
| expected_action | No | The action now expected from the participant. |
| inputs_required | No | What the step declares it needs. Send `fields` as a flat object under flow_proceed's `inputs`. |
| override_problems | No | Why `payload_overrides` were refused. Nothing was patched, generated or sent — every path is judged before any is written, so correcting them and calling again costs the run nothing. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses key side effects beyond annotations: it POSTs to the participant, records payloads and saved step data, does not send with dry_run, patches payloads via payload_overrides without bypassing validation, and mints transaction_id on first action. This is substantial behavioral context that annotations alone do not provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense yet each clause adds essential operational detail: return states, dry-run behavior, side-channel steps, payload overrides, and transaction_id creation. It is front-loaded with 'The loop driver' and remains efficient despite covering a high-complexity tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description covers behavioral states (INPUT_REQUIRED, WAITING), dry_run, trigger_extra, payload_overrides, and transaction_id lifecycle. It is complete for a tool of this complexity, addressing edge cases like blocked non-compliant payloads and providing the needed resolution path.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, providing baseline 3. The description adds meaningful context for `inputs` (flat shape, becoming sessionData.user_inputs) and `payload_overrides` (escape hatch for wrong flow config, not validation bypass, applies to this call only), raising the value beyond the schema. It does not elaborate on every parameter, but the schema already does.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'The loop driver' and explicitly states it 'takes the next step this mock owns, checks its preconditions, generates its payload... and POSTs it to the participant.' It clearly distinguishes itself from siblings by referencing flow_await for participant-owned moves and flow_start/restart via transaction_id minting context.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides actionable guidance: 'call again with `inputs`' for INPUT_REQUIRED steps, 'call flow_await' when WAITING, use 'dry_run: true' to inspect without sending, and use 'trigger_extra' for side-channel steps. It also explains when 'payload_overrides' is needed, giving explicit alternatives and conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
flow_restartRestart a flowA
Abandon this run's current attempt and open a fresh one of the same flow, in the same session. Use it when a run has gone wrong and you want another go: a flow's state is derived by replaying what was exchanged, so a NACKed step or an out-of-sequence callback stays part of the history and flow_start would only resume it. Nothing recorded is destroyed — the abandoned attempt keeps its payloads and stays readable with record_get_payload, because a failed attempt is a compliance finding, not a mistake to erase. The new attempt starts unbound: transaction_id comes back null and the next action mints a fresh one. Prefer this over creating a second session; an abandoned session keeps competing for the participant's callbacks on the endpoint every session shares.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | No | Why this attempt is being abandoned. Recorded against it, and worth supplying — it is what the compliance report can say about the retry. | |
| flow_id | Yes | The flow to restart. Named by flow, never by transaction: the run is what is being restarted, and it may not have a transaction id yet. | |
| session_id | Yes | Session returned by session_create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| attempt | Yes | Which try this is. 1 unless the run has been restarted; every attempt gets its own transaction_id. |
| flow_id | Yes | Address this run by (session_id, flow_id) from here on. |
| outcome | Yes | What the first step of the flow needs. |
| mock_role | Yes | The role this server plays in this flow. |
| session_id | Yes | |
| auto_advance | Yes | |
| callback_url | Yes | What the participant must call back on. Advertised as bap_uri/bpp_uri in every payload this mock sends. |
| transaction_id | Yes | Null for a new run: the transaction id belongs to whoever sends the flow's first action, so it does not exist until that action crosses the wire. Drive the run with flow_id until then; every loop answer reports the id once it is known. |
| abandoned_transaction_id | Yes | The transaction the abandoned attempt was running, or null when it never sent anything. Its payloads stay readable with record_get_payload — restarting destroys no evidence. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations, the description discloses critical behavioral traits: "Nothing recorded is destroyed" (non-destructive despite a restart), the abandoned attempt remains readable, and transaction_id comes back null for the new attempt. It also explains the compliance rationale, which is valuable context not present in the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a well-structured paragraph that front-loads the core purpose, then explains rationale, key behaviors, and alternatives. Every sentence adds value with no fluff or redundancy, making it efficient and appropriately sized for the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers all key aspects: when to use, what happens (including output semantics like null transaction_id), what does not happen (nothing destroyed), and why it's preferred over alternatives. It is complete for a tool with this complexity, especially given the presence of output schema and annotations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already describes all three parameters with 100% coverage, so the baseline is 3. The description does not add significant parameter-specific semantics beyond what the schema provides, although it does mention the return behavior of transaction_id. Since the schema covers everything, a 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function with a specific verb and resource: "Abandon this run's current attempt and open a fresh one of the same flow, in the same session." It distinguishes itself from flow_start (which resumes) and from creating a second session, making its purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance: "Use it when a run has gone wrong and you want another go." It also explains why flow_start is not appropriate (it would resume) and why a second session is discouraged, providing clear alternatives and exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
flow_startStart a flowA
Open a run of one flow and report what its first step needs. Returns the callback URL the participant under test must be able to reach — every payload this server sends advertises it as bap_uri or bpp_uri, so a participant that cannot reach it will never call back. Fails immediately if the flow has no mock config or any step with no owner, so a flow that cannot be driven is rejected before anything is sent. transaction_id comes back null: it belongs to whoever sends the flow's first action, so when that is the participant it is theirs to choose and does not exist yet. Drive the run by flow_id with flow_proceed and flow_await, which report the id once it exists.
| Name | Required | Description | Default |
|---|---|---|---|
| flow_id | Yes | Flow to run, as listed by catalog_list_flows. | |
| session_id | Yes | Session returned by session_create. | |
| auto_advance | No | Override the session default. When on, the receiver chains this mock's own steps as soon as the participant answers, pausing only for inputs, forms and errors. | |
| transaction_id | No | Resume a transaction that already exists. Omit it — a new run does not have an id yet, and inventing one here would be wrong whenever the participant sends the flow's first action, because then the id is theirs to choose. |
Output Schema
| Name | Required | Description |
|---|---|---|
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| attempt | Yes | Which try this is. 1 unless the run has been restarted; every attempt gets its own transaction_id. |
| flow_id | Yes | Address this run by (session_id, flow_id) from here on. |
| outcome | Yes | What the first step of the flow needs. |
| mock_role | Yes | The role this server plays in this flow. |
| session_id | Yes | |
| auto_advance | Yes | |
| callback_url | Yes | What the participant must call back on. Advertised as bap_uri/bpp_uri in every payload this mock sends. |
| transaction_id | Yes | Null for a new run: the transaction id belongs to whoever sends the flow's first action, so it does not exist until that action crosses the wire. Drive the run with flow_id until then; every loop answer reports the id once it is known. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnly=false, openWorldHint=true, idempotent=false), the description surfaces critical gotchas: the returned callback URL must be reachable by the participant or callbacks never arrive; invalid flows are rejected before anything is sent; and transaction_id is null because it belongs to the first action sender. This is rich, non-obvious behavioral context that will help an agent avoid mistakes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and then spends a few dense sentences on essential caveats. Every sentence carries meaningful information, though the callback URL explanation is slightly lengthy; overall it is well-structured for the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the return value (callback URL, null transaction_id), failure preconditions, and the handoff to flow_proceed/flow_await. Since an output schema exists, it doesn't need to enumerate return fields, and the provided context is sufficient for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and every parameter already has a detailed description, so the description doesn't need to compensate. It does reinforce transaction_id's null behavior, but adds little meaning beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource: 'Open a run of one flow and report what its first step needs.' It clearly distinguishes itself from siblings by naming flow_proceed and flow_await as the follow-up tools for driving the run, making the initiation role unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when to use the tool: to start a new flow run, and it points to flow_proceed and flow_await as the next steps. It also states preconditions ('Fails immediately if the flow has no mock config or any step with no owner') that help an agent decide if the tool is applicable. It does not explicitly say 'use X instead when...' but the guidance is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
form_fetchRead a pending formARead-onlyIdempotent
Read the form a flow is waiting on. When the participant hosts it, this fetches the page, screens it for active content, and returns its fields ready to fill — then call form_submit. When this mock hosts it, there is nothing to do but wait for the participant, and the answer says so. In a manual-mode session it returns the link to hand to a person instead of the fields. Omit step_key to use whichever form the flow is currently waiting on.
| Name | Required | Description | Default |
|---|---|---|---|
| step_key | No | Which form step. Omit to use whichever form the flow is waiting on. | |
| session_id | Yes | Session returned by session_create. | |
| transaction_id | Yes | Transaction the form belongs to. |
Output Schema
| Name | Required | Description |
|---|---|---|
| mode | Yes | 'llm_auto' — fill `fields` and call form_submit. 'manual' — give form_url to the human, then call form_submit with the submission_id they receive. |
| role | Yes | 'fill' — the participant hosts this form and this mock must submit it. 'host' — this mock serves it and the participant must submit it. |
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| fields | Yes | Inputs parsed out of the form. Empty in manual mode. |
| method | No | GET or POST, as the form declares. |
| form_url | No | Where the form lives. |
| step_key | Yes | |
| warnings | Yes | Anything suspicious in the page — read these before filling it. |
| action_url | No | Where a submission is POSTed. Resolved against the form's URL. |
| instructions | Yes | What to do next, given the mode and the role. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even though annotations already mark readOnlyHint, openWorldHint, and idempotentHint, the description adds valuable behavioral context: it 'screens for active content', returns fields 'ready to fill', explains the mock-host behavior ('the answer says so'), and clarifies manual-mode returns a link instead. This goes well beyond the annotations without contradicting them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three concise sentences, front-loaded with the core action ('Read the form a flow is waiting on') and then expanding into conditional scenarios. Every sentence earns its place, with no redundant filler or repetition of schema/annotation content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers all major usage modes (participant-hosted, mock-hosted, manual-mode), the next step (form_submit), and the optional step_key behavior. With an output schema present and annotations providing safety and idempotency info, the description fully addresses the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with descriptions for all parameters. The description adds extra meaning to step_key by explaining the omission behavior ('use whichever form the flow is currently waiting on'), which is not in the schema's property description. Session_id and transaction_id are already well-defined in the schema, so no further elaboration is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Read the form a flow is waiting on' – a specific verb and resource. It distinguishes the tool from siblings by explaining its role as a precursor to form_submit and differentiates from flow_get_status/flow_await by focusing on fetching and returning fields.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit usage guidance across three contexts: participant-hosted (fetches fields, then call form_submit), mock-hosted (nothing to do but wait), and manual-mode (returns a link to hand to a person). It also instructs on omitting step_key to use the current form, giving clear when-to-use and what-to-do guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
form_submitSubmit a pending formA
Complete the form step and advance the flow. In llm_auto sessions pass fields (the names come from form_fetch) and this posts them to the participant and reads back the submission id it issues. In manual sessions pass the submission_id the person was given instead. Either way the id is saved where the next step's payload expects it.
| Name | Required | Description | Default |
|---|---|---|---|
| fields | No | Field name → value, for llm_auto. Use the names from form_fetch. | |
| step_key | No | Which form step. Omit to use the one the flow is waiting on. | |
| session_id | Yes | Session returned by session_create. | |
| submission_id | No | The id the counterparty issued. Supply this in manual mode, after a human has submitted the form. | |
| transaction_id | Yes | Transaction the form belongs to. |
Output Schema
| Name | Required | Description |
|---|---|---|
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| outcome | Yes | Where the flow stands now the form is done. |
| step_key | Yes | |
| raw_response | No | The counterparty's answer, when it was not in the expected {success, submission_id} shape. Read it if the id looks wrong. |
| submission_id | Yes | What the counterparty issued for this submission. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses that the tool 'posts them to the participant' and 'reads back the submission id', revealing a network side effect not captured by annotations. It also explains that the id is saved for the next step, adding useful stateful context. It does not cover error conditions or idempotency nuances, but annotations already handle the basic safety profile, so this is solid.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core purpose, and every sentence adds meaningful detail. No redundancy or filler. Ideal structure for an AI agent to quickly parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the full workflow: what triggers the tool, the two usage modes, what the participant receives, and how the output is consumed by the next step. The output schema exists to explain return values, and annotations cover side-effect safety. No critical information is missing for an agent to select and invoke this tool confidently.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with good field descriptions, so baseline is 3. The description adds value by explaining the conditional use of `fields` vs `submission_id` based on session mode, and links `fields` names to form_fetch. This goes beyond simply restating the schema, justifying a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Complete the form step and advance the flow.' It distinguishes this from sibling tools like flow_proceed by focusing specifically on form submission, and it explains the two modes (llm_auto and manual), making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance for both session types ('In llm_auto sessions pass fields... In manual sessions pass submission_id...'). It references form_fetch for field names, providing a workflow hint. However, it does not explicitly state when not to use this tool or mention alternatives like flow_proceed, so it falls just short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
payload_validateValidate a payloadARead-onlyIdempotent
Check a protocol payload against the ONDC spec for this session's build, without sending it anywhere. Runs L0 (JSON Schema) and L1 (the spec's contextual rules); every failure comes back with a rule code and a JSONPath. Use it to inspect a body before committing to it, or to understand a refusal. Note that flow_proceed already gates what it sends, so this is not a required step in the loop. A valid verdict only covers the layers listed in checked.
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | Action to validate as. Defaults to the payload's own context.action, which is almost always what you want. | |
| payload | Yes | The full protocol payload, exactly as it would go on the wire. | |
| session_id | Yes | Session whose build (domain + version) the payload is judged against. |
Output Schema
| Name | Required | Description |
|---|---|---|
| action | Yes | The action the payload was judged as. |
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| status | Yes | |
| checked | Yes | Layers that actually produced a verdict. |
| docs_url | No | The published rule list for this build, when upstream named one. |
| findings | Yes | Every failure found, across every layer that ran. |
| unchecked | Yes | Layers that did not. A `valid` status only covers what is in `checked`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnly, idempotent, openWorld), the description adds that it runs L0 and L1 validation, returns rule codes with JSONPath on failure, and that a valid verdict only covers layers in 'checked'. This provides meaningful behavioral context about validation scope and error output, which the annotations do not.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a few sentences, each with a distinct purpose: what it does, what validation layers run, how to use it, its non-requirement in the flow, and the scope of the verdict. It is front-loaded with the core purpose and contains no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, existing output schema, and sibling tools, the description is complete. It covers the validation scope, error reporting format, usage intent, and relationship to flow_proceed, enabling an agent to select and invoke it correctly without needing additional context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description does not add new parameter-specific information beyond what the schema already states (e.g., action defaults to the payload's context.action). It does not compensate for any gaps because none exist; the schema carries the semantic load.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Check a protocol payload against the ONDC spec for this session's build, without sending it anywhere,' which uses a specific verb and resource, and immediately distinguishes it from sending tools. It clearly identifies the tool's validation role and its non-side-effect nature.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states 'Use it to inspect a body before committing to it, or to understand a refusal' and notes that 'flow_proceed already gates what it sends, so this is not a required step in the loop.' This gives clear when-to-use context and names an alternative, making it easy for an agent to decide.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
receiver_startStart the inbound receiverAIdempotent
Make sure this mock can receive the participant's callbacks, and report the URL it must use. Call it once before session_create. Under the HTTP transport the receiver is already mounted and this just reports the address; on stdio it binds a listener. Safe to call repeatedly. The address must be reachable from the participant — for a remote participant, set RECEIVER_PUBLIC_URL (or the session's receiver_public_url) to a tunnel address instead.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | No | Include a session to get its exact callback URL back. Omit for just the base URL. |
Output Schema
| Name | Required | Description |
|---|---|---|
| mode | Yes | 'mounted' — the receiver shares this server's HTTP port. 'standalone' — a listener of its own, started for the stdio transport. |
| port | No | |
| running | Yes | |
| base_url | Yes | Base URL the participant must be able to reach. |
| callback_url | No | The exact URL for the given session. Give this to the participant as its counterparty subscriber URL. |
| reachability_note | Yes | What to check before assuming the participant can reach this address. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations already indicating idempotentHint and non-read-only, the description adds substantial context: it explains that under HTTP the receiver is already mounted and only reports the address, while on stdio it binds a listener. It also warns about reachability from the participant and recommends setting RECEIVER_PUBLIC_URL for remote cases, which goes beyond any annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is slightly long but every sentence adds value: setup purpose, ordering, transport-specific behavior, idempotency, and remote configuration. It is well-structured front-loaded with the core purpose and then expands into necessary details without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple schema (one optional param) and presence of an output schema, the description fully covers necessary context: when to call, transport differences, idempotency, and remote reachability. It also mentions the output ('report the URL') even though an output schema exists, so the agent is well-equipped.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema covers the sole parameter session_id with 100% coverage, including its behavior ('Include a session to get its exact callback URL back. Omit for just the base URL.'). The description itself does not add further parameter-specific meaning, so the baseline of 3 applies without needing compensation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose with a specific verb and resource: 'Make sure this mock can receive the participant's callbacks, and report the URL it must use.' It distinguishes from siblings like receiver_stop and session_create by emphasizing its role as an initialization step ('Call it once before session_create').
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage timing: 'Call it once before session_create.' It also gives context about transport differences and remote participant configuration. However, it does not explicitly state when not to use the tool or compare it directly with alternatives like receiver_stop, so it lacks full when/when-not/alternatives coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
receiver_stopStop the inbound receiverADestructiveIdempotent
Close the standalone inbound listener. Only meaningful on the stdio transport; under HTTP the receiver shares this server's port and stops with it, and this explains that rather than failing.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| reason | Yes | |
| stopped | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate destructiveness and idempotency, and the description adds valuable behavioral context: the tool is a no-op under HTTP rather than failing, and it clarifies the relationship with the server's port. This goes beyond the structured annotations without contradicting them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single focused sentence, front-loaded with the primary action ('Close the standalone inbound listener') followed by necessary context. Every clause adds value, with no fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter tool with an output schema and strong annotations, the description is complete. It clarifies the key edge case (HTTP transport) and the tool's role relative to the server lifecycle, leaving no significant gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters, so schema coverage is vacuously 100%. The description adds operational meaning beyond the schema by explaining the transport-dependent behavior, which is more relevant than parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action: 'Close the standalone inbound listener.' It uses a specific verb and resource, and distinguishes from siblings like receiver_start by noting transport-specific behavior. The addition of the HTTP context clarifies scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when the tool is meaningful: 'Only meaningful on the stdio transport; under HTTP the receiver shares this server's port and stops with it.' It implies when not to use it, though it does not explicitly name alternative tools or provide exclusionary guidance beyond the transport condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_get_dataRead a transaction's business dataARead-onlyIdempotent
The values a flow has accumulated across its steps — provider ids, order ids, form submission ids — as the mock config saved them. This is what the next step's payload is generated from, so read it when a step reports missing requirements. Large values (resolved form HTML) are listed under 'omitted' rather than returned; ask for one by name.
| Name | Required | Description | Default |
|---|---|---|---|
| keys | No | Restrict to these business-data keys. Omit for everything. | |
| session_id | Yes | Session returned by session_create. | |
| transaction_id | Yes | Transaction to read. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | Business data accumulated across the flow's steps so far. |
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| omitted | Yes | Keys held back for size — typically resolved form HTML. Ask for one by name. |
| transaction_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as read-only and idempotent, so the description adds high-value behavior: large values are listed under 'omitted' rather than returned, and users can request them by name. It also clarifies that values are as saved by the mock config, which is non-obvious and useful.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three focused sentences: what the data is, when to read it, and how omitted values behave. Every sentence adds unique value with no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema and comprehensive annotations, the description provides the essential behavioral context: it explains the data source, the likely use case, and a notable limitation (omitted large values). This is sufficient for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema covers all parameters with descriptions, so the baseline is 3. The description adds meaningful semantics by explaining that large values are omitted and can be retrieved by using the 'keys' parameter ('ask for one by name'), and by giving examples of value types. This goes beyond the schema but does not fully carry parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as reading a transaction's accumulated business data, with concrete examples (provider IDs, order IDs, form submission IDs). It also distinguishes this from related tools like record_get_payload by noting this data is what the next step's payload is generated from.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use this tool: 'read it when a step reports missing requirements.' It also explains the relationship to payload generation, providing useful context. It does not explicitly name alternatives or state when not to use it, but the guidance is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_get_eventsRe-read the session event journalARead-onlyIdempotent
Read this session's event journal without consuming it. You do not normally need this: every session-scoped tool result already carries the events since your last call, delivered once each. Reach for it when a result said more was outstanding, when you want to re-read something already delivered, or to recover a delta lost to an error — reading here never moves the delivery cursor, so it cannot consume what piggyback has not yet shown you.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Most entries to return, newest-biased. Defaults to 50. | |
| since_seq | No | Only entries newer than this journal seq. Omit for everything still held — the journal keeps the last few hundred entries. | |
| session_id | Yes | Session returned by session_create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| more | Yes | Matching entries beyond `limit`. Raise since_seq to walk on. |
| events | Yes | Oldest first. |
| delivered_through | Yes | Journal seq already delivered by piggyback. Reading here does not move it, so anything at or below this has been seen once already. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true, but the description adds substantial context beyond these: the non-consuming behavior, the piggyback delivery model, and the fact that reading cannot consume what is still pending. This goes well beyond the structured fields, enhancing transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Despite its length, every sentence earns its place. The description front-loads the core purpose, then justifies when to use it and clarifies a subtle behavioral detail (cursor movement). It is dense yet efficient, with no filler words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the existence of an output schema, return values need not be described. The description thoroughly covers the tool's context—normal usage, exceptional cases, and the critical cursor behavior—making it complete for a 3-parameter tool with no nested objects.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with all three parameters (limit, since_seq, session_id) already documented. The description does not add meaning beyond what the schema provides, so the baseline score of 3 is appropriate—schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb and resource: 'Read this session's event journal without consuming it.' It differentiates from siblings by emphasizing the non-consuming, re-read nature, which distinguishes it from other record_get_* tools and the piggyback delivery mechanism.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance is provided: 'You do not normally need this' states the default, while 'Reach for it when a result said `more` was outstanding, when you want to re-read something already delivered, or to recover a delta lost to an error' gives clear triggers. It also explains that reading never moves the cursor, which is crucial for choosing this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_get_payloadRead a recorded payloadARead-onlyIdempotent
Fetch a payload this session sent or received, by the handle reported in flow_get_status or flow_await. Payload bodies are held server-side and can be very large — a catalog runs to hundreds of kilobytes — so prefer a jsonpath slice (e.g. $.message.catalog.providers[*].id) over the whole body. The result says whether it was truncated.
| Name | Required | Description | Default |
|---|---|---|---|
| jsonpath | No | JSONPath to slice out instead of the whole body, e.g. $.message.catalog.providers[*].id. Use this on large catalogs. | |
| max_bytes | No | Truncate the serialised result past this many bytes. Defaults to 20000. | |
| payload_id | Yes | Payload handle, as reported by flow_get_status or flow_await. | |
| session_id | Yes | Session returned by session_create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ack | No | The ACK/NACK exchanged for this call, when one was recorded. |
| action | Yes | |
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| payload | Yes | The whole body, or — when `jsonpath` was given — the **list of matches** for it. A single match is therefore still wrapped in an array: `$.context.bpp_uri` on a string field reads `["https://…"]`. Read `jsonpath_matches` before concluding the value is itself a list. |
| direction | Yes | 'outbound' if this mock sent it, 'inbound' if the participant did. |
| timestamp | Yes | |
| truncated | Yes | True when the body was cut short; narrow it with jsonpath. |
| message_id | Yes | |
| payload_id | Yes | |
| size_bytes | Yes | Size of the full stored body. |
| jsonpath_matches | No | How many nodes the `jsonpath` matched. Present only when one was given. `payload` is that many elements long, so the outer array is this count and not part of the stored value. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true. The description adds valuable context beyond annotations: payloads are held server-side, can be very large, and the result includes a truncation indicator. This helps the agent understand performance and response characteristics, though it doesn't cover exhaustive edge cases.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with purpose, followed by practical guidance. No wasted words; every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema, rich parameter descriptions, and annotations, the description provides sufficient operational context: handle source, large-payload warning, jsonpath recommendation, and truncation notice. It is complete for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema covers all parameters with descriptions (100% coverage). The description repeats the jsonpath example but does not add new meaning beyond the schema. Per the baseline rule, with high schema coverage a score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Fetch a payload this session sent or received, by the handle reported in flow_get_status or flow_await.' It clearly distinguishes the tool from sibling record_* tools by focusing on payloads and specifying the handle source.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context: use this tool to retrieve payloads using handles from flow_get_status or flow_await. It also gives practical advice to prefer jsonpath slicing for large payloads. However, it does not explicitly name alternative tools or state when not to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
session_createCreate mock sessionA
Open a session against a network participant under test and list every flow available for its build. Supply the participant's subscriber URL and whether it is a BAP (buyer app) or BPP (seller app); this server automatically takes the opposite role and answers as that counterparty. Domain, version and use-case must be a published combination — call catalog_list_builds first if unsure, because an unknown use-case is rejected rather than silently returning no flows. The returned callback_url is what the participant must send its callbacks to; give it to them before starting a flow.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | ONDC domain code, e.g. ONDC:FIS12. | |
| np_type | Yes | What the participant under test is: BAP (buyer app) or BPP (seller app). The mock takes the opposite role. | |
| usecase | Yes | Use-case name exactly as published, e.g. 'PERSONAL LOAN'. Case- and space-sensitive. | |
| version | Yes | Spec version, e.g. 2.0.3. | |
| auto_advance | No | Defaults to on for llm_auto sessions and off for manual ones. When on, this server sends its own next step as soon as the participant answers, instead of waiting to be asked — pausing for inputs, forms and errors. You do not see less of the flow: everything sent this way comes back as a CHAIN_SENT event on your next tool result. Set it false to drive every step yourself. | |
| subscriber_id | No | Registry subscriber id of the participant, when known. | |
| subscriber_url | Yes | Base URL of the participant under test, e.g. https://bap.example.com. | |
| interaction_mode | No | 'llm_auto' (default) — you supply every input and fill forms yourself. 'manual' — a human supplies them; forms come back as links to hand over. | |
| receiver_public_url | No | Override the URL advertised for callbacks. Set this to your tunnel address (ngrok, cloudflared) whenever the participant is not on this machine — otherwise its callbacks go somewhere it cannot reach. |
Output Schema
| Name | Required | Description |
|---|---|---|
| flows | Yes | Every flow published for this build, ready to start. |
| total | Yes | Number of flows available. |
| session | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description reveals non-obvious behaviors: the server automatically takes the opposite role, an unknown use-case is rejected (not silently empty), and the callback_url must be given to the participant. These are valuable insights beyond the annotations (readOnlyHint=false, openWorldHint=true) and significantly improve the agent's understanding of side effects and failure modes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, each serving a distinct purpose: action, role selection, published-combo requirement, and callback_url handoff. There is no fluff or repetition; the most important info is front-loaded in the first sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (9 params, 5 required) and the existence of an output schema, the description covers the operation's purpose, a critical prerequisite (validating builds), an error condition, and an operational follow-up (giving callback_url to the participant). This is complete enough for an agent to invoke the tool correctly without consulting siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so parameters are already documented, but the description adds relational meaning: it explains that np_type determines the mock's opposite role, and that domain/version/usecase must form a published combination. This goes beyond the schema's individual field descriptions, enriching the agent's ability to choose valid parameter values.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Open a session against a network participant under test and list every flow available for its build.' This clearly states the action (create session) and the immediate outcome (list flows), and it distinguishes itself from sibling tools like flow_start or catalog_list_builds by focusing on session creation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides clear contextual guidance, including the prerequisite step 'call catalog_list_builds first if unsure' and a practical note about handing the callback_url to the participant. It does not explicitly say 'use this before flow_start' or contrast with alternatives like flow_get_status, but the context is strong enough to infer when it applies.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
session_getGet sessionARead-onlyIdempotent
Fetch a session by id: the participant under test, the role this server plays against it, the build, and when the session expires. Returns an error result if the session is unknown or has expired.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Session returned by session_create. |
Output Schema
| Name | Required | Description |
|---|---|---|
| events | No | What has happened in this session since your last call — the participant's callbacks, steps sent automatically, refusals, form submissions. Attached to every session-scoped result and delivered exactly once, so read it here instead of polling. Absent when nothing happened. `more` above zero means call record_get_events for the rest. |
| session | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish read-only and idempotent behavior. The description adds the error case (unknown/expired session) and specifies the contents of the response, going beyond the structured annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise, front-loaded sentences convey purpose, return value, and error behavior without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and low complexity (single parameter, read-only), the description covers the essential purpose, return contents, and error semantics. No significant gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides a description for session_id ('Session returned by session_create'). With 100% schema coverage, the description adds no additional semantics for the parameter, meriting a baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool fetches a session by ID and enumerates the returned fields (participant, role, build, expiry). This distinguishes it from session_create and other siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context for when to use the tool (retrieving a session by its ID) and what it returns, but does not explicitly mention alternatives or exclusions. Since no other sibling tool directly competes, it earns a 4.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
21 tool updates
v0.1.0- First observed
catalog_describe_flow - First observed
catalog_list_builds - First observed
catalog_list_flows - First observed
catalog_load_flow_config - First observed
feedback_list_reports - First observed
feedback_submit_report - First observed
flow_await - First observed
flow_get_status - First observed
flow_proceed - First observed
flow_restart - First observed
flow_start - First observed
form_fetch - First observed
form_submit - First observed
payload_validate - First observed
receiver_start - First observed
receiver_stop - First observed
record_get_data - First observed
record_get_events - First observed
record_get_payload - First observed
session_create - First observed
session_get
TDQS
Scored across 21 tools
Every tool targets a distinct resource and action: flow control (start/proceed/await/restart/status), session management (create/get), catalog discovery (list_builds/list_flows/describe_flow/load_config), receiver lifecycle (start/stop), form handling (fetch/submit), payload validation, record retrieval (payload/data/events), and feedback (submit/list). Even similar-sounding tools like flow_get_status and flow_await have clearly separated purposes: one is pull-based state inspection, the other is push-based waiting with event delivery. No two tools could be confused for each other.
All tool names follow a strict noun_verb or noun_verb_object pattern (e.g., flow_start, session_create, catalog_list_builds, form_submit, record_get_payload). The prefix consistently identifies the resource, and the verb indicates the action. There is no mixing of conventions; all names are lowercase with underscores.
At 21 tools, the set is above the typical 3-15 range but not excessive. Each tool serves a distinct purpose in the ONDC mock participant workflow, and the complexity of the domain (sessions, flows, catalogs, forms, records, feedback) justifies the number. It feels slightly heavy but well-scoped, with no redundant tools.
The tool surface covers the core lifecycle: session creation, flow start/proceed/await/restart, catalog exploration, form processing, payload validation, and record retrieval. Minor gaps exist, such as no session listing or explicit cancellation flow (though flow_restart covers restarting), and no generic message-sending tool outside of flow_proceed. These are workable gaps, not blockers, for the stated testing purpose.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
MCP server for Boson Protocol — on-chain agentic commerce for physical & digital goods.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
Workflow diagnostics, capability routing, and x402 settlement for MCP-compatible agents.
Hosted MCP server for AI-driven data ops. Create apps, manage schemas, and CRUD structured data.
Related MCP Servers
- AlicenseAqualityAmaintenanceGoverned agent execution gateway for LLM workflows, providing deterministic FSM-based execution, audit trails, and idempotency guarantees via MCP.5MIT
- FlicenseNot gradedqualityBmaintenanceAn extensible MCP server and generative UI engine for hosting interactive B2B enterprise workflows with dynamic styling and stateful simulators.-
- AlicenseNot gradedqualityCmaintenanceProvides a sovereign, MIT-licensed MCP server for professional-service workflows, running entirely on your infrastructure with Ed25519 cryptographic signing for every action.MIT
- AlicenseNot gradedqualityCmaintenanceA sovereign, MIT-licensed MCP server for professional-service workflow automation, enabling offline-capable, cryptographically signed operations without vendor lock-in.MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ONDC-Official/automation-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server