Open source · MIT · Self-hostable · 4 KB SDK

Catch and fix the errors your apps throw

oops collects the errors from your browsers, servers, scripts and AI agents, groups them into issues, and tells you how many users each one affects, in which release and in which environment — with the stack trace and the clicks that led there. Resolve them from the dashboard, the API or an MCP client.

Early access: every account gets full access, free. Plans come later, with notice.

Three ways to report

Pick the one that fits each app. They all land in the same inbox.

Browser SDK

One script tag, under 4 KB, no dependencies. Catches uncaught errors and unhandled promise rejections, records clicks, route changes and failed requests as breadcrumbs, and exposes oops.capture() for the errors you catch yourself. Never throws into your page.

<script defer src="https://oops.3m4.net/o.js"
        data-key="oops_pub_…" data-env="production"
        data-release="1.4.2"></script>

Ingest API

A single POST with the project's public key, from Python, Node, Go, a CLI or a cron job. Send frames or the raw stack string — V8, Firefox and Python tracebacks are parsed server-side. Always answers 202: a failing app never gets a second error back.

curl -X POST https://oops.3m4.net/api/ingest \
  -H "X-Project-Key: oops_pub_…" \
  -H "Content-Type: application/json" \
  -d '{"type": "ValueError", "message": "order 42 has no items",
       "platform": "python", "release": "1.4.2",
       "frames": [{"filename": "app/orders.py", "function": "ship",
                   "lineno": 88, "in_app": true}]}'

AI agents via MCP

The MCP server lets Claude Code, Claude Desktop, Cursor or any MCP host read, triage and resolve issues — and report an agent's own failures into a project with report_error.

# an agent reporting its own failure through MCP
report_error(project="checkout-bot",
             type="ToolError", message="stripe refund timed out",
             level="warning", tags={"tool": "refund"})

How it works

1. Create a project

One project per app, site or service. You get a public key for the SDK and the ingest API, and you pick its time zone.

2. Report an error

Paste the script tag, or POST one JSON object from your backend. The server scrubs secrets, parses the stack and groups the event into an issue by fingerprint.

3. Triage the inbox

Open issues sorted by last seen, with events, affected users, environments and releases. Resolve, ignore, reopen — one by one or in bulk, from the dashboard, the API or an AI agent.

Everything you need to fix it, nothing you don't

The dashboard answers the questions you actually ask when something breaks, and stops there.

  • Grouped by fingerprint. 'User 42 not found' and 'User 43 not found' are one issue; the same error from another function is another. Send your own fingerprint to override.
  • Affected users. Not just how many times, but how many people — by the user id you send, or a daily cookie-less hash when you don't.
  • Releases and environments. Every issue lists where it happens. Resolved issues reopen on the next event and get a regressed badge.
  • Breadcrumbs. The last 30 clicks, route changes, failed requests and console messages before the error, with the stack frames and tags next to them.

Careful with data by construction

Error payloads carry whatever your code had in scope, so the server cleans them before storage: secret-looking keys are filtered, query strings and fragments are dropped from URLs, the user agent is reduced to browser, OS and device and thrown away, and IP addresses are hashed unless a project opts in to keep them.

  • ✓ Keys named password, token, secret, authorization, cookie, api_key, card, cvv or ssn are replaced by [Filtered] in tags, extra, breadcrumbs and user objects
  • ✓ No raw user agents stored — only browser, OS and device
  • ✓ Raw IP addresses are not stored by default — only a daily salted hash (a per-project switch keeps them if you need to)
  • ✓ The SDK sets no cookie and writes nothing to the browser
Read the docs
Request
curl -X POST https://oops.3m4.net/api/ingest \
  -H "X-Project-Key: oops_pub_…" \
  -H "Content-Type: application/json" \
  -d '{"type": "ValueError", "message": "order 42 has no items",
       "platform": "python", "release": "1.4.2",
       "frames": [{"filename": "app/orders.py", "function": "ship",
                   "lineno": 88, "in_app": true}]}'
Response
HTTP/1.1 202 Accepted
{ "ok": true, "event_id": "9021", "issue_id": "…", "issue_number": 12 }

Public keys can only report. They can never read anything, and they can be rotated at any time.

Model Context Protocol

Let your AI agent triage the inbox

oops ships an MCP server. Connect it to Claude Code, Claude Desktop, Cursor or any MCP host and ask things like “what broke after the 1.4 release?” or “triage the checkout errors and resolve the ones already fixed”

  • A triage prompt. The server ships a triage prompt that summarises a project's open issues — new vs regressed, most users affected, by environment — and proposes what to fix, resolve or ignore first.
  • Role-scoped keys. A viewer key never even sees the delete tools; editor and admin unlock more. Enforced by the API too.
  • Human in the loop. Destructive actions (delete a project, purge its events and issues) ask you to confirm before anything happens.
  • Audit trail. Every change and every refused call is logged, server-side and agent-side.
  • Local or remote. Run it over stdio with npx oops-errors-mcp (npm) or point your host at https://oops.3m4.net/mcp with your key.
Claude Code · local (npm)
claude mcp add oops --scope user --env OOPS_API_KEY=oops_live_… -- npx -y oops-errors-mcp
Claude Code · remote (nothing to install)
claude mcp add --transport http oops https://oops.3m4.net/mcp --header "Authorization: Bearer oops_live_…"
Any MCP host (JSON)
{
  "mcpServers": {
    "oops": {
      "command": "npx",
      "args": ["-y", "oops-errors-mcp"],
      "env": { "OOPS_API_KEY": "oops_live_…" }
    }
  }
}

Create a key with the role you want under Dashboard → API keys.

See your first error in a minute

Create a project, paste one script tag and throw something on purpose. It lands in the inbox in a second.

Early access. Every account has full access at no cost right now. Plans and limits will be introduced later, with notice before anything changes.

Self-host it (MIT, open source)

The entire stack — Flask API, browser SDK, MCP server and this Qwik app — is MIT-licensed. Run it on your own VPS with onedocker compose up. No billing code, no limits beyond what you configure.

View on GitHub