Skip to main content

MCP Server

Frihet's MCP server implements the Model Context Protocol so AI assistants can interact directly with your ERP. Create invoices, log expenses, look up clients, or manage quotes — all from your IDE or terminal, in natural language.

Current version: 1.5.1 | 52 tools | 11 resources | 10 prompts | Structured output | Compatible with 30+ AI agents.

You:     "Create an invoice for TechStart Ltd, 40 hours of consulting at 75 EUR/hour, due March 1st"
Claude: Done. Invoice INV-2026-089 created. Total: 3,000.00 EUR + 21% VAT = 3,630.00 EUR.

What to expect (and what not)

The MCP server is a stateless bridge between your AI assistant and the Frihet REST API. Each tool call translates into an HTTP request to the API.

What it DOES:

  • Full CRUD on invoices, expenses, clients, products, quotes, and webhooks
  • Invoice search by client name
  • Access to reference data (tax rates, fiscal calendar, categories)
  • Guided workflows (monthly close, tax prep, overdue follow-up)

What it DOES NOT:

  • Document OCR (that's handled by the AI assistant inside the app)
  • PDF generation (use the REST API directly: GET /v1/invoices/:id/pdf)
  • Payment processing (payments are handled via Stripe Connect in the app)

Requirements

  • Frihet account with API access (paid plans)
  • API key generated from the dashboard

Getting your API key

  1. Sign in at app.frihet.io
  2. Go to Settings > Developers > API Keys
  3. Click Create API key
  4. Copy the key (starts with fri_) — it is only shown once

Installation

Universal (30+ agents)

The fastest way to install the MCP server and the business skill:

npx skills add Frihet-io/frihet-mcp

Works with Claude Code, Cursor, Copilot, Codex, Windsurf, Gemini CLI, Goose, Roo Code, and 30+ more agents.

MCP Registry

The server is registered as io.frihet/erp on the official MCP Registry. MCP clients that support the registry can discover and install it automatically by its canonical name.

Direct npx

npx -y @frihet/mcp-server@latest

No global installation needed. npx downloads and runs the latest version automatically.

Manual configuration

There are two connection modes: local (the server runs on your machine via npx) and remote (direct connection to mcp.frihet.io, no installation needed).

Local (stdio)

{
"mcpServers": {
"frihet": {
"command": "npx",
"args": ["-y", "@frihet/mcp-server@latest"],
"env": {
"FRIHET_API_KEY": "fri_your_key_here"
}
}
}
}

Remote (streamable-http)

{
"mcpServers": {
"frihet": {
"type": "streamable-http",
"url": "https://mcp.frihet.io/mcp",
"headers": {
"Authorization": "Bearer fri_your_key_here"
}
}
}
}

Configuration by client

The JSON structure is identical across all clients. Only the config file location changes.

ClientConfig file
Claude Code~/.claude/mcp.json
Claude Desktop~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
Cursor.cursor/mcp.json or ~/.cursor/mcp.json
Windsurf~/.windsurf/mcp.json
ClineVS Code settings or .cline/mcp.json
Codex CLI~/.codex/config.toml (MCP section)
tip

If you use Claude Code, you can add the server with a single command:

claude mcp add frihet -- npx -y @frihet/mcp-server@latest

Then set the FRIHET_API_KEY variable in the resulting ~/.claude/mcp.json file.

Environment variables

VariableRequiredDefault
FRIHET_API_KEYYes
FRIHET_API_URLNohttps://api.frihet.io/v1
FRIHET_MCP_DEBUGNo0
  • FRIHET_API_URL is useful if you're pointing to a staging environment or a custom instance. Must be https:// with a hostname under frihet.io.
  • FRIHET_MCP_DEBUG=1 enables debug-level logs (useful for troubleshooting).

OAuth flow

The MCP server supports OAuth authentication in addition to manual API key setup. When an MCP client initiates the OAuth flow:

  1. The user authenticates via Firebase Auth (email, Google, GitHub, or Microsoft)
  2. The client sends the session token to POST /api/oauth/api-key
  3. The server provisions a new fri_xxx... key labeled "MCP OAuth" with a 365-day expiration
  4. The key is used automatically for subsequent calls

This lets users connect the MCP server without manually copying keys.


Available tools (44)

The server exposes 52 tools organized across 7 categories. Every tool includes structured output (outputSchema + structuredContent) for reliable parsing, plus security and content annotations. Bilingual (EN/ES).

Invoices (6 tools)

ToolDescriptionKey parameters
list_invoicesList invoices with paginationlimit, offset
get_invoiceGet a single invoice by IDid
create_invoiceCreate an invoice with line itemsclientName, items[] (description, quantity, unitPrice), status, dueDate, notes, taxRate
update_invoiceUpdate fields on an invoice (partial)id, plus any field to modify
delete_invoicePermanently delete an invoiceid
search_invoicesSearch invoices by client nameclientName, limit, offset

Possible invoice statuses: draft, sent, paid, overdue, cancelled

Expenses (5 tools)

ToolDescriptionKey parameters
list_expensesList expenses with paginationlimit, offset
get_expenseGet a single expense by IDid
create_expenseLog a new expensedescription, amount, category, date, vendor, taxDeductible
update_expenseModify an existing expense (partial)id, plus any field to modify
delete_expensePermanently delete an expenseid

Clients (5 tools)

ToolDescriptionKey parameters
list_clientsList all clientslimit, offset
get_clientGet a single client by IDid
create_clientRegister a new clientname, email, phone, taxId, address (street, city, state, postalCode, country)
update_clientUpdate client details (partial)id, plus any field to modify
delete_clientPermanently delete a clientid

Products (5 tools)

ToolDescriptionKey parameters
list_productsList products and serviceslimit, offset
get_productGet a single product by IDid
create_productCreate a product or servicename, unitPrice, description, taxRate
update_productModify an existing product (partial)id, plus any field to modify
delete_productPermanently delete a productid

Quotes (5 tools)

ToolDescriptionKey parameters
list_quotesList quoteslimit, offset
get_quoteGet a single quote by IDid
create_quoteCreate a quote for a clientclientName, items[] (description, quantity, unitPrice), validUntil, notes, status
update_quoteModify a quote (partial)id, plus any field to modify
delete_quotePermanently delete a quoteid

Possible quote statuses: draft, sent, accepted, rejected, expired

Webhooks (5 tools)

ToolDescriptionKey parameters
list_webhooksList configured webhookslimit, offset
get_webhookGet webhook configurationid
create_webhookRegister a webhook endpointurl, events[], active, secret
update_webhookModify an existing webhookid, plus any field to modify
delete_webhookPermanently delete a webhookid

Available webhook events: invoice.created, invoice.updated, invoice.deleted, invoice.paid, expense.created, expense.updated, expense.deleted, client.created, client.updated, client.deleted, product.created, product.updated, product.deleted, quote.accepted. See Webhooks for payload format and HMAC verification.


Available resources (8)

MCP resources are reference data the assistant can query without making API calls. They are static and always accessible.

ResourceURIDescription
API schemafrihet://api/schemaEndpoint summary, authentication, rate limits, and error codes
Tax ratesfrihet://tax/ratesVAT (21/10/4%), IGIC (7/3/0%), IPSI, intra-community, IRPF (15%/7%)
Tax calendarfrihet://tax/calendarQuarterly filing dates (Modelo 303, 130, 420, 390)
Expense categoriesfrihet://config/expense-categories8 categories with deductibility rules and tax treatment
Invoice statusesfrihet://config/invoice-statusesStatus flow (draft, sent, paid, overdue, cancelled) with triggers
Vendorsfrihet://config/vendorsList of registered vendors with tax and contact data
Active integrationsfrihet://config/integrationsStatus of connected integrations (Stripe, Shopify, etc.)
Business configurationfrihet://config/businessCompany tax data, fiscal zone, currency, and preferences

Available prompts (7)

Prompts are guided workflows the assistant executes step by step. Invoke them by name.

PromptDescriptionParameters
monthly-closeMonthly close: review unpaid invoices, categorize expenses, verify tax obligations, generate summarymonth (optional)
onboard-clientClient onboarding: determine tax type by location, create record, generate welcome quoteclientName, country, region
quarterly-tax-prepQuarterly tax prep: gather invoices, calculate VAT/IGIC, generate Modelo 303/130 previewquarter, fiscalZone
overdue-followupOverdue follow-up: identify overdue invoices, group by client, draft collection messages
expense-batchBatch expense processing: categorize, apply taxes, verify deductibility, create with confirmationfiscalZone
vendor-analysisVendor analysis: group expenses by vendor, calculate totals, identify trends and savings opportunitiesperiod (optional)
business-healthBusiness health check: key KPIs, month-over-month comparison, alerts, and actionable recommendationsmonth (optional)
tip

You can invoke a prompt directly: "Run the monthly close for February" or "Prep my Q1 taxes".


Usage examples

These are real natural-language requests that the assistant translates into MCP tool calls.

Create an invoice

"Create an invoice for Acme Ltd with 10 hours of consulting at 95 EUR/hour, due March 15th"

The assistant calls create_invoice with clientName: "Acme Ltd", one line item (10 x 95), and dueDate: "2026-03-15". The total is calculated automatically.

Log an expense

"Log an expense of 59.99 EUR for Adobe Creative Cloud, category software, tax deductible"

Calls create_expense with description, amount: 59.99, category: "software", and taxDeductible: true.

Search invoices by client

"Find all invoices for TechStart Ltd"

Calls search_invoices with clientName: "TechStart Ltd" and returns matches with totals and statuses.

Check overdue invoices

"Show me all unpaid invoices"

Calls list_invoices and filters by status: "sent" or "overdue", displaying overdue invoices sorted by amount.

Add a new client

"New client: Design Studio Ltd, VAT GB123456789, email hello@designstudio.co.uk, London EC1A 1BB"

Calls create_client with name, tax ID, email, and address.

Set up automation

"Create a webhook to notify https://my-app.com/hook when an invoice is paid"

Calls create_webhook with url and events: ["invoice.paid"].

Update a product

"Raise the hourly consulting rate to 85 EUR"

Calls update_product with the product id and unitPrice: 85. Only the specified field is modified.


Observability

The MCP server v1.5.1 includes structured logging and tool metrics.

Structured logging

All logs are emitted as JSON to stderr (MCP uses stdout for protocol messages). Each entry includes:

  • level: debug, info, warn, error
  • service: always frihet-mcp
  • timestamp: ISO 8601
  • tool: tool name (when applicable)
  • operation: operation type (tool_call, api_call, api_retry, startup, shutdown_metrics)
  • durationMs: execution time in milliseconds
  • error: error details (message, code, statusCode)

Enable debug logs with FRIHET_MCP_DEBUG=1.

Tool metrics

The server tracks in-memory metrics for each tool call: invocation count, errors, and average duration. On shutdown (SIGINT/SIGTERM), it emits a summary:

{
"level": "info",
"message": "Shutdown after 3600s — 42 calls, 1 errors",
"operation": "shutdown_metrics",
"metadata": {
"tools": {
"list_invoices": { "calls": 15, "errors": 0, "avgMs": 230 },
"create_invoice": { "calls": 8, "errors": 1, "avgMs": 450 }
},
"uptime": 3600
}
}

Automatic rate-limit retry

When the API responds with 429, the server retries automatically with exponential backoff (up to 3 retries). Retries are logged:

{
"level": "warn",
"message": "Rate limited, retrying GET /invoices (attempt 2, delay 2000ms)",
"operation": "api_retry"
}

You don't need to handle rate limiting manually — the server does it for you.


Transport

Frihet's MCP server supports two transport modes. Both expose the same 52 tools, 11 resources, and 10 prompts.

Local (stdio)

The server runs as a local process on your machine. Communication between the MCP client and server uses standard input/output (stdin/stdout).

  • Requires: Node.js installed (downloaded automatically via npx)
  • Advantage: Lower latency, works offline (except for API calls)
  • Use case: Daily development, heavy usage, corporate environments with network restrictions

Remote (streamable-http)

The server runs on Cloudflare Workers. Your MCP client connects directly to https://mcp.frihet.io/mcp over HTTP.

  • Requires: Only an internet connection
  • Advantage: No local installation, no dependencies, works on any device
  • Use case: Quick setup, teams that prefer not to install packages, clients that only support HTTP transport
info

If your MCP client doesn't support streamable-http (some older clients only support stdio), use local mode.


Error handling

Rate limiting

The API allows 100 requests per minute per key. If the limit is exceeded, the server returns a 429 error with the wait time in retryAfter.

The MCP server handles rate limiting automatically with exponential backoff: it retries the request after waiting the indicated time, with no user intervention needed. Maximum 3 retries.

Authentication errors

CodeCauseSolution
401Invalid, expired, or missing API keyVerify the key in your config starts with fri_ and hasn't expired
403The key doesn't have permissions for this resourceGenerate a new key with the required permissions

Other errors

CodeDescription
400Invalid parameters or missing required fields
404The requested resource doesn't exist
408Request timeout (30 seconds)
413The request body exceeds 1 MB
422Valid data but not processable (e.g., fiscal profile not configured)
429Rate limit exceeded (retried automatically)
500Internal server error

All errors return a descriptive bilingual message (EN/ES) so the assistant can communicate the problem clearly to the user.


Limits

ConceptValue
Requests per minute100 per API key
Results per page100 maximum (50 default)
Request body1 MB maximum
Webhook payload100 KB maximum
Webhooks per account20 maximum
Request timeout30 seconds
Rate limit retries3 maximum

MCP Server vs REST API

MCP ServerREST API
Designed forAI assistants (Claude, Cursor, Windsurf)Applications, scripts, integrations
CommunicationNatural language through the MCP clientDirect HTTP/JSON
AuthenticationEnvironment variable in client config (or OAuth)X-API-Key header or Authorization: Bearer
FormatFormatted text + structured output for the assistantRaw JSON
Rate limitingHandled automatically (exponential backoff, 3 retries)Manual (consumer must implement retries)
ObservabilityStructured logging + per-tool metricsRequest logs via X-Request-Id
Use caseTalk to your ERP from your IDEBuild programmatic integrations

Internally, the MCP server translates each tool call into a REST API request. It doesn't duplicate logic — it's a stateless bridge.


Development

To contribute or run the server in development mode:

git clone https://github.com/Frihet-io/frihet-mcp.git
cd frihet-mcp
npm install
npm run build

Run locally:

FRIHET_API_KEY=fri_your_key node dist/index.js

Run with debug logs:

FRIHET_MCP_DEBUG=1 FRIHET_API_KEY=fri_your_key node dist/index.js

Test with the MCP Inspector:

npx @modelcontextprotocol/inspector node dist/index.js


Previous: Webhooks | Next: Claude Code Skill