nofax
This server provides a human-in-the-loop MCP surface for sending phone notifications, requesting human decisions, waiting on them, and inspecting durable request state.
Send one-way phone notifications with
nofax_notify.Request human Allow/Deny approval with
nofax_request_approval, returning a durablerequestId.Request a human choice among up to three explicit options with
nofax_request_choice.Request free-text refinement from a human with
nofax_request_refinement.Wait or long-poll for a human response with
nofax_wait_for_response, repeating while pending.Inspect safe metadata and terminal state of a known request with
nofax_get_request.List pending, unresolved request handles with
nofax_list_pendingfor recovery after interruption.
Allows sending phone notifications and interactive approval requests through ntfy-compatible servers, including one-way notifications, allow/deny decisions, choices, and free-text refinements.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@nofaxrequest approval to deploy release 1.4.0 to production"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Nofax
Human-in-the-loop approvals and notifications for AI coding agents, without running a Nofax SaaS.
Nofax is a small open-source bridge between an agent and a human. Local mode can pause an AI workflow, notify your phone, and return an explicit decision. An optional self-deployed Cloudflare Worker exposes a deliberately narrower remote MCP surface for one-way notifications and safe request inspection.
No Nofax account. No paid model API. No inbound port on your machine. MIT licensed.
Current status: local Nofax is on the stable
0.2.xline. The optional Cloudflare Worker is the upcoming0.3.0remote surface and is developed alongside the local package.
Why Nofax
Agent workflows increasingly need a clean answer to one question: when automation reaches a human decision boundary, how does it ask without pretending that silence means approval?
Nofax keeps that boundary explicit:
pending is never approval;
timeout and transport failure fail closed;
the first accepted terminal response wins;
agent-specific hook schemas stay isolated in adapters;
remote access is intentionally narrower than local access;
Nofax does not grant authority the calling agent did not already have.
Related MCP server: Relay
Two operating modes
Capability | Local Nofax | Remote Worker |
Transport | stdio / CLI hooks | MCP Streamable HTTP |
One-way notification | Yes | Yes |
Allow / Deny | Yes | No |
Explicit choices | Yes | No |
Free-text refinement | Yes | No |
Wait for human response | Yes | No |
Read request metadata | Yes | Yes |
Durable state | Local files | Existing SQLite Durable Object rows |
Hosted by Nofax | No | No — self-deployed Worker |
Remote authentication | Local process boundary | Private bearer key |
The remote Worker is not a hosted remote-approval service. It can send an informational notification and inspect existing request state, but it has no approval callback, choice, refinement, wait, webhook, or arbitrary remote-write endpoint.
Quick start
1. Install
npm install -g nofaxRequires Node.js 20 or newer.
2. Initialize
nofax initNofax creates ~/.nofax/config.json and generates a high-entropy notification topic. With the default transport, subscribe to the displayed topic in the ntfy mobile app.
3. Test
nofax test4. Use it
nofax notify --title "Build finished" "All tests passed"
nofax approve --title "Deploy?" "Release 1.4.0 is ready"
nofax refine --title "Refine draft" "Tell me what to change"An approval resolves to stable terminal JSON:
{"decision":"allow"}or:
{"decision":"deny"}If the request is still pending, times out, disconnects, or hits a transport error, Nofax never converts that condition into approval.
MCP
Start the local stdio MCP server:
nofax mcpLocal MCP exposes:
nofax_notifynofax_request_approvalnofax_request_choicenofax_request_refinementnofax_wait_for_responsenofax_get_requestnofax_list_pending
Interactive requests return a durable request ID. nofax_wait_for_response performs a bounded wait; callers must repeat the wait while the request remains pending rather than infer approval.
Agent integrations
Claude Code
Use Nofax as a local PermissionRequest hook in ~/.claude/settings.json:
{
"hooks": {
"PermissionRequest": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "nofax hook claude"
}
]
}
]
}
}Codex
Codex hooks are enabled by default. Configure ~/.codex/hooks.json:
{
"hooks": {
"PermissionRequest": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "nofax hook codex",
"statusMessage": "Waiting for Nofax approval"
}
]
}
]
}
}Restart Codex, run /hooks, and review/trust the exact Nofax hook definition before relying on it. Codex skips non-managed hooks until they are trusted, and a changed hook definition must be reviewed again. If an administrator or local policy has explicitly disabled hooks, re-enable them with [features] hooks = true in ~/.codex/config.toml.
Codex currently evaluates PermissionRequest hooks before its configured approval reviewer. A terminal Nofax Allow/Deny therefore resolves the request before Codex can route it to approvals_reviewer = "auto_review" (or the legacy guardian_subagent value). If you want Nofax to be the human approval surface, use approvals_reviewer = "user"; do not combine this Nofax approval hook with Auto-review/Guardian expecting both reviewers to run. Current Codex hook input does not expose the effective reviewer, so Nofax cannot safely distinguish a user-routed approval from one that Codex intended to auto-review.
PermissionRequest hooks are also serial with Codex's native approval UI: while Nofax is waiting, the normal Codex approval prompt is not simultaneously available. If Nofax returns no decision (for example after timeout or transport failure), Codex falls back to its normal approval flow. Nofax never converts that fallback condition into approval.
Gemini CLI
Current Gemini CLI builds expose a synchronous BeforeTool hook that can allow or deny a tool call. Route selected tools through Nofax in ~/.gemini/settings.json:
{
"hooks": {
"BeforeTool": [
{
"matcher": "run_shell_command|write_file|replace",
"hooks": [
{
"name": "nofax-approval",
"type": "command",
"command": "nofax hook gemini",
"timeout": 305000
}
]
}
],
"Notification": [
{
"matcher": "ToolPermission",
"hooks": [
{
"name": "nofax-notification",
"type": "command",
"command": "nofax hook gemini"
}
]
}
]
}
}BeforeTool waits for an explicit Nofax Allow/Deny result. A Nofax timeout or transport failure returns Gemini's ask decision, forcing the native interactive confirmation instead of allowing an auto-approval policy to treat the missing Nofax decision as permission. The Notification hook remains advisory and is forwarded only as a phone notification.
Adjust the matcher to the tools you want Nofax to gate. Keep the hook timeout longer than Nofax's configured approval timeout (timeoutSeconds, 300 seconds by default).
Optional remote Cloudflare Worker
The worker/ package provides a private, self-deployed MCP endpoint:
remote MCP client
|
| authenticated Streamable HTTP
v
Cloudflare Worker
|
+--> nofax_notify ------> ntfy ------> phone
|
+--> SQLite Durable Object
|
+--> get request metadata
+--> list pending requestsIt exposes exactly three tools:
nofax_notify— one-way notification only;nofax_get_request— read one safe request projection;nofax_list_pending— read unresolved, unexpired request projections.
Deploy from worker/:
npm ci
npx wrangler login
npx wrangler secret put NOFAX_REMOTE_KEY
npx wrangler secret put NTFY_TOPIC
npm run check
npm run deployPreferred MCP connection:
https://<worker>.workers.dev/mcp
Authorization: Bearer <NOFAX_REMOTE_KEY>Clients that cannot attach a static authorization header can use the compatibility capability path:
https://<worker>.workers.dev/mcp/<NOFAX_REMOTE_KEY>Treat the complete capability URL like a password.
See docs/remote-mcp.md for deployment, threat boundaries, and qualification details.
Important: public ntfy + serverless egress
The default public ntfy.sh service applies publisher quotas. Serverless platforms such as Cloudflare Workers may use shared outbound IP space, so a Worker can receive an ntfy 42908 daily-quota response even when that individual Worker has sent very little traffic. That limit is imposed by ntfy, not by the Cloudflare Workers request quota.
For reliability-sensitive deployments, use a notification provider whose quota is tied to your own authenticated account/identity, or operate a trusted self-hosted transport. Do not build a critical workflow around anonymous public-topic quota assumptions.
Security model
Nofax is a transport and human-interaction component, not an authorization policy engine.
Local mode:
pending, timeout, disconnect, malformed state, and network failure never mean approval;
the first valid terminal response wins;
notification topics and one-time response topics are capabilities;
public ntfy is not end-to-end encrypted from the provider;
redaction is best-effort and cannot reliably identify secrets embedded in arbitrary free-form text.
Remote mode:
only explicit
nofax_notifyperforms an external messaging side effect;request-inspection operations are read-only and do not perform hidden cleanup writes;
remote approval, callback, webhook, refinement, choice, and wait surfaces are absent;
NOFAX_REMOTE_KEYis a bearer credential;remote projections omit callback capabilities, prompt/message text, and internal allowed-decision lists.
Read SECURITY.md before using Nofax with sensitive information.
Configuration
Default local config lives at ~/.nofax/config.json:
{
"version": 1,
"server": "https://ntfy.sh",
"topic": "nofax_<random>",
"timeoutSeconds": 300
}Override the home directory with NOFAX_HOME:
NOFAX_HOME=/path/to/nofax-home nofax configUse another ntfy-compatible server with:
nofax init --server https://ntfy.example.com --forceDevelopment
Local package:
npm ci
npm run check
npm test
npm pack --dry-runRemote Worker:
cd worker
npm ci
npm run checkCI qualifies Node.js 20, 22, and 24 for the local package. The Worker gate runs TypeScript, Vitest, a production-dependency audit, and a Wrangler deployment dry-run.
Project docs
docs/architecture.md— trust boundaries and data flowdocs/remote-mcp.md— remote Worker deployment and qualificationSECURITY.md— security assumptions and vulnerability reportingCONTRIBUTING.md— contribution and test expectationsCHANGELOG.md— release history
Non-goals
Nofax deliberately does not provide:
a Nofax-operated approval SaaS;
a paid model API dependency;
persistent
always approvepolicy;an arbitrary remote shell endpoint;
a public multi-user Worker behind one shared deployment key;
a claim that MCP annotations themselves are a security boundary.
License
MIT © Tomi Šeregi. See LICENSE.
Available Tools
7 toolsnofax_get_requestGet Nofax requestARead-onlyIdempotent
Inspect safe metadata and terminal state for one known durable requestId without waiting. Use nofax_wait_for_response when the caller must wait for a human decision, or nofax_list_pending to recover requestIds after interruption. Secret response topics are never returned.
| Name | Required | Description | Default |
|---|---|---|---|
| requestId | Yes | Durable Nofax request handle to inspect without exposing its secret response topic. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | The durable request was read successfully. |
| request | Yes | Safe request metadata and terminal state; secret response topics are omitted. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, and non-destructive behavior. The description adds meaningful extra context: the call does not wait, reports terminal state, and never returns secret response topics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences front-load the behavior, then provide sibling routing and a security note. Every sentence earns its place with no redundant wording.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read tool with annotations, rich schema coverage, and an output schema, the description covers behavior, alternatives, and the one critical restriction (never returning secret topics). Nothing needed for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single requestId parameter is already well-documented as a durable handle with a hidden secret topic. The description reinforces this but does not add substantially new parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description opens with a specific verb ('Inspect') and clear object: safe metadata and terminal state for one known durable requestId. It explicitly contrasts with waiting and listing siblings, making the tool's scope unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names nofax_wait_for_response for when a caller must wait for a human decision and nofax_list_pending for recovery after interruption. This is explicit routing guidance with no ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nofax_list_pendingList pending Nofax requestsARead-onlyIdempotent
List a bounded set of unresolved Nofax request handles for recovery after client or conversation interruption. Secret response topics are never returned.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of unresolved requests to return; defaults to 20. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | The pending-request scan completed successfully. |
| requests | Yes | Bounded unresolved request projections with no secret response topics. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint, idempotentHint, and destructiveHint, but the description adds valuable behavioral context: it returns a bounded set and never returns secret response topics. This goes beyond the schema and annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is only two sentences and every clause earns its place. The main purpose and the critical security exclusion are both front-loaded without wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only list operation with one optional parameter Roy and a rich output schema, the description covers the essential context. It explains why the tool exists and the sensitive exclusion, though it could slightly enhance guidance on when to prefer this over get_request.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the single 'limit' parameter is already fully documented. The description's mention of a 'bounded set' loosely ties to the limit but does not add specific syntax, defaults, or edge-case guidance beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description has a specific verb ('List'), a clear resource (pending Nofax request handles), and a purpose ('recovery after client or conversation interruption'). It also distinguishes itself from siblings like get_request by focusing on pending handles rather than retrieving a single request.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description conveys a clear usage context: use this tool after client or conversation interruption to recover unresolved handles. It does not explicitly name alternatives or exclusions, but the purpose statement is specific enough to guide selection among siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nofax_notifySend Nofax notificationA
Send a one-way phone notification. This tool is informational and does not create a human-response wait. Notification transport success never counts as approval.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Optional notification title shown to the human; defaults to "Nofax". | |
| message | Yes | Notification body shown to the human. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | The notification transport call completed successfully; this is never approval. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds significant behavioral context beyond annotations: the one-way nature, absence of a human-response wait, and the critical warning that transport success never equals approval. This prevents a dangerous misinterpretation that annotations alone would not cover.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences, the purpose is front-loaded, and the essential non-approval caveat is included without any redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter tool with complete schema descriptions and an output schema present, the description covers all key semantic distinctions (one-way, no wait, no approval) needed for correct invocation. Nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with clear descriptions for both 'message' and 'title'. The tool description adds no additional parameter-level meaning, so the baseline 3 applies as the schema already does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Send'), a resource ('one-way phone notification'), and explicitly says the tool is informational. This differentiates it from sibling request/approval tools by emphasizing the one-way nature and lack of a response wait.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly communicates when to use (informational, no response wait) and when not to rely on it ('never counts as approval'). It doesn't explicitly name alternative tools, but the when-not guidance is strong enough to route an agent correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nofax_request_approvalRequest human approvalA
Send Allow/Deny to the phone and return a durable pending requestId. IMPORTANT: after this tool returns pending, call nofax_wait_for_response and repeat while it remains pending. Never continue the guarded action without a terminal Allow response. Set allowRefine when the human should also be able to send refinement text.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Optional approval prompt title shown to the human; defaults to "Nofax approval". | |
| message | Yes | Guarded action or decision context shown to the human. | |
| allowRefine | No | When true, also let the human return free-text refinement instead of only Allow or Deny. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | The request is unresolved and must not be treated as approval. |
| mustWait | Yes | Signals that the caller must keep waiting for a terminal human response. |
| requestId | Yes | Durable Nofax request handle. |
| instruction | Yes | Fail-closed next-step instruction for the caller. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate this is not read-only, not idempotent, and not destructive. The description adds valuable behavior beyond those: it returns a durable pending requestId, uses an asynchronous polling pattern, and requires a terminal Allow before proceeding, which is not captured by the annotations alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences with no filler. The critical async workflow is front-loaded with 'IMPORTANT', the terminal-Allow warning is prominent, and the optional flag guidance is placed at the end without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has a nontrivial asynchronous approval flow, and the description covers the complete calling pattern: send request, poll with nofax_wait_for_response, repeat while pending, and do not proceed without a terminal Allow. Since an output schema exists, return-value detail is not needed. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all three parameters. The description reinforces allowRefine ('Set allowRefine when the human should also be able to send refinement text') but does not add substantial new meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Send Allow/Deny to the phone and return a durable pending requestId'. It clarifies the outcome and distinguishes this from siblings like nofax_request_choice and nofax_request_refinement by mentioning 'allowRefine' and the wait-for-response flow.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit instructions: 'after this tool returns pending, call nofax_wait_for_response and repeat while it remains pending' and 'Never continue the guarded action without a terminal Allow response'. It also states when to set allowRefine, giving the agent clear conditions and workflow.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nofax_request_choiceRequest human choiceA
Send up to three explicit options to the phone and return a durable pending requestId. IMPORTANT: call nofax_wait_for_response and repeat while pending; do not choose on the human's behalf.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Optional choice prompt title shown to the human; defaults to "Nofax choice". | |
| message | Yes | Question or decision context shown to the human. | |
| options | Yes | One to three explicit choices to present to the human. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | The request is unresolved and must not be treated as approval. |
| mustWait | Yes | Signals that the caller must keep waiting for a terminal human response. |
| requestId | Yes | Durable Nofax request handle. |
| instruction | Yes | Fail-closed next-step instruction for the caller. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description adds that the returned requestId is durable, that the request remains pending, and that the caller must poll rather than assume a terminal answer. It also explicitly forbids deciding for the human, which is useful behavioral guidance. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with no filler. The core behavior and return value come first, followed by a high-value usage warning. The 'IMPORTANT' note earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with a fully documented schema and output schema, the description covers the critical workflow details: send options, receive pending requestId, poll with wait_for_response, and avoid self-serving decisions. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description only reinforces the 'up to three options' constraint and does not add meaning beyond what the schema already documents for message, title, and options.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action: send up to three explicit options to the phone and return a durable pending requestId. This distinguishes it from the sibling tools, especially nofax_notify, nofax_request_approval, and nofax_request_refinement.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides a clear operational protocol: call nofax_wait_for_response and repeat while pending, and do not choose on the human's behalf. It does not formally enumerate when to use this versus the other request-type siblings, but the context is sufficiently clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nofax_request_refinementRequest human refinementA
Ask the human for free-text refinement through the configured Nofax Refine iOS Shortcut. Use this when free-text edits are needed; use nofax_request_approval for Allow/Deny or nofax_request_choice for predefined options. Returns a durable pending requestId; call nofax_wait_for_response and repeat while pending.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Optional refinement prompt title shown to the human; defaults to "Nofax refinement". | |
| message | Yes | Context or draft the human should refine with free text. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | The request is unresolved and must not be treated as approval. |
| mustWait | Yes | Signals that the caller must keep waiting for a terminal human response. |
| requestId | Yes | Durable Nofax request handle. |
| instruction | Yes | Fail-closed next-step instruction for the caller. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations indicate mutation (readOnlyHint false) but description adds the asynchronous nature (durable pending requestId, polling via wait_for_response) and external shortcut prerequisite. It doesn't cover cancellation or timeout, but the key behaviors are disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with the primary action front-loaded and no filler; every sentence earns its place by adding purpose, usage, or follow-up guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 2-parameter tool with an output schema, the description covers purpose, usage, alternatives, and the pending/waiting workflow. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Input schema covers both parameters fully (100% coverage) with clear descriptions, so the description adds little beyond reinforcing that 'message' is the free-text context. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description states a specific verb ('Ask') and resource ('the human for free-text refinement') and explicitly names sibling tools with their use cases, making it easy to distinguish from nofax_request_approval and nofax_request_choice.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use ('when free-text edits are needed') and when-not-to-use alternatives (Allow/Deny vs predefined options), plus follow-up instruction to call nofax_wait_for_response and repeat while pending.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nofax_wait_for_responseWait for Nofax human responseAIdempotent
Long-poll a durable Nofax request for up to 240 seconds. If the result is pending, you MUST call this tool again with the same requestId. Repeat indefinitely until a terminal response is returned or the user explicitly changes/cancels the goal. Do not continue the guarded action while pending.
| Name | Required | Description | Default |
|---|---|---|---|
| requestId | Yes | Durable request handle returned by a nofax_request_* tool. | |
| waitSeconds | No | Maximum seconds to long-poll during this call; defaults to 240. A timeout still returns pending, never approval. |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | No | Human free-text refinement when the terminal decision is refine. |
| status | Yes | Whether the human request is still pending or has reached a terminal response. |
| decision | No | Terminal human decision when resolved, such as allow, deny, refine, or an explicit choice value. |
| mustWait | No | Present and true while the request remains pending. |
| requestId | Yes | Durable Nofax request handle. |
| instruction | Yes | Safety-preserving instruction describing what the caller may do next. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true and destructiveHint=false, and the description adds critical behavioral details: the long-poll mechanism, the 240-second cap, the guarantee that a timeout still returns pending (never approval), and the requirement to re-invoke. This goes beyond what annotations provide, though it does not disclose every edge case (e.g., behavior on request cancellation), but that is adequately covered by openWorldHint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact but includes all essential operational instructions (repeat behavior, do-not-continue) without redundancy. It is front-loaded with the purpose and then explains the required pattern. Slightly more detail could be trimmed, but it is well-structured and efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema (which would describe terminal responses) and annotations covering idempotence and non-destructiveness, the description is sufficient for an agent to call this tool correctly. It covers the polling loop, timeout behavior, and when to stop. The only omission is how to handle cancellation, but that is covered by the user-facing directive in the description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already fully described in the input schema. The description adds the 'durable' qualifier for requestId and reiterates the timeout semantics for waitSeconds, but does not significantly enrich the meaning beyond the schema, which is the baseline for high coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('long-poll') and resource ('durable Nofax request'), and clearly distinguishes from sibling tools like nofax_get_request by emphasizing the blocking wait behavior. It is not a tautology and leaves no ambiguity about the tool's core function.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit, actionable usage rules: it instructs the agent to call the tool again with the same requestId when pending, repeat indefinitely until terminal response, and avoid continuing the guarded action while pending. This is precise guidance on when and how to use the tool, including an explicit stop condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Scored across 7 tools
The three request tools are clearly differentiated by response type (choice, refinement, approval), and wait/get/list separate polling, inspection, and recovery. Minor overlap exists between get_request and wait_for_response, but the descriptions explicitly state when each is appropriate.
All tools share the nofax_ snake_case prefix and mostly follow a nofax_<verb>_<object> pattern. The request_* group is consistent, but list_pending is vaguer than list_pending_requests, and wait_for_response versus get_request mixes slightly different verb styles.
Seven tools fit the narrow human-approval domain well, covering request creation variants, polling, inspection, pending recovery, and one-way notification. There is no redundancy or excessive granularity.
The set covers creation of three request types, long-poll waiting, non-blocking status inspection, pending recovery, and one-way notification. A slight gap is the lack of an explicit cancel or expire tool for pending requests, but the core human-in-the-loop workflow is otherwise well covered.
Maintenance
Related MCP Connectors
Human-in-the-loop for AI agents over MCP: durable approvals with a hosted review page & audit trail
Human-in-the-loop review and approval for AI agents. Audit trail, approval policies, native MCP.
Zero-secret MCP gateway for AI agents: risk-scored, audited calls with human-in-the-loop approval.
Give any AI agent a way to ask a person — for approval, a decision, an answer or a review.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceHuman-in-the-Loop authorization gateway for AI Agents. Securely pause MCP workflows and route high-risk actions to human approvers via Slack or Email.52 npm1MIT
- AlicenseNot gradedqualityBmaintenanceAdds a human-in-the-loop checkpoint to MCP-capable AI coding agents, enabling them to pause and request user feedback before executing actions.11 npm71MIT
- AlicenseAqualityAmaintenanceProvides tools to retrieve the GodPrompt universal system prompt and its components (core skill, protocols, gates, anti-patterns) for AI software development, plus task classification. Designed for progressive context usage.71,904 npm1MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to request human decisions for subjective or high-stakes choices through MCP tools like ask_human and provision_api_key.-