Skip to main content
Glama

Impri

M8ven Score

Human-in-the-loop approval inbox for AI agents.

Your agent wants to send the email, post the reply, run the migration. You want to see it before it happens, from your phone if you're not at a desk. Impri is the inbox in between.

Agent (Claude Code / any MCP client)  →  Impri inbox  →  You approve, edit, or reject
        ↑                                                          |
        └──────────────── agent executes, reports result ──────────┘

Impri demo: an agent pushing an action, the approval inbox, a human approving it, the agent executing

Watch as MP4

The problem

Agents that only read and draft are safe by construction. The moment one can send an email, post a reply, or run a write against a database, "ask the user first" becomes a system-prompt instruction — and a instruction is something a capable model can reason its way past, forget under load, or misjudge on an edge case you didn't anticipate.

Impri turns that instruction into a data dependency instead. The agent pushes a proposed action to an inbox and polls for a decision; the execution branch is only reachable once the API actually returns status: "approved". There's nothing to talk the model past — the gate lives outside the model, not inside its prompt.

Related MCP server: MIDAS

60-second install

No install at all — connect straight to the hosted endpoint if your client supports a remote MCP server:

claude mcp add --transport http impri https://api.impri.dev/mcp --header "Authorization: Bearer $IMPRI_API_KEY"
codex mcp add impri --url https://api.impri.dev/mcp
# then add to ~/.codex/config.toml under [mcp_servers.impri]:
#   bearer_token_env_var = "IMPRI_API_KEY"

Or run the local package (needed if you're pointing at a self-hosted server instead of the cloud):

Claude Code:

claude mcp add impri --env IMPRI_API_KEY=im_... --env IMPRI_BASE_URL=https://api.impri.dev -- npx -y @impri/mcp

Codex:

codex mcp add impri --env IMPRI_API_KEY=im_... --env IMPRI_BASE_URL=https://api.impri.dev -- npx -y @impri/mcp

Cursor — add to .cursor/mcp.json:

{
  "mcpServers": {
    "impri": {
      "command": "npx",
      "args": ["-y", "@impri/mcp"],
      "env": {
        "IMPRI_API_KEY": "im_...",
        "IMPRI_BASE_URL": "https://api.impri.dev"
      }
    }
  }
}

Windsurf — add the same block to mcp_config.json:

{
  "mcpServers": {
    "impri": {
      "command": "npx",
      "args": ["-y", "@impri/mcp"],
      "env": {
        "IMPRI_API_KEY": "im_...",
        "IMPRI_BASE_URL": "https://api.impri.dev"
      }
    }
  }
}

Get an im_... key with one curl call — no signup form:

curl -s -X POST https://api.impri.dev/v1/signup -H "Content-Type: application/json" -d '{"name":"my-agent"}'

IMPRI_BASE_URL defaults to http://localhost:8484 (self-host) if you omit it — set it to https://api.impri.dev for the hosted cloud, as above. Self-hosting instead of the cloud? See Self-host or cloud below.

What the agent can do

Tool

What it does

impri_push_action

Submit a proposed action — title, formatted preview, optional editable fields

impri_await_decision

Poll until a human approves, rejects, or the timeout elapses

impri_report_result

Report whether the approved action actually succeeded

impri_inbox_status

Check how many actions are waiting, before starting a big batch

impri_create_watcher

Create a watcher (RSS / Reddit search / URL diff) that feeds matching items into the inbox

impri_list_watchers

List configured watchers, optionally filtered by status

impri_list_watcher_presets

List the 18 ready-made watcher templates (Hacker News, GitHub releases, npm, arXiv, …)

impri_create_watcher_from_preset

Create a watcher from a preset by id + params, no config schema to write

The loop

1. impri_push_action(kind, title, preview)        → { action_id, status: "pending", inbox_url }
2. impri_await_decision(action_id)                 → waits for a human to approve/reject/edit, or times out
3. If approved: execute the real action
4. impri_report_result(action_id, "executed" | "execute_failed")

Or in plain REST, the same three calls:

ACTION=$(curl -s -X POST https://api.impri.dev/v1/actions \
  -H "Authorization: Bearer $IMPRI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind":"email.send","title":"Outreach: Acme","preview":{"format":"markdown","body":"Hi Sarah, ..."}}')
ID=$(echo "$ACTION" | jq -r .id)

# poll (or long-poll) until a human decides
DECISION=$(curl -s "https://api.impri.dev/v1/actions/$ID" -H "Authorization: Bearer $IMPRI_API_KEY")

# only now, and only if approved
[ "$(echo "$DECISION" | jq -r .status)" = "approved" ] && send_email "$(echo "$DECISION" | jq -r '.decision.final_preview.body // .preview.body')"

The human doesn't have to be staring at a dashboard: an action can notify Slack, Discord, Telegram, ntfy, email, or a generic webhook, and the reviewer can edit the draft before approving — the agent receives that edited text back.

Why not just a prompt instruction?

"Please ask before sending" in the system prompt

Impri

The model has to remember, every time

Execution is unreachable without status: "approved" from the API

No record of who decided what, or when

Every decision is in the audit log

Can't fix a typo without a new draft

Edit-before-approve — the agent gets the edited version back

One-off per agent, per project

One inbox, six notification channels, 18 watcher presets, all agents

The honest caveat: this is a real gate only as long as the approved path is the agent's only path to the side effect — give it the raw credential too and it can route around you.

Self-host or cloud

Cloud — signup above, inbox at app.impri.dev, early beta.

Self-host — full core, MIT, no license key:

git clone https://gitlab.com/sekera.radim/impri.git
cd impri
docker compose up

Server on http://localhost:8484, web inbox on http://localhost:8080. The bootstrap admin key prints to the logs on first start. Details: Self-hosting.

Reference

Everything below is unchanged technical detail: CLI, SDKs, integrations, the full doc set, and legal.

CLI, SDKs & integrations

v0.1, pre-release. MCP is published; the CLI and both SDKs are local-install only (pre-npm / pre-PyPI) for now.

Package

Location

Status

MCP server

mcp/ / npx @impri/mcp

Published

CLI (impri)

cli/

Local build — see CLI reference

Python SDK

sdk/python/

Local install (pip install -e sdk/python)

TypeScript SDK

sdk/typescript/

Local install (npm install ./sdk/typescript)

Framework integrations in integrations/: packages for the Claude Agent SDK, CrewAI, LangChain, and the OpenAI Agents SDK; documented webhook-based patterns for n8n, Make, and Zapier in Integrations.

Notifications

Six channels: Slack, Discord, Telegram, email, ntfy, and generic webhook. See Notification channels and Telegram Approval Bot.

Documentation

Pricing

Free (3 watchers, 100 approvals/mo) · Indie $9/mo (20 watchers, 2,000 approvals/mo, 5-minute checks) · Team $29/mo (unlimited watchers and approvals, 1-minute checks). Self-host the full core for free — no tier limits apply outside the hosted cloud. Details: impri.dev.

License

MIT — see LICENSE. Self-host the full core freely; the hosted cloud and paid tiers are the commercial offering (see MONETIZATION.md).


Made by Radim Sekera. Related project: briefgate.dev — client intake for AI coding agents.

Available Tools

8 tools
impri_await_decisionAInspect

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")

Inputs: action_id (required), timeout_s.

impri_create_watcherAInspect

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 }.

Inputs: spec (required).

impri_create_watcher_from_presetAInspect

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" }

Inputs: params (required), preset_id (required), name, schedule.

impri_inbox_statusAInspect

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.

Inputs: no named parameters.

impri_list_watcher_presetsAInspect

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]

Inputs: no named parameters.

impri_list_watchersAInspect

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.

Inputs: status.

impri_push_actionAInspect

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

Inputs: kind (required), title (required), preview (required), payload, +4 more.

impri_report_resultAInspect

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)

Inputs: status (required), action_id (required), detail.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.4/5.0

    Scored across 8 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose: watcher creation (two variants), listing, action pushing, decision awaiting, result reporting, and inbox status. No overlapping functionality.

    Naming Consistency5/5

    All tools use the 'impri_' prefix and follow a consistent verb_noun or verb_noun_noun pattern (e.g., create_watcher, push_action, list_watcher_presets). The naming is predictable and uniform.

    Tool Count5/5

    With 8 tools, the server covers two main domains—watcher management and action approval—without being bloated or sparse. Each tool serves a necessary role in the workflow.

    Completeness4/5

    The action lifecycle is well-covered (push, await, report, inbox status). For watchers, creation and listing are present, but missing update/delete operations are minor gaps that agents can work around.

    Maintenance

    ActivityActive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers