CLAUDE.md · git:20260729.96d1c6a · 2026-07-29 · sha256 356875235152e5ad

CLAUDE.md git:20260729.96d1c6aA

Immutable. This exact content is served forever at /api/v1/blob/356875235152e5ad.

# CLAUDE.md — Frihet MCP Server

Guidance for AI coding assistants working on this repository. See `AGENTS.md` for build commands and contribution conventions.

## What is this

MCP server that connects AI assistants (Claude · ChatGPT · Cursor · Windsurf · Cline · Antigravity · Codex · Copilot · Gemini CLI) to Frihet ERP. Natural language → invoices, expenses, clients, fiscal reports.

**Live:**
- npm: https://www.npmjs.com/package/@frihet/mcp-server (v1.16.1, 157 tools)
- MCP remote: https://mcp.frihet.io (Cloudflare Worker)
- Smithery: https://smithery.ai/servers/frihet/frihet-mcp
- Anthropic registry: https://registry.modelcontextprotocol.io/?q=io.frihet
- License: MIT

**Repo:** `Frihet-io/frihet-mcp`

---

## Stack

- Node.js >= 18
- TypeScript (strict, target ES2022)
- `@modelcontextprotocol/sdk` (peer dep)
- Zero runtime deps (only 1 in package.json — minimal surface)
- Distribution: npm + Cloudflare Worker (mcp.frihet.io) + Smithery
- Tests: native `node --test` runner

---

## Architecture

```
src/
  index.ts             — MCP server entry (Server + transport)
  client.ts            — Frihet API HTTP client (Bearer auth)
  client-interface.ts  — Typed interface for client mocking
  types.ts             — Shared TypeScript types
  logger.ts            — Structured logging
  observability.ts     — Langfuse LLM observability
  metrics.ts           — Tool call metrics
  openai-profile.ts    — OpenAI compatibility profile
  tools/
    register-all.ts    — Tool registration entry
    invoices.ts        — invoice tools
    expenses.ts        — expense tools
    clients.ts         — client tools
    products.ts        — product tools
    quotes.ts          — quote tools
    crm.ts             — CRM tools
    deposits.ts        — deposit tools
    vendors.ts         — vendor tools
    webhooks.ts        — webhook tools
    einvoice.ts        — e-invoice tools
    intelligence.ts    — AI insights tools
    shared.ts          — Cross-tool helpers
  resources/
    register-all.ts    — MCP resources (read-only context)
  prompts/
    register-all.ts    — MCP prompts (templated)
```

---

## Cross-references

- API client: hits `https://api.frihet.io/v1` (managed in `src/client.ts`)
- Auth: Bearer token from env `FRIHET_API_KEY` (format `fri_*`)
- Observability: Langfuse wired, optional (env `LANGFUSE_PUBLIC_KEY` + `LANGFUSE_SECRET_KEY`) — see `docs/observability.md`
- Worker: `mcp.frihet.io` is a Cloudflare Worker — separate deployment surface (`workers/remote-mcp/`)

---

## Tool design pattern

Every tool follows this contract:

```typescript
server.registerTool(
  'frihet.invoices.create',
  {
    title: 'Create invoice',
    description: 'Create a new invoice for a client. Returns invoice ID + total + PDF URL.',
    inputSchema: { /* Zod or JSON schema */ },
    annotations: {
      readOnlyHint: false,
      destructiveHint: false,
      idempotentHint: false,
      openWorldHint: true,
    },
  },
  async (input) => {
    // 1. Validate input (Zod)
    // 2. Call Frihet API V1 via client
    // 3. Return structured output (NOT prose)
    return { content: [{ type: 'text', text: JSON.stringify(result) }] };
  }
);
```

**Rules**:
- Tool name: `frihet.<resource>.<action>` (dot-separated, lowercase)
- `description` clear in 1 line, mentions input + output
- `inputSchema` strictly typed
- Output: structured JSON, NOT prose
- Idempotency where possible (use `Idempotency-Key` HTTP header)
- Errors: throw `McpError` with cause + suggestion

---

## Build & Test

```bash
npm run build          # tsc → dist/
npm test               # npm run build && node --test dist/__tests__/*.test.js
npm start              # node dist/index.js (local stdio)
```

**Pre-publish checklist**:
- [ ] `npm run build` clean
- [ ] `npm test` all pass
- [ ] Tool count in README badge matches actual count
- [ ] CHANGELOG.md updated
- [ ] Version bumped (semver)
- [ ] Smoke test: install fresh from npm in temp dir + run

---

## Quality bar

Tool errors propagate to user agents which act on the user's business data — treat every change accordingly.

- **Idempotency** — `src/client.ts` mints an `Idempotency-Key` for EVERY mutating
  request (`src/__tests__/idempotency-key-contract.test.ts` pins it on the wire).
  Accepting a caller-supplied key as a tool input is a separate, per-tool step:
  today only `create_credit_note` does (`src/tools/invoices.ts`). Adding it to a
  tool means adding its test in the same diff.
- **Input validation** — strict Zod schemas. Reject ambiguous input rather than infer.
- **Auth scope** — tools must respect API key scope. No privilege escalation.
- **Rate limiting** — client-side backoff on 429. Don't burn the user's quota.
- **PII** — never log full request bodies. Mask NIF/IBAN/email in logs.
- **Side effects** — destructive tools (delete, refund) need an explicit confirmation pattern.

---

## Contact

**Maintainer:** Frihet (https://frihet.io) · support@frihet.io