MCP server

/api/v1 — every verb the ah CLI speaks — is also served as a remote MCP server at https://agenthog.io/mcp. Same tokens, same scoping, same JSON as --json.

When this is the right door. A client that cannot run a shell: a Claude-powered assistant you are building on the Messages API, a cloud or sandboxed agent session where npm i -g is awkward, an editor whose only integration is an MCP URL. For a coding agent in a terminal, ah is the better tool — it composes with pipes and files, and it does not put thirty tool schemas into every turn of context. Nothing here is required to use AgentHog.

Connect

One URL plus a read token from the Tokens page, sent as a bearer header. The token pins which projects the tools can see; narrow it to one project if the client should not see the whole account. A read token gets the read tools and nothing else — the write tools are not even listed to it. A write token (org admins mint those) adds the write verbs below.

claude mcp add --transport http agenthog https://agenthog.io/mcp \
  --header "Authorization: Bearer ah_tok_…"

This release is bearer-token only. Anything with a headers field (Claude Code, Cursor, Windsurf, Zed, VS Code, the Messages API’s MCP connector) works as above. In Claude.ai, an organization administrator can add it as a custom connector with a static Authorization header (Anthropic’s static_headers beta); individual users adding a connector by URL, and ChatGPT, need OAuth, which is not served yet.

Tools

One per ah verb, returning exactly the JSON that verb prints with --json; the write tools send the same bodies the CLI’s HTTP mode does. Every project-scoped tool takes the same three arguments the CLI’s global flags set — project (key or name; optional with one project in scope), since (24h, 7d, 30d, Nd, YYYY-MM-DD) and filter (all, bots, test, server; omit for human + unknown). Bots and test traffic are excluded by default, exactly as in the CLI.

ToolScopeCLI twinDoes
projectsreadah projects listList the projects this token can read — key, name, domains, platforms. Call first when you do not know which project to ask about.
whoamireadah whoamiWhich account and token this connection is using, its scope, and how many projects it can read.
digestreadah digestStart here for 'how are we doing': one-call summary of a project over the window — sessions vs the previous equal window, top campaigns/sources/entry pages/events, dead and rage clicks, returning %, identified users, crawler summary, biggest mover.
trafficreadah trafficSessions per day by classification (human, unknown, suspected bot, crawler) with bounce %, engaged % and conversions, plus a top-sources table.
activereadah activeDAU / WAU / MAU — distinct people per day, week or month, optionally split by a dimension. The default window scales with granularity (30d daily, 84d weekly, 180d monthly).
retentionreadah retentionCohort retention triangle: people grouped by the day/week/month of their first session, and the % still active N periods later. All-time — no window.
campaignsreadah campaignsPer-utm_campaign performance: sessions, conversions, conversion %, junk share (bots + crawlers), top utm_content.
referrersreadah referrersTraffic sources (utm_source, else referrer host, else direct) ranked by engaged %, with conversion % and average duration; low-volume sources in an unranked tail.
crawlersreadah crawlersCrawler hits from the server request log (needs the server middleware): per-crawler counts, last seen, top paths, and an AI-crawler subtotal (GPTBot, ClaudeBot, PerplexityBot…).
eventsreadah eventsRecent events newest first (time, session, name, path, key props); or, with `name` and `by`, one event broken down by a dimension. Server-relayed events are included by default.
events_topreadah events topEvent names ranked by count and distinct sessions — the fastest way to learn what a project actually tracks.
clicksreadah clicks <path>Click targets on one page path grouped by element name and selector, then DEAD clicks (nothing happened) and RAGE clicks (3+ on the same element within 1.5s).
pathsreadah paths --to <event>The most common event sequences that end at a target event — semi-automatic funnel discovery.
sessions_listreadah sessions listRecent sessions newest first: id, start, source/campaign, entry page, pageviews, duration, classification and bot score. Filter to converted, returning or bounced sessions, a UTM source/campaign, or an experiment variant.
sessions_showreadah sessions show <id>One session in full: visitor, classification and bot signals, source, device, geo, then the chronological event timeline with relative offsets.
usersreadah usersIdentified people: email or anon id, key traits, session count, first and last seen. Filter by a trait key, first-touch source, or returning. No window — identities are cumulative.
userreadah user <ref>One person: identity card (email, traits, first/last seen), their sessions, and their last 20 events. Matches an email, a user_id trait, or an anon id, merging every identity that shares it.
funnelreadah funnelRun a saved funnel by name, or an ad-hoc one from 2+ event names matched as an ordered subsequence within each session. Returns per-step counts, conversion %, and median/p90 time between steps; optionally a per-session table or a dimension × step matrix.
funnels_listreadah funnels listThe project's saved funnels and their steps.
goals_listreadah goals listThe project's conversion goals (name → event). A session that contains a goal event counts as converted.
revenuereadah revenueReal-money revenue over the mapped purchase events: net, gross, refunds, orders, payers, ARPU, ARPPU, AOV — per currency, with optional breakdowns and a day/week/month series. Unmapped → { mapped: false } with setup instructions, never a zero.
ltvreadah ltvCumulative revenue per person by acquisition cohort (historical, not predicted). All-time — no window.
revenue_configreadah revenue configThe project's revenue mappings (which events carry money, and where the amount lives) with a live sanity count per mapping — including events whose amount did not parse. Explains a `revenue` result, or why it says mapped: false.
economyreadah economyIn-game virtual-currency flows over the mapped economy events: per currency, sourced (paid vs earned) and sunk amounts, net flow, top sources and sinks, plus an instrumentation-health line (unparseable amounts, sign disagreements, balance drift). Unmapped → { mapped: false }.
economy_configreadah economy configThe project's economy mappings: which events source or sink which virtual currency, with the amount, currency and balance props each reads. Explains an `economy` result, or why it says mapped: false.
changes_listreadah changes listThe project's changelog — deploys, experiments and other logged changes with timestamps — to line up against a metric that moved.
changes_showreadah changes show <id>One logged change by id or unique id prefix: title, time, kind, description, tags, variant, version, url, author.
flags_listreadah flags listFeature flags: key, state, traffic %, variants and weights, and whether an experiment is live on each.
flags_showreadah flags show <key>One feature flag in full: state, traffic %, variants and weights, description, and its experiment history.
experiments_listreadah experiments listThe project's experiments, live and concluded: flag, metric, control, start/stop, winner and conclusion where decided.
experiments_showreadah experiments show <flag>The live (else latest) experiment on a flag: hypothesis, metric, secondary metrics, guardrails, minimum duration, and status. For the numbers, call `experiments_results`.
experiments_resultsreadah experiments results <flag>Per-variant results for the live (else latest) experiment on a flag: exposures, conversions, conversion %, and chance to beat control. The verdict is gated on the configured minimum duration; the numbers are live from the first exposure.
reports_listreadah reports listShared reports the organization can open — slug, title, description, revision count, last updated.
reports_readreadah reports read <slug>A shared report resolved: the prose and every live widget's current rows, with as-of time, TTL and any widget error. Waits for stale widgets to recompute.
usagereadah usageThe account's monthly event volume against its plan allowance, with a per-project breakdown.
schemareadah schemaThe contract for `sql`: the readable tables and columns, helper functions, bind parameters (:since, :until) and the promises the surface keeps. Read before writing a query.
sqlreadah sqlRun a read-only SQL SELECT against the queryable tables (see `schema`). Scoped server-side to the token's projects and rate-limited; anything but a SELECT is rejected. Use :since / :until in the query and pass the window as arguments.
reports_showreadah reports show <slug>A shared report's metadata: title, description, author, revision count, and each live widget's cache state (as-of, TTL, stale, error). For the rows, call `reports_read`.
reports_historyreadah reports history <slug>A shared report's revisions, newest first: number, author, time, summary of what changed.
reports_pullreadah reports pull <slug> [--rev N]One revision of a shared report in full — the authoring Markdown source verbatim plus its parsed blocks. Pull before `reports_update` so the next revision edits the current text.
reports_widgetsreadah reports widgetsThe report widget library: every widget kind, its column contract, and the limits — the `schema` of report authoring. Read before writing a ```widget fence.
revenue_suggestreadah revenue suggestPropose revenue mappings from the props already in the data: for each candidate event, the amount prop, the share of occurrences that parse as a number (the honesty column), and the exact `revenue_map` arguments. Read-only — apply a proposal with `revenue_map`.
economy_suggestreadah economy suggestPropose economy mappings from the props already in the data — economy-shaped events with a guessed flow direction (labelled as a guess) and the share of amounts that parse. Read-only — apply a proposal with `economy_map`.
test_ips_listreadah test-ips listThe account's own IPs whose traffic is labelled `test` instead of counted as visitors.
reports_previewreadah reports preview --fileValidate a report's authoring Markdown and run every widget once, returning the resolved report plus warnings and hints. Persists nothing (a read token is enough) — the loop is preview until clean, then `reports_create`.
reports_refreshread · refreshes cacheah reports refresh <slug>Recompute a shared report's live widgets now, bypassing their TTL (not the 60-second floor). Any token; changes cached rows only.
goals_setwriteah goals set <name> <event>Define (or redefine) a conversion goal: a session containing the event counts as converted from the next sweep on.
funnels_savewriteah funnels save <name> <steps…>Save (or replace) a named funnel so `funnel` can run it by name.
changes_addwriteah changes addLog a change — a deploy, an experiment ramp, a pricing edit — so it lines up against the traffic and revenue that followed. Backdatable.
changes_updatewriteah changes update <id>Edit a logged change. Only the fields passed are changed; pass an empty string to clear desc, variant, version, url or author.
changes_removewrite · destructiveah changes rm <id>Delete a logged change.
trackwriteah track <event>Record ONE event no SDK saw — a deploy, a migration, a correction, a webhook you are relaying by hand — now or backdated. Lands on a server session (never counted as traffic; visible in `events`, `revenue`, `economy`, funnels with filter=server). Attribute it to a person with `person` (their user_id) and/or `email`, else it joins the shared unattributed server anon. No idempotency key: calling this twice writes the event twice. Bulk imports stay in the CLI (`ah track --file`).
flags_createwriteah flags create <key>Create a feature flag: boolean (on/off) or multivariate with weighted variants. Starts enabled at `traffic` percent (0 = dark launch: created, nobody enrolled, ramp later with `flags_rollout`).
flags_rolloutwriteah flags rollout <key> <pct>Ramp a flag: set the percent of sessions enrolled.
flags_weightswriteah flags weights <key> <spec>Re-weight a multivariate flag's variants. Refused while an experiment is live on it unless `force` is true (that invalidates the experiment's numbers).
flags_enablewriteah flags enable <key>Turn a flag on (serving its variants again).
flags_disablewriteah flags disable <key>Kill switch: turn a flag off so every session gets the fallback. Reversible with `flags_enable`.
flags_archivewrite · destructiveah flags archive <key>Retire a flag once its winner is shipped in code. Refused while an experiment is live on it.
experiments_startwriteah experiments start <flag> --metric <event>Open an analysis window on a multivariate flag: name the decision metric (an event), the control variant, a minimum duration, and optional secondary and guardrail metrics. Check exposure is flowing (`flags_show`) before starting.
experiments_stopwrite · destructiveah experiments stop <flag>Close the experiment window on a flag, optionally recording the winner and a conclusion. The flag keeps serving; ship the winner in code, then `flags_archive`.
revenue_mapwriteah revenue map <event> --amount <prop>Declare that an event you already send carries money and where the amount lives. Applies retroactively over all history; nothing is re-ingested. `revenue_suggest` proposes these.
revenue_unmapwrite · destructiveah revenue unmap <event>Remove an event's revenue mapping. Retroactive like `revenue_map`: its history stops counting as money.
economy_mapwriteah economy map --event E --source|--sinkDeclare that an event sources (adds) or sinks (removes) virtual currency. Convention: props `amount`, `currency`, `balance`. Applies retroactively; `economy_suggest` proposes these.
economy_unmapwrite · destructiveah economy unmap --event ERemove exactly one (event, amount-prop) economy mapping; a bundle event's other mappings survive.
reports_createwriteah reports create [<slug>] --filePublish a shared report from its authoring Markdown — visible to the whole organization immediately (no draft state). Preview first with `reports_preview`; read `reports_widgets` for the fence format.
reports_updatewriteah reports update <slug> --filePublish a new revision of a shared report from new source. History is kept — `reports_history` and `reports_pull` reach older revisions.
reports_deletewrite · destructiveah reports delete <slug>Delete a shared report with all its revisions and cached rows. Not reversible.
projects_createwriteah projects create <name>Create a project in the token's account and get its key (ah_xxxxxxxx). Needs an ACCOUNT-WIDE write token — one narrowed to specific projects is refused.
test_ips_addwriteah test-ips add [ip]Label an IP as the account's own: its traffic reads as `test` instead of counting as visitors. Omit `ip` to use the address this request came from.
test_ips_removewrite · destructiveah test-ips rm <ip>Stop labelling an IP as the account's own; its future traffic counts as visitors again.

What the server is, and is not

  • Stateless Streamable HTTP. One POST per JSON-RPC message, one JSON document back. No Mcp-Session-Id is issued, GET and DELETE return 405, and there is no server-to-client stream. Protocol revisions 2025-06-18 and 2025-03-26 negotiate (the older HTTP+SSE transport is not served). JSON-RPC batches of up to 20 messages are accepted, and each element pays the rate limit.
  • Scope is the permission model. Exactly as on /api/v1: a read token lists and calls only the read tools; a write token also gets track, goals, funnels, changes, flags, experiments, revenue and economy mappings, reports, projects and test IPs. Every tool carries the spec’s annotations — readOnlyHint on reads, destructiveHint on deletes, archives, unmaps and stops — so a client that gates on them can auto-approve a read and ask before a delete. A token pasted into a chat client should be a read token unless it has a reason not to be.
  • track writes one event through POST /ingest with the same conventions as ah track (server session, server:<person> anon, typed props, backdating via at). No idempotency key: two calls, two events. Bulk imports stay in the CLI (ah track --file).
  • Token-scoped. A tool can only see the projects its token can; a project outside that scope is a 404 in the tool result, never a leak.
  • Rate-limited per token: 60 requests a minute with a burst of 20 (HTTP 429 beyond that). The sql tool also carries the /api/v1/sql limit.
  • Tool errors are results. A bad argument, an unknown project or a rejected query comes back as isError: true with the same message the CLI would print, so the model can correct itself; protocol errors (unknown method, malformed JSON-RPC) use JSON-RPC error codes.
  • Not yet: OAuth and dynamic client registration, resources and prompts, bulk event import.

Self-hosted

The URL above is this deployment’s; a self-hosted AgentHog serves its own at /mcp. Rate limits are tunable with AGENTHOG_MCP_RATE_PER_MIN and AGENTHOG_MCP_RATE_BURST.