mt5-mcp
Enables AI agents to interact with MetaTrader 5 for market data, live streaming, and trading operations, running locally over stdio.
README
MT5-MCP
MT5-MCP is an MCP (Model Context Protocol) server exposing MetaTrader 5 — market data, live streaming with a durable log, and full order/position lifecycle management — as tools for AI agents (Claude, Cursor, or any MCP-aware client). Runs locally against the MT5 terminal already installed on this machine; MetaTrader 5 is the only backend connector for now.
Current status: Bolts 1–5 shipped. Market data, live streaming, and order/position tools (with a mandatory dry-run-by-default safety layer) are all live. See docs/aidlc/BOLTS.md for what's next (history/audit tools, the auth checkpoint).
Docs
- AI-DLC Inception charter — purpose, scope, stack, architecture, safety layer, risks
- Tool & data model spec — the original full tool surface spec
- Construction Bolt backlog — ordered, reviewable units of work and what each one actually shipped
- Incident/investigation notes — the stdio-hang investigation; do not use
stdiotransport for any tool that touches MetaTrader5 (see below)
Install
python -m venv .venv
.venv\Scripts\pip install -e ".[dev]"
.venv\Scripts\pytest -q
Copy .env.example to .env and set MT5_PATH to your terminal's terminal64.exe (auto-detection works if the terminal is already running, but an explicit path is more reliable — see diagnostics/FINDINGS.md for why relying on auto-detection is risky).
Run the server
.venv\Scripts\mt5-mcp
# or: .venv\Scripts\python.exe -m mt5_mcp
Default transport is streamable-http, bound to 127.0.0.1:3403 (loopback only, reserved in E:\MyAgent\workflow\ports\REGISTRY.md). This is deliberate — stdio was the original design but was found to hang indefinitely on any tool that calls into MetaTrader5 (root cause never identified despite extensive isolation; see diagnostics/FINDINGS.md). stdio is still available (MT5_MCP_TRANSPORT=stdio) but should not be trusted for anything beyond the ping tool.
Connect an MCP client
Claude Code:
claude mcp add --transport http mt5-mcp http://127.0.0.1:3403/mcp
Claude Desktop / other JSON-config clients, add to the client's MCP server config:
{
"mcpServers": {
"mt5-mcp": {
"url": "http://127.0.0.1:3403/mcp"
}
}
}
(Exact key names for HTTP-transport servers vary by client — check that client's docs if this doesn't work as-is.)
The server must already be running (mt5-mcp in a terminal) before the client connects — this project doesn't yet register itself as a background/managed process.
Public access (client on a different machine)
A DEV instance of this server is reverse-proxied at https://mt5-mcp-dev.delena.buzz (nginx + Cloudflare, port 3403 on this host) so a client on another machine can connect without a VPN/SSH tunnel:
claude mcp add --transport http mt5-mcp https://mt5-mcp-dev.delena.buzz/mcp
⚠️ No authentication gate today — explicit, documented decision, not an oversight. Anyone with the URL can call every read-only tool and every execution tool. MT5_MCP_DRY_RUN is a server-side env var on this host, not something a remote caller can flip — but check its current value before relying on it as a safety net: it does not always default to dry-run-on in practice, only in the absence of an explicit override, and this host's .env is not committed (check E:\MyAgent\workflow\ports\REGISTRY.md's :3403 row for the live current status, since it changes and this file doesn't get re-edited on every toggle). When dry-run is on, execution tools always return simulated responses. When it's off, an unauthenticated caller can place/modify/cancel/close a real order on the connected account, bounded only by MT5_MCP_MAX_LOT_SIZE/MT5_MCP_MAX_OPEN_POSITIONS (always enforced regardless of dry-run) and the kill-switch (MT5_MCP_KILL_SWITCH_PATH — create that file to immediately block place_order). Either way, an unauthenticated caller can always read real market data and real open-position state (tickets/volumes/P&L). Full CSS integration is planned but not built — see docs/aidlc/INCEPTION.md's "Auth / security note" and E:\MyAgent\workflow\css\CLIENT-REGISTRY.md's mt5-mcp row (status waived-no-auth) for the reasoning and current status. Treat this URL accordingly until that changes.
If you run your own reverse proxy in front of this server, add its hostname to MT5_MCP_PUBLIC_HOSTNAMES (comma-separated) — FastMCP's built-in DNS-rebinding protection otherwise rejects any Host header besides 127.0.0.1/localhost/::1 with a 421.
Tools
All tools return the standard envelope: {success, error_code, error_message, retryable, request_id, data}.
Market data (read-only)
get_historical_ohlcv(symbol, timeframe, from_date?, to_date?, from_bar?, to_bar?, limit?, include_volume?, include_spread?, session_filter?, price_type?, only_completed_bars?)—timeframe: M1/M5/M15/M30/H1/H4/D1/W1/MN1.price_typeonly supports"bid"(or omitted) — ask/mid/last not implemented.get_symbol_info(symbol)— contract size, tick size/value, digits, swaps, margin, current bid/ask.
Live streaming (durable log, not true push — see below)
subscribe_live_data(symbol, data_types?)—data_types:["tick"]and/or["bar"](fixed M1). Returns asubscription_id.unsubscribe_live_data(subscription_id?, symbol?)— stop by id or all subscriptions for a symbol.get_stream_log(symbol, from_time?, to_time?, data_type?, limit?)— read back logged ticks/bars, including after unsubscribing.
Orders (execution — dry-run by default, see Safety below)
place_order(symbol, order_type, side, volume, price?, stop_loss?, take_profit?, comment?, magic_number?, deviation?, client_order_id?)—order_type:market/limit/stop.side:buy/sell.pricerequired for limit/stop.client_order_idis logged for traceability only — it does not deduplicate retries.modify_order(ticket, price?, stop_loss?, take_profit?, volume?, expiration?)— modifies a pending order.expirationis not implemented — passing it raisesunsupported_parameter.cancel_order(ticket)— cancels a pending order.
Positions
get_open_positions(symbol?, magic_number?, comment?)— read-only.modify_position(ticket, stop_loss?, take_profit?)— changes SL/TP on an open position.close_position(ticket, volume?)— full or partial close.close_all_positions(symbol?, side?, magic_number?)— bulk close.
Health
ping()— no MT5 connection required, works even if MT5_PATH is wrong.
Not implemented: stop_limit/trailing_stop order types, get_order_history/get_deal_history/get_position_history (Bolt 6), CSS auth (deferred, see INCEPTION.md).
Safety layer (order/position tools)
- Dry-run is on by default. No real order ever gets placed unless you explicitly set
MT5_MCP_DRY_RUN=falsein the server's environment. It's an env var, not a tool parameter — an agent can't flip it mid-conversation. Dry-run responses use real current market prices, so they're shaped like a real fill would be. - Kill-switch: create a file at
MT5_MCP_KILL_SWITCH_PATH(default:<repo root>\MT5_MCP_KILL_SWITCH) andplace_order(only — the sole action that creates new exposure) is blocked immediately, independent of the dry-run setting. Delete the file to re-enable.modify_order/cancel_order/modify_position/close_position/close_all_positionsare deliberately not blocked by the kill-switch — an emergency stop shouldn't also trap you inside an existing position. - Limits:
MT5_MCP_MAX_LOT_SIZE(default0.10) andMT5_MCP_MAX_OPEN_POSITIONS(default3) — both enforced server-side onplace_order, not just documented. - Audit log: every order/position attempt — dry-run or real, success or failure — is written to a local SQLite log (
MT5_MCP_AUDIT_LOG_DB, default<repo root>\mt5_mcp_audit_log.db), before the tool call returns. - Nothing here authorizes a live (non-demo) account. The connector only ever points at whatever
MT5_PATH's terminal is logged into — currentlyOctaFX-Demo. Pointing this at a real account is a distinct, explicit decision this project has not made.
Environment variables
| Variable | Default | Purpose |
|---|---|---|
MT5_PATH |
auto-detect | Path to terminal64.exe |
MT5_MCP_TRANSPORT |
streamable-http |
stdio | sse | streamable-http — see the stdio warning above |
MT5_MCP_HTTP_HOST |
127.0.0.1 |
Bind host for http/sse transports |
MT5_MCP_HTTP_PORT |
3403 |
Bind port (reserved in the port registry) |
MT5_MCP_PUBLIC_HOSTNAMES |
(none) | Comma-separated extra Host headers to accept from a reverse proxy — required for any public hostname to work, see "Public access" above |
MT5_MCP_DRY_RUN |
true |
Must be exactly false to allow real order execution; anything else (including unset/typo) stays dry-run |
MT5_MCP_KILL_SWITCH_PATH |
<repo root>\MT5_MCP_KILL_SWITCH |
If this file exists, place_order is blocked |
MT5_MCP_MAX_LOT_SIZE |
0.10 |
Max volume per place_order call |
MT5_MCP_MAX_OPEN_POSITIONS |
3 |
Max concurrent open positions before place_order is blocked |
MT5_MCP_STREAM_LOG_DB |
<repo root>\mt5_mcp_stream_log.db |
SQLite path for subscribe_live_data/get_stream_log |
MT5_MCP_AUDIT_LOG_DB |
<repo root>\mt5_mcp_audit_log.db |
SQLite path for the order/position audit trail |
All .db files are gitignored — they're local runtime state, not source.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.