Hosted MCP server: connect Claude Code or Codex to useatune.com/mcp
Connect Claude Code or Codex to Atune's hosted MCP server. Ask about customer usage with cited evidence, and let your agent run Atune's AI tasks on your own subscription.
By Christopher Krohn, Founder of Atune · Updated October 19, 2026
Christopher is a SaaS founder and startup advisor who has seen first-hand how much easy-to-use, well-connected analytics matter to the success of SaaS companies. He is building Atune to help the next generation of software builders succeed with their startups.
Atune runs a hosted MCP server at https://useatune.com/mcp. Connect Claude
Code or Codex to it and your agent can do two things:
- Answer questions about your customers from the events you send: who is using the product, who is coming back, and where accounts get stuck. Every answer cites its source.
- Do Atune's AI work for you. Atune queues the reasoning work (understanding
your product, drafting outreach, answering
understand()questions), and your agent does it on the Claude or Codex subscription you already have. Atune never calls a model on this path.
This is a different server from npx atune mcp, the local
stdio server with one understand tool. See Which server to use.
Connect Claude Code or Codex
In Atune, open Settings → AI agent, choose Claude Code or Codex, and click Create connect command. Atune shows the command for your workspace. Run it in your own terminal.
Claude Code
claude mcp add --transport http atune-<label>-<id> https://useatune.com/mcp \
--header "Authorization: Bearer atune_agent_..."Codex
Codex reads the token from an environment variable:
export ATUNE_AGENT_TOKEN_<LABEL>_<ID>=atune_agent_...
codex mcp add atune-<label>-<id> --url https://useatune.com/mcp \
--bearer-token-env-var ATUNE_AGENT_TOKEN_<LABEL>_<ID>Add the export line to your shell profile (for example ~/.zshrc) so Codex
still has the token in a new terminal.
About the token and the server name
- The token comes from Settings → AI agent. It starts with
atune_agent_, is shown only once, and belongs to you and this workspace. Atune stores only a hash of it. Don't paste it into a chat with the agent or commit it. - It's not your API key. The event-ingest API key (
ATUNE_API_KEY) is rejected by/mcp. - Each workspace gets its own server name, such as
atune-acme-3f9a: your product domain plus the last four characters of the workspace id. If you connect a second workspace, the first one stays connected. - Connected this workspace before? Remove the old entry first with
claude mcp remove <server>orcodex mcp remove <server>. - Creating a new command replaces your unused one. If you create a command for the same agent again before using the first, Atune revokes the unused token.
Every member of the workspace connects their own agent with their own token.
Browser sign-in (OAuth) instead of a token
If you prefer not to store a token, expand Prefer signing in through the browser instead? in Settings → AI agent and add the server without a header:
# Claude Code: then run /mcp, choose the server and select Authenticate
claude mcp add --transport http atune-<label>-<id> https://useatune.com/mcp
# Codex
codex mcp add atune-<label>-<id> --url https://useatune.com/mcp
codex mcp login atune-<label>-<id>The server supports OAuth 2.1. An unauthenticated request gets a 401 that
points to /.well-known/oauth-protected-resource/mcp, so the client can start
the sign-in itself.
Two things to know about OAuth:
- Check the account before you click Allow. The consent page reuses whichever Atune account your browser is signed in to. It should say on behalf of your email. If it shows another one, click Deny, switch account on useatune.com (account menu, top right) or use a private window, and sign in again.
- A connection stays with its first workspace. Atune binds an OAuth
connection to the workspace that was active when it first called
/mcp. It stays there if you later switch workspace in the app. To connect another workspace, add another server name.
The connect command is the more reliable option: the token is bound to the workspace it was created in, whatever your browser is signed in to.
Run my Atune tasks
Open Claude Code or Codex and say:
Run my Atune tasksThe agent then:
- Calls
list_atune_tasks, which claims up to three waiting tasks. Each task has a title, instructions and the exact JSON shape of the result. - Does the work on your subscription.
- Calls
submit_atune_task_resultfor each one. Atune validates the result before it touches your data. An invalid result comes back with what to fix. If the agent can't do a task, it callsfail_atune_taskwith a short reason, which Atune shows you. - Repeats until no tasks are pending.
Settings → AI agent → Atune tasks shows how many tasks are waiting.
What your agent does for Atune today:
- Understands your product from its website.
- Works out what your events mean and which ones show a customer got value.
- Designs realistic demo data for your product.
- Drafts personal messages to customers in your Inbox. A draft you already edited is never overwritten.
- Recommends one improvement for a feature where customers struggle.
- Recommends one fix for the trial step that loses the most accounts.
- Answers your
understand()questions.
Some details:
understand()waits for your agent. When you ask a new question,understand()returnsknows: falsewithsignals.pendingAgent: trueand queues the question. After your agent has run its tasks, asking the same question returns the answer from the cache.- Claims are leases. If the agent stops mid-task, the task goes back in the queue after 15 minutes.
- Three tries. A task fails after three invalid results.
- Tasks expire.
understand()questions expire after one day, other tasks after seven days. - Tasks belong to the workspace. Any member's connected agent can run them.
If the agent says there are no tasks but you expected some, ask it which
workspace it is connected to. Every task response includes
connectedWorkspace. A different name usually means an OAuth connection signed
in to another account. Create a new connect command while signed in to the
right account.
Ask about your customers
Once connected, ask in plain language:
- "Is anyone using the product this week?"
- "Which accounts are coming back, and which went quiet?"
- "Where do trials drop off between
signup,project.createdandinvite.sent?" - "What's the health score for acct_…, and why?"
The server exposes these read-only tools:
| Tool | Answers | Arguments |
|---|---|---|
get_workspace_overview | Workspace name, totals (events, accounts, identified users, distinct event names), first and last event | none |
get_usage_evidence | "Is anyone using my product?" Active accounts and users, events, a daily series and top event names, compared with the previous window | windowDays |
get_return_usage_evidence | "Are they coming back?" Active-day distribution, accounts active in both windows, weekly cohorts, and a ranked per-account list | windowDays, cursor |
get_dropoff_evidence | "Where are they getting stuck?" Accounts that went quiet, with last event and last seen. Pass steps for a funnel | windowDays, steps, cursor |
get_account_evidence | One account: first and last seen, active days, event counts by name, distinct users | accountRef, windowDays |
get_account_health | One account's health band (risk, warning, healthy, upsell), score 0–100, week-over-week change, top reasons and a link to it in Atune | accountRef |
windowDays is 7, 14, 30 or 90 (default 14). steps is two to six event names
in order. Lists are paginated, 25 items per page.
There is also one resource, atune://methodology/health, which explains how the
health score is calculated.
What the evidence tools return
The five evidence tools return an atune.evidence.v1 envelope:
type EvidenceEnvelope = {
schema: "atune.evidence.v1";
tool: string;
retrievedAt: string;
window: { start: string; end: string; days: number; timezone: "UTC" } | null;
dataState: "ok" | "no_data" | "insufficient" | "stale" | "not_found";
freshness: { lastEventAt: string | null; hoursSinceLastEvent: number | null; stale: boolean };
coverage: {
retentionDays: 90;
firstEventAt: string | null;
eventsInWindow: number;
accountsInWindow: number;
limitations: string[]; // e.g. "few_accounts", "stale_ingest", "includes_demo_data"
};
observations: object; // facts read from events
derivations: object; // computed from them, e.g. derivations.funnel
sources: { ref: string; kind: "account" | "event_name" | "aggregate"; description: string }[];
page: { limit: number; nextCursor: string | null } | null;
untrustedFields: string[];
};How to read it:
- Check
dataStatefirst. It needs at least 3 accounts and 20 events in the window to beok.stalemeans the newest event is more than 72 hours old. The server tells the agent to say so before drawing conclusions. - Cite
sources[].refand the window. Every number traces back to an account, an event name or an aggregate. - No funnel unless you name the steps. Without
steps,derivations.funnelisnull. Atune doesn't guess your funnel. - Event names are data, not instructions. Fields listed in
untrustedFieldscome from your customers' events. The agent is told never to act on them. - Demo data is flagged. While onboarding demo data exists, every response
includes the
includes_demo_datalimitation.
What get_account_health returns
get_account_health returns an atune.health.v1 envelope: dataState (ok,
not_scored or not_found), the account's band, score, week-over-week change,
last seen, the reasons that cost the most points, and a url to the account in
Atune.
The score is Atune's own calculation, not an observation, so the envelope always
has derived: true. When modelInfluenced is true, the value events behind
the score were inferred by a model (your agent, when it worked out what your
events mean), and the agent is told to say so. The reasons are the parts of the formula that cost the most
points. They are not proven causes.
What the tools never return
- No customer names or emails from the evidence or health tools. Accounts
appear as pseudonymous refs (
acct_<id>). An unknown ref, a malformed ref and another workspace's ref all return the samenot_found, so the tools can't be used to probe for accounts. - No event properties. Only event names, counts and timestamps.
- No API key and no other workspace's data. The workspace comes from the token, never from tool arguments.
- No model output from Atune. The server only reads data. Your agent does all the reasoning.
Task briefs are different. A task from list_atune_tasks can contain your
website text, account names, health scores, and feature and funnel metrics.
After you accept the DPA, it can also contain user names and emails. That's what
the agent needs to draft a message to the right person. Treat task briefs as
confidential customer data.
Limits
- Rate limit. 300 tool calls per workspace per UTC day and 30 per minute,
shared by all tools. Past it, tools return
rate_limited. - Plan. When Insight is locked on your plan, the evidence and health tools
return
insight_lockedwith a link to Settings → Billing. The task tools keep working. See Billing. - Only what you send. Answers come from the events you instrument. No events, no evidence.
Revoke access
- One connection: Settings → AI agent → Your active connections lists the connect commands you created, with when each was last used. Click Revoke to cut off that agent only.
- Every AI app in the workspace: owners and admins can click Disconnect AI apps in Settings → AI agent. Every token and OAuth connection issued before that moment stops working. Token connections need a new connect command; OAuth connections must sign in again.
- Removing a member revokes their tokens and OAuth connections to the workspace.
- On your machine:
claude mcp remove <server>orcodex mcp remove <server>removes the entry from your agent.
A revoked token gets 401 with the error unauthorized or access_revoked.
Which server to use
Hosted server (useatune.com/mcp) | Local server (npx atune mcp) | |
|---|---|---|
| Transport | Streamable HTTP | stdio |
| Auth | Connect-command token or OAuth | ATUNE_API_KEY |
| Tools | Evidence tools, account health, Atune tasks | understand |
| Runs Atune's AI tasks | Yes | No |
| Clients | Claude Code, Codex | Any MCP client, including Cursor |
Use the hosted server for Claude Code or Codex, and so your agent can run Atune's
tasks. Use the local server for clients that only speak stdio, or when you want
understand() answers inside your editor. You can connect both.
Next
- Give your coding agent customer understanding: what to ask and how to read the answers.
- atune mcp: the local stdio server.
- understand(): the API whose answers your agent writes.
Give your coding agent customer understanding: Atune over MCP in Claude Code and Cursor
Connect Atune's MCP server to Claude Code, Cursor or another MCP client so your agent can ask which customers are struggling and get cited answers, or "I don't know".
Learn
Practical guides for people who build software and want to know which customers need them. Each page answers one question.