Firmus is also a remote MCP (Model Context Protocol) server: a connector you add to Claude once. Claude can then identify the French companies in a file you attach or a list you paste, add registry columns to them, hand the whole file back as a CSV, fetch the record of one company, list what changed about it, watch it and read what happens to it next, or count the companies matching a description, export them, and be told which new ones match it later. You write no code. Every answer says where it comes from and when: a company record or an enriched row carries the date the registry last changed it, and an event the date it happened, so Claude can cite its sources rather than assert.
Firmus is company data from the French national registry, INSEE Sirene, and nothing else. It holds no contact data — no email addresses, no phone numbers, no named people — and no officers or shareholders, so it cannot search by person: "every company this person runs" has no answer here.
The server lives at:
https://api.firmus.sh/mcp
Add the connector
- In Claude's connector settings, add a custom connector.
- Name it
Firmusand givehttps://api.firmus.sh/mcpas its URL. If Claude offers fields for an OAuth client ID and secret, leave them empty: Claude registers itself with Firmus when it connects. - Connect. Claude opens a Firmus page in your browser.
Sign in and allow access
- Sign in to the Firmus console with your email address and password, or choose Create an account (a password of at least 12 characters; the organization is named after your email domain). Either way you come back to the next screen.
- The screen is titled Connect followed by the app's name, and shows three facts:
- Returns to: the host your browser is sent back to. It should be Claude's.
- Identity: either Published at a host, or "Registered itself. Firmus has not verified the name; check the host it returns to." In the second case, Returns to is the line to trust.
- Access:
read, "Look up legal entities and establishments", and, when the app asks for it,suggest, "Search companies by name or identifier".
- Under Acts for, pick the organization whose plan the calls count against. Choose Allow access, and the browser returns to Claude. Deny returns to Claude with nothing granted.
Claude is now connected. If the screen says "This request has expired or has already been answered", go back to Claude and connect again. If it says the account "is not a member of an organization", there is nothing to connect Claude to yet: sign in with an account that belongs to one.
To end the access, open Connected apps in the console, choose Disconnect on the connection, and confirm: Claude's access stops working within a second. Removing the connector in Claude only stops Claude from using it; the console is where the access is revoked on the Firmus side.
Enrich a CRM export
Attach the CSV export, then ask:
Identify the companies in this file, then add their activity, workforce band and head office city as new columns. Add a column with the confidence, and give me the result as a CSV.
What Claude does depends on the file's size:
- Up to 500 rows:
resolveto identify each row, thenenrichwith whatresolvereturned, one call after the other. The answer arrives in the conversation. - A whole file, or more than 500 rows:
submit_jobwith the file's content, which answers with a job id, thenjob_statusuntil the job has finished. Claude then gives you a download link.
submit_job finds the name, postal code, city, address, SIREN, SIRET and VAT number columns
from the headers, and says which it used: if it picked the wrong one, tell Claude which
column to use instead. Every other column is carried through untouched.
The file you download is yours, every row and column kept, with Firmus's columns appended,
all prefixed firmus_: firmus_resolve_status, firmus_resolve_confidence and
firmus_registry_number for the identification, firmus_candidates on a row with more than
one possible company, then firmus_enrich_status, the columns you asked for, and
firmus_data_updated_at, the date the registry last changed that company's record. Without
a choice of columns, enrich adds name, status, activity, workforce band and head office
address. Then comes firmus_partial, true on a row whose search ran out of time even
after the job tried it again: its not_found or ambiguous is not a verdict. Claude
reports how many such rows the job holds; ask it to submit them again. The last two columns
are firmus_partially_disclosed, true when something on the row is withheld from public
reuse, so an empty name or address is withheld by law rather than missing, and
firmus_sources, the registries the row's values come from: insee_sirene, followed by
bodacc and the date of the latest notice when you asked for a legal field. Quote those
two when you pass the file on.
The labels for legal form, activity, workforce band and size category are the registry's
own, in French: Activités des sièges sociaux, not "Activities of head offices". Ask Claude
to translate them if your file needs English.
The link opens without signing in, for anyone holding it, until the job is deleted seven days after submission: share it as you would the file. If a job failed partway, the file holds the rows answered before it stopped, and the job's error says how many: ask Claude to submit the rest. Claude sends the file to Firmus as text inside its own call, so a very large export can be too long for Claude to send in one piece even when your plan allows it. Split it, or have a developer upload it as a file job.
What changed for this supplier since June
What has changed for our supplier Danone since June 2026? Cite each change with its date.
Claude calls resolve to find the SIREN behind the name (or skips it if you give the SIREN),
then timeline with occurred_from set to 2026-06-01. The answer lists the events newest
first, ten at a time unless you ask for more: a cessation, a rename, a change of activity,
legal form or workforce band, a head office or an establishment that moved, opened or closed.
Each event carries the date it happened (occurred_on), the date Firmus recorded it
(recorded_at) and its source, and for a change of value what it was and what it became.
The registry's part of the log is young, and an empty or short answer usually means that. It starts no earlier than 29 October 2026, the day the event log began recording: nothing the registry processed before then is in it, and no earlier registry history is filled in. The gazette's notices, below, go back to January 2008. A change effective in June that the registry processed after that date does appear, under its June date. So "nothing since June" means nothing was recorded since the log began, not that nothing happened. To tell the two apart, ask Claude to look the company up: its record carries the date the registry last changed it. If that date is after June and the timeline is empty, the record changed in a way the timeline does not show — before the log began, or in a field it does not track — and the record gives the current values but not the previous ones.
Two more things shape the answer:
- Once a month, Firmus records late the changes its daily updates missed, and some days the registry changes a large part of itself at once. Both are left out unless you ask for them: add "include the monthly corrections and mass operations" to the question.
- The events come from INSEE Sirene and from the BODACC legal gazette: insolvency proceedings, sales of a business, removals from the trade register and other legal notices. The gazette's notices since 2008 were loaded at once and count as a mass operation, so "has this supplier ever been in insolvency" needs the phrase above. The BODACC covers companies in the trade register only: for an association or a sole trader outside it, an empty timeline says nothing about proceedings.
A company that has left the registry still has its timeline: Claude is told it is no
longer in the registry, lookup no longer finds it, and its events keep their kinds and
dates but not their values. Its removal is one of the monthly corrections, so ask for those
to see it.
An event about a company or establishment that is partially disclosed today — the person behind it asked for parts of the record to be withheld from public reuse — keeps its kind and dates but not the values that changed. The full list of event kinds is in list events.
Identify a messy list
Paste the list as you have it — names, cities, typos and all — and ask:
Find the SIREN of each of these companies. Give me the confidence for each, and list separately the ones you could not match with certainty.
danone paris Michelin, Clermont-Ferrand boulangeries paul, lille société générale
Claude calls resolve with one row per line, up to 500 a call. Each row comes back with a
status:
matched: one company, with a confidence between 0 and 1 and the parts of your line the match rests on. A typo or a missing word lowers the confidence, and can leave the row ambiguous.ambiguous: no safe answer. Up to three candidates come back, each with its own confidence, and Claude is told to show them to you rather than pick one. A name with no city or postal code — the last line above — is never matched however exact it is: give the city, and ask again.not_found: no company close enough. Below Firmus's threshold the answer is a refusal, not a guess.invalid: the row could not be read, with a message saying why.
A ceased company is matched and marked ceased: a list often holds companies that have since
closed, and saying so is the answer. A batch spends at most 10 seconds searching names; a
row it did not reach comes back not_found and marked partial, is not counted, and Claude is
told to send it again. Each matched company comes back as a short card — SIREN, name, head
office city, activity code, status — and Claude calls lookup for its dated record. How
matching works is in the resolve reference.
Watch companies and hear what happens to them
Watch our three biggest suppliers, 552032534, 552081317 and 542051180, and tell me what has happened to them since we last talked.
Claude calls watch with the numbers, then watched_events. Without a list named, the
numbers go to the organization's watchlist "Watched from an assistant", created the first
time. Each number comes back added, already_watched, not_found — unknown to the
registry, so not watched — or invalid, with how many of the plan's watched companies are
used. Watching starts then: for what happened before, ask for the company's timeline.
watched_events reads the events of every watched company, oldest first, ten at a time
unless you ask for more, each with its date and source. It answers with a cursor: Claude
can keep it and pass it next time, so "since we last talked" reads only what is new. An
item marked retyped is a legal notice first recorded without its details and now
readable; it replaces the earlier one of the same kind and date. An event about a company
that is partially disclosed today keeps its kind and dates but not its values.
The same lists also deliver by webhook and email digest, set up in the console; watch companies explains both.
Count companies, and export them
How many IT services companies with at least 10 employees have their head office in the Rhône? Show me how they split by size, then export them all.
Claude turns the question into explicit filters and calls segment: here NAF division 62,
département 69, workforce band 11 and up. It answers with the exact count, how it splits
by département, activity, workforce band and legal form, and at most ten companies, each
with its source and dates — never more in the conversation. The answer says back how each
filter was read, so check it: "IT services" read as the whole division 62 is not the same
count as 62.02A alone. Ask Claude to change a filter and run it again.
Claude never lists a company that is partially disclosed, and lists sole traders, who are natural persons, only if you ask for them and agree to an acknowledgement it shows you: your organization is the controller of any prospecting of them, informs each of them under article 14 of the GDPR and honours their opposition. Every answer also carries a notice: the counts are built from INSEE Sirene and do not reflect an opposition to prospecting recorded only in the RNE. Claude is told to repeat it when it shows companies.
To export, Claude saves the segment and calls segment_export, which writes every company it
may list to a CSV in the background; job_status then gives the download link, as for any
file. The file opens on a few lines starting with # — the RNE notice, the segment and its
filters, and any acknowledgement — before its header. What the filters accept is in
run a segment.
Be told which companies enter a segment
Tell me every time a new IT services company in the Rhône with 10 employees or more shows up, and when one drops out.
Claude saves the segment if it is not saved yet, then calls watch_segment, with
include_leavers for the companies that drop out. Without a list named, the segment is
followed by the same "Watched from an assistant" list watch uses. Nothing is reported for
the companies already in the segment: following starts then, and the first ones arrive
after the next daily update of the segment index. Ask for an export if you want today's.
They arrive in watched_events, beside the events of watched companies, as companies that
entered or left the segment, each with the date of the index update that showed it, its
record as a sample shows it, and the RNE notice, which Claude is told to repeat. A company
that is partially disclosed, or a sole trader in a segment saved without the
acknowledgement, never appears. If the segment's daily update fails three times in a row,
it is paused and nothing arrives; asking Claude to follow it again resumes it, from that
moment on. unwatch_segment stops; the segment stays saved. The same
companies reach the list's webhooks and digest, set up in the console.
Limits, and what is counted
Calls Claude makes count against the organization you chose at Acts for, exactly as calls made with one of its API keys: the same plan, the same allowances. The plan is a flat monthly fee: nothing is charged per row, and a spent allowance is a refusal, never an extra invoice.
| Free | Pro | Scale | |
|---|---|---|---|
Agent rows a month, resolve and enrich together | 1 000 | 25 000 | 250 000 |
Rows per resolve or enrich call | 500 | 500 | 500 |
| Rows per file job | 1 000 | 25 000 | 100 000 |
| Size of a file job | 2 MB | 20 MB | 50 MB |
Lookups a month: each lookup, timeline, batch and job | 1 000 | unlimited | unlimited |
| Requests per second, for the whole organization | 2 | 15 | 60 |
| Watched companies, across every watchlist | 5 | 1 000 | 10 000 |
| Saved segments | 3 | 100 | 1 000 |
| Watched segments, across every watchlist | 1 | 10 | 100 |
Exported rows a month, segment_export | 1 000 | 25 000 | 250 000 |
What spends agent rows. Each row resolve looks up and each row enrich enriches or
finds missing from the registry is one row; the month runs on the calendar, UTC. Resolving a
500-row list and then enriching it spends at most 1 000. A file job is checked before it
starts, for every row once per step — 2 000 for a 1 000-row file resolved then enriched —
and is refused if that does not fit in what is left; until it finishes, those rows count as
spent, so a resolve or enrich call can be refused while a job runs. A single call is
admitted while one row is left, so it can take you past the figure by up to its own 500.
What is not counted. A row that cannot be read, a row the 10-second budget did not reach,
and a row resolve could not match that then passes through enrich. Polling job_status
and downloading the result are not lookups either, though on Free they stop once the month's
lookups are spent. The connector's own messages to Firmus —
connecting, listing the tools — are not counted against any monthly allowance, though they
do count against the requests per second.
When an allowance is spent, resolve, enrich and submit_job are refused with
402 quota_exceeded until the first day of the next month, UTC. On Free, lookup and
timeline keep working while the 1 000 lookups last; on Pro and Scale they always do. The
console's Usage screen shows the agent rows spent this month. Beyond a plan's rows is the
next plan, and beyond Scale's a contract.
Watched companies are a stock, not a monthly volume. watch and unwatch count against
no monthly allowance; watched_events is one lookup per page. A watch that would take the
organization past its watched companies adds none of the numbers and is refused with 402
quota_exceeded, with no wait: it frees up when numbers are unwatched, not when the month
turns.
Segments. Each segment call is one lookup, like lookup; segment_export is one, or two when it saves the segment first. Saved segments are a stock,
like watched companies: a save past the plan's figure is refused with no wait, and deleting
a saved segment, from your own integration, frees its place. Exported rows are a monthly
volume of their own, not agent rows: an export is checked before it starts for every
company the segment may list, refused whole with 402 quota_exceeded if that does not fit
in what is left, and counts only the rows it writes. Watched segments are a stock too:
watch_segment and unwatch_segment count against no monthly allowance, and following one
segment more than the plan's figure is refused with 402 quota_exceeded, with no wait,
until unwatch_segment frees one.
One resolve or enrich call runs at a time per organization. A second one — from
Claude, or from your own integration using the organization's API keys — is refused with
429 concurrency_limited and a number of seconds to wait. A file job is never refused that
way. If your production code calls these endpoints, connect Claude to a separate
organization, or expect those waits. Going over the requests per second is 429
rate_limited, also with a wait.
When a call is refused for any of these reasons, or because a company does not exist, Claude receives the refusal's code, its message and the seconds to wait when there are any, rather than an empty answer, and can tell you which it was. The headers and counters behind every figure in the table are in rate limits.
The thirteen tools
| Tool | What it does |
|---|---|
resolve | Identifies the French company behind each row of messy data — a name with a city or postal code, a street address, a VAT number, a SIREN or a SIRET — up to 500 rows per call. A row with no safe answer is reported as ambiguous or not found, not guessed. |
enrich | Adds chosen columns to the companies resolve matched, or to a list of SIRENs, up to 500 rows per call. Unless asked for more: name, status, activity, workforce band and head office address. On request: legal form, creation and cessation dates, size category, head office coordinates, the number of active establishments, the latest event of each kind, and from the BODACC legal gazette whether an insolvency proceeding is open, the last accounts filed and the last sale of a business. Each row names its sources: INSEE Sirene, with the date the registry last changed the record, and, when a legal field is asked for, the BODACC, with the publication date of the latest notice; each legal fact carries its own date and the link to its notice. |
lookup | Fetches one company by SIREN, or one establishment by SIRET: a compact card with its status, legal form code, activity code, workforce band, dates and address, plus the date the registry last changed the record. |
timeline | Lists what changed about one company and its establishments, newest first, 10 events per page by default: from the registry, and from the BODACC (insolvency proceedings, sales of a business, removals from the trade register, registrations, other legal notices, their corrections), each BODACC event with the link to its notice. Filters by kind, severity and dates. Filed accounts are left out unless asked for by kind; monthly corrections and the BODACC's history since 2008 are left out unless asked for. An empty list means the log holds nothing for that company, not that nothing ever happened to it; a company that left the registry is said to be removed, its values withheld; a SIREN neither the registry nor the log knows is a not-found error. |
submit_job | Sends a whole file to be resolved, enriched, or both, in the background, and answers with a job id rather than the rows. Detects the columns from the headers and says which it used. |
job_status | Reads a job: its status, the rows processed, how many rows were matched, ambiguous or not found, and how many are not conclusive because their search ran out of time. Once the job has finished, it carries the download link of the result CSV. |
watch | Follows up to 1 000 SIRENs or SIRETs in a watchlist, by default the organization's "Watched from an assistant". Each number answers added, already watched, not found or invalid, with the watched companies used and included; a request past the allowance adds nothing and is refused. Counts against no monthly allowance. |
unwatch | Stops following up to 100 numbers, from the same list by default. Each answers removed, not watched or invalid; the allowance is freed at once. Counts against no monthly allowance. |
watched_events | Reads the events of every watched company, and the companies that entered or left a watched segment, oldest first, 10 per page by default, with a cursor to pass back for what arrives next. Filters by watchlist. One lookup per page. |
segment | Counts the active French companies matching explicit filters — activity, département, commune, postal code, workforce band, size, legal form, registration date, a recent head office move or workforce rise, an open insolvency proceeding — with four facets and at most ten companies, each with its source and dates. Says back how each filter was read. Saves the segment on request, and runs a saved one again. One lookup per call. |
segment_export | Writes every company of a segment that may be listed to a CSV, in the background, from a saved segment or from filters it saves first, and answers with a job id for job_status. Never writes a partially disclosed unit; sole traders only for a segment saved with their acknowledgement. Counts the rows written against the month's exported rows. |
watch_segment | Follows a saved segment from a watchlist, by default "Watched from an assistant": the companies that newly match it, and on request those that stop matching, arrive in watched_events from the next daily update of the index, never those already in it. Never delivers a partially disclosed company; sole traders only for a segment saved with their acknowledgement. A follow past the plan's watched segments is refused. Counts against no monthly allowance. |
unwatch_segment | Stops a watchlist following a segment, from the same list by default. The segment stays saved; its place in the watched segments is freed once no list follows it. Counts against no monthly allowance. |
On enrich and lookup, values a company has had withheld from public reuse come back
empty, and partially_disclosed: true says so. The fields, themes and event kinds enrich
accepts are listed in the enrich reference.
From another MCP client
Any client that speaks Streamable HTTP can connect to the same URL. A client that supports
OAuth signs in as above. One that does not can send an API key from the console instead,
as a header — a key with the read scope, never in the query string:
Authorization: Bearer fk_live_…
A request without a valid credential is answered 401, with a WWW-Authenticate header
pointing at https://api.firmus.sh/.well-known/oauth-protected-resource/mcp, which is how
an OAuth client finds where to sign in. See authentication for keys and
scopes.