MCP tools reference

One remote MCP server, Streamable HTTP transport, at https://api.pendnt.dev/mcp. Every call is authenticated the same way as the REST API: Authorization: Bearer <api_key>, scoped to that key's workspace.

Connecting

The server is stateless: no Mcp-Session-Id handshake, no server-side session state between calls — every request is self-contained, so it works cleanly behind Workers without needing sticky sessions. All actual state (requests, endpoints, events, wakeups, KV) lives server-side, addressed by your workspace, exactly like the REST routes.

Claude Code

claude mcp add --transport http pendnt https://api.pendnt.dev/mcp \
  --header "Authorization: Bearer $PENDNT_API_KEY"

.mcp.json

{
  "mcpServers": {
    "pendnt": {
      "type": "http",
      "url": "https://api.pendnt.dev/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_PENDNT_API_KEY"
      }
    }
  }
}

See Claude Code integration and Claude Agent SDK integration for full setup, including the permission-flow hook.

Tools

Every tool returns its result as a single JSON-encoded text content block. Tools that error (e.g. an unknown id) return an MCP tool error rather than a JSON error body.

request_approval

Ask a human operator to approve/deny an action, or answer a question, before the agent proceeds. Delivers to the operator's configured channels (email, web inbox, etc). Blocks for up to wait_s seconds (0–25; longer is clamped) waiting for an answer; if it returns still pending, call check_request with the returned id to keep polling — the request itself stays open (durable) for timeout_s seconds (default 86400 = 24h) regardless of how long this call waited.

ArgTypeNotes
titlestring, requiredShort summary shown to the human, e.g. "Deploy to prod?"
detailsstring, optionalLonger context shown below the title
kind"approval" | "question", optional"approval" (default) shows Approve/Deny. "question" shows options (if given) plus free text.
optionsstring[], optionalFor kind: "question": fixed choices offered as buttons, in addition to free text
timeout_snumber, optionalHow long the request stays open before auto-expiring (default 86400)
wait_snumber, optionalLong-poll duration before returning; capped at 25

Returns: { "id", "status", "answer" }

check_request

Poll the status of a request previously created by request_approval (or POST /v1/requests). Optionally long-polls up to wait_s seconds (max 25) if it's still pending.

ArgTypeNotes
idstring, requiredThe request id returned by request_approval
wait_snumber, optionalLong-poll duration, 0–25

Returns: { "id", "status", "answer" }. Errors not_found if the id doesn't exist.

notify

Fire-and-forget message to the operator's configured channels. Does not block or expect a reply — use request_approval instead if the agent needs to wait for a human response.

ArgTypeNotes
messagestring, requiredThe notification text
level"info" | "warning" | "error", optionalSeverity hint for channel formatting (default "info")

Returns: { "id", "status": "answered" }

create_endpoint

Provisions a new https://.../in/<slug> URL that stores any HTTP request sent to it (e.g. a GitHub webhook, a Stripe event, or an OAuth callback). Use wait_for_event to retrieve what arrives at it.

ArgTypeNotes
namestring, optionalA human-readable label, e.g. "gh-webhook"
require_tokenboolean, optionalIf true, incoming requests need ?token=<secret> or X-Endpoint-Token, or are rejected 403

Returns: { id, name, slug, url, secret, require_token, created_at }

list_endpoints

Lists all inbound webhook endpoints created for this workspace. No arguments. Returns: { "endpoints": [...] }

wait_for_event

Long-polls (up to wait_s seconds, max 25) for new events — inbound webhook deliveries and fired wakeups — with seq > since_seq. Pass the returned last_seq back in as since_seq on the next call so you don't re-read the same events.

ArgTypeNotes
endpoint_idstring, optionalRestrict to events from one endpoint (id from create_endpoint); omit for all events in the workspace
since_seqnumber, optionalOnly return events with seq greater than this (default 0)
wait_snumber, optionalLong-poll duration if nothing is available yet, 0–25

Returns: { "events": [...], "last_seq" }

schedule_wakeup

Schedules a future event (delivered via wait_for_event, kind: "wakeup") — useful to resume a paused or deferred agent later. Provide exactly one of at (absolute ISO 8601 timestamp) or in_s (seconds from now).

ArgTypeNotes
atstring, optionalAbsolute ISO 8601 timestamp, e.g. "2026-09-01T00:00:00Z"
in_snumber, optionalSeconds from now to fire at
payloadany, optionalArbitrary JSON attached to the wakeup event

Returns: { "id", "fire_at" }

list_wakeups

Lists scheduled, fired, and cancelled wakeups for this workspace. No arguments. Returns: { "wakeups": [{ id, fire_at, payload, status, created_at }] }

cancel_wakeup

Cancels a scheduled wakeup before it fires. No effect if it has already fired or been cancelled.

ArgTypeNotes
idstring, requiredThe wakeup id returned by schedule_wakeup

Returns: { "ok": true }. Errors not_found if the id doesn't exist.

kv_get

Reads a value previously written with kv_set from this workspace's small per-workspace KV scratchpad.

ArgTypeNotes
keystring, required

Returns: { "key", "value", "updated_at" }. Errors not_found if unset.

kv_set

Writes a string value (<= 64KB) to this workspace's KV scratchpad, keyed by key. Overwrites any existing value.

ArgTypeNotes
keystring, required
valuestring, required<= 64KB

Returns: { "key", "value", "updated_at" }

kv_delete

Deletes a value from the KV scratchpad. No-op if the key doesn't exist.

ArgTypeNotes
keystring, required

Returns: { "ok": true }

whoami

Returns the workspace id, plan, plan limits, and API base URL for the workspace this API key belongs to — useful to sanity-check which workspace/environment the agent is talking to before doing anything else. No arguments.

Early access — launched August 2026.