Skip to main content
Glama
maelguimet

mcp-french-open-data

by maelguimet

mcp-french-open-data

Français · English

An MCP server that gives AI assistants (Claude, Cursor, ChatGPT, …) typed, read-only access to French public open data. It covers addresses, companies and communes. All the APIs it wraps are free and keyless.

Demo: an MCP client calling each tool over stdio

It is a small but complete reference implementation:

  • Tools: 5 read-only tools with validated input (zod) and descriptions written for models.

  • Transports: stdio, plus stateless Streamable HTTP with API-key auth.

  • Operations: structured JSON logs on stderr, upstream timeouts, readable error mapping, and polite per-API rate limiting.

  • Tests: unit tests with mocked HTTP, protocol tests through the official SDK client, and an opt-in live smoke test.

Tools

Tool

What it does

Upstream

search_address

Geocodes a free-text French address. Returns ranked matches with postcode, INSEE code, score and coordinates.

IGN Géoplateforme geocoding (BAN)

reverse_geocode

Finds the nearest addresses to a lat/lon, with their distance in metres.

IGN Géoplateforme geocoding (BAN)

search_company

Searches companies by name, address, leader or SIREN/SIRET, with postcode, département, NAF and active-only filters.

API Recherche d'entreprises (SIRENE/RNE)

get_company

Returns one company by SIREN: legal form, VAT number, head office, leaders and published revenue/net income.

API Recherche d'entreprises

list_communes

Lists communes by name, postcode or département, with INSEE code, postcodes and population.

geo.api.gouv.fr

Every tool is annotated readOnlyHint: true. Upstream failures come back as tool errors (isError: true) with a readable message, for example Recherche d'entreprises rate limit reached; retry after 5 s.. They never surface as raw stack traces.

Upstream APIs and limits

API

Base URL

Published limit

This server

Géoplateforme geocoding

https://data.geopf.fr/geocodage/

50 req/s per IP

≤ 40 req/s

Recherche d'entreprises

https://recherche-entreprises.api.gouv.fr/

7 req/s per IP

≤ 5 req/s

Découpage administratif

https://geo.api.gouv.fr/

—

≤ 20 req/s

The BAN address API at api-adresse.data.gouv.fr was retired in January 2026 and replaced by the IGN Géoplateforme service, which this server uses. The limits are applied per process. Company data excludes non-public ("non-diffusible") entities. Leaders' birth dates, which the upstream returns, are not passed on.

Related MCP server: French Open Data & IGN

Install and run

Requires Node.js ≥ 20.

git clone https://github.com/maelguimet/mcp-french-open-data.git
cd mcp-french-open-data
npm ci
npm run build

# stdio (for local clients such as Claude Desktop or Cursor)
node dist/index.js

# Streamable HTTP on http://127.0.0.1:3000/mcp
export MCP_API_KEY="$(openssl rand -hex 32)"
npm run start:http

Try it without an AI client: npm run demo connects the bundled SDK client over stdio and calls every tool. Use npm run demo -- --http http://127.0.0.1:3000/mcp for HTTP; it reads MCP_API_KEY. The real output is in docs/demo.md.

With Docker:

docker build -t mcp-french-open-data .
docker run --rm -p 3000:3000 -e MCP_API_KEY -e ALLOWED_HOSTS=localhost,127.0.0.1 mcp-french-open-data

Client configuration

Claude Desktop (stdio)

Edit claude_desktop_config.json. On macOS it is in ~/Library/Application Support/Claude/; on Windows, in %APPDATA%\Claude\.

{
  "mcpServers": {
    "french-open-data": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-french-open-data/dist/index.js"]
    }
  }
}

Cursor

Edit ~/.cursor/mcp.json, or .cursor/mcp.json in a project. You can use stdio:

{
  "mcpServers": {
    "french-open-data": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-french-open-data/dist/index.js"]
    }
  }
}

or the HTTP server with the API key:

{
  "mcpServers": {
    "french-open-data": {
      "url": "http://127.0.0.1:3000/mcp",
      "headers": { "Authorization": "Bearer ${env:MCP_API_KEY}" }
    }
  }
}

ChatGPT

ChatGPT only connects to remote MCP servers, through a public HTTPS URL or OpenAI's Secure MCP Tunnel. It cannot use a local stdio server. Its connection settings offer OAuth or No authentication; they don't offer a custom API key header. So:

  1. Deploy the HTTP server behind HTTPS, for example with the Docker image behind a reverse proxy. Set ALLOWED_HOSTS to your domain.

  2. Because the data is public and every tool is read-only, you can start it with MCP_AUTH=none (no key). This is an explicit opt-in; without it, the server refuses to start with no key.

  3. In ChatGPT, open Plugins → + → Add custom MCP server. Enter https://your-domain/mcp, choose No authentication, acknowledge the warning and select Create as a plugin. Then install the plugin.

For the OpenAI Responses API, use an mcp tool with server_url set to your public URL. The authorization value is sent as a bearer token, so the API key should work there. See the OpenAI MCP docs. The menu names are taken from those docs (October 2026) and may change.

Environment variables

Variable

Default

Purpose

MCP_TRANSPORT

stdio

stdio or http. --http on the command line also selects HTTP.

MCP_API_KEY

—

Required for HTTP; at least 16 characters. Accepted as Authorization: Bearer <key> or x-api-key: <key>.

MCP_AUTH

—

Set to none to serve HTTP without a key, as an explicit opt-in.

HOST / PORT

127.0.0.1 / 3000

HTTP bind address.

ALLOWED_HOSTS

—

Comma-separated Host allow-list (DNS-rebinding protection) when binding to 0.0.0.0.

LOG_LEVEL

info

debug, info, warn or error. Logs go to stderr as JSON lines.

GEOCODING_BASE_URL, ENTREPRISES_BASE_URL, GEO_BASE_URL

public endpoints

Override the upstreams, e.g. for a proxy or cache.

See .env.example.

Security

  • Authentication: the HTTP transport requires an API key by default. Keys are compared in constant time (SHA-256 digests compared with crypto.timingSafeEqual). Requests without a valid key get 401 and a WWW-Authenticate header. stdio needs no key, because it only talks to the process that launched it.

  • Statelessness: HTTP is stateless. Each request gets a fresh server and transport, so clients share no state.

  • Binding: by default the server binds to 127.0.0.1, with the SDK's DNS-rebinding protection. On 0.0.0.0, put it behind TLS and set ALLOWED_HOSTS.

  • Scope: every tool is read-only over public data. No credentials for any upstream are stored or needed.

  • Validation and logging: inputs are validated before any network call (e.g. a SIREN must have 9 digits). Logs record the tool, the upstream status and the latency, never the API key.

  • Keep .env out of version control. It is in .gitignore.

Development

npm run lint        # ESLint (typescript-eslint)
npm run typecheck   # tsc on src, tests and scripts
npm test            # vitest: mocked HTTP + MCP protocol tests (no network)
npm run test:live   # opt-in smoke test against the real APIs (LIVE=1)
npm run build       # compile to dist/

.github/workflows/ci.yml runs lint, typecheck, tests and build on Node 20 and 22.

License

MIT © 2026 Maël Guimet. Data comes from French public services under their open licences: Licence Ouverte / Etalab 2.0 for BAN, SIRENE and geo.api.gouv.fr.

Available Tools

5 tools
get_companyGet a company by SIRENA
Read-only

Fetch one French company by its 9-digit SIREN: legal form, VAT number, creation and closure dates, head office, leaders and published yearly revenue/net income.

ParametersJSON Schema
NameRequiredDescriptionDefault
sirenYes9-digit SIREN, e.g. 356000000

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=true, so the safety profile is covered. The description adds real value by listing what the response contains (legal form, VAT, dates, head office, leaders, revenue), which compensates for the absent output schema; it does not cover auth or not-found behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One sentence, front-loaded with the verb, the resource, and the identifier, with the payload enumeration trailing behind. No filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter read with no output schema, the return-field enumeration covers most of what an agent needs to decide and interpret. Missing only edge-case behavior such as what happens when the SIREN does not resolve.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single parameter is fully documented with a pattern and example. The description's '9-digit SIREN' restates the schema constraint without adding format, validation, or fallback guidance, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Fetch one French company') plus the key identifier (9-digit SIREN) and enumerates the returned data. The singular 'one ... company' implicitly contrasts with the sibling search_company, but no sibling is named explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the agent can infer this is the lookup to use when it already holds a SIREN rather than search criteria. There is no explicit when-to-use statement, no prerequisites, and no named alternative for cases where the SIREN is unknown.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_communesList French communesA
Read-only

Look up French communes by name, postcode or département (geo.api.gouv.fr). Returns INSEE code, postcodes, département, région and population. Give at least one filter.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoCommune name, e.g. 'Lyon'
limitNoMaximum results (1-50)
postcodeNo5-digit French postcode, e.g. 75011
departementNoDépartement code, e.g. 69, 2A or 974

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnlyHint=true, destructiveHint=false, openWorldHint=true). The description goes further by disclosing the upstream source and the returned fields (INSEE code, postcodes, département, région, population), plus the at-least-one-filter rule. No rate limits or error behavior, but that is a minor gap given annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler; the lookup keys and return contract are front-loaded ahead of the invocation constraint. Every clause carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description takes on the burden of stating what comes back and does so explicitly. It also conveys the mandatory-filter requirement, leaving nothing an agent needs to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so name, postcode, departement and limit are already documented with patterns and examples. The description restates the three filter keys but adds no format or constraint detail beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('look up'), a precise resource ('French communes'), names the three lookup keys, and cites the data source (geo.api.gouv.fr). This is clearly distinguishable from address geocoding (search_address) and company lookups in the sibling set.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Give at least one filter' adds a real usage constraint that the schema does not enforce (required parameters = 0), telling the agent how to invoke it correctly. However, it names no alternatives or when-not conditions relative to search_address or reverse_geocode.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

reverse_geocodeReverse geocode a pointA
Read-only

Find the nearest French addresses to a latitude/longitude (WGS84). Returns addresses with their distance in metres. Coverage: France including overseas départements.

ParametersJSON Schema
NameRequiredDescriptionDefault
latYesLatitude, e.g. 48.8566
lonYesLongitude, e.g. 2.3522
limitNoMaximum results (1-10)

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/openWorld/non-destructive, so the safety profile is covered. The description adds real context beyond them: the output carries a distance in metres, and the geographic coverage is France including overseas départements, which tells the agent when results will be empty.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: purpose, return shape, and coverage. No filler, and the core purpose is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does so adequately (addresses plus distance in metres) and defines coverage limits. It could say more about ordering or how many results come back by default, but the limit parameter in the schema fills that gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds the WGS84 datum, which the schema does not state, giving genuine meaning beyond the field-level descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('reverse geocode', 'find nearest French addresses') with the input format (latitude/longitude, WGS84). The reverse direction distinguishes it from the forward-looking sibling search_address.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The framing 'find the nearest addresses to a lat/lon' implies the use case (you have coordinates and want an address), and the coverage note implicitly scopes it to France. However, no alternative is named and no when-not-to-use condition is given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_addressSearch French addressesA
Read-only

Geocode a free-text French address with the national address base (BAN, via the IGN Géoplateforme). Returns ranked matches with label, postcode, city, INSEE code, relevance score (0-1) and WGS84 coordinates. Use this to normalise or locate an address.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNoRestrict to one result type
limitNoMaximum results (1-20)
queryYesAddress text, e.g. '8 bd du port cergy'
citycodeNoINSEE commune code (not the postcode), e.g. 75111
postcodeNo5-digit French postcode, e.g. 75011

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With readOnlyHint and openWorldHint already provided, the description adds valuable context about the data source (BAN via IGN Géoplateforme) and the exact return fields including relevance score and WGS84 coordinates. It does not cover rate limits or error modes, but the annotations lighten that burden.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tightly written sentences, front-loaded with the core action and followed by return info and usage. No filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no output schema, the description fills the gap by enumerating return fields and the data source. Input parameters are fully covered by the schema, and annotations handle the safety profile, so the agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all five parameters are fully documented in the schema. The description adds no parameter-level details beyond 'free-text', and the baseline score of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb ('Geocode') and resource ('free-text French address') and names the authoritative data source. The forward-geocoding intent clearly distinguishes it from the sibling reverse_geocode tool, even without naming it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states a clear primary use case ('normalise or locate an address') but does not name alternatives or specify when not to use this tool over siblings such as reverse_geocode or list_communes.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_companySearch French companiesA
Read-only

Search the French company register (SIRENE/RNE via API Recherche d'entreprises) by name, address, leader name or SIREN/SIRET. Returns SIREN, name, status, NAF activity code, head office and establishment counts. Follow up with get_company for details.

ParametersJSON Schema
NameRequiredDescriptionDefault
nafNoNAF/APE activity code, e.g. 62.01Z
pageNo
queryYesName, address, leader, SIREN or SIRET
per_pageNo
postcodeNo5-digit French postcode, e.g. 75011
active_onlyNoExclude closed companies
departementNoDépartement code, e.g. 69, 2A or 974

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, openWorldHint=true, and destructiveHint=false, so safety is covered. The description adds genuine value beyond the annotations by naming the return payload (SIREN, name, status, NAF code, head office, establishment counts), which is important since there is no output schema. It omits pagination/rate-limit behavior, keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: purpose and data source first, then return fields, then the follow-up routing. Every sentence carries distinct information with no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter, read-only search tool with no output schema, the description covers the source, searchable inputs, and the return payload, which is what an agent needs to call it and interpret results. It could be a 5 with a note on result limits/paging, but the essentials are present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 71%, so most parameters (naf, postcode, departement, per_page, active_only) are already documented in the schema. The description's 'by name, address, leader name or SIREN/SIRET' essentially restates the query parameter's own description, adding no new syntax or format guidance, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Search) plus resource (French company register) and names the underlying data source (SIRENE/RNE via API Recherche d'entreprises). It also enumerates the searchable keys (name, address, leader, SIREN/SIRET), so an agent can immediately distinguish it from search_address, reverse_geocode, and list_communes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent to the sibling tool with 'Follow up with get_company for details,' establishing the search-vs-detail relationship. There is no explicit when-not guidance (e.g., when to prefer search_address or a SIREN-specific lookup), so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv0.1.0
    • First observedget_company
    • First observedlist_communes
    • First observedreverse_geocode
    • First observedsearch_address
    • First observedsearch_company

TDQS

A4.2/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: reverse_geocode (coords→address) vs search_address (text→coords) are opposite directions, and get_company (fetch by SIREN) vs search_company (search register) are cleanly separated by lookup versus discovery. list_communes is a separate administrative resource entirely. No overlap or confusion.

Naming Consistency5/5

All five names follow a strict verb_noun snake_case pattern: reverse_geocode, get_company, search_address, search_company, list_communes. Verbs (reverse, get, search, list) are standard and predictable, and resource nouns are consistent.

Tool Count5/5

Five tools is well-scoped for a French open-data server covering addresses, companies, and communes. Each tool earns its place with no redundancy, and the surface is neither thin nor bloated.

Completeness4/5

The set covers forward and reverse geocoding, company search and detail retrieval, and commune lookup, forming a solid lifecycle for the domain. Minor gaps exist (e.g. no establishment/SIRET-level lookup or batch geocoding), but agents can work around these via the existing tools.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Provides spatial context and geographic data access for LLMs through France's Géoplateforme services, including geocoding, altitude queries, administrative boundaries, cadastral data, and vector data exploration.
    10
    18 npm
    29
    MIT
  • A
    license
    Not graded
    quality
    F
    maintenance
    An experimental MCP server providing spatial context for LLMs by interfacing with French Geoplateforme services. It enables tasks such as geocoding, altitude lookups, and querying administrative, cadastral, or urban planning data.
    8 npm
    4
    MIT