e-conomic MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@e-conomic MCP Serverlist overdue invoices with customer names"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
e-conomic MCP Server by InboundCPH
A FastMCP server that exposes the Visma e-conomic REST API as 73 MCP tools over Streamable HTTP. The server is the gate in front of your e-conomic tokens: one access key per person, e-mail + password login hosted by the server, or Google/Microsoft login with an allowlist, plus read-only mode and an audit log. Runs on Railway in minutes.
Built by Ian Rosenfeldt, founder of INBOUND CPH A/S.
Dansk guide: GUIDE.md tager dig trin for trin gennem e-conomic-tokens, Railway, login og klienter. AI agents: AGENTS.md tells Claude Code / Codex how to set the server up for you.
Claude / Codex / Cursor ──login──▶ your MCP server (Railway) ──API tokens──▶ e-conomicQuick start
Let an AI coding agent do it (recommended):
git clone https://github.com/inbound-cph/economic-mcp-byinboundcph.git
cd economic-mcp-byinboundcph
claude # or: codexAsk: "Help me set up the e-conomic MCP server on Railway." The agent follows
AGENTS.md, runs the Railway CLI for you and tells you what to click in e-conomic,
Google/Microsoft and Railway.
Manual, with the Railway CLI from your clone:
railway login
railway init --name economic-mcp
railway add --service economic-mcp --variables "MCP_READ_ONLY=true" \
--variables "ECONOMIC_APP_SECRET_TOKEN=demo" --variables "ECONOMIC_AGREEMENT_GRANT_TOKEN=demo"
railway service economic-mcp && railway volume add --mount-path /data # login state survives deploys
python scripts/new_key.py cfo --service economic-mcp # prints a key once + the command to store it
railway domain --service economic-mcp
railway up --detach --service economic-mcp
python scripts/doctor.py --public-url https://<your-domain>Then replace the demo tokens with your own (GUIDE.md step 1), add one key per person or
personal login (step 3) and connect your client (step 4).
Related MCP server: Acumatica MCP Server
Features (73 tools)
Company:
get_company_info(agreement/company details via/self)Customers: list/get/create/update/delete customers, contacts, delivery locations, per-customer draft/booked invoices, totals, customer groups
Suppliers: list/get/create suppliers, supplier groups
Products: list/get/create/update/delete products, product groups
Invoices: draft/booked/sent/paid/unpaid/overdue/not-due invoices, invoice totals,
create_draft_invoice,update_draft_invoice,book_draft_invoice,register_invoice_as_sent,delete_draft_invoice, PDF download (draft + booked, base64)Quotes: draft/sent/archived quotes,
register_quote_as_sentOrders: draft/sent/archived orders
Accounting: chart of accounts, account entries by accounting year, accounting years, periods, year/period totals, journals, journal entries and vouchers,
create_finance_voucher,create_journal_voucher(raw)Reference data: payment terms, payment types, VAT zones/accounts/types, currencies, layouts, units, departments, departmental distributions, employees
Escape hatch:
economic_api_request— call any e-conomic REST endpoint (method, path, params, body) not covered by a dedicated tool
All list tools support pagination (skip_pages, page_size, maximum 1000). Filter-capable
list tools accept e-conomic filter syntax, e.g. name$like:acme, date$gte:2026-01-01,
customer.customerNumber$eq:123. Every tool carries MCP annotations (readOnlyHint,
destructiveHint) so clients can ask before changing the books.
Authentication
The server refuses to start without authentication. Pick a method by setting its variables; the mode is detected automatically.
Mode | Variables | Who gets in |
Access keys (simplest) |
| Whoever holds a key; the audit log shows the name; delete the variable to revoke |
E-mail + password login |
| The people listed, via the server's own login page. Works in claude.ai / Claude Desktop connectors without Google or Microsoft |
Google login |
| Google accounts on the allowlist with a verified e-mail |
Microsoft login |
| Members of your Entra tenant, further narrowed by the optional allowlist |
Which one? A small group (the CFO, a finance person, someone in management) using Claude Code, Codex, Cursor or Claude Desktop: access keys, one per person, no identity provider needed. Sharing the server with a whole organisation through claude.ai / Claude Desktop connectors (Team and Enterprise plans): those connectors require an OAuth login. Use Google or Microsoft login if you have Workspace or Microsoft 365 (everybody can see the connector, but only the e-mails on the allowlist or in your tenant get in), or e-mail + password login hosted by the server if you have neither. Keys can be combined with any login; the three login methods are mutually exclusive.
E-mail + password login in detail: the server hosts a small login page. Passwords are stored
only as PBKDF2-SHA256 hashes (600 000 rounds) in the MCP_USER_* variables, compared in
constant time; five failed attempts per e-mail or IP lock login for 15 minutes; each login
page belongs to a single short-lived OAuth transaction; authorization codes are single-use
with PKCE; access tokens live one hour, refresh tokens 30 days with rotation, stored as
hashes under FASTMCP_HOME so logins survive deploys. Because any MCP client can register
itself, the login page always shows the address the user will be sent back to, and
MCP_ALLOWED_CLIENT_REDIRECT_URIS (e.g. http://localhost:*,https://claude.ai/*) can
restrict destinations; set it when you know which clients you use. Clients refresh silently, so a user
who uses the server at least once every 30 days never logs in again; tune with
MCP_LOGIN_SESSION_DAYS (1–365) and MCP_LOGIN_ACCESS_TOKEN_MINUTES (5–1440). There is no
MFA and no self-service password reset: the admin runs new_user.py again. Prefer
Google/Microsoft when you have them.
Google and Microsoft login use OAuth 2.1 with PKCE through FastMCP's OAuth proxy: MCP
clients discover the server's OAuth metadata, register dynamically, the user sees a short
consent page and then the Google/Microsoft login. The allowlist is enforced when the
login completes (rejected accounts receive access_denied) and on every request.
Access keys can be combined with either login, for example keys for automations and a
few power users while everyone else signs in personally. MCP_ALLOWED_* without a login
mode is rejected as a misconfiguration.
Login needs the server's public URL: set MCP_PUBLIC_URL=https://…. On Railway it is
derived from RAILWAY_PUBLIC_DOMAIN automatically. Register
https://<domain>/auth/callback as the redirect URI at Google/Microsoft (exact console
steps in GUIDE.md step 3).
Login state (OAuth client registrations, encrypted upstream tokens) is stored under
FASTMCP_HOME. When a Railway volume is attached the server uses it automatically, so
users stay logged in across deploys. Optional hardening: MCP_JWT_SIGNING_KEY (keeps
sessions valid when you rotate the OAuth client secret) and
MCP_ALLOWED_CLIENT_REDIRECT_URIS (restrict which MCP clients may complete a login,
e.g. http://localhost:*,https://claude.ai/*).
MCP_ALLOW_UNAUTHENTICATED=true disables all of this for local testing only; the server
then listens on 127.0.0.1 and logs a warning.
Read-only mode, write users and audit log
MCP_READ_ONLY=truehides every tool that creates, changes, books or deletes anything (15 tools) and limitseconomic_api_requesttoGET. Start with it on.MCP_WRITE_USERS=cfo,anna@firma.dklimits the write tools to the listed identities (key names or e-mails) when read-only is off. Everyone else sees only the 58 read tools, cannot call the write tools even by name, and getsGETonly from the generic API tool.Every tool call is logged as
tool=… user=… status=… duration_ms=…on theeconomic-mcp.auditlogger.useris the e-mail of the logged-in person, the key name (cfo,anna) for personal access keys, orservice-token. Arguments and data are never logged.
Configuration reference
Variable | Default | Purpose |
|
| e-conomic |
|
| e-conomic |
| Google login | |
| Microsoft login | |
|
| Scope exposed by your Entra app |
| Comma-separated allowlist | |
| One access key per person (32+ chars); | |
| Access key for automations (identity | |
|
| |
|
| Lifetimes for e-mail login sessions and access tokens |
| from | Public https URL, needed for login |
|
| Hide write tools for everyone |
| everyone | Comma-separated key names / e-mails allowed to use write tools |
|
| Local testing only |
| derived from client secret | Signing key for issued tokens |
| all | Redirect URI patterns for MCP clients |
|
| Bind address |
|
| Injected by Railway |
| platform data dir / Railway volume | Login state storage |
|
| HTTPS only (http for localhost) |
|
| HTTP client tuning |
|
| Logging |
.env.example documents the same variables with comments.
e-conomic tokens
e-conomic uses two token headers (see developer docs):
X-AppSecretToken identifies your app, X-AgreementGrantToken grants it access to one
agreement. Both default to demo, e-conomic's read-only demo agreement.
Sign up for a free developer agreement at e-conomic.com/developer.
In the developer agreement: Apps → New app, choose the least role you need, save the AppSecretToken.
Click Tokens on the app, open the installation URL while logged into the target agreement, approve, and save the AgreementGrantToken.
Verify with
GET https://restapi.e-conomic.com/selforpython scripts/doctor.py.
Run locally
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # set MCP_AUTH_TOKEN_<NAME>, or MCP_ALLOW_UNAUTHENTICATED=true for local play
python server.py
python scripts/doctor.pyThe MCP endpoint is http://127.0.0.1:8000/mcp, health at /health.
Deploy on Railway
Two ways; both use railway.json (start command python server.py, health check /health).
From your clone with the CLI (see Quick start). Update with
git pull && railway up --detach.From a GitHub fork: New Project → Deploy from GitHub repo → set variables → Settings → Networking → Generate Domain. Railway redeploys when the fork changes.
The volume (railway service <name> then railway volume add --mount-path /data, part of the quick start) is where login
state lives; the server detects RAILWAY_VOLUME_MOUNT_PATH automatically. Without it every
deploy logs all users out.
Connect an MCP client
Endpoint: https://<your-domain>/mcp.
Claude Code
claude mcp add --transport http --scope user economic https://<your-domain>/mcp
# then /mcp inside Claude Code to log in; or, with an access key:
claude mcp add --transport http economic https://<your-domain>/mcp --header "Authorization: Bearer <your key>"claude.ai / Claude Desktop: Settings → Connectors → Add custom connector → paste the
URL → Connect (personal login). For access-key-only servers use mcp-remote:
{
"mcpServers": {
"economic": {
"command": "npx",
"args": ["-y", "mcp-remote@latest", "https://<your-domain>/mcp", "--header", "Authorization:${AUTH_HEADER}"],
"env": {"AUTH_HEADER": "Bearer <your-access-key>"}
}
}
}Codex
codex mcp add economic --url https://<your-domain>/mcp
codex mcp login economicAccess key instead: bearer_token_env_var = "ECONOMIC_MCP_TOKEN" under [mcp_servers.economic] in ~/.codex/config.toml.
Clients with native Streamable HTTP (.mcp.json, Cursor, Windsurf):
{
"mcpServers": {
"economic": {
"type": "http",
"url": "https://<your-domain>/mcp",
"headers": {"Authorization": "Bearer ${ECONOMIC_MCP_TOKEN}"}
}
}
}Omit headers when using personal login.
Skills (ready-made workflows)
The skills/ folder ships seven Danish skills for Claude Code, Codex and any client
that follows the Agent Skills standard: debtor follow-up, monthly report, customer 360,
account statements and reconciliation, precise data answers, draft invoices and journal
vouchers. Write skills always show a proposal and wait for a yes; booking is only done on
explicit request. See skills/README.md.
Install in Claude Code as a plugin:
/plugin marketplace add inbound-cph/economic-mcp-byinboundcph
/plugin install economic@economic-mcpOr copy them as personal skills for Claude Code and Codex:
python scripts/install_skills.pyTest
pip install -r requirements-dev.txt
python -m pytest -qThe suite uses FastMCP's in-memory client and HTTPX mock transport; it never touches e-conomic. It covers the e-conomic client, all auth modes and the allowlist, read-only mode, tool annotations, the audit log and the fail-closed startup.
Reliability and security
Mandatory authentication: per-person access keys or personal login with an allowlist enforced at login and per request; optional read-only mode; audit log with the caller's name.
Pooled HTTP client for the server lifespan; transport failures and HTTP
429,502,503,504retried with bounded backoff.Every non-GET operation carries one e-conomic
Idempotency-Key, reused across retries.API paths reject absolute URLs, query strings, fragments and relative traversal; product numbers and fiscal years use e-conomic's custom resource encoding.
API errors keep HTTP status, structured body, developer hint and
logIdwithout logging tokens.HTTPS-only base URL (http allowed for localhost only); no outbound calls other than e-conomic and the identity provider.
See SECURITY.md for the security model and how to report issues.
Notes / gotchas
Stateless Streamable HTTP with FastMCP's host/origin protection defaults.
e-conomic paginates with
skippages/pagesize(max 1000); exposed asskip_pages/page_size.register_invoice_as_sentbooks and sends the draft through/invoices/booked; likebook_draft_invoicethis is irreversible.register_quote_as_sentfetches and reposts the complete unchanged quote, as e-conomic requires.create_draft_invoicelines need aproductNumberthat exists on the agreement (list_products).demotokens are read-only; write tools fail with them.The e-conomic API has no versioned URL; runtime dependencies are pinned for reproducible deployments.
Troubleshooting
Server exits with "refuses to start": no auth configured. Set a personal key (
MCP_AUTH_TOKEN_<NAME>) or the Google/Microsoft variables."Invalid authentication configuration: …": the message names the missing or invalid variable.
access_deniedat login: the account is not on the allowlist (Google also requires a verified e-mail).E-mail login says "For mange forsøg": five wrong passwords locked that e-mail/IP for 15 minutes.
E-mail login page says the page expired: the login link is valid for 10 minutes and once; reconnect from the client.
Google
redirect_uri_mismatch: the redirect URI must be exactlyhttps://<domain>/auth/callback.Microsoft
AADSTS65001/AADSTS650057: add the scope under API permissions and setrequestedAccessTokenVersionto 2.Clients keep asking to log in after deploys: attach a Railway volume.
401from e-conomic: verify both tokens and that the grant has not been revoked.Write tools missing:
MCP_READ_ONLY=true; set it tofalsewhen you are ready.429or temporary5xx: retried automatically; adjustECONOMIC_MAX_RETRIESonly if necessary.Invalid fiscal-year path: pass the exact
yearfromlist_accounting_years; split years such as2025/2026are encoded automatically.
API reference
REST docs: https://restdocs.e-conomic.com/
FastMCP auth: https://gofastmcp.com/servers/auth
Contributing
This is a public, source-available project by InboundCPH. Improvements are welcome:
open an issue or a pull request. Run python -m pytest -q before submitting, keep write
tools tagged write, and never commit tokens or .env files. See CONTRIBUTING.md.
License
PolyForm Shield 1.0.0, see LICENSE. Copyright INBOUND CPH A/S. In short: you may use, change and share the software freely, including inside your own business and to help your own clients, but you may not sell it or offer it as a product or service that competes with it or with what INBOUND CPH offers using it.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Headless API-first double-entry accounting & bookkeeping engine. 84 MCP tools over HTTP.
wFirma.pl (Polish accounting) via MCP: invoices, contractors, payments, reports. Full read-write.
Fakturownia.pl (Polish invoicing) via MCP: invoices, clients, products, warehouse. Full read-write.
- OneOAuthai.withone
Search, document and execute authenticated API calls across 700+ apps via one MCP server
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables natural language management of e-conomic accounting, including customers, products, and invoices, with full CRUD and PDF download capabilities.17MIT
- AlicenseAqualityAmaintenanceEnables querying and acting on any Acumatica ERP tenant's contract-based REST API through 8 generic tools, covering all entities with read-only by default safety.8MIT
- AlicenseNot gradedqualityCmaintenanceProvides governed access to ConnectWise Manage (PSA) data including service tickets, companies, contacts, configurations, projects, sales, time, schedule, finance, and procurement through 68 tools, with read-only mode by default and optional write operations, deployed to Azure with credentials stored in Key Vault.MIT
- AlicenseNot gradedqualityBmaintenanceExposes ~60 tools for the Merit Aktiva accounting API, covering sales/purchase invoices, payments, customers, vendors, items, general ledger, offers, reference data, and reports with both read and write operations.17MIT