Impri MCP server — human-in-the-loop approval inbox for AI agents
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Impri API key as a Bearer token. Get one at impri.dev.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Poll until the human approves, rejects, or the timeout elapses. Checks GET /actions/:id every 5 seconds and returns as soon as the action leaves the pending state. Decision meanings: "approved" — proceed with the action; any reviewer edits are included in preview/payload "rejected" — abort; respect the decision and do not proceed "expired" — the approval window closed; create a new action if the task is still relevant On timeout the action stays pending in the inbox. Call impri_inbox_status to check queue depth and consider pausing further submissions. Typical usage: 1. impri_push_action → get action_id 2. impri_await_decision(action_id) → wait for human decision 3. If approved: execute the action, then impri_report_result(action_id, "executed")
The id returned by impri_push_action.
Maximum seconds to wait before returning (default 300 — 5 minutes). After timeout the action is still pending; retry or call impri_inbox_status.
Poll until the human approves, rejects, or the timeout elapses. Checks GET /actions/:id every 5 seconds and returns as soon as the action leaves the pending state. Decision meanings: "approved" — proceed with the action; any reviewer edits are included in preview/payload "rejected" — abort; respect the decision and do not proceed "expired" — the approval window closed; create a new action if the task is still relevant On timeout the action stays pending in the inbox. Call impri_inbox_status to check queue depth and consider pausing further submissions. Typical usage: 1. impri_push_action → get action_id 2. impri_await_decision(action_id) → wait for human decision 3. If approved: execute the action, then impri_report_result(action_id, "executed")
| Argument | Type | Description |
|---|---|---|
| action_id* | string | The id returned by impri_push_action. |
| timeout_s | number | Maximum seconds to wait before returning (default 300 — 5 minutes). After timeout the action is still pending; retry or call impri_inbox_status. |
{
"type": "object",
"required": [
"action_id"
],
"properties": {
"action_id": {
"type": "string",
"description": "The id returned by impri_push_action."
},
"timeout_s": {
"type": "number",
"description": "Maximum seconds to wait before returning (default 300 — 5 minutes). After timeout the action is still pending; retry or call impri_inbox_status."
}
}
}Create a watcher that monitors external sources (RSS feeds, Reddit, URL diffs) and delivers matching items to the approval inbox or a webhook. The watcher runs on the schedule you specify, deduplicates items by URL/content-hash, and delivers only new matches. The first run establishes a baseline and does not generate alerts. Example — watch an RSS feed for AI-related news: spec: { name: "AI launches radar", kind: "rss", config: { url: "https://openai.com/news/rss.xml" }, keywords: ["launch", "gpt-", "voice"], keywords_none: ["funding", "benchmark"], min_score: 1, schedule: { every: "8h", jitter: "4h" } } Returns { watcher_id, name, kind, status, next_run_at }.
| Argument | Type | Description |
|---|---|---|
| spec* | object | Watcher specification (name, kind, config, keywords, keywords_none, min_score, schedule). See SPEC.md §3.2 for the full schema. |
{
"type": "object",
"required": [
"spec"
],
"properties": {
"spec": {
"type": "object",
"description": "Watcher specification (name, kind, config, keywords, keywords_none, min_score, schedule). See SPEC.md §3.2 for the full schema."
}
}
}Create a watcher from a preset template by supplying the preset id and param values. Presets handle all watcher config construction — URL building, keyword setup, SSRF validation — so you only provide the param values listed by impri_list_watcher_presets. The schedule defaults to the preset's recommended interval but can be overridden. The name defaults to "{preset title}: {primary param value}" if omitted. Returns { watcher_id, name, kind, status, next_run_at }. Examples: Watch the HN front page (no params needed): preset_id: "hn-front-page" params: {} Watch a subreddit for new posts: preset_id: "reddit-subreddit" params: { subreddit: "MachineLearning" } Watch a GitHub repo for new releases, check every 2 hours: preset_id: "github-releases" params: { owner: "fastify", repo: "fastify" } schedule: { every: "2h" } Watch HN for keyword with a custom min_points threshold: preset_id: "hn-keyword" params: { keyword: "rust programming", min_points: "25" }
| Argument | Type | Description |
|---|---|---|
| name | string | Optional display name for the watcher. Defaults to "{preset title}: {primary param value}" when omitted. |
| params* | object | Key/value map of param values as strings. Required params must be present; optional params may be omitted to use preset defaults. |
| schedule | object | Optional schedule override. Omit to use the preset's default schedule. |
| preset_id* | string | Preset identifier from impri_list_watcher_presets (e.g. "hn-front-page", "reddit-subreddit", "github-releases"). |
Check how many actions are waiting for human decisions. Returns the pending count and a brief list of pending action titles. Call this before starting a large batch of tasks — if the inbox is backed up, pause and let the operator catch up to avoid actions expiring before they are reviewed.
No arguments.
{
"type": "object",
"required": [],
"properties": {}
}List all available watcher presets with their parameters. Presets are pre-configured watcher templates for common sources (Hacker News, Reddit, GitHub, npm, YouTube, arXiv, etc.). Each preset has an id, a human-readable title, required and optional params, and a default schedule. Call this first to discover which preset fits your monitoring goal, then use impri_create_watcher_from_preset to create the watcher by supplying only the preset_id and param values. No deep knowledge of watcher config schemas is needed. Example output: Community: - hn-front-page: "Hacker News Front Page" (rss) — no params required - reddit-keyword: "Reddit – Keyword Search" (reddit_search) — params: query, [subreddit]
No arguments.
{
"type": "object",
"required": [],
"properties": {}
}List all configured watchers, optionally filtered by status. Returns the watcher count and a summary line per watcher (id, name, kind, status). Use this to audit what is being monitored, check for degraded watchers, or find a watcher_id for further operations.
| Argument | Type | Description |
|---|---|---|
| status | string | Filter watchers by status. Omit to return all watchers regardless of status. |
{
"type": "object",
"required": [],
"properties": {
"status": {
"enum": [
"active",
"paused",
"degraded"
],
"type": "string",
"description": "Filter watchers by status. Omit to return all watchers regardless of status."
}
}
}Submit an action to the Impri human-approval inbox. The action appears in the operator's web and mobile inbox as a card with a title, formatted preview, and optional tap-to-edit fields. The operator approves or rejects with one tap; you poll for the decision with impri_await_decision. Returns { action_id, status: "pending", inbox_url }. Save action_id — you need it for all follow-up calls. Example — send a draft Reddit reply for review: kind: "reddit.comment" title: "Reply: Why is resume advice so conflicting?" preview: { format: "markdown", body: "The advice conflicts because different advisors optimise for different audiences..." } target_url: "https://reddit.com/r/cscareerquestions/comments/..." editable: ["preview.body"] // lets the reviewer tweak wording before approving
| Argument | Type | Description |
|---|---|---|
| kind* | string | Taxonomy label used for inbox filtering (e.g. 'reddit.comment', 'email.send', 'blog.publish'). Free-form; choose a consistent scheme. |
| title* | string | Short headline shown in the inbox card. Keep it under 120 characters. |
| payload | any | Opaque data echoed back in the webhook callback — useful for storing context (e.g. Reddit post id, draft id, queue position). Not shown to the reviewer. |
| preview* | object | The content the reviewer reads before deciding. |
| editable | array | Dot-notation fields the reviewer may edit before approving (e.g. ['preview.body']). The final edited values are echoed back in the approved action. |
Report whether you successfully executed an approved action. Closes the audit loop — the operator sees 'executed' or 'execute_failed' in the inbox alongside the original action and decision. Always call this after attempting an approved action, even on failure. Statuses: "executed" — action was carried out successfully "execute_failed" — execution attempt failed (include the error in detail)
| Argument | Type | Description |
|---|---|---|
| detail | string | Optional message — error description on failure, short confirmation on success. |
| status* | string | Outcome of executing the approved action. |
| action_id* | string | The id returned by impri_push_action. |
{
"type": "object",
"required": [
"action_id",
"status"
],
"properties": {
"detail": {
"type": "string",
"description": "Optional message — error description on failure, short confirmation on success."
},
"status": {
"enum": [
"executed",
"execute_failed"
],
"type": "string",
"description": "Outcome of executing the approved action."
},
"action_id": {
"type": "string",
"description": "The id returned by impri_push_action."
}
}
}{
"type": "object",
"required": [
"preset_id",
"params"
],
"properties": {
"name": {
"type": "string",
"description": "Optional display name for the watcher. Defaults to \"{preset title}: {primary param value}\" when omitted."
},
"params": {
"type": "object",
"description": "Key/value map of param values as strings. Required params must be present; optional params may be omitted to use preset defaults.",
"additionalProperties": {
"type": "string"
}
},
"schedule": {
"type": "object",
"required": [],
"properties": {
"every": {
"type": "string",
"description": "Run interval in duration format (e.g. \"30m\", \"1h\", \"6h\", \"1d\"). Must be at least 60s; tier minimums apply."
},
"jitter": {
"type": "string",
"description": "Random delay added to each run to spread load (e.g. \"5m\"). Optional."
},
"window": {
"type": "string",
"description": "Active time window in HH:MM-HH:MM format (e.g. \"06:00-22:00\"). Runs outside the window are skipped. Optional."
}
},
"description": "Optional schedule override. Omit to use the preset's default schedule."
},
"preset_id": {
"type": "string",
"description": "Preset identifier from impri_list_watcher_presets (e.g. \"hn-front-page\", \"reddit-subreddit\", \"github-releases\")."
}
}
}| expires_in | number | Seconds until the action auto-expires (default 86400 = 24 h). After expiry the status becomes 'expired' and no decision can be made. |
| target_url | string | URL the reviewer can open for context (e.g. the Reddit thread, the email draft). Optional but strongly recommended. |
| idempotency_key | string | Stable key to prevent duplicate submissions on retry. The same key within 24 h returns the original action instead of creating a new one. |
{
"type": "object",
"required": [
"kind",
"title",
"preview"
],
"properties": {
"kind": {
"type": "string",
"description": "Taxonomy label used for inbox filtering (e.g. 'reddit.comment', 'email.send', 'blog.publish'). Free-form; choose a consistent scheme."
},
"title": {
"type": "string",
"description": "Short headline shown in the inbox card. Keep it under 120 characters."
},
"payload": {
"description": "Opaque data echoed back in the webhook callback — useful for storing context (e.g. Reddit post id, draft id, queue position). Not shown to the reviewer."
},
"preview": {
"type": "object",
"required": [
"format",
"body"
],
"properties": {
"body": {
"type": "string",
"description": "Full text of what you want the reviewer to approve."
},
"format": {
"enum": [
"markdown",
"text"
],
"type": "string",
"description": "Render format for the preview body."
}
},
"description": "The content the reviewer reads before deciding."
},
"editable": {
"type": "array",
"items": {
"type": "string"
},
"description": "Dot-notation fields the reviewer may edit before approving (e.g. ['preview.body']). The final edited values are echoed back in the approved action."
},
"expires_in": {
"type": "number",
"description": "Seconds until the action auto-expires (default 86400 = 24 h). After expiry the status becomes 'expired' and no decision can be made."
},
"target_url": {
"type": "string",
"description": "URL the reviewer can open for context (e.g. the Reddit thread, the email draft). Optional but strongly recommended."
},
"idempotency_key": {
"type": "string",
"description": "Stable key to prevent duplicate submissions on retry. The same key within 24 h returns the original action instead of creating a new one."
}
}
}