DEV Community

Cover image for I Built an MCP Server for My ERP — Here's What I Learned
berthelius
berthelius

Posted on • Originally published at frihet.io

I Built an MCP Server for My ERP — Here's What I Learned

There's a new way to manage a business. Not an app, not a dashboard, not another browser tab. You talk to your AI assistant and it accesses your invoices, expenses, and clients directly.

I built Frihet, an AI-native business management platform. When Anthropic released the MCP protocol, I knew the ERP needed to speak it natively. So I built an MCP server. Here's what I learned.

What the MCP Server Does

31 tools and 5 prompts across 6 categories:

Resource Operations
Invoices Create, read, update, delete, search, list
Expenses Create, read, update, delete, list
Clients Create, read, update, delete, list
Products Create, read, update, delete, list
Quotes Create, read, update, delete, list
Webhooks Create, read, delete, list

In practice, you tell Claude:

"Create an invoice for Acme Ltd for 2,500 EUR for January consulting"

The invoice is created with correct tax details, VAT calculated, and invoice number assigned. No browser needed.

What's New in v1.2

The initial release had 31 tools. v1.2 adds three capabilities that make the server significantly more useful:

MCP Resources (5)

Static reference data your AI assistant can access without making API calls:

  • API schema — Full OpenAPI spec for Frihet's REST API
  • Tax rates — Country-specific tax rates (VAT, IGIC, IVA, etc.)
  • Tax calendar — Filing deadlines by jurisdiction
  • Expense categories — Standard categories with tax deduction rules
  • Invoice statuses — All valid statuses and their transitions

These are read-only and always available. When Claude needs to calculate VAT on an invoice, it reads the tax rates resource instead of guessing or asking you.

MCP Prompts (5)

Guided workflows for common accounting tasks:

  • monthly-close — Walk through month-end reconciliation step by step
  • onboard-client — Create a new client with all required fields, then generate a welcome invoice
  • quarterly-tax-prep — Gather all data needed for quarterly tax filing
  • overdue-followup — Find overdue invoices and draft follow-up actions
  • expense-batch — Bulk-record expenses from a receipt dump

Each prompt chains multiple tools in a logical sequence. Instead of figuring out which 4 tools to call and in what order, you invoke one prompt.

Structured Output

Every tool now declares an outputSchema and returns structuredContent. This means MCP clients can parse responses programmatically instead of relying on text extraction. If you're building automations on top of the server, this is the feature that matters most.

Universal Install

npx skills add Frihet-io/frihet-mcp
Enter fullscreen mode Exit fullscreen mode

Works with Claude Code, Cursor, Windsurf, and 30+ other agents that support the skills registry.

Architecture

User → AI Assistant (Claude/Cursor)
         ↓ MCP Protocol
    @frihet/mcp-server (npm)
         ↓ REST API calls
    api.frihet.io/v1
         ↓ Auth (X-API-Key)
    Firebase Cloud Functions
         ↓
    Firestore
Enter fullscreen mode Exit fullscreen mode

The MCP server is a thin bridge between any MCP client and Frihet's REST API. It runs in two modes:

Local (stdio): For Claude Code, Cursor, Windsurf. Runs as a local process.

{
  "mcpServers": {
    "frihet": {
      "command": "npx",
      "args": ["-y", "@frihet/mcp-server"],
      "env": { "FRIHET_API_KEY": "fri_your_key" }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Remote (streamable-http): Via mcp.frihet.io, a Cloudflare Worker that accepts MCP connections from anywhere.

What I Learned Building It

1. MCP tools need great descriptions

The AI reads your tool descriptions to decide which tool to use. Vague descriptions = wrong tool selection. I spent more time writing tool descriptions than writing the actual tool code.

Bad:

name: "create_invoice"
description: "Creates an invoice"
Enter fullscreen mode Exit fullscreen mode

Good:

name: "create_invoice"
description: "Create a new invoice for a client. Requires client_id, at least one line item with description and amount. Optionally accepts tax_rate, due_date, currency, and notes. Returns the created invoice with assigned number and calculated totals."
Enter fullscreen mode Exit fullscreen mode

2. Input validation is critical

AI models will send unexpected input shapes. Zod schemas for every tool input saved me from countless edge cases. The AI doesn't always respect your schema perfectly, so validate aggressively and return clear error messages.

3. Bilingual tool responses matter

Frihet supports ES and EN. The MCP server accepts a locale parameter and returns responses in the user's language. This sounds trivial but it makes a huge difference in UX when the AI passes through the response.

4. The remote MCP is harder than local

Local stdio is straightforward. The remote Cloudflare Worker using streamable-http had more edge cases: CORS, authentication headers, connection timeouts, and the fact that MCP sessions are stateful but Cloudflare Workers are stateless.

5. Open source builds trust

When your MCP server accesses financial data, users need to trust it. Making it MIT and putting the code on GitHub was a deliberate choice. Users can inspect exactly what the server does with their data. No black boxes.

The Difference Between API and MCP

Frihet already had a REST API. The MCP server is fundamentally different:

  • API = for developers who write code
  • MCP = for anyone who uses an AI assistant

Someone who doesn't code but uses Claude daily can now manage invoicing without opening a browser. A dev team in Cursor can query company data without switching context.

Real Usage Patterns I've Seen

  1. "Create invoice for [client] for [amount]" — Most common. The AI resolves the client by name, applies tax rules, assigns the number.

  2. "Show unpaid invoices older than 30 days" — Uses search_invoices with filters. The AI formats results into a readable summary.

  3. "What's my total revenue this quarter?" — Combines multiple API calls. The AI calculates totals from invoice data.

  4. "Record a 47.50 EUR fuel expense from yesterday" — Creates expense with correct date, category suggestion, and VAT deduction.

Try It

# Universal install (works with 30+ agents)
npx skills add Frihet-io/frihet-mcp

# Or run directly
npx @frihet/mcp-server
Enter fullscreen mode Exit fullscreen mode

Source: github.com/Frihet-io/frihet-mcp
npm: @frihet/mcp-server
Docs: docs.frihet.io

MIT license. 31 tools, 5 resources, 5 prompts. Works with Claude Code, Cursor, Windsurf, and any MCP client.

If you're building an MCP server for your product, happy to share more details in the comments.

Top comments (0)