MCP server
POST https://api.ax1om.ai/mcp · streamable HTTP · 11 tools. Point a
client at it, send your credential in the Authorization header,
and an agent can run a scoring trial end to end: check fit honestly, prepare
a scrubbed export, train a model on your own conversion history, read the
results, score records live, and check those scores against what actually
converted.
Why this exists: ax1om for AI agents.
What this is
The Model Context Protocol is how an AI agent calls an external tool. A predictive scoring MCP server is one that gives the agent access to a trained model that ranks conversion likelihood, instead of asking the agent to invent a score itself.
That distinction is the whole point. A language model can reason about a lead, summarize it, draft the outreach, and decide what to do next. It should not be the scoring model. Prioritizing on conversion history is a job for a model trained on your outcomes, measured, monitored for stability, and explainable per record. ax1om is that model. The agent consumes the prediction and decides what to do with it.
Most scoring an agent can reach today is a rules engine wearing a different hat: enrichment, signals, and hand-set ICP weights. ax1om trains a dedicated model per customer on that customer's own conversion history, converted and non-converted records alike, and every score carries the factors behind it. Nothing here is shared across customers and no third-party intent data is involved.
Connect an agent
The server is mounted on the main API, so there is nothing to install and nothing to run. For an MCP client that speaks HTTP, including Claude Desktop, Claude Code, and Cursor:
{ "mcpServers": { "ax1om": { "type": "http", "url": "https://api.ax1om.ai/mcp", "headers": { "Authorization": "Bearer ax1m_sk_your_key_here" } } }}For a client that only speaks stdio, bridge it:
{ "mcpServers": { "ax1om": { "command": "npx", "args": [ "-y", "mcp-remote", "https://api.ax1om.ai/mcp", "--header", "Authorization: Bearer ax1m_sk_your_key_here" ] } }}
Mint a key in the app under Settings, API keys. The secret
(ax1m_sk_...) is shown once. A test key
(ax1m_sk_test_...) works the same way and meters against a
separate free allowance.
Authentication
Two credential types, and which one you need depends on the tool.
| Credential | Where it comes from | What it reaches |
|---|---|---|
ax1m_sk_... API key | Settings, API keys at app.ax1om.ai | score_records · test_webhook |
| App session token | An authenticated app.ax1om.ai session | Every tool |
API keys authorize live scoring only. That is not an MCP restriction, it is how the public API already works, and this server does not widen it. Call a tool that needs a session token with only an API key and you get a plain refusal saying so, rather than a confusing 401.
The server holds no credentials of its own. Every call it makes carries your credential to the real route, which runs its own auth, entitlement checks, rate-limit bucket, and metering. Keys are never logged and never appear in a tool result.
On browser authorization
An agent can now authorize in a browser instead of being handed a token. Point your MCP client at the endpoint above and connect: it registers itself, your browser opens, you sign in (or create an account - connecting starts your trial) and approve exactly what the agent may do - score records · upload data · train models · read model results. Every grant is yours to revoke at any time under Settings · Connected agents in the app, and revoking cuts off the agent immediately.
Accounts with multi-factor authentication approve on an MFA-verified session - the check happens at the moment you authorize the agent, not on every call the agent makes. Header credentials stay fully supported as the fallback for headless and warehouse setups; nothing already configured needs to change.
Tool reference
11 tools, 4 of which never touch the network: nothing about your data leaves your machine when you call them.
| Tool | Network | Credential | What it does |
|---|---|---|---|
assess_fit | No | none | The four-point fit checklist: a definable conversion outcome, enough conversions, months of history, and a CRM that can export a CSV. Returns fit, fit_with_caveats, or not_yet. A not_yet comes with next steps that need nothing from ax1om. |
generate_export_spec | No | none | Which columns may leave your org and which never may, how to derive the email domain, and how to build the conversion label. Set warehouse to snowflake or databricks and you get a commented SQL scrub template instead of spreadsheet steps. |
validate_csv | No | none | Lints your header row, and any sample values you pass, against the drop rules, then proposes a column mapping for what is left. The report never repeats back a value it flagged. Run it before every upload. |
safe_export_policy | No | none | The keep and drop tables verbatim, for a security reviewer who would rather read the rules than infer them from a generated query. |
upload_csv | Yes | Session token | Uploads a scrubbed CSV as a training dataset and returns the column metadata ax1om read from it. Max 100MB, .csv only. |
train_model | Yes | Session token | Starts a training run. Training is asynchronous: this returns a run id, then poll get_model_results. |
get_model_results | Yes | Session token | Model state and raw training metadata, including run status. |
get_readout | Yes | Session token | The model-quality readout as structured text: AUC named and explained, lift in the top band, what it trained on, the features that drove the score, and the Feature Stability Score. Metrics the model does not have are reported as unavailable rather than guessed. |
check_validation | Yes | Session token | The scoring-vs-outcomes check-in: cohort conversions by score band for a model's live scores, with maturity honesty - cohorts too young to grade say so (counts shown, rates withheld) rather than rendering noise. The natural week-2 and week-4 POC questions: are the top bands converting, and is it too early to tell? |
score_records | Yes | API key | Live scoring through POST /v1/score. Returns a 0-100 score per record plus the conversion likelihood it ranks by, and the factors behind it when explain is on. Max 1000 records per request. Metered. |
test_webhook | Yes | API key | Posts one sample record to the inbound /v1/webhooks/score endpoint and returns the exact flat response your receiver will get. Use a test key so it meters against the test allowance. |
On test_webhook
ax1om does not deliver outbound webhooks to a url you supply, so there is no
delivery endpoint to ping. /v1/webhooks/score is an
inbound endpoint: Marketo, Zapier, or your own service posts
a record and gets a score back in the response. That is the path an
integration actually exercises, so that is the one this tool tests. It takes
a model_id, not a url.
A trial, end to end
The four local tools exist so an agent can do the preparation work before anything is sent anywhere. A typical run:
- Check fit first.
assess_fitis deterministic and answers honestly, including when the answer is no. A first model trains on as few as 50 conversions, and if you are below that the tool says so and gives you next steps that need nothing from ax1om. - Generate the export spec.
generate_export_specreturns exactly which columns may leave and which never may. In the warehouse lane it returns SQL instead, so the scrub runs where the data lives. - Lint the file locally.
validate_csvchecks the header row against the drop rules and proposes a column mapping. No file, header, or value is sent anywhere. - Upload, train, read.
upload_csv, thentrain_model, then pollget_model_resultsand readget_readoutfor AUC, lift, the driving features, and the Feature Stability Score. The readout is structured text; there is no PDF export of it.
assess_fit({ conversion_outcome_defined: true, conversion_count: 340, months_of_history: 18, crm_exports_csv: true, crm: "salesforce"}){ "verdict": "fit", "checks": [ { "name": "conversion_outcome_defined", "pass": true }, { "name": "conversion_count", "pass": true }, { "name": "months_of_history", "pass": true }, { "name": "crm_exports_csv", "pass": true } ]}Scoring inside an agent
Once a model is trained, score_records is the tool an agent
calls in normal operation. Set explain to true and each score
comes back with the factors behind it, which is what lets the agent explain
its own prioritization to a human instead of asserting it.
score_records({ model_id: "mdl_abc123", records: [ { "Title": "VP of Revenue Operations", "Industry": "Software", "LeadSource": "Webinar" } ], explain: true}){ "model_id": "mdl_abc123", "scores": [ { "score": 87, "conversion_likelihood": 0.871, "top_reason_1": "Title seniority", "top_reason_2": "Industry: Software", "top_reason_3": "Webinar source" } ], "records_scored": 1, "usage": { "current": 151, "limit": 10000, "remaining": 9849 }}
The score is a 0-100 ranking of conversion likelihood. It is not
a percentage chance of conversion, and the per-record factors do not sum to
it. A prospecting agent uses it to choose target accounts, an SDR agent to
order outreach, a routing agent to set priority. In each case the model
supplies the prediction and the reasons; the agent decides the action.
Compare it to what you run today
A readout tells you how the model scored itself. It does not tell you whether it beats the process you already run. That question has one honest answer and it is arithmetic on your own historical months: the leads your team treated as qualified, against the leads ax1om would have ranked at the top, over the same records, at the same volume.
The comparison needs a column you should never send us. Whatever your CRM
calls it - MQL, qualified, lead grade, your current score - it is your
estimate of who was worth working, and it stays on your machine. So does
the comparison itself. Your agent already holds the export locally,
score_records returns the ax1om side, and the arithmetic
happens where both already sit. Nothing about how you qualify today reaches
ax1om. That is the same reason the
scrubbed export works: the fewer approvals a
trial needs, the sooner it happens.
Paste this at an agent that has your export and this server connected:
You have my CRM export on this machine and the ax1om MCP server connected.Run a head-to-head between ax1om and the way my team qualifies leads today.
Ground rules, before anything else:- My qualification column, my current score, and my conversion outcomes stay on this machine. Never send them to a tool or to any network call.- The only thing that goes to ax1om is what score_records needs: the feature columns the export spec allows. Call generate_export_spec if you are not sure which those are.- Do the arithmetic locally. Report it to me, not to anyone else.
Then:1. Read the export and ask me two questions before assuming anything: which column marks the leads my team treated as qualified, and which column marks a conversion. Name the candidates you found and let me choose.2. Call get_readout and note the months the model trained on. Keep the comparison to records outside that window. If that leaves too few records to work with, tell me the comparison is in-sample and that it flatters ax1om.3. Keep only matured records: scored long enough ago that an outcome has had time to land. Use 30 days unless I tell you my sales cycle is longer. Tell me how many records you dropped as too recent.4. Score what is left with score_records, 1000 records per call.5. Count my side: how many records my qualification column marks, and how many of those converted.6. Count ax1om's side at the same volume: the top N by ax1om score, where N is the count from step 5, and how many of those converted.7. Report counts first, then rates. Withhold the rates if either set has fewer than 50 matured records. Below that the gap is noise, and a percentage reads as a finding it is not.8. List the conversions my rules did not mark that ax1om's top N did, with the factors behind each score, so I can see why it ranked them.9. Close by saying what this is not: one historical read on my own data, not a forecast.The rules that keep it honest
Four of the steps above exist to stop the comparison flattering us. They are the same rules ax1om applies to its own numbers, and an agent that drops them produces a result you should not believe:
- Matured records only. A record scored last Tuesday has not had time to convert. Counting it as a non-conversion punishes both sides at random. The recipe uses the same 30-day maturity window ax1om uses internally, widened to your sales cycle if yours is longer, and says out loud how many records it set aside.
- Historical months, not last week. The whole method depends on records old enough to have outcomes. Run it over the months you already know the answer to; running it over recent leads measures nothing but how recently they arrived.
- Counts before rates, and no rates on thin sets. Below about 50 matured records in either set, the difference between the two is noise wearing a percent sign. The recipe reports the counts and withholds the rates rather than printing a number that reads as a finding.
- The same volume on both sides. Any model looks better if you let it pick fewer records. Taking exactly as many ax1om-ranked records as your rules marked removes that move from the argument, in either direction.
The last step matters most and it is the one a comparison usually skips. The list of conversions your rules did not mark is the why these leads? answer in its most useful form: real records, with real outcomes you can look up, and the factors that ranked each one. If those factors are not ones you would have named yourself, that is worth knowing before you route anything on the score.
What comes back has the shape below. Every number in it is invented. It is there to show the format, not to report what any comparison returned - ax1om publishes no result it has not measured on a customer's own data, and your own run is the only number that means anything here.
Head-to-head · records scored on or before 2026-06-30
Matured records 4,120 Dropped as too recent 860 inside the 30-day window Excluded as in-sample 1,240 inside the training months
Your qualified set 412 records · 57 conversions · 13.8% ax1om top 412 412 records · 91 conversions · 22.1%
Rates shown: both sets clear the 50-record floor.
Conversions your rules did not mark, that ax1om's top 412 ranked (44)
rank score factors 7 94 Title seniority · Industry: Software · Webinar source 23 88 Title seniority · Repeat pricing-page visits 41 85 Industry: Software · Demo request ...
Conversions ax1om's top 412 did not rank, that your rules marked (10)
Read these before you trust the rest. If they share something the model never saw, that is a field to add, not a reason to discard the comparison.
This is one historical read on your own records. It is not a forecast.Checking in once the model is live
The head-to-head is a one-off: it settles the question at the start, on
records that already have outcomes. Once ax1om is scoring for real, the
same question comes back on a schedule, and it no longer needs your export.
check_validation reads cohort conversions by score band for
the scores the model has already written, with the maturity window applied.
Cohorts too young to grade say so and return counts with the rates
withheld, rather than rendering noise as a trend.
That is the week-2 and week-4 check-in: are the top bands converting, and is it too early to tell? Both are real answers. A model two weeks into a trial has usually not had time to be right yet, and a tool that says so is more useful than one that draws a line through four points.
What leaves your org
Scrub the direct identifiers before the data leaves, then trial on the scrubbed file. A dataset that never contained direct identifiers usually does not need an infosec review, a DPA, or procurement, so you can evaluate on real data without asking anyone's permission first.
generate_export_spec is the machine-readable form of that
policy and safe_export_policy returns the rules verbatim. The
CSV instructions and the warehouse SQL both compile from one definition, so
they cannot drift apart. Two details in the generated SQL are deliberate and
commented inline:
- The record id is hashed; the email domain is not. Hashing is deterministic, so you hash your own ids the same way and the returned scores still join back to your CRM. The domain stays legible because it is a company identifier rather than personal data, and because business-versus-personal email is one of the strongest features. The local part is stripped in the query and the full address never leaves.
- Dates are truncated to the calendar day, never jittered. Truncation drops the time of day, which is the part that behaves like a fingerprint, and costs the model nothing. Jitter on a conversion date would corrupt the label.
Limits and metering
-
score_recordstakes up to 1000 records per request and meters against your monthly plan allowance, exactly like any other call to the scoring API. Test keys meter against the separate test allowance instead. -
upload_csvaccepts.csvonly, up to 100MB. -
train_modelis asynchronous. It returns a run id; pollget_model_resultsrather than waiting on the call. - Sessions are stateless and responses are JSON, so the server scales horizontally without session affinity.
- The four local tools have no limits and no metering. They never leave your machine.
The same predictions are available over plain HTTP if you would rather not run an agent: see the API reference. For how the model is trained and what the score means, see how it works and the learn center.