mcp-kraken
[!WARNING]Alpha software. Interfaces and defaults may change in any minor releaseuntil v1.0. No liability for any financial loss, missed trades ormisrouted withdrawals. Not financial advice. Not affiliated with Kraken orPayward Inc. See the full Disclaimer below before grantingthe server credentials with trading or withdrawal permissions.
An MCP server that exposes the Kraken cryptocurrencyexchange Spot REST API over HTTP, secured with bearer tokens you managelocally.
- Full Kraken Spot REST surface, mapped to typed MCP tools.
- Proactive API-key permission detection — calls that the key cannot performare rejected before they leave the box, with a clear error.
- Built-in token CLI: generate, list, and revoke bearer tokens used by HTTPclients to authenticate against the MCP itself.
GET /healthliveness probe — no credentials required; safe for Dockerhealthchecks, Kubernetes probes, and load-balancer pings.- Single-process, stateless beyond the SQLite token store; ready forcontainerised deployment behind a reverse proxy.
WebSocket v2 and FIX transports are explicitly out of scope for the firstrelease — see TODO.md.
Architecture
┌────────────┐ HTTPS / bearer ┌───────────────┐ HMAC-signed ┌─────────┐
│ MCP client │ ───────────────────▶ │ mcp-kraken │ ─────────────────▶│ Kraken │
│ (Claude…) │ ◀─────────────────── │ FastMCP HTTP │ ◀─────────────── │ REST v0 │
└────────────┘ └───────────────┘ └─────────┘
│
▼
SQLite (bearer-token hashes)
Two authentication boundaries:
| Boundary | Mechanism |
|---|---|
| MCP client → mcp-kraken (you control) | Opaque bearer tokens (SHA-256) |
| mcp-kraken → Kraken (you control) | KRAKEN_API_KEY + HMAC signature |
Requirements
- Python
>=3.12 - uv for dependency management
- just for the dev command runner (optional)
- A Kraken Spot API key — generate one inAccount → Security → API. Thepermissions you enable on the key directly determine which MCP tools succeed(see Permissions below).
Quick start
# Clone and install
git clone https://github.com/XavierBeheydt/mcp-kraken.git
cd mcp-kraken
uv sync --dev
# Configure
cp .env.example .env
$EDITOR .env # set KRAKEN_API_KEY and KRAKEN_API_SECRET
# Issue a bearer token for your MCP client
uv run mcp-kraken token create "claude-desktop" --expires-in 90d
# → copy the printed token; it will never be shown again
# Start the HTTP server (defaults to 0.0.0.0:8765/mcp)
uv run mcp-kraken serve
Point your MCP client at http://localhost:8765/mcp/ and authenticate withthe bearer token. Two methods are supported:
| Method | When to use |
|---|---|
Authorization: Bearer mck_… header |
Preferred — token stays out of URLs and logs |
?apikey=mck_… query parameter |
Fallback for clients that cannot set custom headers (e.g. Claude Desktop remote connector) |
The server strips ?apikey= from the URL before forwarding to the MCPlayer, and redacts it from access logs (apikey=***).
CLI
mcp-kraken serve # run the HTTP server
mcp-kraken token create NAME # mint a new bearer token (printed once)
mcp-kraken token list # list known tokens (hashes only)
mcp-kraken token revoke ID # revoke a token by id
mcp-kraken version # print the installed version
token create accepts --expires-in 90d (or 12h, 30m, 3600 seconds).Omit it for a token that never expires. The full plaintext is only shown onceat creation — the server only stores the SHA-256 hash plus the short id.
Local testing with Claude Desktop
Claude Desktop accepts MCP servers either as a remote HTTPS connector or as alocal command (stdio). Pure self-signed certs are rejected — the cert has tobe signed by a CA the OS trusts.
Option A — HTTPS via mkcert (Custom Connector)
mkcert creates a local CA, installsit into the system trust store, and signs certs from it.
brew install mkcert # or your package manager's equivalent
just cert-local # mkcert -install + generates certs/{key,cert}.pem
just serve-https # serves HTTPS on 0.0.0.0:8765/mcp
Then in Claude Desktop: Settings → Connectors → Add custom connector, withURL https://localhost:8765/mcp/ and the bearer token frommcp-kraken token create.
Tip — Claude Desktop cannot set custom headers. If the connector UIhas no "Authorization header" field, append the token as a query paraminstead:
https://localhost:8765/mcp/?apikey=mck_…The server converts it to a properAuthorization: Bearerheaderinternally and redacts the value from its access logs.
Option B — stdio (Command Connector)
For purely local use you can skip HTTPS entirely:
uv run mcp-kraken serve --stdio
Wire it into Claude Desktop's config file (claude_desktop_config.json):
{
"mcpServers": {
"kraken": {
"command": "uv",
"args": ["--directory", "/abs/path/to/mcp-kraken", "run", "mcp-kraken", "serve", "--stdio"],
"env": {
"KRAKEN_API_KEY": "...",
"KRAKEN_API_SECRET": "..."
}
}
}
}
stdio sessions are inherently local — the bearer-token layer is bypassed.
Configuration
Settings come from environment variables, optionally loaded from .env:
| Variable | Default | Purpose |
|---|---|---|
KRAKEN_API_KEY |
— | Kraken API public key. |
KRAKEN_API_SECRET |
— | Kraken API private key (base64). |
KRAKEN_BASE_URL |
https://api.kraken.com |
Override for testing. |
MCP_KRAKEN_HOST |
0.0.0.0 |
Bind address. |
MCP_KRAKEN_PORT |
8765 |
TCP port. |
MCP_KRAKEN_PATH |
/mcp |
HTTP path the MCP transport mounts on. |
MCP_KRAKEN_TOKEN_DB |
./data/tokens.db |
SQLite file holding bearer-token metadata. |
MCP_KRAKEN_SSL_KEYFILE |
— | TLS private key (PEM). Pair with _SSL_CERTFILE. |
MCP_KRAKEN_SSL_CERTFILE |
— | TLS certificate (PEM). Pair with _SSL_KEYFILE. |
MCP_KRAKEN_HTTP_TIMEOUT |
30 |
Seconds before outbound Kraken calls time out. |
MCP_KRAKEN_LOG_LEVEL |
INFO |
Standard Python log level. |
MCP_KRAKEN_AUTH_DISABLED |
false |
Dev only. Skip bearer-token enforcement. |
The full sample lives in .env.example.
Tools
Public market-data tools (no Kraken credentials needed):
get_server_time, get_system_status, get_assets, get_asset_pairs,get_ticker, get_ohlc, get_order_book, get_recent_trades,get_recent_spreads.
Private tools (require KRAKEN_API_KEY + KRAKEN_API_SECRET):
- Account:
get_account_balance,get_extended_balance,get_trade_balance,get_trade_volume,get_ledgers,query_ledgers,get_credit_lines,get_api_key_info,request_export_report,get_export_status,retrieve_export,remove_export. - Trading:
get_open_orders,get_closed_orders,query_orders,get_trade_history,query_trades,get_open_positions,add_order,add_order_batch,amend_order,edit_order,cancel_order,cancel_all_orders,cancel_all_orders_after,cancel_order_batch. - Funding:
get_deposit_methods,get_deposit_addresses,get_deposit_status,get_withdrawal_methods,get_withdrawal_addresses,get_withdrawal_info,withdraw,get_withdrawal_status,cancel_withdrawal,wallet_transfer. - Earn:
list_earn_strategies,list_earn_allocations,allocate_earn,deallocate_earn,get_earn_allocation_status,get_earn_deallocation_status. - Subaccounts:
create_subaccount,account_transfer. - WebSocket auth:
get_websockets_token(token for the future WS layer —seeTODO.md).
Kraken API key permissions
Kraken keys can be issued with any subset of:
| UI label | Capability flag |
|---|---|
| Query funds | query_funds |
| Deposit | deposit |
| Withdraw | withdraw |
| Earn | earn |
| View open orders & trades | query_open_orders |
| View closed orders & trades | query_closed_orders |
| Create & modify orders | create_modify_orders |
| Cancel & close orders | cancel_orders |
| View ledger entries | query_ledger |
| Export data | export_data |
| WebSocket interface | websocket |
On the first private call, mcp-kraken introspects the key viaGetAPIKeyInfo and caches the resulting permission set. Subsequent toolinvocations are checked against that cache; missing permissions raiseKrakenPermissionError with the list of flags the key would need. If theintrospection itself fails (older keys may not support GetAPIKeyInfo), theserver falls back to letting Kraken enforce permissions over the wire.
IP restrictions, expiry, query date ranges, and custom nonce windows areconfigured on the key itself in the Kraken UI; the server passes throughwhatever the key allows.
Development
just sync # uv sync --all-extras --dev
just test # pytest
just check # lint + format-check + mypy + tests
just fix # auto-fix lint and format
just docker-build # local image build
Run just with no arguments for the full recipe list.
Docker
The published image is ghcr.io/xavierbeheydt/mcp-kraken:
| Tag | Pushed by | Notes |
|---|---|---|
latest |
release workflow | Latest non-prerelease tag. |
vX.Y.Z, vX.Y, vX |
release workflow | Semver tags on every release. |
dev |
dev-publish workflow | Tip of the dev branch. |
dev-<sha7> |
dev-publish workflow | Per-commit tag on dev. |
The reference deployment uses compose.yml:
cp .env.example .env # set KRAKEN_API_KEY / KRAKEN_API_SECRET
docker compose up -d
The container runs as a non-root user (uid 10001), with a read-only rootfilesystem, no added capabilities, and a SQLite token-store volume at/data. Put it behind a TLS-terminating reverse proxy in production — theserver speaks plain HTTP internally.
Health endpoint
GET /health returns 200 {"status":"ok"} without a bearer token — safefor orchestrators, load balancers, and uptime monitors:
curl http://localhost:8765/health
# {"status":"ok"}
Both the Dockerfile HEALTHCHECK and compose.yml use this endpoint.
Versioning & release flow
Versions are derived from git tags viahatch-vcs; there is no version numberto bump in pyproject.toml.
feature → PR → dev → dev-publish workflow → ghcr.io/…:dev[-sha]
↑
test workflow
tag v1.2.3 → release workflow → ghcr.io/…:1.2.3, :latest
+ GitHub Release
+ fast-forward main to the tag
Branch conventions:
main— protected; always equals the latest released commit.dev— default integration branch; every push runs tests and republishesthe:devimage.- topic branches → PR into
dev. - Releases are cut by tagging the desired
devcommitvX.Y.Z. The releaseworkflow tests it, builds and pushes the image with semver tags, opens aGitHub Release with auto-generated notes, and fast-forwardsmainto thetag. Ifmaincannot be fast-forwarded (e.g.mainhas diverged) theworkflow emits a warning and leaves the merge for a human.
To prerelease, tag v1.2.3-rc1: the workflow builds and pushes1.2.3-rc1, 1.2-rc1, 1-rc1, marks the GitHub Release as prerelease, anddoes not publish the :latest tag.
Disclaimer
[!CAUTION]Read this section before pointing
mcp-krakenat a Kraken API key withtrading or withdrawal permissions.
Alpha software. Tool signatures, default behaviours, configuration keysand the on-disk token format may change in any minor release until v1.0.Run a non-production instance against a read-only Kraken API key first,and read each tool's docstring before granting the server credentials withtrading or withdrawal permissions.
No liability. The software is provided as is, without warranty of anykind, express or implied. The author is not responsible for any direct,indirect, incidental, or consequential financial loss arising from the use,misuse or unavailability of this software — including but not limited tomisrouted withdrawals, unintended trades, missed executions, exchangedowntime, API rate-limit hits, or compromised credentials.
Not financial advice. Nothing in this software, its documentation, orany tool output constitutes investment, trading, tax or legal advice. Youare solely responsible for the decisions you make and the orders you submit.
Not affiliated with Kraken or Payward Inc. "Kraken" is a trademark ofits respective owner. This project is an independent client of the publicKraken REST API, written against the publicly documented API surface.