Skip to main content
Glama
ONDC-Official

ondc-mcp

Official

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 test

Layout

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

*.tool.ts

Protocol edge. Schemas, annotations, result shaping. Knows MCP only.

*.service.ts

Business logic.Imports nothing from the SDK. Throws AppError.

*.repository.ts

Data access. Interface + in-memory implementation.

*.schema.ts

zod schemas;z.infer<> types derive from them.

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

{ isError: true } result

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-console is an ESLint error — load-bearing here, not stylistic.

  • src/entrypoints/stdio.test.ts spawns 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:

  1. 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 a 406.

  2. A full _meta envelope on every requestprotocolVersion, clientInfo, clientCapabilities. A missing key is a -32602 naming it.

  3. Mcp-Method, plus Mcp-Name for tools/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 401 with WWW-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.

  • /health and /ready stay 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.expiresAt is unset — silently, as a plain 401. Both shipped verifiers populate it from the JWT exp claim.

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:

REDIS_URL

Store

Behaviour

unset

InMemoryCacheStore

Zero infrastructure. A restart wipes everything.

redis://...

RedisCacheStore

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 dev

Keys 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 every flow_proceed and 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. createContainer says so in place.

  • A failed read throws, it does not return undefined. undefined means "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 read

What 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

test/harness.ts: a real Client ↔ real McpServer over InMemoryTransport

HTTP

app.inject() — full stack, no socket

stdio

Real subprocess, asserting stdout purity

CacheStore

One shared contract suite (test/cache-store-contract.ts) run against every implementation

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

  1. src/modules/<name>/ with *.schema.ts, *.service.ts, *.tool.tssession/ is the smallest complete example.

  2. Write schemas first — everything else derives from them.

  3. Keep the service free of SDK imports.

  4. 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/fastify publishes a latest tag that lags its siblings, so a caret range silently mixes versions. npm run sdk:check surfaces the GA bump.

  • SDK types are confined to mcp/, entrypoints/, plugins/mcp.ts, lib/define-tool.ts and lib/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-eslint supports <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.mts references Buffer.

  • @modelcontextprotocol/node peer-depends on hono even under Fastify. It is a transitive requirement of the adapter, not a stray dependency.

Available Tools

21 tools
catalog_describe_flowDescribe a flowA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
flow_idYesFlow identifier, as listed by catalog_list_flows.
session_idYesSession returned by session_create.

Output Schema

ParametersJSON Schema
NameRequiredDescription
tagsYes
flow_idYes
sequenceYesThe ordered main sequence.
mock_roleYesThe role this session's mock plays.
step_countYes
descriptionYes
extra_sequenceYesParallel or unsolicited steps, if any.

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 buildsA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
domainNoRestrict the catalog to one domain code, e.g. ONDC:FIS12. Omit for all.

Output Schema

ParametersJSON Schema
NameRequiredDescription
totalYesNumber of domains returned.
buildsYes

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 sessionA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
session_idYesSession returned by session_create.

Output Schema

ParametersJSON Schema
NameRequiredDescription
buildYes
flowsYes
totalYes
mock_roleYes
session_idYes

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 configA
Idempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
flow_idYesFlow whose mock-runner config should be loaded.
session_idYesSession returned by session_create.

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaYesConfig identity as published by the config-service.
stepsYes
flow_idYes
cache_keyYesServer-side handle for the cached config, for later execution.
step_countYes
total_bytesYesSize of the whole config held server-side.
helper_lib_bytesYesSize of the shared helper library carried by the config.
validation_lib_bytesYes

TDQS

A4.1/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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 sessionA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
session_idYes
include_bodyNoRender each incident as the fully-redacted report that would be uploaded. This is how you answer 'what are you sending about me?'.

Output Schema

ParametersJSON Schema
NameRequiredDescription
eventsNoWhat 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.
sharingYesWhere these go, in one sentence, so it can be repeated to the user.
incidentsYes

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
outcomeYes
attemptedNoWhat you tried, in order, including what did not work.
diagnosisYesWhat you concluded was actually wrong.
session_idYes
incident_idYesFrom the ISSUE_OPEN event, or from feedback_list_reports.
tooling_gapNoWhat would have let you resolve this faster.
suspected_causeYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
stateYesThe **derived** state. If it disagrees with your `outcome`, the report keeps both — that disagreement is itself a finding.
eventsNoWhat 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.
messageYes
acceptedYes
incident_idYes

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 participantA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindsNoSession 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_idNoThe flow started with flow_start. Works before the transaction id exists, so prefer it.
flow_idsNoSession scope only. Wake only for these flows. Same rule as `kinds`: other flows' events are delivered, they just do not end the wait.
after_seqNoRun 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_idYesSession returned by session_create.
timeout_msNoHow long to block. Capped server-side; defaults to the cap.
transaction_idNoA specific transaction. Only known once the flow's first action has crossed the wire.

Output Schema

ParametersJSON Schema
NameRequiredDescription
seqYesRun 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.
nextNoWhat the loop needs now the wait is over. Run scope only — a session wait covers several runs, so it answers with `runs` instead.
runsNoSession scope only: where every run in this session stands, so you can pick which to drive next.
eventNo
scopeYes'run' — you named a flow or transaction, and this reports that one. 'session' — you named neither, and this reports the whole session.
eventsNoWhat 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_outYesTrue when nothing arrived. Call again to keep waiting.
transaction_idYesThe 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

A5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 statusA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
flow_idNoThe flow started with flow_start. Works before the transaction id exists, so prefer it.
session_idYesSession returned by session_create.
transaction_idNoA specific transaction. Only known once the flow's first action has crossed the wire.

Output Schema

ParametersJSON Schema
NameRequiredDescription
seqYesLatest event number. Pass it to flow_await as after_seq.
nextYesWhat the loop needs next, without doing it.
eventsNoWhat 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.
attemptYesWhich try of this flow the run is on. 1 unless restarted.
flow_idYes
sequenceYesThe main sequence, in order.
abandonedNoSet 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.
attentionNoWhy auto-advance stopped, if it did.
mock_roleYes
extra_stepsYesSide-channel steps — unsolicited updates and their replies.
flow_statusYes
missed_stepsYesExchanges that did not fit the flow. Compliance findings.
transaction_idYesNull while the flow's first action has not yet crossed.
reference_data_keysYesForm steps with a resolved artefact waiting in business data.

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
inputsNoValues 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_runNoGenerate 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_idNoThe flow started with flow_start. Works before the transaction id exists, so prefer it.
session_idYesSession returned by session_create.
trigger_extraNoFire 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_idNoA specific transaction. Only known once the flow's first action has crossed the wire.
payload_overridesNoPatch 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

ParametersJSON Schema
NameRequiredDescription
ackNoHow the participant answered a SENT step.
actionNoIts protocol action or form type.
eventsNoWhat 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.
reasonNoMachine-readable cause of a block.
detailsNoEverything known about the block — requirement codes, errors.
messageYes
outcomeYes
ack_bodyNoThe participant's synchronous response, verbatim.
form_urlNoWhere the form lives, for whichever side has to open it.
step_keyNoThe step this outcome is about.
form_roleNo'fill' — the participant hosts the form and this mock must submit it. 'host' — this mock serves the form and the participant must submit it.
overridesNoPaths 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_idNoHandle for the payload produced. Read it with record_get_payload.
validationNoHow 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_statusNo
input_problemsNoWhy 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_idNoThis 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_actionNoThe action now expected from the participant.
inputs_requiredNoWhat the step declares it needs. Send `fields` as a flat object under flow_proceed's `inputs`.
override_problemsNoWhy `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

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
reasonNoWhy this attempt is being abandoned. Recorded against it, and worth supplying — it is what the compliance report can say about the retry.
flow_idYesThe 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_idYesSession returned by session_create.

Output Schema

ParametersJSON Schema
NameRequiredDescription
eventsNoWhat 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.
attemptYesWhich try this is. 1 unless the run has been restarted; every attempt gets its own transaction_id.
flow_idYesAddress this run by (session_id, flow_id) from here on.
outcomeYesWhat the first step of the flow needs.
mock_roleYesThe role this server plays in this flow.
session_idYes
auto_advanceYes
callback_urlYesWhat the participant must call back on. Advertised as bap_uri/bpp_uri in every payload this mock sends.
transaction_idYesNull 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_idYesThe 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

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
flow_idYesFlow to run, as listed by catalog_list_flows.
session_idYesSession returned by session_create.
auto_advanceNoOverride 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_idNoResume 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

ParametersJSON Schema
NameRequiredDescription
eventsNoWhat 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.
attemptYesWhich try this is. 1 unless the run has been restarted; every attempt gets its own transaction_id.
flow_idYesAddress this run by (session_id, flow_id) from here on.
outcomeYesWhat the first step of the flow needs.
mock_roleYesThe role this server plays in this flow.
session_idYes
auto_advanceYes
callback_urlYesWhat the participant must call back on. Advertised as bap_uri/bpp_uri in every payload this mock sends.
transaction_idYesNull 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

A4.4/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 formA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
step_keyNoWhich form step. Omit to use whichever form the flow is waiting on.
session_idYesSession returned by session_create.
transaction_idYesTransaction the form belongs to.

Output Schema

ParametersJSON Schema
NameRequiredDescription
modeYes'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.
roleYes'fill' — the participant hosts this form and this mock must submit it. 'host' — this mock serves it and the participant must submit it.
eventsNoWhat 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.
fieldsYesInputs parsed out of the form. Empty in manual mode.
methodNoGET or POST, as the form declares.
form_urlNoWhere the form lives.
step_keyYes
warningsYesAnything suspicious in the page — read these before filling it.
action_urlNoWhere a submission is POSTed. Resolved against the form's URL.
instructionsYesWhat to do next, given the mode and the role.

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
fieldsNoField name → value, for llm_auto. Use the names from form_fetch.
step_keyNoWhich form step. Omit to use the one the flow is waiting on.
session_idYesSession returned by session_create.
submission_idNoThe id the counterparty issued. Supply this in manual mode, after a human has submitted the form.
transaction_idYesTransaction the form belongs to.

Output Schema

ParametersJSON Schema
NameRequiredDescription
eventsNoWhat 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.
outcomeYesWhere the flow stands now the form is done.
step_keyYes
raw_responseNoThe counterparty's answer, when it was not in the expected {success, submission_id} shape. Read it if the id looks wrong.
submission_idYesWhat the counterparty issued for this submission.

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 payloadA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
actionNoAction to validate as. Defaults to the payload's own context.action, which is almost always what you want.
payloadYesThe full protocol payload, exactly as it would go on the wire.
session_idYesSession whose build (domain + version) the payload is judged against.

Output Schema

ParametersJSON Schema
NameRequiredDescription
actionYesThe action the payload was judged as.
eventsNoWhat 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.
statusYes
checkedYesLayers that actually produced a verdict.
docs_urlNoThe published rule list for this build, when upstream named one.
findingsYesEvery failure found, across every layer that ran.
uncheckedYesLayers that did not. A `valid` status only covers what is in `checked`.

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 receiverA
Idempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
session_idNoInclude a session to get its exact callback URL back. Omit for just the base URL.

Output Schema

ParametersJSON Schema
NameRequiredDescription
modeYes'mounted' — the receiver shares this server's HTTP port. 'standalone' — a listener of its own, started for the stdio transport.
portNo
runningYes
base_urlYesBase URL the participant must be able to reach.
callback_urlNoThe exact URL for the given session. Give this to the participant as its counterparty subscriber URL.
reachability_noteYesWhat to check before assuming the participant can reach this address.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 receiverA
DestructiveIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
reasonYes
stoppedYes

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 dataA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
keysNoRestrict to these business-data keys. Omit for everything.
session_idYesSession returned by session_create.
transaction_idYesTransaction to read.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYesBusiness data accumulated across the flow's steps so far.
eventsNoWhat 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.
omittedYesKeys held back for size — typically resolved form HTML. Ask for one by name.
transaction_idYes

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 journalA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMost entries to return, newest-biased. Defaults to 50.
since_seqNoOnly entries newer than this journal seq. Omit for everything still held — the journal keeps the last few hundred entries.
session_idYesSession returned by session_create.

Output Schema

ParametersJSON Schema
NameRequiredDescription
moreYesMatching entries beyond `limit`. Raise since_seq to walk on.
eventsYesOldest first.
delivered_throughYesJournal seq already delivered by piggyback. Reading here does not move it, so anything at or below this has been seen once already.

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 payloadA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
jsonpathNoJSONPath to slice out instead of the whole body, e.g. $.message.catalog.providers[*].id. Use this on large catalogs.
max_bytesNoTruncate the serialised result past this many bytes. Defaults to 20000.
payload_idYesPayload handle, as reported by flow_get_status or flow_await.
session_idYesSession returned by session_create.

Output Schema

ParametersJSON Schema
NameRequiredDescription
ackNoThe ACK/NACK exchanged for this call, when one was recorded.
actionYes
eventsNoWhat 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.
payloadYesThe 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.
directionYes'outbound' if this mock sent it, 'inbound' if the participant did.
timestampYes
truncatedYesTrue when the body was cut short; narrow it with jsonpath.
message_idYes
payload_idYes
size_bytesYesSize of the full stored body.
jsonpath_matchesNoHow 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

A4.3/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
domainYesONDC domain code, e.g. ONDC:FIS12.
np_typeYesWhat the participant under test is: BAP (buyer app) or BPP (seller app). The mock takes the opposite role.
usecaseYesUse-case name exactly as published, e.g. 'PERSONAL LOAN'. Case- and space-sensitive.
versionYesSpec version, e.g. 2.0.3.
auto_advanceNoDefaults 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_idNoRegistry subscriber id of the participant, when known.
subscriber_urlYesBase URL of the participant under test, e.g. https://bap.example.com.
interaction_modeNo'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_urlNoOverride 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

ParametersJSON Schema
NameRequiredDescription
flowsYesEvery flow published for this build, ready to start.
totalYesNumber of flows available.
sessionYes

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 sessionA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
session_idYesSession returned by session_create.

Output Schema

ParametersJSON Schema
NameRequiredDescription
eventsNoWhat 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.
sessionYes

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

  1. 21 tool updatesv0.1.0
    • First observedcatalog_describe_flow
    • First observedcatalog_list_builds
    • First observedcatalog_list_flows
    • First observedcatalog_load_flow_config
    • First observedfeedback_list_reports
    • First observedfeedback_submit_report
    • First observedflow_await
    • First observedflow_get_status
    • First observedflow_proceed
    • First observedflow_restart
    • First observedflow_start
    • First observedform_fetch
    • First observedform_submit
    • First observedpayload_validate
    • First observedreceiver_start
    • First observedreceiver_stop
    • First observedrecord_get_data
    • First observedrecord_get_events
    • First observedrecord_get_payload
    • First observedsession_create
    • First observedsession_get

TDQS

A4.4/5.0

Scored across 21 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count4/5

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.

Completeness4/5

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

ActivityActive
ResponsivenessNo issues

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

Related MCP Servers

Latest Blog Posts

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