zero-mcp
MCP server for the German broker Finanzen.net ZERO 🇩🇪
Local stdio MCP server wrapping the unofficial Python client finanzen-zero-api.
Unofficial and unsupported. Finanzen.net ZERO has no public API. This server wraps
finanzen-zero-api, which mimics the broker's private web/app endpoints; they can change at any time. Use it only on an account you are allowed to automate, and never with money you cannot afford to lose. Order tools move real money.
zero-mcp turns the finanzen-zero-api Python client into a
local Model Context Protocol server. It is published on PyPI as
finanzen-zero-mcp and installs the zero-mcp
console script. An MCP host such as Claude Desktop, Claude Code or Cursor starts the server over
stdio; an assistant can then read the account, search instruments, inspect charts, list depot
positions and watchlist entries, review orders, and place or cancel orders. ZERO_MODE controls
whether the mutating tools are exposed and whether orders need confirmation — see
Configuration.
Contents
- Features
- Tools
- Requirements
- Installation
- Configuration
- Connect an MCP host
- Usage examples
- Authentication and 2FA
- Output conventions
- Safety and security
- Architecture
- Development
- Limitations
- Project status
- License
Features
- Full library coverage. Account, instrument search/master data/detail/charts, depot positions, watchlist, orders, and the app-push 2FA that unlocks order execution.
- Local stdio only. The MCP host spawns the process; there is no listening port, no browser and no Playwright/Selenium dependency.
- One serialized session. All tools share a single lock-protected
ZeroClient; broker calls are serialized so concurrent requests cannot race the login, session refresh, 2FA unlock or order flow. - Errors meant for a model. Missing configuration, bad credentials, 2FA timeouts, broker rejections and network failures become actionable MCP tool errors instead of stack traces.
- Offline test suite. A mocked broker client and a real stdio subprocess test; no live calls and no credentials needed in CI.
Tools
Fifteen tools are registered in the default mode. The ten read tools are always available; the five
write tools are absent from tools/list when ZERO_MODE=READ.
| Tool | Kind | What it does |
|---|---|---|
get_account |
read | Cash account (Verrechnungskonto): buying/transfer power, IBAN, saldo, closing date. |
search_instruments |
read | Typeahead search by name, WKN or ISIN; per-asset-class hit counts. |
get_instrument |
read | Master record: asset class, trading state, fees, venues and MIC codes. |
get_instrument_detail |
read | Market data and fundamentals: quote, ranges, volume, profile, dividends. |
get_chart |
read | Price history for one scale (Intraday … Maximum). |
get_positions |
read | Depot positions with quantity, latest quote and entry quotes. |
get_watchlist |
read | Watchlist entries with quotes and metadata. |
list_orders |
read | Orders from one filter bucket (the broker's UI tabs) — Open (working, default), Filled (executed) or Canceled — with has_next pagination info. |
get_session_status |
read | Whether the session is unlocked for order execution. |
list_enrolled_devices |
read | Devices that can receive the 2FA push (with serials). |
add_to_watchlist |
write | Add an instrument by ISIN. |
remove_from_watchlist |
write | Remove an instrument by ISIN. |
unlock_order_execution |
write | Send the app push and wait for approval. |
place_order |
write, real money | Place a market/limit/stop-limit/OCO/trailing-stop order. |
cancel_order |
write, real money | Cancel an open order by its order_id. |
Order tools unlock the 2FA session automatically and can block for up to 60 seconds while the push is
approved. Their confirmation policy is set by ZERO_MODE (see Configuration); for
device selection see Authentication and 2FA.
Requirements
| Requirement | Why |
|---|---|
| Python 3.13+ | The project targets 3.13 and is strictly typed. |
| A Finanzen.net ZERO account | Email + password login is the only supported method. |
| The ZERO mobile app | Needed only for order execution: the 2FA push is approved on a paired device. Read-only tools work without it. |
Network access to mein.finanzen-zero.net |
Every endpoint lives there. There is no sandbox. |
| An MCP host | Claude Desktop, Claude Code, Cursor, or any client that launches local stdio servers. |
Installation
From this checkout, with uv:
git clone https://github.com/wtfuii/zero-mcp.git
cd zero-mcp
uv sync
uv sync installs the server and its dependencies into .venv. The MCP host should run the
zero-mcp console script through uv run (see Connect an MCP host).
With pip:
pip install finanzen-zero-mcp
zero-mcp
Or run it without installing, with uv:
uvx --from finanzen-zero-mcp zero-mcp
The PyPI distribution is finanzen-zero-mcp; the console script keeps the shorter name zero-mcp.
zero-mcp reads MCP messages from stdin and writes them to stdout. Running it directly in a
terminal will appear to hang; that is expected — an MCP host normally owns the process.
Configuration
Configuration is read from environment variables, which the MCP host passes to the stdio process.
| Variable | Required | Default | Meaning |
|---|---|---|---|
ZERO_USERNAME |
for any broker call | — | The ZERO login e-mail address (the client's email). |
ZERO_PASSWORD |
for any broker call | — | The ZERO account password. |
ZERO_DEFAULT_DEVICE |
no | — | 2FA device serial used when several devices are enrolled. |
ZERO_MODE |
no | WRITE |
READ, WRITE or YOLO; see below. Case-insensitive. |
Startup and tools/list work without credentials; a tool call then fails with a clear
not configured message. Credentials are held in memory by the ZeroClient, are never written to
disk by this server, and are never logged. The password is stored as a SecretStr.
Environment variables are visible to the spawned process and (depending on the host) to other local processes. Do not commit an MCP config containing your password, and prefer
ZERO_MODE=READunless you actively want trading tools.
Safety modes (ZERO_MODE)
ZERO_MODE is one switch with three mutually exclusive, case-insensitive values:
| Value | Registered tools | Order confirmation |
|---|---|---|
READ |
read tools only; the five write tools (watchlist edits, 2FA unlock, place/cancel order) are not registered | not applicable |
WRITE (default) |
all fifteen tools | the model must obtain the user's explicit confirmation before place_order or cancel_order |
YOLO |
all fifteen tools | no confirmation requirement in the server instructions or order tool descriptions |
Tools removed in READ never appear in tools/list. WRITE and YOLO differ only in the
instruction attached to the order tools; neither changes tool annotations. In every mode the broker's
app-push 2FA and any tool-approval prompt configured in the MCP host still apply — the server cannot
override its host.
YOLOis a footgun. It removes the model-level requirement to ask before placing or cancelling an order. Use it only on an account and with amounts you can afford to trade without a human in the loop.
Connect an MCP host
Use an absolute path to this checkout:
{
"mcpServers": {
"finanzen-zero": {
"command": "uv",
"args": ["run", "--directory", "/absolute/path/to/zero-mcp", "zero-mcp"],
"env": {
"ZERO_USERNAME": "you@example.com",
"ZERO_PASSWORD": "your-password",
"ZERO_DEFAULT_DEVICE": "optional-device-serial",
"ZERO_MODE": "WRITE"
}
}
}
}
- Claude Desktop:
claude_desktop_config.json(Settings → Developer → Edit Config). - Cursor:
.cursor/mcp.json(project) or~/.cursor/mcp.json(global). - Any host that accepts
command/args/env.
GUI hosts often start with a minimal PATH that does not contain uv. After uv sync, point the
config at the console script directly instead:
{
"mcpServers": {
"finanzen-zero": {
"command": "/absolute/path/to/zero-mcp/.venv/bin/zero-mcp",
"env": {
"ZERO_USERNAME": "you@example.com",
"ZERO_PASSWORD": "your-password"
}
}
}
}
On Windows the script is .venv\Scripts\zero-mcp.exe.
Claude Code
claude mcp add finanzen-zero \
--env ZERO_USERNAME=you@example.com \
--env ZERO_PASSWORD=your-password \
--env ZERO_MODE=WRITE \
-- uv run --directory /absolute/path/to/zero-mcp zero-mcp
Read-only setup
Enable only the ten read tools and keep the trading surface out of the model's context entirely:
{
"mcpServers": {
"finanzen-zero": {
"command": "uv",
"args": ["run", "--directory", "/absolute/path/to/zero-mcp", "zero-mcp"],
"env": {
"ZERO_USERNAME": "you@example.com",
"ZERO_PASSWORD": "your-password",
"ZERO_MODE": "READ"
}
}
}
}
Restart the MCP host after changing environment variables. The process logs its mode and whether credentials are configured to stderr on startup, never to stdout.
Usage examples
Once the server is connected, ask the assistant in natural language:
- “What is my current buying power and next closing date?”
- “Search for Apple and show me the one-year chart.”
- “Which positions do I hold and what are they worth at the latest quote?”
- “List my open orders and cancel order ID
GBR….” - “Place a limit buy for 1 share of Apple at €200 on gettex.”
- “I approved the push — check whether order execution is unlocked.”
The assistant discovers the account through the read tools. There is no separate login tool, and the shared session is reused across calls.
Authentication and 2FA
Login is handled entirely by finanzen-zero-api:
- The first broker call performs a Cognito SRP login over HTTP through the broker's
/apic/authcproxy. No browser and no API key are involved. - The one-hour IdToken is refreshed with the refresh-token cookie; a rejected session is re-established once and the request retried.
- Sessions are in memory. Restarting the MCP server logs in again; no cookies are persisted.
Order execution additionally requires the app-push session TAN unlock:
place_order/cancel_orderprobeis_authorized; when locked they request a push to the configured device and wait for approval.unlock_order_executionexposes that step explicitly, with a configurable timeout and no-op when already unlocked. It is useful only for pre-authorizing a batch or waiting longer than the order tools' built-in 60 seconds.- If exactly one device is enrolled it is used automatically. With several devices, set
ZERO_DEFAULT_DEVICEor calllist_enrolled_devicesand pass a serial; otherwise the call fails rather than guessing.
Keep the host clock synchronized (NTP): SRP signs a UTC timestamp, and large clock skew makes the login fail.
Output conventions
- Tool results are JSON objects. Lists are nested under a descriptive key (
positions,orders,entries,devices,bars) and usually come with acount. - Keys use the Python client's snake_case field names (the names documented in the
finanzen-zero-apiREADME), not the broker's camelCase wire aliases. - Account, position, order and watchlist amounts are decimal strings (e.g.
"1000.50") so precision survives the JSON round-trip. Parse them before doing arithmetic. Market-data values such as chart bars and instrument detail quotes keep the broker's wire floats and are numbers. - Timestamps are ISO 8601 strings; dates use
YYYY-MM-DD. Account amounts are EUR; instrument and order prices use the instrument's quote currency (quote_currency_code), not necessarily EUR. - Failures are MCP
isErrorresults with a human/model-readable message, including the broker's HTTP status, error code and field errors when available.
Safety and security
- Real orders.
place_orderandcancel_orderare markeddestructiveHintandreadOnlyHint=false. A market order can fill immediately and cannot be undone. If a placement fails after submission (timeout or network error), checklist_ordersbefore retrying — the order may already exist. - Credentials. Passwords arrive via environment variables and stay in memory. This server does
not read
.envfiles, keychains or config files. Treat MCP host config files as secrets when they containZERO_PASSWORD. - Unofficial endpoints. The broker can change or block these private endpoints at any time; schema drift is surfaced as a tool error rather than silently wrong data. Automating a brokerage account may violate the broker's terms — use only an account you are allowed to automate.
Architecture
src/zero_mcp/
├── server.py # MCPServer (MCP SDK v2), dynamic tool registration, stdio main()
├── config.py # ZERO_* env settings, lazy credential validation
├── client.py # ClientProvider + lazy, lock-protected shared ZeroClient
├── errors.py # zero_api/httpx exceptions → actionable ToolError
├── serialization.py # Pydantic model → JSON-safe dict
├── __main__.py # python -m zero_mcp
└── tools/ # vertical slices, one module per broker area
├── account.py
├── instrument.py
├── portfolio.py
├── watchlist.py
├── orders.py
└── sessiontan.py
The MCP server is deliberately thin: it owns argument mapping, error translation, tool annotations,
ZERO_MODE gating and the confirmation/YOLO instructions. Everything else — HTTP, SRP login, refresh,
2FA, Pydantic models — belongs to finanzen-zero-api.
Development
uv sync
uv run mypy . # strict; run first
uv run pytest # offline; no broker calls
uv build # wheel + sdist
uvx twine check --strict dist/*
To exercise the server by hand, launch it through any MCP client or the MCP Inspector:
npx @modelcontextprotocol/inspector uv run --directory . zero-mcp
Set ZERO_USERNAME/ZERO_PASSWORD in the inspector's environment only if you intend to make live
(read-only) calls. There is no live smoke test in CI and tests must never contact the broker.
See AGENTS.md for the architecture rules, MCP SDK conventions and contribution
constraints. Releases are cut from a vX.Y.Z tag and published to PyPI through Trusted Publishing;
see RELEASING.md for the registry setup and release checklist.
Limitations
- Version coupling. The wrapper pins
finanzen-zero-api>=0.1.0,<0.2.0. Model or endpoint changes in the alpha client can break tool output until the wrapper is updated. - stdio only. No HTTP/SSE transport, no multi-user server, no OAuth. One process, one account.
- No order modification. The broker client supports placing and cancelling, not amending.
- Blocking 2FA.
place_order,cancel_orderandunlock_order_executionwait for the phone approval; MCP hosts with a short tool timeout may abort the call before the push is accepted. - No streaming quotes. Charts and details are snapshots returned by the private endpoints.
- One page of orders.
list_ordersreturns a single page plushas_next; the page size is bounded by the tool'ssizeargument (max 1000). - Unknown rate limits. The broker publishes none; avoid tight polling loops.
Project status
Alpha (0.1.0). All slices currently supported by finanzen-zero-api are wrapped: account,
instruments, portfolio, watchlist, orders and session TAN/2FA. The tool surface may change between
minor versions while the wrapper stabilizes. Pin the version you depend on.
License
MIT — see LICENSE. This project is not affiliated with Finanzen.net, Finanzen.net ZERO, or Baader Bank.
Metadata
Release files for finanzen-zero-mcp 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| finanzen_zero_mcp-0.1.0.tar.gz | 22.1 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| finanzen_zero_mcp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 51.7 kB
Release files / finanzen_zero_mcp-0.1.0.tar.gz
| Download URL | finanzen_zero_mcp-0.1.0.tar.gz |
|---|---|
| Size | 22.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
80cc47e90ee800352e488a7ab39b6c071f361d9f7e5264f4f504d255bb21b87b
|
|
BLAKE2b-256 checksum How to use checksums |
a924c12e5eec208433b011eb97c86c26ee6d1b88e6a877999fd568049ae95e84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.
Transparency logRelease files / finanzen_zero_mcp-0.1.0-py3-none-any.whl
| Download URL | finanzen_zero_mcp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 29.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4939f62cc754842e902d66f6ad21329e8b90afb45af6343f0d47c0be16c08d47
|
|
BLAKE2b-256 checksum How to use checksums |
47cb5c25fb7e45c888c32622416c8a21b62b6902ee485dd9bb4ff2118267b8f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.
Transparency logSecurity for finanzen-zero-mcp 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for finanzen_zero_mcp-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.