search_establishment
Find establishments in the PPF directory by SIRET, SIREN, status, or update date. Returns active/inactive SIRETs with details to verify before invoicing.
Instructions
Search for establishments (SIRETs) in the PPF directory by criteria.
An establishment is a physical place of business activity identified by its 14-digit SIRET. Each company (SIREN) can have multiple establishments.
BEHAVIOR:
Returns a paginated list of matching establishments; empty list if none match.
At least one search criterion should be provided; omitting all returns an error.
Pagination: if the response includes 'nextUpdatedAfter', pass it as updated_after to get the next page.
RESPONSE: each item includes siret, siren, name, administrativeStatus (Active/Inactive), approvedPlatformId, and timestamps (createdAt, updatedAt).
USAGE GUIDELINES:
Prefer get_establishment_by_siret when you already know the exact SIRET (faster, direct lookup).
Use search_establishment with siren to enumerate all establishments of a company.
Always verify administrativeStatus == Active before sending an invoice to that establishment.
Call this before create_directory_line to confirm the target SIRET is registered in the PPF directory.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| siret | No | Establishment SIRET number (14 digits, no spaces). Example: '12345678900012'. Use when you know the exact establishment; returns at most one result. | |
| siren | No | Parent company SIREN (9 digits). Returns all establishments registered under this company. Use to discover all SIRETs for a given SIREN. | |
| administrative_status | No | Administrative status of the establishment in the PPF directory. Active: establishment is open and reachable for invoicing. Inactive: establishment is closed; invoices cannot be sent to it. | |
| updated_after | No | Pagination cursor: only return establishments updated after this date/time (ISO 8601, e.g. 2024-09-01T00:00:00Z). Use the 'nextUpdatedAfter' field from the previous response to fetch the next page. | |
| limit | No | Maximum number of results per page (1-500, default 50). |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- tools/directory_tools.py:147-225 (handler)MCP tool handler for search_establishment. This is the @mcp.tool() decorated async function that defines the tool's Pydantic schema (parameters: siret, siren, administrative_status, updated_after, limit) and delegates to client.search_establishment().
@mcp.tool() async def search_establishment( siret: Annotated[ Optional[str], Field( default=None, description=( "Establishment SIRET number (14 digits, no spaces). " "Example: '12345678900012'. " "Use when you know the exact establishment; returns at most one result." ), ), ] = None, siren: Annotated[ Optional[str], Field( default=None, description=( "Parent company SIREN (9 digits). " "Returns all establishments registered under this company. " "Use to discover all SIRETs for a given SIREN." ), ), ] = None, administrative_status: Annotated[ Optional[str], Field( default=None, description=( "Administrative status of the establishment in the PPF directory. " "Active: establishment is open and reachable for invoicing. " "Inactive: establishment is closed; invoices cannot be sent to it." ), ), ] = None, updated_after: Annotated[ Optional[str], Field( default=None, description=( "Pagination cursor: only return establishments updated after this " "date/time (ISO 8601, e.g. 2024-09-01T00:00:00Z). " "Use the 'nextUpdatedAfter' field from the previous response to fetch the next page." ), ), ] = None, limit: Annotated[ int, Field(default=50, ge=1, le=500, description="Maximum number of results per page (1-500, default 50)."), ] = 50, ) -> dict: """ Search for establishments (SIRETs) in the PPF directory by criteria. An establishment is a physical place of business activity identified by its 14-digit SIRET. Each company (SIREN) can have multiple establishments. BEHAVIOR: - Returns a paginated list of matching establishments; empty list if none match. - At least one search criterion should be provided; omitting all returns an error. - Pagination: if the response includes 'nextUpdatedAfter', pass it as updated_after to get the next page. RESPONSE: each item includes siret, siren, name, administrativeStatus (Active/Inactive), approvedPlatformId, and timestamps (createdAt, updatedAt). USAGE GUIDELINES: - Prefer get_establishment_by_siret when you already know the exact SIRET (faster, direct lookup). - Use search_establishment with siren to enumerate all establishments of a company. - Always verify administrativeStatus == Active before sending an invoice to that establishment. - Call this before create_directory_line to confirm the target SIRET is registered in the PPF directory. """ client = get_directory_client() return await client.search_establishment( siret=siret, siren=siren, administrative_status=administrative_status, updated_after=updated_after, limit=limit, ) - clients/directory_client.py:79-98 (helper)Low-level HTTP client method implementing the actual API call. POST /v1/siret/search with the search parameters sent as JSON body. Returns the API response as a dict.
async def search_establishment( self, siret: Optional[str] = None, siren: Optional[str] = None, administrative_status: Optional[str] = None, updated_after: Optional[str] = None, limit: int = 50, ) -> dict[str, Any]: """POST /v1/siret/search — Search establishments in the directory.""" body: dict[str, Any] = {"limit": limit} if siret: body["siret"] = siret if siren: body["siren"] = siren if administrative_status: body["administrativeStatus"] = administrative_status if updated_after: body["updatedAfter"] = updated_after response = await self._request("POST", "/v1/siret/search", json=body) return response.json() - server.py:31-64 (registration)The function register_directory_tools (imported from tools/directory_tools.py) is called in server.py to register all directory tools including search_establishment on the FastMCP instance.
mcp = FastMCP( name="mcp-facture-electronique-fr", instructions=( "MCP server for French electronic invoicing (2026 reform, AFNOR XP Z12-013). " "Compatible Solution (CS) mode: intermediary between the company's information system and " "an Approved Platform (AP).\n\n" "**Flow Service** — submit and track flows (B2B invoices Factur-X/UBL/CII, " "e-reportings B2BInt/B2C, CDAR lifecycle statuses):\n" " • submit_flow: submit an invoice or an e-reporting\n" " • submit_lifecycle_status: emit a status (Approved, Refused, Cashed…)\n" " • search_flows: search flows by criteria\n" " • get_flow: retrieve metadata or document of a flow\n" " • healthcheck_flow: check the AP availability\n\n" "**Directory Service** — query and maintain the PPF directory:\n" " • get_company_by_siren / search_company: verify a taxable entity\n" " • get_establishment_by_siret / search_establishment: verify an establishment\n" " • search/create/update_routing_code: manage routing codes\n" " • get/search/create/update/delete_directory_line: manage receiving addresses\n\n" "**Recommended workflow before issuing an invoice:**\n" "1. get_directory_line(addressing_identifier=RECIPIENT_SIREN) → verify registration\n" "2. submit_flow(file_base64=..., processing_rule='B2B', flow_type='Invoice')\n" "3. get_flow(flow_id=...) → track status\n\n" "Auth: OAuth2 Bearer JWT (automatic renewal). " "Config via environment variables (.env)." ), ) # --------------------------------------------------------------------------- # Tool registration # --------------------------------------------------------------------------- register_flow_tools(mcp) register_directory_tools(mcp) - tools/directory_tools.py:31-31 (registration)The register_directory_tools function that contains the @mcp.tool() decorator registration for search_establishment (and all other directory tools).
def register_directory_tools(mcp: FastMCP) -> None: - tools/directory_tools.py:147-225 (schema)The Pydantic/FastMCP schema for search_establishment is defined inline in the function signature via Annotated types and Field() descriptors. Parameters: siret (optional str), siren (optional str), administrative_status (optional str), updated_after (optional str), limit (int, default 50, 1-500).
@mcp.tool() async def search_establishment( siret: Annotated[ Optional[str], Field( default=None, description=( "Establishment SIRET number (14 digits, no spaces). " "Example: '12345678900012'. " "Use when you know the exact establishment; returns at most one result." ), ), ] = None, siren: Annotated[ Optional[str], Field( default=None, description=( "Parent company SIREN (9 digits). " "Returns all establishments registered under this company. " "Use to discover all SIRETs for a given SIREN." ), ), ] = None, administrative_status: Annotated[ Optional[str], Field( default=None, description=( "Administrative status of the establishment in the PPF directory. " "Active: establishment is open and reachable for invoicing. " "Inactive: establishment is closed; invoices cannot be sent to it." ), ), ] = None, updated_after: Annotated[ Optional[str], Field( default=None, description=( "Pagination cursor: only return establishments updated after this " "date/time (ISO 8601, e.g. 2024-09-01T00:00:00Z). " "Use the 'nextUpdatedAfter' field from the previous response to fetch the next page." ), ), ] = None, limit: Annotated[ int, Field(default=50, ge=1, le=500, description="Maximum number of results per page (1-500, default 50)."), ] = 50, ) -> dict: """ Search for establishments (SIRETs) in the PPF directory by criteria. An establishment is a physical place of business activity identified by its 14-digit SIRET. Each company (SIREN) can have multiple establishments. BEHAVIOR: - Returns a paginated list of matching establishments; empty list if none match. - At least one search criterion should be provided; omitting all returns an error. - Pagination: if the response includes 'nextUpdatedAfter', pass it as updated_after to get the next page. RESPONSE: each item includes siret, siren, name, administrativeStatus (Active/Inactive), approvedPlatformId, and timestamps (createdAt, updatedAt). USAGE GUIDELINES: - Prefer get_establishment_by_siret when you already know the exact SIRET (faster, direct lookup). - Use search_establishment with siren to enumerate all establishments of a company. - Always verify administrativeStatus == Active before sending an invoice to that establishment. - Call this before create_directory_line to confirm the target SIRET is registered in the PPF directory. """ client = get_directory_client() return await client.search_establishment( siret=siret, siren=siren, administrative_status=administrative_status, updated_after=updated_after, limit=limit, )