Skip to main content
Glama
geneva-tax-mcp

geneva-tax-mcp

by cyrusgch

Geneva Tax MCP

A strictly read-only local MCP server for Geneva (Switzerland) personal tax declarations (GeTax / Dr. Tax PDFs) and tax simulations via the official ESTV calculator.

No write, submit or send tool. Read-only by construction.

Quick examples

Show my 2024 salary and tax totals, including the source page and extraction confidence.

Compare my 2023 and 2024 declarations and show only recognized differences.

Estimate the tax for a hypothetical single household in Geneva, using only the income and deductions I provide explicitly.

Related MCP server: estv-tax

Features

MCP tool

Purpose

list_tax_returns()

Years and documents available in the local folder

get_tax_return(year, sections, include_raw)

Normalized declaration (ICC/IFD totals, key fields, provenance, confidence)

compare_tax_returns(year1, year2)

Differences between two years on recognized fields

simulate(...)

Tax simulation via the official ESTV calculator (Geneva included)

find_location(query, year)

Resolve a municipality/postal code to an ESTV tax location id

list_deductions_estv(...)

ESTV deduction sheet for a household

Every extracted value carries its provenance (document, original label, and page for text-layer PDFs) and a confidence level (exact / approx), and distinguishes zero / absent / unrecognized. Responses only expose paths relative to the tax folder.

Installation

Prerequisites: Python 3.11+, Tesseract (for OCR of scanned PDFs, optional).

git clone https://github.com/cyrusgch/geneva-tax-mcp.git mcp-taxes
cd mcp-taxes
py -m venv .venv                      # or python3 -m venv .venv
.venv/Scripts/python.exe -m pip install -e .   # Windows
# .venv/bin/pip install -e .                    # macOS / Linux

# French language pack for OCR (optional, ~1.1 MB)
curl -L -o tessdata/fra.traineddata https://github.com/tesseract-ocr/tessdata_fast/raw/main/fra.traineddata

MCP configuration

The tax folder is auto-detected (Windows: My Drive\Impots, Impots, Documents\Impots; macOS: Google Drive, Documents/Impots; Linux: ~/Impots...). Override:

export GENEVA_TAX_DATA_ROOT="/path/to/my/tax/folder"   # optional

Claude Code

claude mcp add geneva-tax -s project \
  -e "GENEVA_TAX_DATA_ROOT=C:\path\to\tax\folder" \
  -- "/path/to/mcp-taxes/.venv/Scripts/python.exe" -m geneva_tax_mcp.server

Codex (OpenAI)

codex mcp add geneva-tax \
  --env "GENEVA_TAX_DATA_ROOT=C:\path\to\tax\folder" \
  -- "C:\path\to\mcp-taxes\.venv\Scripts\python.exe" -m geneva_tax_mcp.server

Or directly in ~/.codex/config.toml:

[mcp_servers.geneva-tax]
command = "C:/path/to/mcp-taxes/.venv/Scripts/python.exe"
args = ["-m", "geneva_tax_mcp.server"]
env = { GENEVA_TAX_DATA_ROOT = "C:/path/to/tax/folder" }

Verify with codex mcp list.

Generic format (any stdio MCP client)

{
  "mcpServers": {
    "geneva-tax": {
      "command": "/path/to/.venv/bin/python",
      "args": ["-m", "geneva_tax_mcp.server"],
      "env": { "GENEVA_TAX_DATA_ROOT": "/path/to/tax/folder" }
    }
  }
}

Tests

.venv/Scripts/python.exe -m pip install -e ".[dev]"   # installs pytest
.venv/Scripts/python.exe -m pytest tests/ -q

Anonymized fixtures (Jean Dupont), no real data. Includes store, simulator (mocked HTTP), OCR, symlink and corrupted-PDF tests.

.venv/Scripts/ruff.exe check src tests scripts      # lint
.venv/Scripts/ruff.exe format --check src tests scripts
.venv/Scripts/python.exe -m pytest tests/ -q --cov=geneva_tax_mcp --cov-fail-under=70

A GitHub Actions workflow (.github/workflows/ci.yml) runs lint, format and the coverage-gated suite on every push and pull request (Ubuntu + Windows, Python 3.11/3.12/3.13).

Security and privacy

  • No writes into the data folder (PDFs opened read-only). The only writes are the technical ESTV cache, which is forced to the project cache/ folder (an external ESTV_MCP_CACHE_DIR cannot redirect it), gitignored, purged after 7 days, and contains only the explicit simulation parameters you sent and the returned estimates (no PDF content). Note: because the project lives in a cloud-synced folder (e.g. Google Drive), this cache is synchronized too — it is not encrypted.

  • Simulations only send explicit parameters to the official ESTV calculator (swisstaxcalculator.estv.admin.ch, whitelisted), and return the sent payload for audit.

  • Simulation results = estimates produced by the official ESTV calculator, non-binding.

  • MCP responses expose paths relative to the tax folder (no username/machine layout).

Known limitations

  • 2025 "Dr. Tax" PDF: partially badly encoded fonts (partial extraction).

  • Scanned forms: automatic OCR via Tesseract (approx confidence).

  • .tax GeTax files: binary dvbern-tax format, encrypted, not usable without GeTax (see scripts/spike_tax.py).

  • Undocumented ESTV API: may change without notice; retry on rate limit.

Structure

src/geneva_tax_mcp/   MCP server, PDF parser, store, simulator, ESTV client, OCR
scripts/              tools (.tax spike)
tests/                anonymized fixtures + regression tests
ARCHITECTURE.md       design decisions, trust boundaries and roadmap
AGENTS.md             guide for AI agents

License

MIT — see LICENSE. The ESTV client (src/geneva_tax_mcp/estv_client.py) is vendored code from noaahh/estv-mcp (MIT), attribution kept.

Available Tools

6 tools
compare_tax_returnsA

Compare two declarations on the recognized fields (totals + key fields).

Returns the values for both years and the difference (year2 - year1). Only fields recognized with confidence are compared.

Inputs: year1 (required), year2 (required). Returns: object

find_locationB

Resolve a municipality name or postal code to an ESTV tax location id (for simulate).

Inputs: query (required), language, tax_year. Returns: object

get_tax_returnA

Return the normalized declaration for a year.

sections filters the detailed fields (e.g. ["salary", "movable_wealth"]). Summary totals (ICC/IFD) are always included. include_raw=True adds all raw PDF lines with their page number.

Inputs: year (required), sections, include_raw. Returns: object

list_deductions_estvC

List the ESTV deduction sheet for a household (ids to pass to simulate).

Inputs: income1 (required), location (required), age1, age2, +10 more. Returns: object

list_tax_returnsA

List the tax years and documents available in the local folder.

Returns, per year, the documents found (GeTax form, summary, supporting documents, scans) and whether a text-layer form is usable. Paths are relative to the tax folder.

Inputs: no named parameters. Returns: object

simulateA

Simulate the tax of a household with the official ESTV calculator.

EXPLICIT parameters (no data is injected automatically from the PDFs). location: postal code or municipality name (e.g. '1201', 'Genève', 'Carouge'). deductions: ids from the ESTV sheet (see list_deductions_estv), e.g. {'PRAEMIEN3A': 7258}. Returns the payload sent (audit) and a non-binding estimate.

Inputs: income1 (required), location (required), age1, age2, +12 more. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 6 tools

    Disambiguation5/5

    Each tool targets a distinct operation: listing available returns, retrieving a normalized declaration, comparing two declarations, listing deduction options, simulating tax, and resolving location IDs. Even the two list_* tools are clearly separated by their object.

    Naming Consistency4/5

    Most tools follow a clear snake_case verb_noun pattern such as get_tax_return, list_tax_returns, and find_location. The single tool named simulate is the only mild deviation because it lacks an explicit object, but the pattern remains predictable overall.

    Tool Count5/5

    Six tools is a well-scoped size for this domain. Each tool supports a distinct part of the tax workflow without redundancy or unnecessary surface area.

    Completeness5/5

    The toolset covers the full local workflow: discover available returns, retrieve normalized data, compare years, load deduction options, resolve locations, and run simulations. There are no apparent dead ends for an agent trying to analyze or estimate a household's Swiss tax situation.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      Enables AI assistants to calculate Swiss income, wealth, inheritance, capital payment, and corporate taxes for any municipality, compare tax burdens, and find cheapest locations without an API key.
      13
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Enables parsing German bank statement PDFs into structured, validated transaction data, exporting all transactions as German-style CSV, and verifying statement totals via proof calculations, all locally within MCP-compatible clients.
      3
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables an AI assistant to build and update an IRPF 2026 tax return entirely on your machine, reading and writing the official program's .DBK backup file, adding income and expenses, computing tax under both the simplified and complete models, explaining every calculation line by line, checking integrity and flagging pending items. Nothing is sent over the network, and the resulting file is restored and transmitted by the user in the official Receita Federal program.
      AGPL 3.0