Skip to content

Connect an AI agent over MCP

AI agents are only useful in your business if you can trust them with it. Routario speaks MCP (the Model Context Protocol), the open standard for connecting AI agents to tools and data — so any spec-compliant agent, whether it’s Claude, ChatGPT, or one you build yourself, can work with your workspace.

The difference is what the agent is allowed to do. Every agent connects through a key that:

  • starts with zero access — a fresh key can reach nothing until you grant it;
  • can propose work but never make it live on its own — a person stays in the loop;
  • can read only a short, named set of things — never crawl your contacts, invoices, or deals.

Governed agent access is built in, not a paid control surface bolted on top.

A single endpoint —

https://<your-workspace>.routario.com/mcp

— that any MCP client can connect to with a bearer token. Once connected, the agent discovers exactly the tools its key is granted, and nothing else.

This is the part that matters, so it comes first.

1. Keys start closed. A brand-new key authenticates but can touch nothing. You grant exactly the areas it needs — “draft automations,” “read run status” — and it gets those and only those. This is the same access list your people, agents, and field devices are on; see Access: who can do what.

2. It can propose, but not deploy. The one tool that builds something — build — only ever produces a draft. It reads what your workspace can do, proposes the flows and agents to meet a goal, and stages them switched off. Nothing runs. A person reviews and confirms each piece in the app. Turning a flow live is a separate tool, arm, gated behind an Execute grant that no key holds by default — so going live is deliberately a human’s decision unless you explicitly grant it.

3. Business records are reachable only one grant at a time. Beyond the automation layer, an agent can work with your CRM and tasks — read and update deals, contacts, companies and to-dos. Nothing here is on by default: each of those is its own grant, named for the exact thing it does, so “may read your deals” and “may change a deal’s stage” are two separate decisions you make separately. A key you never granted them cannot see that they exist. Sending — email, an invoice pushed to your accounting system, anything that acts outside Routario — is not exposed over MCP at all.

4. Discovery doesn’t leak. When a client asks the endpoint which tools are available, it only ever sees the tools its own key is granted. A read-only key never even learns that a make-live tool exists.

5. A tool takes only what it declares. Every call is checked against the tool’s published inputs before anything runs. An input the tool doesn’t have, a value outside its list of options, or an id that isn’t an id is refused, and the refusal names the right one. A misspelled filter can’t be quietly ignored. The names Routario uses internally to pass a tool its own facts, such as which project a note belongs to, are refused outright, so a caller can’t set them.

Two ways in. One-click sign-in is simplest for an off-the-shelf agent like Claude or ChatGPT; a scoped developer key (the numbered steps below) suits scripts, self-hosted installs, and CI.

Add Routario to your agent as a remote (custom) MCP connector, using the branded endpoint:

https://mcp.routario.com/mcp

Your client runs the standard OAuth sign-in: it asks which workspace you’re connecting, sends you to Routario to log in, and shows a consent screen listing exactly what the agent is asking for. Approve it and you’re connected — with no token to copy or store. What you approve follows the same grant model as everywhere else: by default the agent can draft and monitor, never make anything live.

Claude Code connects the same way, from the terminal. Routario doesn’t hand out client registrations automatically, so give Claude Code a client name of its own (any name works; claude-code is fine) and a fixed local port for the sign-in to come back to:

claude mcp add --transport http --client-id claude-code --callback-port 8765 \
routario https://mcp.routario.com/mcp

Then, inside Claude Code, run /mcp, pick routario and authenticate. Your browser opens Routario’s sign-in, asks which workspace, and shows the consent screen. Tick only what the sessions need. For keeping deals up to date that is usually the deal, contact, company, note, task and attachment tools. The token is kept in your system keychain, never in a config file, and every change it makes is attributed to that connection in Settings → Logs.

When a session works for a named person, it can give their username or e-mail as a task’s assignee (assigned_to: "jakub"). A name nobody in the workspace goes by is refused with the list of people. It is never stored as an assignee who doesn’t exist.

The sign-in lasts 90 days. After that, run /mcp again, or claude mcp login routario.

Prefer to pin the exact scopes, or connecting a script or a self-hosted install? Mint a bearer key instead.

Each key carries a set of scopes in the form <type>:<id>:<actions>. Repeat the --scope flag to add more:

routario apikey mint "Acme ops agent" \
--scope module:meta_drafter:write \
--scope run:*:read \
--scope flow:*:read

That key can draft automations and monitor runs and flows — a sensible “propose and watch” agent. The token prints once — store it like a password; it’s never recoverable.

A key minted with no --scope flags authenticates but can do nothing — the default-deny baseline you saw above.

To let a key make flows live by itself, add --scope flow:*:execute. That’s the line you deliberately don’t cross unless you want the agent to go live without a human — for most setups, leave it off and confirm in the app instead.

Configure your agent’s MCP client with the workspace URL and the bearer token:

URL: https://<your-workspace>.routario.com/mcp
Header: Authorization: Bearer <your-token>

The endpoint is a stateless JSON-RPC service — it implements the standard initialize, tools/list, and tools/call methods, so a compliant client needs no special handling.

You can verify the connection with the official MCP Inspector before wiring up a full agent:

npx @modelcontextprotocol/inspector --cli \
https://<your-workspace>.routario.com/mcp \
--header "Authorization: Bearer <your-token>" \
--method tools/list

Routario’s endpoint handshakes, authenticates the bearer, and returns the grant-scoped tool list. Because it speaks the standard protocol, any spec-compliant MCP client can connect the same way.

Every tool is grant-gated. A read tool is satisfied by a read or a write grant (write includes read). A client only ever sees the tools its key permits.

ToolWhat it doesGrant it needs
buildDescribe a use-case in plain words → a draft plan of flows and agents. Asks clarifying questions; never deploys anything.Write on module:meta_drafter
get_planCheck a draft from build — whether a person has confirmed and armed each piece yet.Read on module:meta_drafter
list_runsRecent automation runs and their status.Read on run:*
get_runThe status and progress of a single run.Read on run:*
list_flowsYour automations — each with a one-line description of what it does and its trigger.Read on flow:*
armMake a drafted flow live — the make-live boundary. Only arms flows the key’s owner drafted.Execute on flow:* — held by no key by default

Granted individually, never as a bundle. Each tool needs a grant naming that exact capability — module:<tool name> — so reading your pipeline and changing it are separate permissions.

ToolWhat it doesGrant it needs
crm_deal_list · crm_deal_lookupFind deals, or look one up by id.Read on that tool
crm_deal_readEverything already on a deal in one call — its company, the people on it and the people at its company, notes, tasks, documents, and its link.Read on that tool
crm_deal_referenceYour pipeline stages, lead sources and the roles a person can hold on a deal — the names the other tools take.Read on that tool
crm_deal_create · crm_deal_update · crm_deal_move_stageOpen a deal, change its fields, move it along the pipeline.Write on that tool
crm_deal_stakeholder_add · crm_deal_stakeholder_removePut a person on a deal in a role (Decision maker, Champion…), or take them off.Write on that tool
crm_contact_list · crm_contact_create · crm_contact_updateFind, add and correct people.Read / Write on that tool
crm_company_list · crm_company_lookup · crm_company_create · crm_company_updateThe same for companies.Read / Write on that tool
list_tasks · create_task · update_task · complete_taskSee what is outstanding, add work, tick it off. Assign by username, e-mail or full name.Read / Write on that tool
crm_note_list · crm_add_noteRead a record’s notes; attach a note to a deal, contact or company.Read / Write on that tool

Read before you write. An agent that cannot see what is already on a deal adds the note that is already there, or a second copy of the task. crm_deal_read answers “what’s here?” in one call, so an agent can add only what is missing. crm_deal_create finds a deal with the same name at the same company instead of opening a duplicate, and says so (created: false). Every deal tool hands back the deal’s link, so the agent can show you what it touched. Taking a person off a deal marks them removed. It deletes nothing, and adding them back restores them.

Documents on your deals, companies and contacts

Section titled “Documents on your deals, companies and contacts”
ToolWhat it doesGrant it needs
record_attachment_listWhat is filed on a record, newest first.Read on that tool
record_attachment_addFile a document on a deal, company or contact.Write on that tool
record_attachment_detachTake a filed document off a record.Write on that tool

A filed document goes into Memory like one you drop on the page: read, indexed and searchable. Filing the same file twice leaves one document and one filing.

The file itself arrives one of two ways:

  • Small files (up to 4 MB) can travel inside the tool call, base64-encoded, with their filename.

  • Anything bigger (up to about 12 MB) goes up through the API first. From a terminal, with a key that has the Memory write scope (Settings → Connections → API keys):

    printf '{"filename": "pitch.pdf", "mime_type": "application/pdf", "content_base64": "%s"}' \
    "$(base64 -i pitch.pdf)" > body.json
    curl https://<your-workspace>.app.routario.com/api/v1/memory \
    -H "Authorization: Bearer <key>" -H "Content-Type: application/json" \
    --data-binary @body.json

    Then file it with record_attachment_add and the memory_item_id that returns. This way the file never passes through the AI model, which could not reliably write out a large file anyway.

Nothing here deletes. Detaching takes the document off that one record; the document stays in Memory and on any other record it is filed on. To replace a document, attach the new one and detach the old one.

ToolWhat it doesGrant it needs
table_view_listThe saved views on a table — what each filters to, sorts by and shows.Read on that tool
table_view_updateReshape a view: its filters, columns, sort, name.Write on that tool
dashboard_listThe boards you have, and how many tiles each holds.Read on that tool
dashboard_readWhat a board currently says — each tile’s numbers, with their units.Read on that tool
dashboard_tile_add · dashboard_tile_removePut a chart or view on a board, or take one off.Write on that tool

A view’s filters and columns replace what was there rather than merging into it — a view that silently kept filters nobody mentioned would not be the view you asked for. Read it first, then send back the whole list you want.

Reading a board gives you data, not a picture: each tile’s figures with the units they are in. Rendering a board as an image is a separate capability and is not offered here — a picture is not something to reason over.

A data product is a table that has introduced itself: what it answers, the role that owns it, what each column means, and how far to trust each row. Over MCP an agent asks it exactly the way a flow does, and gets the same answer: rows, never prose, each with its row_id, a trust of high, low or expired, and the owner, plus an explicit nothing_found when no row matched.

ToolWhat it doesGrant it needs
list_data_productsThe products this connection may read, each with its purpose, owner, example questions and column meanings.Read on that tool
ask_data_productAsk one product a question in plain words. Routario turns it into a filter on the product’s columns, runs it, and returns the rows plus the filter and strategy it used. One small model call per question.Read on that tool
lookup_data_productRows of one product by an exact filter (equals, contains, has, not, in, wildcard). No model call.Read on that tool

A connection sees only the products whose tables it may read. The tool grant lets it ask; a read grant on the table — table:<slug>:read, the same grant the REST API checks — decides which products it sees. A product it may not read answers exactly like one that does not exist, so the refusal never confirms what is being withheld.

On the Log in with Routario consent screen, the products you may open yourself are listed under Data products. Tick the ones the agent should ask; the three tools come with them. You cannot hand a connection a table you could not open in the app. With a developer key, grant both:

routario apikey mint "Support desk in Claude" \
--scope module:list_data_products:read \
--scope module:ask_data_product:read \
--scope module:lookup_data_product:read \
--scope table:commercial_terms:read

Every call is logged as a data_product.queried event with the connection as its actor: which product, the filter, and the row_id and trust of every row returned, or nothing_found. Never the rows’ values.

The tool descriptions tell the agent how to use the answer: call list_data_products first, use ask_data_product for a question in words and lookup_data_product when it already knows the column and value, cite the row_id of every row it relies on, treat low and expired rows as unconfirmed, and when nothing_found is true, say the product has no answer and who owns it rather than filling the gap from general knowledge.

Your invoices and expenses — drafts only

Section titled “Your invoices and expenses — drafts only”
ToolWhat it doesGrant it needs
invoice_listInvoices and drafts, newest first.Read on that tool
invoice_draft_create · invoice_line_addPrepare an invoice as a draft and put lines on it.Write on that tool
expense_listSupplier invoices and receipts, optionally by VAT period.Read on that tool
expense_draft_createRecord what a supplier sent, as a draft.Write on that tool

Nothing here can issue an invoice or confirm an expense. Issuing assigns a number from a gapless sequence and makes the document legally binding; confirming an expense freezes the supplier’s details and fixes which VAT period it is filed in. Both are decisions with legal or filing consequences, and both stay with a person, in the app. An agent prepares; you commit.

Expenses are filed by their taxable supply date (DUZP) where there is one, not by the date on the document — the month your accountant files by, which is not always the month the paperwork arrived.

These are the same capabilities your flows and in-app agents use — one definition, so a tool behaves identically whichever asks for it.

The build → get_plan → arm sequence is the whole loop: an agent proposes a draft, anyone can watch a person review it, and going live is a distinct, separately-granted step. Draft and make-live are never bundled — a key that can draft cannot, by that fact, deploy.

Once connected, talk to your agent in plain language — it maps your ask to the tools above. A few to try:

  • “What automations do I have, and what does each one do?” — lists your flows, each with a one-line description and its trigger.
  • “Did last night’s runs succeed? Show me anything that failed.” — pulls recent runs and drills into a failure.
  • “Draft an automation: when an invoice PDF arrives by email, pull out the total and post it to our #finance Slack channel — but don’t turn it on.” — returns a draft, staged off. Nothing runs until you review it in the app.
  • “Which deals are still open, and who’s the contact on each?” — reads your pipeline (needs the deal and contact read grants).
  • “What does the ops board say this morning, and what changed?” — reads each tile’s figures with their units.
  • “Show that table only the open engagements, newest first.” — reshapes a saved view.
  • “What do we charge to ship to Canada, and is that price confirmed?” — finds the data product that answers it, looks the row up, and quotes its trust and row_id.
  • “Draft an invoice to Acme for two days of survey work at 12 000 each.” — prepares a draft for you to check and issue.
  • “What supplier invoices landed in September’s VAT period?” — filed by taxable supply date, not by the date on the paper.
  • “Log a call with Marie at Bosch and put a follow-up on my list for Thursday.” — adds a note and a task in one go.
  • “What’s already on the DM Drogerie deal? Add Petr as its champion.” — reads the whole deal first, then puts the person on it in that role.
  • “What’s the status of that draft — has anyone armed it yet?” — checks whether each piece has been confirmed and made live.

Notice the shape: the agent can propose a whole automation and watch what’s running, but the moment of going live stays with a person in the app — unless you deliberately grant the execute scope.

A Routario MCP key is just another actor on your access list, checked the same way your people and agents are. It starts fully closed; it discovers only what it’s granted; it can draft but not deploy; its reads are a deliberately narrow window onto the automation layer rather than a door into your business data. That posture is the same in a self-hosted install and in managed hosting — it travels with the key, not the deployment.