The io.frihet/erp Model Context Protocol (MCP) server provides an AI-native ERP interface for ES/EU fiscal compliance and core accounting workflows. Its scope includes invoicing, tax handling, and banking, with support for compliance formats listed in its description (VeriFactu/TicketBAI/Facturae).
Surface truth: the catalogue contains 158 canonical operations. The local full profile serves 163 tool names, 11 resources, and 10 prompts (158 canonical operations plus 5 fiscal aliases). The hosted grouped profile serves 166 tool names, 7 resources, and 10 prompts (the same names plus 3 discovery tools, with API-backed resources kept local-only). The separately reviewed OpenAI profile serves 33 tool names, 0 resources, and 0 prompts. Catalogue membership is not a promise that a backing API is enabled for every workspace.
What is this
An MCP server that connects your AI assistant to Frihet. Create invoices by talking. Query expenses in natural language. Manage your entire business from your IDE.
code
You: "Create an invoice for TechStart SL, 40 hours of consulting at 75 EUR/hour, due March 1st"
Claude: Done. Invoice INV-2026-089 created. Total: 3,000.00 EUR + 21% IVA = 3,630.00 EUR.
158 canonical operations. Five fiscal aliases. Ten prompts. The local package serves 11 resources; the hosted Worker deliberately serves the 7 static resources, while API-backed workspace resources remain local-profile only.
Try it instantly (no signup)
Kick the tires with zero setup — no account, no API key:
bash
FRIHET_DEMO=1 npx -y @frihet/mcp-server
In demo mode the server answers from realistic example fixtures (Spanish invoices with IVA/IGIC, expenses, clients, products, a bank account, and more) — every record uses demo_-prefixed IDs and the server prints a DEMO MODE banner on startup. Nothing is persisted and no network call is ever made. Writes are simulated and fiscal actions (e-invoice, VeriFactu, TicketBAI, FACe, payroll) return a clearly-labeled simulation — never a real submission to any tax authority.
When you're ready for your real data, drop the flag and add your key (app.frihet.io → Settings → API keys). See Install below.
For AI agents
If you are an agent reading this repository rather than a person reading a page, everything you need is machine-readable and generated from the running server — you do not have to parse this README.
_meta["io.frihet/capability"] on every entry of tools/list
How to behave once connected
the instructions string returned by initialize — your client hands it to you automatically
Three rules the contract encodes, in short:
Orient before acting.get_business_context and the frihet://tax/rates resource decide the correct fiscal treatment. Do not recall a Spanish tax rate from memory.
Draft, show, stop.create_invoice, create_quote and create_credit_note all default to status=draft — no fiscal number, no hash, nothing sent to a tax authority. Present the draft and hand back.
Human authority is not yours to assume. Any tool with a non-empty externalSideEffects reaches a client's inbox, a webhook, money, or AEAT / VeriFactu / TicketBAI / FACe. Several also take confirm=true; that flag records a human decision — never set it to satisfy your own plan.
docs/agent-onboarding.json is regenerated from the live surface by npm run generate:agent-onboarding and gated in CI by npm run gate:agent-onboarding, so its tool lists and counts cannot drift from the server.
Claude Code plugin (skill + MCP server in one install)
This repository is also a Claude Code plugin (frihet-erp): installing it wires up both the business-management skill and the MCP server.
bash
# Try it locally
claude --plugin-dir /path/to/frihet-mcp
Marketplace availability is pending. Use the local plugin command above or the Claude Code MCP command below to connect today.
Skill invocation: /frihet-erp:frihet-mcp. The bundled .mcp.json launches @frihet/mcp-server via npx — set FRIHET_API_KEY in your environment (get one at app.frihet.io → Settings → API keys).
Claude Code — one command
bash
claude mcp add frihet -s user -e FRIHET_API_KEY=fri_your_key_here -- npx -y @frihet/mcp-server
claude mcp list # verify: frihet ✓ Connected
The CLI owns the config file, so there is nothing to hand-edit and no path to get wrong. (User scope writes ~/.claude.json, not ~/.claude/mcp.json.)
Pasting a JSON mcpServers block into ~/.codex/config.toml is a TOML parse error that takes down your whole Codex config, not just this server. Use the command above.
Claude Desktop, Cursor, Windsurf, Cline — JSON config
The JSON above is identical for these four clients; only the file path changes. Claude Code and Codex are not in this table — they manage their own config through the CLI commands shown above.
Remote (no install)
Use the hosted endpoint at mcp.frihet.io -- zero local dependencies, runs on Cloudflare Workers.
With OAuth 2.0 + PKCE (browser-based login, no API key needed):
Clients that support OAuth (Claude Desktop, Smithery, etc.) can connect directly to https://mcp.frihet.io/mcp and authenticate via browser. The server implements the full OAuth 2.1 authorization code flow with PKCE.
Copy the key (starts with fri_) -- it's only shown once
What you can do
Talk to your ERP. These are real prompts, not marketing copy.
Invoicing
code
"Show me all unpaid invoices"
"Create an invoice for Acme SL with 10h of consulting at 95/hour"
"Mark invoice abc123 as paid"
"How much has ClientName been invoiced this year?"
Expenses
code
"Log a 59.99 EUR expense for Adobe Creative Cloud, category: software, tax-deductible"
"List all expenses from January"
"What did I spend on travel last quarter?"
Clients
code
"Add a new client: TechStart SL, NIF B12345678, email admin@techstart.es"
"Show me all my clients"
"Update ClientName's address to Calle Mayor 1, Madrid 28001"
CRM
code
"Add a contact to Acme SL: Ana Garcia, CTO, ana@acme.es"
"Log a call with TechStart: discussed Q2 proposal, they're interested in upgrade"
"Add a note to ClientName: prefers invoices in English, payment NET 30"
"Show me all activities for Acme SL"
Quotes
code
"Create a quote for Design Studio: logo design (2000 EUR) + brand guidelines (3500 EUR)"
"Show me all pending quotes"
Webhooks
code
"Set up a webhook to notify https://my-app.com/hook when invoices are paid"
"List all my active webhooks"
What to expect
This MCP is a structured data interface -- you describe what you want in natural language, and the AI creates, queries, or modifies business records in Frihet. Most of the 158 canonical operations are CRUD operations over the REST API; the rest are read-only summaries and fiscal/e-invoice actions. Alias and discovery names are counted separately.
Works great:
code
"Create an invoice for TechStart SL, 40h consulting at 75 EUR/h" --> creates the invoice
"Show unpaid invoices over 1,000 EUR" --> queries and filters
"Log a 120 EUR expense for the Madrid train, category: travel" --> records the expense
"Update client Acme's email to billing@acme.es" --> modifies the record
Does not do:
OCR or PDF scanning -- you cannot upload an invoice image and have it read
File upload or attachment handling
Image processing of any kind
If you need to digitize paper invoices or receipts, extract the data first (e.g., Claude Vision API, a dedicated OCR service, or manual entry), then use the MCP to create the record:
code
1. Scan/photograph the invoice
2. Use Claude Vision: "Read this invoice image and extract the vendor, items, amounts, and dates"
3. Then: "Create an expense in Frihet for [extracted data]"
Catalogue operations (158)
Invoices (12)
Tool
What it does
list_invoices
List invoices with pagination
get_invoice
Get full invoice details by ID
create_invoice
Create a new invoice with line items
update_invoice
Update any invoice field
delete_invoice
Delete a draft invoice; a sent/paid one is cancelled, not destroyed (confirm=true required)
search_invoices
Find invoices by client name, date, or status
send_invoice
Email invoice to client (PDF attachment) — reaches a third party, confirm=true required
mark_invoice_paid
Mark an invoice as paid with optional payment date
get_invoice_pdf
Get bounded invoice PDF bytes as base64
get_invoice_einvoice
Get bounded XML or Factur-X PDF bytes for an invoice
create_credit_note
Create a credit note linked to an existing invoice
apply_late_fee
Apply a late payment fee to an overdue invoice
Expenses (5)
Tool
What it does
list_expenses
List expenses with pagination
get_expense
Get expense details
create_expense
Record a new expense
update_expense
Modify an expense
delete_expense
Delete an expense
Clients (5)
Tool
What it does
list_clients
List all clients
get_client
Get client details
create_client
Register a new client
update_client
Update client info
delete_client
Remove a client
CRM: Contacts (3)
Tool
What it does
list_client_contacts
List all contacts for a client
create_client_contact
Add a contact person to a client
delete_client_contact
Remove a contact from a client
CRM: Activities (2)
Tool
What it does
list_client_activities
List CRM activities (calls, emails, meetings, tasks)
log_client_activity
Log a call, email, meeting, or task against a client
CRM: Notes (3)
Tool
What it does
list_client_notes
List all notes for a client
create_client_note
Add a free-form note to a client
delete_client_note
Remove a note from a client
Products (5)
Tool
What it does
list_products
List products and services
get_product
Get product details
create_product
Add a product or service
update_product
Update pricing or details
delete_product
Remove a product
Quotes (6)
Tool
What it does
list_quotes
List all quotes
get_quote
Get quote details
create_quote
Draft a new quote
update_quote
Modify a quote
delete_quote
Delete only a clean draft with no delivery, response, attachment, or conversion evidence; refuse protected drafts; cancel non-drafts (confirm=true required)
send_quote
Email quote to client for acceptance
Webhooks (6)
Tool
What it does
list_webhooks
List configured webhooks
get_webhook
Get webhook details
create_webhook
Register a new webhook endpoint
update_webhook
Modify events or URL
delete_webhook
Remove a webhook
test_webhook
Send a test payload to a configured webhook endpoint
Intelligence (4)
Tool
What it does
get_business_context
Full snapshot: profile, plan, recent activity, top clients, current month
get_monthly_summary
Monthly P&L: revenue, expenses, profit, tax liability, top clients by revenue
get_quarterly_taxes
Quarterly tax prep: Modelo 303/130 fields, collected vs deductible, liability
duplicate_invoice
Clone an invoice for recurring billing (copies items/client/tax, starts as draft)
E-Invoicing (10)
Tool
What it does
send_einvoice
Dispatch an invoice in 11 formats (XRechnung, Factur-X, FatturaPA, PEPPOL, Facturae, UBL, CII) via email / Chorus Pro / SDI / PEPPOL / download
get_einvoice_status
Poll Hatchet workflow run status until succeeded/failed — returns ackId, XML URL, PDF/A-3 URL
validate_einvoice_xml
Validate raw XML against format schema + schematron rules (KOSIT / Mustang / XSD / Schematron)
export_datev
Export accounting data as DATEV EXTF (Buchungsstapel / Debitoren / Kreditoren) in CP1252 encoding
einvoice_export
Export e-invoice data in machine-readable formats (JSON/XML) for archival or integration
face_submit
Submit invoice to FACe (Spain B2G government e-invoicing platform)
face_status
Poll submission status from FACe for a submitted invoice
ticketbai_submit
Submit TicketBAI fiscal record to Basque Country tax authority (Hacienda)
ticketbai_status
Poll TicketBAI submission status from the Basque tax authority
ksef_submit
NOT_DEPLOYED — Submit invoice to KSeF (Poland) — stub: transport is infra-ready in Frihet-ERP but not yet exposed as a live endpoint (production gated on KSeF cert); returns a labeled "unavailable" error until activated
Time Tracking (6)
Tool
What it does
list_time_entries
List time entries with filter by user, project, date range, billable status
get_time_entry
Get full details of a single time entry by ID
create_time_entry
Log hours for a project (billable flag, description, date)
update_time_entry
Update any field on an existing time entry (PATCH semantics)
delete_time_entry
Soft-delete a time entry (confirm=true required)
get_time_summary
Aggregate total/billable/non-billable hours for a period, with optional groupBy (user/project/day)
Recurring Invoices (8)
Tool
What it does
list_recurring_invoices
List all recurring invoice templates (filter by active/paused)
get_recurring_invoice
Get full details of a recurring template by ID
create_recurring_invoice
Create a new recurring invoice template (daily/weekly/monthly/quarterly/yearly)
update_recurring_invoice
Update template fields — affects future generated invoices only
pause_recurring_invoice
Pause an active template — no invoices generated while paused
resume_recurring_invoice
Resume a paused template — next invoice on next scheduled cycle
delete_recurring_invoice
Permanently delete a template (confirm=true required)
run_recurring_now
Manually trigger immediate generation of the next invoice instance
Team Management (4)
Tool
What it does
list_team_members
List active members + pending invites (owner excluded)
invite_team_member
Invite a new member by email with role (admin/editor/accountant/viewer)
update_team_member_role
Change an existing member's role (admin/editor/accountant/viewer)
remove_team_member
Remove a member from the workspace (confirm=true required)
Gestoria — Accountants (5)
Tool
What it does
gestoria_message_send
Send a message in a contextual thread (documentRequest / filingItem / obligation)
gestoria_messages_list
List messages in a thread, newest first; paginate backwards with before
gestoria_template_create
Create a reusable document request template with variables + due-date offset
gestoria_template_bulk_send
Bulk send a template to up to 500 client workspaces in one call
gestoria_aging_consolidated
Cross-client AR aging report (buckets, per-workspace breakdown, top overdue)
Audit GL (3)
Tool
What it does
frihet_gl_entry_approve
Approve a GL journal entry (gestor/admin only — TRUST AREA)
frihet_gl_entry_reject
Reject a GL entry with a mandatory reason (TRUST AREA)
frihet_gl_entry_audit_log
Retrieve full audit trail for a GL entry
White-label Portal Domain (3)
Tool
What it does
frihet_portal_domain_add
Add a custom domain to the client portal (returns DNS CNAME records)
frihet_portal_domain_verify
Verify DNS propagation for a custom portal domain
frihet_portal_domain_remove
Remove a custom portal domain (reverts to default Frihet subdomain)
Self-onboard & VIES (2)
Tool
What it does
frihet_portal_onboard_link_generate
Generate a time-limited self-onboard link for a prospective client
frihet_tax_id_vies_lookup
Validate an EU VAT number (CIF intracomunitario) via VIES
IGIC — Canary Islands Indirect Tax (4)
Tool
What it does
frihet_modelo_415_summary
M415 annual operations >€3,005 (Canarias equivalent of M347) — not deployed, returns NOT_DEPLOYED
frihet_modelo_425_summary
M425 annual IGIC recap for Canary Islands businesses — not deployed, returns NOT_DEPLOYED
frihet_modelo_418_summary
M418 monthly individual IGIC return, régimen especial del grupo de entidades — not deployed, returns NOT_DEPLOYED
frihet_aiem_calculate
AIEM (Arbitrio Importación) calculation for Canarias — not deployed, returns NOT_DEPLOYED
Impuesto sobre Sociedades — Corporate Tax (2)
Tool
What it does
frihet_modelo_200_summary
Modelo 200 annual IS return — not deployed, returns NOT_DEPLOYED
frihet_modelo_202_summary
Modelo 202 installment payments (1P/2P/3P) — not deployed, returns NOT_DEPLOYED
Bank Categorization Rules (2)
Tool
What it does
frihet_bank_rules_list
List all bank auto-categorization rules (conditions + actions + status)
frihet_bank_rule_create
Create a new rule to auto-categorize transactions by description, amount, counterparty
Deposits (7)
Tool
What it does
list_deposits
List deposits with pagination
get_deposit
Get deposit details by ID
create_deposit
Record a new client deposit
update_deposit
Update deposit fields
delete_deposit
Delete a deposit (confirm=true required)
apply_deposit
Apply a deposit balance against an invoice
refund_deposit
Issue a refund for a deposit
Vendors (5)
Tool
What it does
list_vendors
List all vendors/suppliers
get_vendor
Get vendor details
create_vendor
Add a new vendor
update_vendor
Update vendor info
delete_vendor
Remove a vendor
Banking (5)
Tool
What it does
list_bank_accounts
List connected bank accounts
get_bank_account
Get details for a bank account
list_transactions
List bank transactions with filters
categorize_transaction
Assign a category and expense/income type to a transaction
match_transaction_to_invoice
Link a bank transaction to an existing invoice
Fiscal — Spanish Tax Models (7)
Tool
What it does
get_modelo_303_summary
Quarterly IVA return (Modelo 303) — collected vs deductible, net payable
get_modelo_130_summary
Quarterly IRPF installment for self-employed (Modelo 130)
get_modelo_390_summary
Annual IVA summary (Modelo 390)
get_modelo_180_summary
Annual withholding summary for rentals (Modelo 180) — not deployed, returns NOT_DEPLOYED
Get VeriFactu submission status for a fiscal record
verifactu_resubmit
Resubmit a rejected VeriFactu fiscal record
ticketbai_status
Poll TicketBAI submission status — cross-reference from E-Invoicing (10); NOT counted toward this section's 7
Vacation Rentals / Stay (5)
Tool
What it does
list_reservations
List rental reservations with filters
get_reservation
Get reservation details
create_reservation
Create a new reservation
list_properties
List all rental properties
sync_channel
Trigger OTA channel sync (Airbnb, Booking.com, etc.)
POS — Point of Sale (4)
Tool
What it does
list_terminals
List registered POS terminals
get_sale
Get details for a POS sale transaction
list_sales
List POS sales with pagination
refund_sale
Issue a refund for a POS sale
Kitchen / Restaurant (6)
Tool
What it does
list_kitchen_tickets
List kitchen order tickets for the live board, filtered by status or station
get_kitchen_ticket
Get a single kitchen ticket by ID with all items and their individual statuses
update_kitchen_ticket
Advance a ticket's status (queued → preparing → ready → served) or reassign it to another station
list_kitchen_stations
List all kitchen stations with id, name, and active status
list_menu_items
List the kitchen menu catalog with free-text search and active/inactive filter
kitchen_flow_summary
Slow-station detection: aggregate open tickets per station and flag the bottleneck
HR — Human Resources (9)
Tool
What it does
leave_request_create
Create a leave request (vacation, sick, personal)
leave_approve
Approve a pending leave request
leave_reject
Reject a leave request with a reason
leave_cancel
Cancel an approved or pending leave request
leave_list
List leave requests with filters (user, status, date range)
attendance_clock_in
Record clock-in for an employee
attendance_clock_out
Record clock-out for an employee
overtime_report
Read daily/weekly overtime, aggregate minutes/hours, and compliance alerts computed over the selected YYYY or YYYY-MM records
anomaly_list
List attendance anomalies (missing punches, excessive overtime)
Payroll (2)
Tool
What it does
payroll_export
Read normalized payroll-ready employee data; the format value is an echoed destination label, not a generated file
payroll_checklist
List payable employees with payroll-profile readiness, missing fields, and monthly review state
Onboarding (2)
Tool
What it does
onboarding_status
Get onboarding completion status for the current workspace
onboarding_persona_set
Set or update the business persona (freelancer, SME, gestoría, etc.)
Permissions (2)
Tool
What it does
permissions_matrix
Get the documented RBAC-model snapshot (not a runtime authorization guarantee)
permissions_me
Compare RBAC-model fields with actual API-key scopes and known scope denials (non-exhaustive)
Period Close (3)
Tool
What it does
period_close_status
Get the current or selected YYYY fiscal-year range, open/closed state, and nullable closing details
period_close
Close an accounting period (gestor/admin only — TRUST AREA)
period_reopen
Reopen a closed period with a mandatory reason (TRUST AREA)
All canonical operations (and their aliases) return structured output via outputSchema -- typed JSON, not raw text. List response shapes follow their API family; not every list endpoint is paginated.
Capability and side-effect truth
On the full MCP surfaces, every tools/list entry includes _meta["io.frihet/capability"]:
registered means the name and handler exist in this server build;
callability is api_dependent (the handler calls the API; deployment, workspace enablement, and authorization still decide), runtime_checked (the handler explicitly distinguishes an absent backend from empty data), deferred, unavailable, or local—never an unconditional “available” claim;
writesFrihet, externalInteraction, and externalSideEffects distinguish state changes and calls to external entities/providers;
MCP action annotations remain the standard source for read-only, destructive, idempotent, and open-world hints.
The ChatGPT/OpenAI host is a separately reviewed surface: exactly 33 business operations with complete descriptions, 0 discovery meta-tools, 0 prompts, and 0 resources. Its 17 reads and 16 writes are deliberately narrow, and all writes require literal confirm=true. Ten writes may deliver full business events to active endpoints previously configured by the workspace owner; webhook administration itself remains excluded. Direct email delivery, the legacy monthly summary, raw invoice PDFs, invoice lifecycle transitions, updating an existing quote, regulated filing, deleting client parent records, deleting expenses with their linked files, deleting products, and deleting vendors are also excluded. This surface must not be inferred from the full catalogue.
Resources
Context the AI can read to make smarter decisions.
The local package serves 11 resources: 7 static references plus 4 API-backed workspace resources. The hosted Worker serves the 7 static resources. The OpenAI-reviewed host serves 0 resources.
AR aging analysis: group unpaid invoices by bucket (0-30/31-60/61-90/90+ days), top debtors, collection actions
--
expense-batch
Process expenses in bulk: categorize, apply tax rates, flag missing receipts
fiscalZone?
How it works
graph LR
AI["Your AI assistant"]
MCP["frihet-mcp"]
API["api.frihet.io"]
DB["Frihet ERP"]
AI -- "create_invoice()" --> MCP
MCP -- "POST /v1/invoices" --> API
API --> DB
DB -- "201 + invoice data" --> API
API -- "structured JSON" --> MCP
MCP -- "typed response + suggestions" --> AI
style AI fill:#09090b,stroke:#4ade80,color:#fafafa
style MCP fill:#09090b,stroke:#fafafa,color:#fafafa
style API fill:#09090b,stroke:#3f3f46,color:#a1a1aa
style DB fill:#09090b,stroke:#3f3f46,color:#a1a1aa
The server translates tool calls into REST API requests. It handles authentication, rate limiting (automatic retry with backoff on 429), pagination, and error mapping.
Two transports:
stdio (local) -- npx @frihet/mcp-server with FRIHET_API_KEY
Streamable HTTP (remote) -- https://mcp.frihet.io/mcp with Bearer token or OAuth 2.0+PKCE
Environment variables
Variable
Required
Default
FRIHET_API_KEY
Yes (stdio)
--
FRIHET_API_URL
No
https://api.frihet.io/v1
FRIHET_TOOL_MODE
No
full
Tool exposure: depth served on demand
Frihet's differentiator is depth — full ES/EU fiscal coverage plus native compliance (VeriFactu, TicketBAI, Facturae/FACe; KSeF Poland infra-ready, activation pending), banking, CRM, HR/payroll, stay/PMS and POS. But a flat list of every tool, loaded into an agent's context up front, is the 2026 context-rot problem: it crowds out the task and degrades tool selection before any work begins.
FRIHET_TOOL_MODE lets you choose how that depth is exposed.
Mode
Behavior
full (default)
Canonical tools and fiscal aliases are exposed with full descriptions and schemas. Public descriptors add conservative callability and side-effect truth; operation names, schemas and handlers are unchanged.
grouped
Progressive disclosure. Each tool's description collapses to a one-line [group] summary — full schema via describe_tool('name'), and three lightweight discovery tools are added. The agent loads depth only for the tools it actually needs.
In grouped mode operation names, input schemas and handlers are unchanged. Descriptors also expose the same conservative capability and action truth as the full profile. Discovery flows through three meta-tools:
list_tool_groups() — the domain map (invoicing, expenses, fiscal/compliance, banking, CRM, HR/payroll, stay/PMS, POS, intelligence, products, platform) with a one-line blurb and tool count for each.
search_tools(query) — free-text search across tool name, title, summary and group; returns matching tools with their group, summary, read-only flag and input fields. Optional group filter and limit.
describe_tool(name) — the full original description and input fields for one tool, on demand, before you call it.
jsonc
// claude_desktop_config.json — opt in to grouped mode{"mcpServers":{"frihet":{"command":"npx","args":["@frihet/mcp-server"],"env":{"FRIHET_API_KEY":"fri_...","FRIHET_TOOL_MODE":"grouped"}}}}
Grouped exposure changes description density, not operation behavior. The versioned OpenAI-reviewed profile is composed separately and remains independently gated.
API limits
Limit
Value
Requests per minute
100 per API key
Results per page
100 max (50 default)
Request body
1 MB max
Webhook payload
100 KB max
Webhooks per account
20 max
Rate limiting is handled automatically with exponential backoff.
Claude Code Skill
Beyond raw MCP tools, this repo includes a Claude Code skill that adds business context: Spanish tax rules, workflow recipes, financial reports, and natural language commands.