Metatrader 5 Mcp Server — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Metatrader 5 Mcp Server (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
MetaTrader 5 integration for Model Context Protocol (MCP). Provides read-only access to MT5 market data through Python commands, built on the FastMCP v3 framework. Optionally encodes responses in TOON for LLM token savings.
fastmcp-slim[server]>=3.4,<4 directly instead of the empty fastmcp meta-package. This bypasses a known FastMCP v3 packaging hazard that could leave the fastmcp namespace empty after a pip upgrade. Also: MetaTrader5 is now platform-gated to Windows, so the wheel installs cleanly on Linux/macOS too (with a runtime guard that explains why the tools can't run there).copy_rates_from_pos, etc.) are automatically encoded in TOON format when it would save ≥10 % of tokens over compact JSON. The LLM never has to ask for it; the server detects the shape. Install with pip install "mt5-mcp[toon]".fastmcp>=3.0,<4. The framework derives JSON schemas from your Python type annotations; no more string-encoded JSON parameters.gradio_server.py and the [ui] extra are gone. This release is FastMCP-only.stdio for Claude Desktop / VS Code, Streamable HTTP on /mcp, and legacy SSE. --transport all runs them concurrently.--asgi emits an app:app for uvicorn, gunicorn, or hypercorn.lint (ruff) + cross-platform pytest jobs on every push.fastmcp.Client; CI runs them on Windows + Linux.# Default: stdio (Claude Desktop, VS Code, etc.)
python -m mt5_mcp
# or:
mt5-mcp
# Streamable HTTP with rate limiting
python -m mt5_mcp --transport http --host 0.0.0.0 --port 8000 --rate-limit 30
# All transports at once
python -m mt5_mcp --transport all --port 8000
# ASGI app for production (mount behind Uvicorn / Gunicorn / Hypercorn)
python -m mt5_mcp --asgi📖 Documentation:
history_deals_get, history_orders_get, positions_get.mt5_execute), submit structured MT5 queries (mt5_query), or run full analyses with indicators, charts, and forecasts (mt5_analyze).ta, numpy, matplotlib ship in the namespace for RSI, MACD, Bollinger Bands, multi-panel charts, and more.mt5_queryStructured JSON interface that maps directly to MT5 read-only operations with automatic validation, timeframe conversion, and friendly error messages.
{
"operation": "copy_rates_from_pos",
"symbol": "BTCUSD",
"parameters": {"timeframe": "H1", "count": 100}
}Tip:parametersis a real JSON object in v0.6.0 — no more string-encoded JSON like the v0.5.x"parameters": "{\"timeframe\":\"H1\"}"form.
mt5_analyzePipeline tool that chains a query → optional indicators → charts and/or Prophet forecasts (with optional ML signals) in one request.
{
"query": {
"operation": "copy_rates_from_pos",
"symbol": "BTCUSD",
"parameters": {"timeframe": "D1", "count": 180}
},
"indicators": [
{"function": "ta.trend.sma_indicator", "params": {"window": 50}},
{"function": "ta.momentum.rsi", "params": {"window": 14}}
],
"forecast": {"periods": 30, "plot": true, "enable_ml_prediction": true}
}mt5_executeFree-form Python execution inside a curated namespace. Ideal for quick calculations, prototyping, and bespoke formatting.
rates = mt5.copy_rates_from_pos('BTCUSD', mt5.TIMEFRAME_H1, 0, 100)
df = pd.DataFrame(rates)
df['RSI'] = ta.momentum.rsi(df['close'], window=14)
result = df[['time', 'close', 'RSI']].tail(10)git clone <repository-url>
cd MT5-MCP
pip install -e .Optional extras:
# Everything
pip install -e .[all]The TOON token-efficient output encoder is not bundled in this release — the upstream toon-format/toon-python package has no PyPI wheel, and PyPI rejects direct-URL dependencies. The TOON heuristic in mt5_mcp.toon_output silently falls back to JSON when the encoder isn't installed. Vendoring the encoder is tracked for v0.6.4.
This installs:
fastmcp — MCP server framework (built on the official mcp SDK)MetaTrader5 — official MT5 Python librarypandas, numpy, matplotlib, ta — data + chartingprophet, xgboost, scikit-learn — forecasting + ML signalsuvicorn, starlette, httpx — HTTP transportpydantic — request/response validationAdd to your Claude Desktop configuration file at %APPDATA%\Claude\claude_desktop_config.json:
{
"mcpServers": {
"mt5": {
"command": "python",
"args": ["-m", "mt5_mcp"]
}
}
}Or, if mt5-mcp is on your PATH:
{
"mcpServers": {
"mt5": {
"command": "mt5-mcp",
"args": []
}
}
}For logging:
{
"mcpServers": {
"mt5": {
"command": "python",
"args": ["-m", "mt5_mcp", "--log-file", "C:\\path\\to\\mt5_mcp.log"]
}
}
}{
"mcpServers": {
"mt5-http": {
"url": "http://localhost:8000/mcp/"
}
}
}Works with MCP Inspector, Claude Desktop (HTTP mode), VS Code extensions, and any remote deployment.
python -m mt5_mcp --asgi # prints "app:app" hint
uvicorn mt5_mcp.__main__:app --host 0.0.0.0 --port 8000 --workers 2The lifespan context is wired in, so FastMCP startup/shutdown runs correctly under multi-worker Uvicorn.
python -m mt5_mcp [--transport stdio|http|sse|all] [--host HOST] [--port PORT]
[--path PATH] [--rate-limit N]
[--log-level LEVEL] [--log-file FILE]
[--asgi]| Flag | Default | Description |
|---|---|---|
--transport | stdio | One of stdio, http, sse, all |
--host | 127.0.0.1 | Host for HTTP/SSE transports |
--port | 8000 | Port for HTTP/SSE transports |
--path | /mcp | URL path for the HTTP endpoint |
--rate-limit | 10 | Requests per IP per minute (0 disables) |
--log-level | INFO | One of DEBUG, INFO, WARNING, ERROR |
--log-file | — | Write logs to this file in addition to stderr |
--asgi | — | Emit ASGI app handle (don't actually run the server) |
Status: the shape-detection heuristic and theformat_response()entry point ship in this release, but the upstreamtoon-format/toon-pythonencoder has no PyPI wheel, so PyPI rejects ourRequires-Dist: toon_format @ https://...reference. The heuristic silently falls back to JSON until the encoder is vendored (tracked for v0.6.4). The code, tests, and savings measurement below are the design target.
The server is designed to automatically encode tabular tool responses in TOON — a line-oriented, indentation-based format designed for LLM contexts. TOON declares array shapes once ([N] count + {field1,field2,...} column list) and uses indentation instead of braces, so tabular payloads (MT5 rate bars, indicator values, transaction history) are 20–40 % smaller than compact JSON.
The LLM doesn't choose. The server detects the shape and applies TOON only when it helps. There is no output_format or wire_format parameter on any tool.
pip install "mt5-mcp[toon]"This installs toon-format/toon-python — the canonical Python implementation of the TOON spec. The package's PyPI distribution is a stub; the [toon] extra pulls the real release directly from GitHub.
When the response contains a uniform array of ≥5 dicts in the data field AND encoding it as TOON saves ≥10 % of tokens vs. compact JSON, the server replaces that array with a TOON string and adds a sibling marker:
{
"operation": "copy_rates_from_pos",
"success": true,
"metadata": {"symbol": "BTCUSD", "timeframe": "H1", "count": 50},
"data_format": "toon",
"data": "data[50]{time,close,vol}:\n 1700000000,63000.0,0\n 1700003600,63010.0,100\n ..."
}The "data_format": "toon" marker tells the LLM the data field is a TOON document (decode with any TOON library, or call back through mt5_query to round-trip).
When the heuristic doesn't fire — single dicts, small arrays, heterogeneous rows, error envelopes, non-tabular shapes — the response is unchanged compact JSON. No surprises.
mt5_execute is intentionally excluded from the TOON heuristic: its output is already a pre-formatted text string (markdown tables, JSON snippets, plain text) that is more universally parseable than TOON.
| Response shape | JSON | TOON | Saved |
|---|---|---|---|
copy_rates 50 bars (embedded as TOON) | 3,171 | 2,391 | 24.6 % |
copy_rates 200 bars (embedded as TOON) | 12,585 | 9,405 | 25.3 % |
mt5_analyze 20 rows + indicators | 956 | 673 | 29.6 % |
mt5_execute 30 rows | 709 | 564 | 20.5 % |
| Representative total | 17,656 | 13,295 | 24.7 % |
Tiny responses (symbol_info lookups, error envelopes) cost 1–3 extra tokens because TOON's [N] array header is overhead on objects with one or two keys. The heuristic keeps those as JSON automatically.
mcp Python SDK).mt5, datetime, pd, ta, numpy, matplotlib) while blocking trading calls and disallowed modules.mt5.initialize() / mt5.shutdown() attempts and highlights the correct workflow.FastMCP instance and middleware wiringcannot import name 'FastMCP' from 'fastmcp')If you see ImportError: cannot import name 'FastMCP' from 'fastmcp' (unknown location) when running mt5-mcp, the underlying fastmcp package directory is empty. This is a known packaging hazard in FastMCP v3 caused by pip's install/upgrade sequence — the fastmcp meta-package can wipe files written by its companion fastmcp-slim package, leaving an empty namespace.
Recovery (one-time):
pip uninstall -y fastmcp fastmcp-slim
pip install mt5-mcpOr, if you prefer to keep using the legacy pip install --upgrade mcp workflow that triggered the issue:
pip install --force-reinstall fastmcp-slim==3.4.7mt5-mcp v0.6.3+ depends directly on fastmcp-slim[server]>=3.4,<4, so fresh installs skip this path entirely.
python -m mt5_mcp --log-file mt5_debug.logOr configure it in the Claude Desktop config (see Configuration above).
"MT5 connection error: initialize() failed"
"Symbol not found"
mt5_query with operation: symbols_get to list available symbols."No data returned"
"Rate limit exceeded"
--rate-limit, or set 0 to disable.This server provides read-only access to MT5 data. Trading functions are explicitly excluded from the safe namespace:
order_send() — Place ordersorder_check() — Check orderpositions_get() — Get positions (read-only but blocked to prevent confusion)positions_total() — Position countOnly market data and information retrieval functions are available.
MIT License
Contributions are welcome! Please ensure:
pytest -q)ruff check src tests)~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.