abusend MCP server

abusend runs a Model Context Protocol server. AI clients such as Claude Code, Claude Desktop, Cursor or VS Code can use it to look at your projects, investigate verdicts and flows, and draft, replay and tune rules with your permissions. Drafted rules are always saved monitoring; enforcing stays a deliberate step.

1. Create an access token

In the panel, go to Account & security → API & MCP → Personal access tokens → New token and choose:

Field Meaning
Name For your own reference, for example "Claude Code laptop".
Organization Limit the token to one organization, or leave it empty to cover all your organizations.
Max role viewer can only read. analyst can also change actions, rules, lists and attributes. admin can additionally apply project-setting fixes (for example allowing an origin). The token never gets more than your own role in an organization.
Expires in 1–365 days (default 90).

The token (abp_…) is shown once. Store it in your client's secret store or in an environment variable, never in a repository. You can revoke it at any time on the same page. Changing your password (or an operator resetting it) revokes all your tokens: create new ones afterwards.

The same token works for the panel API (/api/panel/v1) with Authorization: Bearer abp_…, and no CSRF header is needed.

2. Connect a client

Replace https://abusend.example.com/mcp with your panel URL plus /mcp, and abp_… with your token.

Claude Code

claude mcp add --transport http abusend https://abusend.example.com/mcp \
  --header "Authorization: Bearer abp_…"

Then run claude mcp list to check the connection. Inside Claude Code, /mcp shows the tools.

Claude Desktop

Claude Desktop's built-in remote connectors expect OAuth. To use an access token, use the mcp-remote bridge (Node ≥ 18) in claude_desktop_config.json (Settings → Developer → Edit config):

{
  "mcpServers": {
    "abusend": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://abusend.example.com/mcp", "--header", "Authorization:${ABUSEND_AUTH}"],
      "env": { "ABUSEND_AUTH": "Bearer abp_…" }
    }
  }
}

The header value goes through an environment variable. Some platforms break args entries that contain spaces, and the variable avoids that. Restart Claude Desktop afterwards.

Cursor

~/.cursor/mcp.json (global) or .cursor/mcp.json (project):

{
  "mcpServers": {
    "abusend": {
      "url": "https://abusend.example.com/mcp",
      "headers": { "Authorization": "Bearer abp_…" }
    }
  }
}

VS Code (GitHub Copilot agent mode)

.vscode/mcp.json:

{
  "servers": {
    "abusend": {
      "type": "http",
      "url": "https://abusend.example.com/mcp",
      "headers": { "Authorization": "Bearer abp_…" }
    }
  }
}

To avoid committing the token, use an input variable. Put "inputs": [{"type": "promptString", "id": "abusend-token", "password": true}] next to servers and write "Authorization": "Bearer ${input:abusend-token}".

Any other client

Configure a Streamable HTTP server with the URL and the Authorization header. To check a token from the command line:

curl -s https://abusend.example.com/mcp \
  -H "Authorization: Bearer abp_…" -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

3. Tools

Every tool takes project as a project id or its exact name. It can be left out when you have exactly one project. Results are compact JSON with ids, and long lists are cut (truncated: true). The tools run the same panel API as the panel, with your role.

Tool What it does Kind
list_projects Projects you can access, with organization and role read
get_project_status Environment, to-dos, last-24h decisions with decided_by, the friction funnel, top rules and signals read
list_actions Actions (labels; they have no mode) with token requirement, 24 h outcomes, verification counts and what "Your app decides" does there read
get_action One action: token settings and the rules in scope with their state (Monitoring / Enforcing / Off) read
set_action_token Set an action's token requirement (required / optional) and token_missing (review / deny); needs confirmation write, idempotent
search_verdicts Flows and verdicts filtered by action, decision, decided_by, rule, check, reason, user, IP, device, risk level, since; paginated. Verdicts show would_decision and would_challenge ({mode, checks}) read
get_flow One flow as a timeline: signals (hints), matched rules, verifications with status and time, final decision read
get_user End user: attributes, list status, devices, recent flows read
list_events Events your server reported (POST /v1/events), newest first, filtered by user and/or type; paginated. With a user, also totals: per type what event_count / event_sum / event_last give a rule now (1h, 24h, 7d, 30d; last_at) read
get_device Device: users, list status, verifications, recent flows read
list_networks Where traffic comes from: the window's verdicts grouped by client IP, autonomous system or country, with IP data (country, ASN, org, flags — hints), flows, users, devices, decisions, risk and, for IPs, list status; paginated read
get_ip One client IP: IP data, first/last verdict, the window's decisions, top users and devices, actions, and the allow/block entries naming it (address or CIDR) read
list_rules / get_rule Rules in evaluation order: condition, outcome and check group (checks: {mode, items: [{check_id, check, weight?}]}), action scope, state (Off / Monitoring / Enforcing), origin (watch for a Monitoring rule Watch created alone), hits, unseen_attributes (attributes the condition reads that were never received, and event.<type> for event types never reported) read
list_rule_templates Rule templates, their parameters and the attributes they declare (including many top-ups in a short time and high total in 24 hours on reported events) read
list_rule_fields Fields and helpers for conditions, including your declared attributes, the event functions event_count(type, window), event_sum(type, window), event_last(type) and your known event types (scope event); filterable read
simulate_rule Replay a new, changed or deleted rule on the first verdicts of recent flows: matched, changed decisions, users per day per check (a new "one of these" group is shared out by weight: expected counts), missing-field warnings; items carry challenge: {mode, checks}; tier none · small (< 200: report counts, not shares) · full read
create_rule Create a rule from a template or an expression; always saved monitoring; declares the template's attributes and lists unseen_attributes write
update_rule Change a rule's name, condition, outcome, check group or scope (its state stays as it is) write, idempotent
set_rule_mode Set a rule to monitor (Monitoring) or enforce (Enforcing) — the only monitor/enforce switch; enforcing shows the replay and needs confirmation write
set_rule_enabled Enable or disable a rule write, idempotent
delete_rule Delete a rule write, destructive
list_checks Connected checks with kind, provider, health, on_* settings and 7-day stats read
list_lists Allow and block lists read
add_to_list Add a user, IP/CIDR, device or value, with optional expiry in days and a note write, idempotent
remove_from_list Remove a value from a list write, destructive
list_attributes User and context attributes with scope, detected or configured type, and wrong-type counts read
set_attribute_type Set an attribute's type (for example a timestamp in ms); declaring works before the server sends it write, idempotent
list_counters Shared counters: definition (source, action or event type, filter, count or sum, group_by), totals for the last hour and 24 hours, the largest groups, the rules reading them read
save_counter Create a shared counter, or replace the one with this key (counting something else starts it from zero); rules read it with counter("key", "1h") write, idempotent
get_stats Decision time series and totals (1h / 24h / 7d / 30d) read
get_risk Risk thresholds (where medium, high and critical start; defaults 25 / 50 / 75), signal weights (default, current, enabled), how recent verdicts spread over risk scores and levels, and the signals seen most (24h / 7d / 30d). Risk is a hint: the levels only name score ranges that rules read read
set_risk_thresholds Set where the risk levels start (medium, high, critical; 1 ≤ medium < high < critical ≤ 100). Changes risk.level for every rule that reads it from the next verdict; stored verdicts keep their level. The confirmation shows the preview (verdicts changing level, what the rules reading risk would match); needs confirmation write, idempotent
get_integration_status Last assessment and verdict, origins seen and refused read
apply_todo_fix Apply a to-do's server-side fix (allow an origin, require the token, use a widget check for high risk, block unfinished verifications) write

Check groups. create_rule, update_rule and simulate_rule take the checks of an outcome challenge either as check (one check, key or id) or as checks, a group of 1–3 distinct checks — not both:

{"outcome": "challenge",
 "checks": {"mode": "any", "items": [{"check": "captcha", "weight": 70}, {"check": "hcaptcha", "weight": 30}]}}

mode is any (one of these, picked at random by weight when the verification is issued; weight 0–100, default 1, 0 = fallback only, at least one above 0), sequence (all, one after another) or parallel (all at once; weights are dropped for these two). An invalid group is refused with invalid_rule. Compact rule output shows checks; see RULES.md §2.3 for how groups decide.

Each tool carries annotations (readOnlyHint, destructiveHint, idempotentHint), so clients can ask for confirmation before writes. Most clients do this by default. There are no tools to connect checks or store provider secrets: use the panel for those.

Drafting rules with an agent. Rules an agent creates are always saved in Monitoring: they record what they would have done ("would have: Verify with SMS") and never change a decision. Run simulate_rule before create_rule; move a rule to Enforcing with set_rule_mode only after its monitoring hits look right and its unseen_attributes is empty. A rule's state is the only monitor/enforce switch — actions have no mode, and an enforcing rule applies on every action of its scope, new ones included. Events the customer's server reports (POST /v1/events) are read with event_count("topup", "1h"), event_sum("topup", "24h") and days_since(event_last("topup")), and the user's attempts at an action with attempts("topup", "5m") (every verdict call, a retry after a verification not counted again); a window is minutes, hours or days from "1m" to "30d" and the arguments are quoted literals (anything else does not compile). Totals across users — every payment from one country, everything hotmail users bought — are shared counters: define one with save_counter and read counter("key", "15m") (window at most 24h: the total of the request's group); it counts from when it is created. Enforcing a rule is the step that changes live decisions (with the token settings of set_action_token); the in-panel assistant asks you to confirm it with the replay summary, and MCP clients should do the same.

4. Security notes