Pushary
Server Details
An MCP connector that lets your AI agents ask you questions, request permission approvals, and send alerts as push notifications to your phone and mac notch, so you can unblock and approve your agents from anywhere.
- Status
- Healthy
- Uptime
- 100.0% over 56 days
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
TDQS
Scored across 5 tools
Each tool has a distinct role: ask_user asks a decision, propose_scope asks for a boundary, send_notification is one-way, wait_for_answer reads state, and cancel_question retracts. ask_user and propose_scope both 'send a real question,' which could cause some initial confusion, but the descriptions clearly delineate decision input versus scope agreement.
All five tools follow a clean verb_noun snake_case pattern (ask_user, cancel_question, propose_scope, send_notification, wait_for_answer). No mixed conventions or vague verbs.
Five tools is well-scoped for a human-in-the-loop decision/question service. Each tool earns its place across the ask/wait/cancel/notify/scope lifecycle without redundancy.
The lifecycle is largely covered: create questions, read/await answers, cancel them, send notifications, and propose scope. The notable gap is the absence of an enumerate/list-pending-questions tool, so recovering a lost question ID depends on previously returned handles.
Available Tools
6 toolsask_userAsk User a QuestionDestructiveInspect
Request an unresolved decision or missing input from the user through Pushary. Supports confirm, select and input questions. Delivery and waiting follow the account policy; a call waits at most 55 seconds and may return immediately. Returns the question state, answer when available, delivery information and handoff fields. answerUrl is optional. Use wait_for_answer to read a pending result and cancel_question to retract it. Sends a real question; it does not grant permission for other actions.
| Name | Required | Description | Default |
|---|---|---|---|
| env | No | Set to "test" from a test suite. The question is stored and returned as pending, and nothing is delivered to a phone, browser or Slack. The X-Pushary-Env: test header does the same for every call on the connection. | |
| tags | No | Deliver only to subscribers that have any of these tags. | |
| type | No | Question type: confirm renders yes/no buttons, select renders the options list, input renders a free-text field. | confirm |
| wait | No | true (default) blocks until the user answers or the timeout fires. Set false to return immediately with a pending correlationId and poll it yourself via wait_for_answer. | |
| action | No | The concrete operation about to happen, one line. Shown as the Action line. Cut to 500 chars. | |
| intent | No | The user's stated task (from their last prompt), one line. Shown as the Intent line so the user can see why the agent stopped. Cut to 500 chars. | |
| blocker | No | The single gating reason the agent stopped, one line. Shown as the Blocker line. Cut to 500 chars. | |
| context | No | One or two sentences about what the agent is working on, shown above the question so the user can decide without opening the terminal. | |
| options | No | The 2 to 6 choices for a select question. Required when type is "select", ignored otherwise. The answered value is the chosen option string. | |
| repoKey | No | Stable repository identity for the working directory, e.g. "github.com/acme/api". Lets an approval routing rule scoped to one repository avoid governing another. Optional; omit it and only workspace-wide routing rules apply. | |
| question | Yes | The complete question, up to 8000 characters. Preserve every point. Notifications show a short preview; the answer interface shows the full question. | |
| toolName | No | The tool this approval is for (e.g. "Bash"), so the user can choose to always-allow it. | |
| toolPath | No | MACHINE-POPULATED. Exact absolute Write file_path from the runtime, for diagnostic correlation only. Models must omit it. | |
| agentName | No | Name of the agent asking, format "{Agent} - {project}" (e.g. "Claude Code - myproject"). Shown in the notification title so the user knows which session needs them. Falls back to the MCP client name if omitted. Cut to 100 chars. | |
| machineId | No | Stable machine id of the asking agent, so two machines never collapse into one session. | |
| questions | No | ONE question, in the richer Claude-compatible shape: a header, per-option descriptions, multiSelect, and an optional write-in. Exactly one keeps already-installed clients answerable; asking several means several calls. Runtime-populated; ordinary callers should omit it and use question/type/options. | |
| requestId | No | MACHINE-POPULATED. The CALLER's own identifier for one logical invocation, used only when the runtime supplies no toolUseId. Mint it once, outside your retry loop, and send the same value on every attempt, so three retries of one ask become one decision. Do NOT derive it from the question text or reuse it across two deliberate asks: both collapse a real second question into the first one's answer. If you are a model deciding to call this tool, omit this field. | |
| scopePath | No | Set ONLY when this approval exists because the path falls outside the scope the user ratified via propose_scope. Approving then widens the run scope to include this exact path, so the user is not asked again for the same area. | |
| sessionId | No | Opaque per-session id of the asking agent, so parallel sessions are attributed separately. | |
| timeoutMs | No | How long this call blocks, in milliseconds (max 55000). Defaults to the site policy timeout. Ordinary questions stay open until answered or cancelled. A timeout ends this poll only; follow up with wait_for_answer. | |
| toolUseId | No | MACHINE-POPULATED. The agent RUNTIME's own identifier for the tool call this approval gates, forwarded verbatim by a hook that received it. Do NOT invent, guess, derive, or reuse a value: two different questions sent under the same id collapse into one, and the second one never reaches a human. If you are a model deciding to call this tool, omit this field. | |
| actionBody | No | The diff (Edit/Write) or full command (Bash/apply_patch), secret-redacted and size-capped. Rendered as a collapsible detail block; never used as the push body. | |
| toolTarget | No | Compact target of the tool call (e.g. the command head "git push" for Bash, or a file extension like ".ts" for Edit/Write). Used to mine policy suggestions. | |
| waitEndsAt | No | MACHINE-POPULATED. When the agent hook stops waiting live and hands control back to the terminal. The question may remain answerable after this time. Ordinary callers should omit it. | |
| callbackUrl | No | Webhook URL that receives a POST with the answer when the user responds, signed with the X-Pushary-Signature header. Useful when the agent process may exit before the answer arrives. | |
| externalIds | No | Deliver only to subscribers matching these external IDs. | |
| pausedAware | No | MACHINE-POPULATED. true from a hook that ends a paused approval exactly as the same approval unanswered after its full wait. Any other value is ignored. If you are a model deciding to call this tool, omit this field. | |
| placeholder | No | Hint text shown inside the free-text field for input questions | |
| questionOwner | No | MACHINE-POPULATED. Ownership supplied by the supported personal Codex bridge. Models must omit this field. | |
| subscriberIds | No | Deliver only to these subscriber IDs. Omit all targeting fields to reach every connected device. | |
| permissionMode | No | MACHINE-POPULATED. The agent runtime's own permission or approval mode for the tool call this approval gates, recorded with the decision. Any other value is ignored. If you are a model deciding to call this tool, omit this field. | |
| sessionToolAware | No | MACHINE-POPULATED. Set by a Pushary hook whose engine applies a session tool grant with its risky-command ceiling, so the grant is only offered where it takes effect. If you are a model deciding to call this tool, omit this field. | |
| localSurfaceAvailable | No | MACHINE-POPULATED. false from a hook that cannot show its own approval prompt for this call, so the phone is asked every time and never spared for presence at the keyboard. Any other value is ignored. If you are a model deciding to call this tool, omit this field. |
Output Schema
| Name | Required | Description |
|---|---|---|
| env | No | Echoed when the call was test traffic. |
| held | No | Present when the question was stored but deliberately not delivered: test traffic, or a permission ask with no toolName and no sessionId. |
| hint | No | What to do next, when there is a next step. |
| mode | No | The site delivery mode that stopped this call from waiting. |
| note | No | Free text the user added alongside their answer. |
| type | Yes | The question type that was rendered. |
| value | No | The user's answer: "yes" or "no" for confirm, the chosen option for select, the typed text for input. |
| paused | No | True when nothing was sent because the last approvals in this session went unanswered. Withdraw the question, then end the call as it would end unanswered. |
| status | No | The question state. Only pending is a live unanswered wait; cancelled, expired, missing, and unavailable must not be described as timeouts. |
| warning | No | Present only when no channel is connected, naming what the user has to connect. |
| answered | No | True once the user responded. Absent on the wait:false path, where nothing was awaited. |
| delivery | No | Per-channel reach for the push carrying this question. |
| question | Yes | The question exactly as the user saw it. |
| timedOut | No | True when the initial wait ended while the question was still live. Poll once with wait_for_answer, then follow handoffAction when present, otherwise nextAction. |
| answerUrl | No | Optional signed-in dashboard page where the user can answer this question. |
| noDevices | No | True when no phone, browser, or Slack channel could receive the question. Do not wait; follow handoffAction immediately. |
| nextAction | No | Backward-compatible next step: keep waiting while pending or ask in the current client. Follow handoffAction first when present. |
| suppressed | No | True when the PHONE push was deliberately held because a terminal on this machine is active. It says nothing about the notch, the dashboard or Slack, which are unaffected and may still be showing this question. A caller with no screen of its own should treat it as the terminal's to answer; a caller that can render the question itself should keep waiting. |
| waitEndsAt | No | When the agent hook stops waiting live. On an idempotent replay this is the original question's deadline, which the hook must reuse. |
| answerSource | No | Recorded answering surface, when known. Missing provenance is not proof of a phone answer; sandbox is simulated. |
| deliveryMode | No | Effective delivery policy for this decision. |
| correlationId | Yes | Id of the question that was created. Pass it to wait_for_answer to keep waiting, or to cancel_question to retract it. |
| handoffAction | No | Race-safe directive for updated clients. Takes precedence over nextAction: cancel before asking in the current client, or stop the handoff. |
| policyTimeoutMs | No | Policy wait window in milliseconds. Callers must also honor their host deadline. |
| expiresInSeconds | No | How long the question stays answerable. |
cancel_questionCancel Pending QuestionADestructiveIdempotentInspect
Retract a pending question that is no longer needed or is moving to the current client. Returns cancelled:true only when a pending question was removed. False may mean it was already answered, expired, missing or unavailable. An unavailable state includes handoffAction:stop because cancellation could not safely inspect or fence the question. Does not retract an answer already recorded.
| Name | Required | Description | Default |
|---|---|---|---|
| handoff | No | True when you are cancelling because you are about to ask the same question in the current client. For the next minute the Pushary hook then lets your own question tool through instead of sending it back to the phone. Set automatically whenever a live question is cancelled. | |
| correlationId | Yes | The correlationId of the pending question to cancel, as returned by ask_user or send_notification |
Output Schema
| Name | Required | Description |
|---|---|---|
| hint | No | What to do when cancellation could not safely inspect the question. |
| status | No | Present when Pushary could not safely read or fence the question state. |
| cancelled | Yes | True when a still-pending question was removed. False when it was already terminal, missing, or unavailable; inspect status and handoffAction when present. |
| askHandoff | No | True when the session was marked as handing off to the current client, so the hook will not re-ask on the phone for the next minute. |
| correlationId | Yes | The question this result refers to, echoed back. |
| handoffAction | No | Stop rather than opening another answer surface when the question state is unavailable. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare the safety profile (readOnlyHint=false, destructiveHint=true, idempotentHint=true), and the description usefully extends this by explaining what cancelled:false means (already answered, expired, missing, unavailable) and the handoffAction:stop edge case. This adds real behavioral context about failure modes, though some of it overlaps with the output schema.
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 core action and its scope are front-loaded in the first sentence, followed by tightly packed return semantics. Four sentences with little waste, though the return-value detail is dense relative to a two-parameter tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter mutation tool, the description, annotations, and output schema together cover purpose, safety, and result interpretation. It could still say more about interaction with wait_for_answer, but nothing essential to 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 coverage is 100%, so both parameters are already documented, including a detailed handoff description. The prose only echoes the 'moving to the current client' rationale for handoff and adds no syntax or format detail beyond the schema; baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Retract a pending question') plus the scope ('no longer needed or is moving to the current client'). It is clearly distinguishable from siblings like ask_user and wait_for_answer without opening a schema.
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?
Gives clear conditions for use ('no longer needed', 'moving to the current client') and one exclusion ('Does not retract an answer already recorded'). It stops short of naming sibling alternatives or an explicit not-use case against wait_for_answer, so it is strong but not fully routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
propose_scopePropose Run ScopeADestructiveInspect
Request agreement on an unresolved or user-requested boundary for this session. Sends a real scope question and returns ratified, answered, contract and enforcement information. Only supported hooks can enforce file paths on path-bearing tool calls; promises are recorded but not enforced. Empty enforces means no automatic boundary checking. A contract never overrides host permissions or authorizes a separate action. The call waits at most 55 seconds; a pending proposal can be read with wait_for_answer.
| Name | Required | Description | Default |
|---|---|---|---|
| doneWhen | Yes | What "finished" means for this run, one or two lines. Carried for the human to judge against; never enforced automatically. | |
| promises | No | Boundaries that are not file paths: recipients, channels, spend limits, systems you will not open. For an agent whose work is not code (marketing, sales, support, operations), this is where the boundary goes. Shown to the user labelled "Promised, not checked" and recorded in the ledger, but NEVER enforced, because the gate judges a file path and these have none. Do not put these in allowedPaths. | |
| agentName | No | Name of the agent asking, format "{Agent} - {project}". | |
| machineId | No | Stable machine id, so two machines never collapse into one session. | |
| sessionId | Yes | Your per-session id, as your client reports it for THIS run. Required, and it is the key the gate reads the contract back by: a value that matches no live session still returns ratified:true and enforces nothing. Never invent one, and never reuse one from another run. | |
| timeoutMs | No | How long this call blocks, in milliseconds (max 55000). | |
| allowedPaths | No | Globs you intend to change, e.g. ["src/**", "docs/*.md"]. File paths only: a word that is not a path ("hubspot", "summer-campaign") matches no file and makes every edit read as out of scope. A bare directory is expanded for you, so "docs" also covers "docs/**". Omit or leave empty to propose no path restriction, which the user is told plainly. | |
| offLimitsPaths | No | Globs you promise not to touch, e.g. [".env*", "infra/**"]. These win wherever they overlap allowedPaths. A leading "**/" needs a directory before it, so "**/.env*" is expanded for you to also cover a root ".env". |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Present only when the scope is not in force, saying what to do instead of proceeding. |
| value | No | The raw answer behind ratified, "yes" or "no". |
| status | No | The underlying scope-question state. |
| answered | Yes | True when the user responded at all. Answered but not ratified means they declined, so ask what scope they want rather than proceeding. |
| contract | Yes | The scope as it is STORED and gated, echoed back so you and the server hold the same contract. Paths are the EXPANDED ones: a bare directory and a leading "**/" each gain the variant they would otherwise have missed, so this can contain more entries than you sent. The user was shown the paths you sent, because the added twin says the same thing to a reader; the expansion only changes what the matcher covers, never what it means. |
| enforces | Yes | What this contract CONTAINS that can be checked, not a promise about what the gate on this machine will do. An EMPTY array means nothing here is checked automatically: the contract is a recorded promise, and every action stays governed by the permission policy exactly as it was before. Never tell the user a boundary is enforced when this is empty. |
| hookSeen | No | Whether any agent hook has actually reported this sessionId. FALSE means the gate will look this contract up under a key that does not exist, so nothing will be checked no matter what ratified says: fix the session id rather than proceeding as if a scope were in force. ABSENT means the check could not run, which is not evidence either way. |
| ratified | Yes | True only on an explicit yes. The contract is in force for this session only when this is true; anything else means proceed as if no scope was agreed. |
| nextAction | No | Keep waiting with the same correlationId while the proposal is pending. Follow handoffAction first when present; a poll ending does not expire or cancel the proposal. |
| correlationId | Yes | Id of the scope question. Keep waiting with this id while the question is pending. |
| handoffAction | No | Race-safe directive for updated clients. Takes precedence over nextAction. |
| enforcementNote | No | Present only when there is something true to say about the limits of this contract. Repeat it to the user rather than paraphrasing it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial context beyond the annotations: promises are recorded but never enforced, empty enforcement means no automatic checking, contracts never override host permissions, and the call blocks up to 55 seconds. It does not, however, explain the destructiveHint=true / idempotentHint=false profile — what state is altered or that a re-proposal is not idempotent — leaving a gap for a mutation-flagged tool.
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?
Purpose is front-loaded in the first sentence and every subsequent sentence carries enforcement or routing information rather than filler. It is dense and slightly prose-heavy for a five-sentence block, but nothing reads as wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not detail returns, yet it names the key return fields (ratified, answered, contract, enforcement) to orient the agent. Combined with the rich annotations and schema, the only omission is the meaning of the destructive flag.
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 every parameter thoroughly, including the enforcement semantics of allowedPaths, promises and offLimitsPaths. The description only reinforces the 55-second timeout already encoded as maximum 55000, adding no new syntax or semantics, so the 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?
States a specific verb and resource ('Request agreement on an unresolved or user-requested boundary for this session'), making it clearly a scope-contract proposal rather than a generic question. It is distinguishable from ask_user by being boundary-specific, but it never explicitly contrasts itself with that nearest sibling.
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?
Gives a clear trigger ('an unresolved or user-requested boundary for this session') and routes the agent to a sibling for the follow-up case ('a pending proposal can be read with wait_for_answer'). It stops short of stating when a plain ask_user would be the better choice instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
schedule_reminderSchedule a Personal ReminderDestructiveInspect
Remind the authenticated user later: a timer, alarm, ping, or reminder delivered by Pushary even after the agent exits. One-time only; up to 30 days away, 25 pending per user/site. Provide body plus inMinutes or at with an explicit UTC offset. Use a unique requestId for each schedule and reuse it unchanged on retries. Use reminderId to retrieve the final outcome. Confirm the returned time and report any warning. Omit arguments to list pending reminders; use cancelReminderId to cancel a scheduled one. Never use ask_user for a reminder. Does not schedule agent work or customer campaigns. Respects stop/mute and active membership at delivery.
| Name | Required | Description | Default |
|---|---|---|---|
| at | No | Future ISO 8601 timestamp with explicit UTC offset or Z, at most 30 days away. Resolve the user's local time and timezone before scheduling; never guess a timezone. | |
| env | No | ||
| body | No | What to remind the authenticated user about, at most 180 UTF-16 units after secret redaction (emoji may use two). Omit all fields to list their pending reminders. | |
| title | No | ||
| agentName | No | ||
| inMinutes | No | Minutes from the server clock; use for timers and relative reminders. | |
| machineId | No | ||
| requestId | No | Unique ID for this scheduling operation. Reuse it unchanged on retries to return the original reminder, including after it settles. | |
| sessionId | No | ||
| reminderId | No | Look up your reminder, including its final outcome and delivery status, instead of scheduling or cancelling. | |
| cancelReminderId | No | Cancel this user's scheduled reminder instead of creating one. Already-dispatching reminders cannot be cancelled. |
send_notificationSend Push NotificationADestructiveInspect
Send a one-way notification to connected devices for a requested update or a meaningful unattended result. Use ask_user when an answer is needed. Delivery follows the account policy and optional recipient filters. context adds a detail page; context.askQuestion creates a linked decision. Returns web/mobile delivery counts and a warning when no delivery channel is connected. Sends real notifications.
| Name | Required | Description | Default |
|---|---|---|---|
| env | No | Set to "test" from a test suite. The notification is recorded in the activity feed and nothing is delivered to a phone or browser. The X-Pushary-Env: test header does the same for every call on the connection. | |
| url | No | URL opened when the user taps the notification. Ignored if context is provided, because a context detail page URL is generated automatically. | |
| body | Yes | Notification body text (max 500 chars). One or two sentences the user can act on without opening anything. | |
| tags | No | Deliver only to subscribers that have any of these tags. | |
| title | Yes | Notification title shown on the lock screen (max 100 chars). Lead with the outcome, e.g. "Build finished" or "Migration failed". | |
| context | No | Structured context rendered as a rich detail page when the user taps the notification. Strongly recommended for task_complete and error notifications so the user can act from their phone. | |
| iconUrl | No | URL of the notification icon image | |
| imageUrl | No | URL of a large image shown in the notification | |
| agentName | No | Name of the agent sending this notification, format "{Agent} - {project}" (e.g. "Claude Code - myproject"). Shown in the notification so the user knows which session is talking. Falls back to the MCP client name if omitted. | |
| machineId | No | Stable machine id of the sending agent, so two machines never collapse into one session. | |
| sessionId | No | Opaque per-session id of the sending agent, so parallel sessions are attributed separately in the activity feed. | |
| externalIds | No | Deliver only to subscribers matching these external IDs. | |
| subscriberIds | No | Deliver only to these subscriber IDs. Omit all targeting fields to reach every connected device. |
Output Schema
| Name | Required | Description |
|---|---|---|
| env | No | Echoed when the call was test traffic. |
| hint | No | What to do next, when there is a next step. |
| sent | No | Total devices reached, web plus mobile. Zero is a successful call that found nobody to deliver to, not an error. |
| warning | No | Present only when the notification reached zero devices, naming what the user has to connect. |
| delivery | No | Per-channel outcome. The two channels are independent with no cross-fallback, so each reports its own result. |
| attribution | No | Whether real session and machine identifiers were supplied. Unattributed notifications are delivered without creating a live session. |
| notificationId | No | Trace ID for this notification; provider acceptance does not confirm a person saw it. |
| linkedCorrelationId | No | Present only when context.askQuestion embedded a decision prompt. Pass it to wait_for_answer to collect the response. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag a non-readonly, non-idempotent, open-world, destructive action; the description adds real operational context beyond that: 'Sends real notifications' (contrasted against the env=test dry-run), that delivery follows account policy, and that a warning is returned when no channel is connected. It does not explain why destructiveHint is set or what happens to already-delivered notifications, so it falls short of full coverage.
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?
Front-loaded with purpose and the ask_user contrast, then delivery behavior, then the return/warning note, closing with the important 'Sends real notifications' caveat. Dense and mostly waste-free, though the final sentence slightly overlaps the opening framing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 13 parameters, nested objects, full schema coverage, an output schema, and rich annotations, the description fills exactly the remaining gaps: sibling routing, real-send semantics, and failure signaling. Nothing needed to call it correctly 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 baseline is 3, but the description adds structural meaning the schema only implies: context renders as a detail page, context.askQuestion produces a linked decision (pairing with wait_for_answer), and the targeting fields act as optional recipient filters. These are meaningful relationships beyond field-level docs.
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 and resource ('Send a one-way notification to connected devices') plus the triggering conditions ('a requested update or a meaningful unattended result'). It explicitly contrasts itself with the sibling ask_user, so an agent can route between the two without opening either schema.
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?
Gives an explicit when-to-use rule ('one-way... use ask_user when an answer is needed') naming the alternative tool, and further clarifies that context.askQuestion creates a linked decision rather than a one-way send. Delivery scoping via account policy and recipient filters is also noted.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_answerWait for User AnswerARead-onlyIdempotentInspect
Read the answer or current state of an existing question from ask_user or send_notification. Waits up to timeoutMs, capped at 55 seconds. Returns answered, the answer when available, status and handoff information. Only pending is a live unanswered question; cancelled, expired, missing and unavailable are terminal states. Does not send another question.
| Name | Required | Description | Default |
|---|---|---|---|
| timeoutMs | No | How long this one poll blocks, in milliseconds (default 30000, max 55000). Follow handoffAction when present, otherwise nextAction. | |
| correlationId | Yes | The correlationId from an earlier ask_user response, or the linkedCorrelationId from a send_notification with an embedded askQuestion |
Output Schema
| Name | Required | Description |
|---|---|---|
| hint | No | What to do next, when there is a next step. |
| note | No | Free text the user added alongside their answer. |
| value | No | The user's answer: "yes" or "no" for confirm, the chosen option for select, the typed text for input. Present only when answered is true. |
| status | Yes | The actual question state. Only pending is a live unanswered wait. |
| answered | Yes | True once the user responded. False means follow handoffAction when present, otherwise nextAction; do not guess that every unanswered state is a timeout. |
| nextAction | No | Backward-compatible next step for older clients. Follow handoffAction first when present. |
| answerSource | No | Recorded answering surface, when known. Missing provenance is not proof of a phone answer; sandbox is simulated. |
| handoffAction | No | Race-safe directive for updated clients. Takes precedence over nextAction. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, closed-world. The description adds real value beyond them: the wait is capped at 55 seconds, 'pending' is the only live state, and cancelled/expired/missing/unavailable are terminal, which tells the agent how to interpret results and whether to keep polling.
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?
Front-loaded with the core action and tightly written; the state taxonomy is the most valuable part. The trailing return-value sentence slightly overlaps the output schema but is brief.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations covering the safety profile and an output schema covering the return values, the description supplies exactly the missing pieces: wait semantics, the timeout cap, and the terminal-state taxonomy. Nothing an agent needs to call this correctly is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters are fully documented in the schema, including the default, maximum, and the handoffAction/nextAction guidance. The description only restates the 55s cap, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource: reads the answer/current state of an existing question created by ask_user or send_notification. Explicitly states what it does NOT do ('Does not send another question'), which cleanly separates it from the ask_user and send_notification siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Tells the agent the source of the correlationId (ask_user response or linkedCorrelationId from send_notification) and clarifies the non-sending behavior, routing work back to ask_user. No explicit guidance on cancel_question vs waiting, so it stops short of the 5 bar.
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.
1 tool update
- Added
schedule_reminder
1 tool update
- Changed
ask_user1 field changed- added
Input schema / properties / questionOwnerAdded value: +{ + "additionalProperties": {}, + "description": "MACHINE-POPULATED. Ownership supplied by the supported personal Codex bridge. Models must omit this field.", + "properties": {}, + "type": "object" +}
1 tool update
- Changed
ask_user1 field changed- changed
Input schema / properties / timeoutMs / descriptionPrevious value: -"How long this call blocks, in milliseconds (max 55000). Defaults to the site policy timeout. The question stays open for 10 minutes regardless, so a timeout here is not a refusal; follow up with wait_for_answer."New value: +"How long this call blocks, in milliseconds (max 55000). Defaults to the site policy timeout. Ordinary questions stay open until answered or cancelled. A timeout ends this poll only; follow up with wait_for_answer."
1 tool update
- Changed
send_notification1 field changed- added
Output schema / properties / notificationIdAdded value: +{ + "description": "Trace ID for this notification; provider acceptance does not confirm a person saw it.", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + "type": "string" +}
1 tool update
- Changed
send_notification2 fields changed- changed
Input schema / properties / context / properties / type / descriptionPrevious value: -"What kind of update this is. Use \"task_complete\" when work finished, \"error\" when something failed (delivered with high urgency), \"info\" for everything else."New value: +"What kind of update this is. Use \"task_complete\" when work finished, \"error\" when something failed (delivered with high urgency), \"info\" for everything else. Error severity describes this notification, not the agent session health." - added
Output schema / properties / attributionAdded value: +{ + "description": "Whether real session and machine identifiers were supplied. Unattributed notifications are delivered without creating a live session.", + "enum": [ + "session", + "unattributed" + ], + "type": "string" +}
1 tool update
- Changed
propose_scope1 field changed- changed
Output schema / properties / nextAction / descriptionPrevious value: -"Poll one live question once; otherwise ask in the current chat whether to continue without an enforced scope."New value: +"Keep waiting with the same correlationId while the proposal is pending. Follow handoffAction first when present; a poll ending does not expire or cancel the proposal."
3 tool updates
- Changed
ask_user4 fields changed- changed
Input schema / properties / question / descriptionPrevious value: -"The question shown on the user's lock screen (500 chars; a longer one is cut). Phrase it so it is answerable at a glance; put background in context instead."New value: +"The complete question, up to 8000 characters. Preserve every point. Notifications show a short preview; the answer interface shows the full question." - added
Input schema / properties / question / maxLengthAdded value: +8000 - changed
Input schema / properties / questions / items / properties / question / maxLengthPrevious value: -500New value: +8000 - changed
Output schema / properties / nextAction / descriptionPrevious value: -"Backward-compatible next step: poll once or ask in the current client. Follow handoffAction first when present."New value: +"Backward-compatible next step: keep waiting while pending or ask in the current client. Follow handoffAction first when present."
- Changed
propose_scope1 field changed- changed
Output schema / properties / correlationId / descriptionPrevious value: -"Id of the scope question. Pass it to wait_for_answer once when the first wait times out."New value: +"Id of the scope question. Keep waiting with this id while the question is pending."
- Changed
send_notification1 field changed- changed
Input schema / properties / context / properties / askQuestion / properties / question / maxLengthPrevious value: -500New value: +8000
1 tool update
- Changed
ask_user1 field changed- added
Input schema / properties / permissionModeAdded value: +{ + "description": "MACHINE-POPULATED. The agent runtime's own permission or approval mode for the tool call this approval gates, recorded with the decision. Any other value is ignored. If you are a model deciding to call this tool, omit this field.", + "maxLength": 64, + "type": "string" +}
1 tool update
- Changed
ask_user2 fields changed- added
Input schema / properties / pausedAwareAdded value: +{ + "description": "MACHINE-POPULATED. true from a hook that ends a paused approval exactly as the same approval unanswered after its full wait. Any other value is ignored. If you are a model deciding to call this tool, omit this field.", + "type": "boolean" +} - added
Output schema / properties / pausedAdded value: +{ + "description": "True when nothing was sent because the last approvals in this session went unanswered. Withdraw the question, then end the call as it would end unanswered.", + "type": "boolean" +}
1 tool update
- Changed
ask_user1 field changed- added
Input schema / properties / localSurfaceAvailableAdded value: +{ + "description": "MACHINE-POPULATED. false from a hook that cannot show its own approval prompt for this call, so the phone is asked every time and never spared for presence at the keyboard. Any other value is ignored. If you are a model deciding to call this tool, omit this field.", + "type": "boolean" +}
1 tool update
- Changed
ask_user1 field changed- changed
Output schema / properties / answerUrl / descriptionPrevious value: -"The signed-in dashboard page where this question is waiting. Print it when you tell the user you are waiting, so they can answer from a browser."New value: +"Optional signed-in dashboard page where the user can answer this question."
1 tool update
- Changed
ask_user14 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"The concrete operation about to happen, one line. Shown as the Action line."New value: +"The concrete operation about to happen, one line. Shown as the Action line. Cut to 500 chars." - removed
Input schema / properties / action / maxLengthRemoved value: -500 - added
Input schema / properties / action / minLengthAdded value: +0 - changed
Input schema / properties / agentName / descriptionPrevious value: -"Name of the agent asking, format \"{Agent} - {project}\" (e.g. \"Claude Code - myproject\"). Shown in the notification title so the user knows which session needs them. Falls back to the MCP client name if omitted."New value: +"Name of the agent asking, format \"{Agent} - {project}\" (e.g. \"Claude Code - myproject\"). Shown in the notification title so the user knows which session needs them. Falls back to the MCP client name if omitted. Cut to 100 chars." - removed
Input schema / properties / agentName / maxLengthRemoved value: -100 - added
Input schema / properties / agentName / minLengthAdded value: +0 - changed
Input schema / properties / blocker / descriptionPrevious value: -"The single gating reason the agent stopped, one line. Shown as the Blocker line."New value: +"The single gating reason the agent stopped, one line. Shown as the Blocker line. Cut to 500 chars." - removed
Input schema / properties / blocker / maxLengthRemoved value: -500 - added
Input schema / properties / blocker / minLengthAdded value: +0 - changed
Input schema / properties / intent / descriptionPrevious value: -"The user's stated task (from their last prompt), one line. Shown as the Intent line so the user can see why the agent stopped."New value: +"The user's stated task (from their last prompt), one line. Shown as the Intent line so the user can see why the agent stopped. Cut to 500 chars." - removed
Input schema / properties / intent / maxLengthRemoved value: -500 - added
Input schema / properties / intent / minLengthAdded value: +0 - changed
Input schema / properties / question / descriptionPrevious value: -"The question shown on the user's lock screen (max 500 chars). Phrase it so it is answerable at a glance; put background in context instead."New value: +"The question shown on the user's lock screen (500 chars; a longer one is cut). Phrase it so it is answerable at a glance; put background in context instead." - removed
Input schema / properties / question / maxLengthRemoved value: -500
1 tool update
- Changed
ask_user3 fields changed- added
Input schema / properties / toolPath / formatAdded value: +"starts_with" - changed
Input schema / properties / waitEndsAt / patternPrevious value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"New value: +"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" - changed
Output schema / properties / waitEndsAt / patternPrevious value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"New value: +"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
1 tool update
- Changed
ask_user1 field changed- added
Input schema / properties / sessionToolAwareAdded value: +{ + "description": "MACHINE-POPULATED. Set by a Pushary hook whose engine applies a session tool grant with its risky-command ceiling, so the grant is only offered where it takes effect. If you are a model deciding to call this tool, omit this field.", + "type": "boolean" +}
1 tool update
- Changed
propose_scope12 fields changed- changed
Input schema / properties / allowedPaths / descriptionPrevious value: -"Globs you intend to change, e.g. [\"src/**\", \"docs/*.md\"]. Omit or leave empty to propose no path restriction, which the user is told plainly."New value: +"Globs you intend to change, e.g. [\"src/**\", \"docs/*.md\"]. File paths only: a word that is not a path (\"hubspot\", \"summer-campaign\") matches no file and makes every edit read as out of scope. A bare directory is expanded for you, so \"docs\" also covers \"docs/**\". Omit or leave empty to propose no path restriction, which the user is told plainly." - changed
Input schema / properties / offLimitsPaths / descriptionPrevious value: -"Globs you promise not to touch, e.g. [\"**/.env*\", \"infra/**\"]. These win wherever they overlap allowedPaths."New value: +"Globs you promise not to touch, e.g. [\".env*\", \"infra/**\"]. These win wherever they overlap allowedPaths. A leading \"**/\" needs a directory before it, so \"**/.env*\" is expanded for you to also cover a root \".env\"." - added
Input schema / properties / promisesAdded value: +{ + "description": "Boundaries that are not file paths: recipients, channels, spend limits, systems you will not open. For an agent whose work is not code (marketing, sales, support, operations), this is where the boundary goes. Shown to the user labelled \"Promised, not checked\" and recorded in the ledger, but NEVER enforced, because the gate judges a file path and these have none. Do not put these in allowedPaths.", + "items": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "maxItems": 10, + "type": "array" +} - changed
Input schema / properties / sessionId / descriptionPrevious value: -"Your per-session id. Required: a scope with no session cannot be enforced, and must never leak into another run."New value: +"Your per-session id, as your client reports it for THIS run. Required, and it is the key the gate reads the contract back by: a value that matches no live session still returns ratified:true and enforces nothing. Never invent one, and never reuse one from another run." - changed
Output schema / properties / contract / descriptionPrevious value: -"The scope exactly as it was put to the user, echoed back so the agent and the human are holding the same contract."New value: +"The scope as it is STORED and gated, echoed back so you and the server hold the same contract. Paths are the EXPANDED ones: a bare directory and a leading \"**/\" each gain the variant they would otherwise have missed, so this can contain more entries than you sent. The user was shown the paths you sent, because the added twin says the same thing to a reader; the expansion only changes what the matcher covers, never what it means." - changed
Output schema / properties / contract / properties / allowedPaths / descriptionPrevious value: -"Globs the run may change. Empty means no path restriction was proposed, which the user was told plainly."New value: +"Globs the run may change, after expansion. Empty means no path restriction was proposed, which the user was told plainly." - changed
Output schema / properties / contract / properties / offLimitsPaths / descriptionPrevious value: -"Globs the run promised not to touch. These win wherever they overlap allowedPaths."New value: +"Globs the run promised not to touch, after expansion. These win wherever they overlap allowedPaths." - added
Output schema / properties / contract / properties / promisesAdded value: +{ + "description": "Non-path boundaries as the user saw them. Recorded, never enforced.", + "items": { + "type": "string" + }, + "type": "array" +} - added
Output schema / properties / enforcementNoteAdded value: +{ + "description": "Present only when there is something true to say about the limits of this contract. Repeat it to the user rather than paraphrasing it.", + "type": "string" +} - added
Output schema / properties / enforcesAdded value: +{ + "description": "What this contract CONTAINS that can be checked, not a promise about what the gate on this machine will do. An EMPTY array means nothing here is checked automatically: the contract is a recorded promise, and every action stays governed by the permission policy exactly as it was before. Never tell the user a boundary is enforced when this is empty.", + "items": { + "enum": [ + "paths" + ], + "type": "string" + }, + "type": "array" +} - added
Output schema / properties / hookSeenAdded value: +{ + "description": "Whether any agent hook has actually reported this sessionId. FALSE means the gate will look this contract up under a key that does not exist, so nothing will be checked no matter what ratified says: fix the session id rather than proceeding as if a scope were in force. ABSENT means the check could not run, which is not evidence either way.", + "type": "boolean" +} - changed
Output schema / requiredPrevious value: -[ - "correlationId", - "ratified", - "answered", - "contract" -]New value: +[ + "correlationId", + "ratified", + "answered", + "enforces", + "contract" +]
1 tool update
- Changed
ask_user1 field changed- added
Input schema / properties / toolPathAdded value: +{ + "description": "MACHINE-POPULATED. Exact absolute Write file_path from the runtime, for diagnostic correlation only. Models must omit it.", + "maxLength": 4096, + "pattern": "^\\/.*", + "type": "string" +}
2 tool updates
- Changed
ask_user1 field changed- added
Output schema / properties / answerSourceAdded value: +{ + "description": "Recorded answering surface, when known. Missing provenance is not proof of a phone answer; sandbox is simulated.", + "enum": [ + "dashboard", + "mobile_app", + "mobile_background", + "decide_page", + "live_page", + "answer_link", + "inbox", + "slack", + "mac_app", + "sandbox" + ], + "type": "string" +}
- Changed
wait_for_answer1 field changed- added
Output schema / properties / answerSourceAdded value: +{ + "description": "Recorded answering surface, when known. Missing provenance is not proof of a phone answer; sandbox is simulated.", + "enum": [ + "dashboard", + "mobile_app", + "mobile_background", + "decide_page", + "live_page", + "answer_link", + "inbox", + "slack", + "mac_app", + "sandbox" + ], + "type": "string" +}
1 tool update
- Changed
ask_user2 fields changed- added
Output schema / properties / deliveryModeAdded value: +{ + "description": "Effective delivery policy for this decision.", + "enum": [ + "push_first", + "push_only", + "notify_only", + "terminal_only" + ], + "type": "string" +} - added
Output schema / properties / policyTimeoutMsAdded value: +{ + "description": "Policy wait window in milliseconds. Callers must also honor their host deadline.", + "minimum": 0, + "type": "number" +}
Publisher details
- Operator
- https://ralphnex.com
- Operator website
- https://pushary.com
- Vendor relationship
- Unknown
- Documentation
- https://pushary.com/docs
- Trust center
- Unknown
- Restrictions
- Unknown
Related MCP Connectors
Push notifications for AI agents - send instant iPhone notifications from any MCP client.
Let AI agents query data and act across all your business apps via MCP.
Connect any AI agent to 1,000+ apps and 27,000+ actions through one remote MCP server (OAuth).
MCP connector that lets ChatGPT list, search, and run your Apple Shortcuts via a local Mac agent
Related MCP Servers
- AlicenseAqualityAmaintenanceAn MCP server that enables AI agents to pause and request human approval or information via Slack, Telegram, or macOS dialogs before proceeding with actions.215Apache 2.0
- AlicenseAqualityAmaintenanceMCP server for AI agents to send notifications, copy to clipboard, request confirmations, and collect text input from users across their devices.1063 npmApache 2.0
- AlicenseBqualityDmaintenancePushinator MCP lets you send push notifications to your devices from your LLM-powered workflows.1MIT
- FlicenseNot gradedqualityCmaintenanceEnables any MCP-compatible AI agent to ask humans questions in real time via a mobile-friendly PWA with push notifications, operating local-first without third-party services.-
Glama MCP Gateway
Add one secure layer between your agents and this server.