Meta-Trader-MCP
README.md
# Meta-Trader-MCP
**One MCP server for MetaTrader 5 — on every platform.**
Windows native · macOS/Linux via Wine · or a remote bridge to any Windows host.
[](https://github.com/shubhvisputek/meta-trader-mcp/actions/workflows/ci.yml)
[](LICENSE)
[](https://pypi.org/project/meta-trader-mcp/)
[](pyproject.toml)
Meta-Trader-MCP exposes a unified AI interface to MetaTrader 5 over the
[Model Context Protocol](https://modelcontextprotocol.io): live quotes,
historical candles, technical indicators, order execution, position
management, and headless Strategy Tester backtests — all behind a mandatory
risk interceptor.
---
## ⚠️ Risk disclaimer (read this first)
**This software can place real orders against a live brokerage account and
can cause real financial loss.** It is provided *as is*, with no warranty and
no financial advice of any kind — see [DISCLAIMER.md](DISCLAIMER.md).
Safety defaults:
* **Trading is OFF by default.** The server starts read-only; every
state-changing tool is rejected until you explicitly set
`MTM_ENABLE_TRADING=true` (or pass `--enable-trading`).
* Every order passes a **non-bypassable risk interceptor**: max-lot cap,
equity-drawdown ceiling, payload guardrails and rate limiting.
* Credentials are read only from the environment / OS keychain and are never
logged ([SECURITY.md](SECURITY.md)).
---
## Quick start (Claude Desktop, one click)
1. Download `meta-trader-mcp.mcpb` from the
[latest release](https://github.com/shubhvisputek/meta-trader-mcp/releases).
2. Double-click it. Claude Desktop installs the server and asks for your
settings (runtime mode, optional MT5 login — the password is stored in the
OS keychain, never in a file).
3. Done.
> **You do not need to run anything to start the server.** Claude Desktop
> launches it automatically over stdio every time the app starts, and shuts
> it down when the app closes. No terminal, no autostart, no background
> service.
If MetaTrader 5 isn't running yet, that's fine — see the mental model below.
## How it works (mental model)
```text
Claude Desktop / MCP client (you chat)
│ spawns on app launch, stdio
▼
meta-trader-mcp serve (this package)
│ connects lazily, on the FIRST tool call
▼
MetaTrader 5 terminal (your broker connection)
```
* The MCP client owns the server's lifecycle — the server "loads with the
LLM".
* The server **never requires MT5 at startup**. The first tool call
connects; if the terminal is down you get a structured, non-fatal answer:
```json
{ "status": "ERROR", "code": "MT5_NOT_RUNNING",
"message": "MetaTrader 5 terminal is not running. Start MT5 and retry." }
```
Start MT5 and ask again — the same call now succeeds, no restart needed.
## Install matrix
| You are… | Recommended install |
|----------|--------------------|
| A Claude Desktop user | The `.mcpb` one-click bundle (above) |
| Using Cursor / Claude Code / another MCP client | `uvx` config snippet (below) — zero install |
| A developer (Windows, trading) | `pip install "meta-trader-mcp[windows]"` |
| A developer (macOS/Linux) | `pip install meta-trader-mcp` + `local-wine` or `remote-bridge` mode |
| Running the Windows bridge companion | `pip install "meta-trader-mcp[remote]"` on the Windows box |
| Wanting start-with-MT5 / always-on serving | add the `[autostart]` extra |
```bash
# Developers / virtualenvs
pip install meta-trader-mcp # base (macOS/Linux/Windows)
pip install "meta-trader-mcp[windows]" # Windows: pulls the MetaTrader5 binding
pip install "meta-trader-mcp[remote]" # remote-bridge HTTP companion (FastAPI/uvicorn)
pip install "meta-trader-mcp[autostart]" # psutil-based supervisor
# Isolated app install (recommended for end users on a workstation)
pipx install "meta-trader-mcp[windows]"
# Zero-install run (no global state) — great for MCP client configs
uvx --from "meta-trader-mcp[windows]" meta-trader-mcp serve
```
The `MetaTrader5` binding is an **optional** `[windows]` extra, so the base
package installs cleanly on macOS/Linux/CI — importing `meta_trader_mcp`
never raises a Windows-only `ImportError`.
## Per-client configuration
Any MCP client that reads a JSON config gets the same client-managed launch
with one entry:
```json
{
"mcpServers": {
"meta-trader-mcp": {
"command": "uvx",
"args": ["--from", "meta-trader-mcp[windows]", "meta-trader-mcp", "serve", "--transport", "stdio"],
"env": { "MTM_MODE": "auto", "MTM_ENABLE_TRADING": "false" }
}
}
}
```
| Client | Config file location |
|--------|---------------------|
| Claude Desktop (manual) | `%APPDATA%\Claude\claude_desktop_config.json` (Windows) / `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) |
| Claude Code | `.mcp.json` in your project, or `claude mcp add meta-trader-mcp -- uvx --from "meta-trader-mcp[windows]" meta-trader-mcp serve` |
| Cursor | `~/.cursor/mcp.json` or `.cursor/mcp.json` per project |
| Other MCP hosts | Same `command`/`args`/`env` triple in the host's MCP config |
On macOS/Linux replace `meta-trader-mcp[windows]` with plain
`meta-trader-mcp` and set `MTM_MODE` to `local-wine` or `remote-bridge`.
## Runtime modes
| Mode | When to pick it |
|------|-----------------|
| `windows-native` | You run MT5 on this Windows machine. Auto-selected by `auto`. Direct, in-process binding — lowest latency. |
| `local-wine` | macOS/Linux with MT5 installed under [Wine](https://www.winehq.org). Explicit opt-in: `--mode local-wine`. |
| `remote-bridge` | MT5 runs on a Windows VPS/VM elsewhere. `--mode remote-bridge --host <ip> --port 8080`. |
| `auto` (default) | Windows → `windows-native`. Anywhere else the server *asks you to choose* instead of guessing. |
### local-wine setup (macOS/Linux)
1. Install Wine (`brew install --cask wine-stable` / your distro package).
2. Install MT5 into a dedicated prefix:
`WINEPREFIX=~/.mt5 wine64 mt5setup.exe`
(the server expects the masdevid-style layout
`~/.mt5/drive_c/Program Files/MetaTrader 5/terminal64.exe`; override with
`MT5_TERMINAL_PATH`).
3. Install a **Windows** Python inside the prefix and the bridge package:
`WINEPREFIX=~/.mt5 wine64 python.exe -m pip install "meta-trader-mcp[remote,windows]"`
4. Run the in-prefix bridge once per session (or let the adapter launch the
terminal for you):
`WINEPREFIX=~/.mt5 wine64 python.exe -m meta_trader_mcp.main bridge --port 18812`
5. Start your MCP client with `MTM_MODE=local-wine`. Tool calls now route
host → loopback bridge → MT5 under Wine.
### remote-bridge setup
On the **Windows host next to MT5**:
```powershell
pip install "meta-trader-mcp[remote,windows]"
meta-trader-mcp bridge --host 0.0.0.0 --port 8080
```
On your machine: `MTM_MODE=remote-bridge`, `MTM_REMOTE_HOST=<windows-ip>`,
`MTM_REMOTE_PORT=8080`. A Docker recipe for the client side ships in
[docker-compose.yml](docker-compose.yml).
> Plain HTTP is acceptable only on a trusted LAN. For anything else put the
> bridge behind TLS (`MTM_REMOTE_USE_TLS=true` + a reverse proxy).
## Configuration reference
All settings come from environment variables or a local `.env`
(see [.env.example](.env.example)). CLI flags override the environment.
| Variable | Default | Meaning |
|----------|---------|---------|
| `MTM_MODE` | `auto` | `auto` \| `windows-native` \| `local-wine` \| `remote-bridge` |
| `MTM_ENABLE_TRADING` | `false` | **Must** be `true` for any state-changing tool |
| `MTM_TRANSPORT` | `stdio` | `stdio` (client-managed) \| `http` (background/shared) |
| `MTM_HTTP_HOST` | `127.0.0.1` | HTTP bind host (loopback by default — keep it that way) |
| `MTM_HTTP_PORT` | `8000` | HTTP bind port |
| `MTM_WATCH_PROCESS` | `terminal64.exe` | Process the `supervise` command watches |
| `MTM_STOP_WITH_MT5` | `true` | Stop the supervised server when MT5 exits |
| `MT5_LOGIN` | — | MT5 account number (optional; terminal session reused if unset) |
| `MT5_PASSWORD` | — | MT5 password. Keychain via `.mcpb`; never logged |
| `MT5_SERVER` | — | Broker server name |
| `MT5_TERMINAL_PATH` | — | Explicit `terminal64.exe` path (native/wine) |
| `MTM_WINE_PREFIX` | `~/.mt5` | Wine prefix containing MT5 |
| `MTM_WINE_BINARY` | `wine64` | Wine launcher binary |
| `MTM_REMOTE_HOST` | — | Companion bridge host (remote-bridge mode) |
| `MTM_REMOTE_PORT` | `8080` | Companion bridge port |
| `MTM_MAX_LOT` | `10.0` | Risk: max volume of a single order |
| `MTM_MAX_DRAWDOWN_PCT` | `5.0` | Risk: equity-drawdown ceiling blocking new entries |
**Credential safety:** secrets live in the environment / OS keychain only.
`.env` is gitignored; the settings object masks the password in any debug
output; tests use mocks exclusively.
## Tool reference
All tools return JSON. State-changing tools (marked ⚡) pass the risk
interceptor first and require `MTM_ENABLE_TRADING=true`.
### Market data (read-only)
| Tool | Parameters | Example prompt |
|------|-----------|----------------|
| `get_market_status` | — | "Is my MT5 connected? What's the latency?" |
| `get_historical_candles` | `symbol`, `timeframe` (`M1`…`MN1`), `count` | "Show me the last 50 H1 candles for EURUSD" |
| `get_live_ticks` | `symbol` | "What's the current spread on XAUUSD?" |
| `compute_indicator` | `symbol`, `timeframe`, `indicator` (`SMA`/`EMA`/`RSI`/`MACD`), `period` | "Compute the 14-period RSI on GBPUSD H4" |
Example response (`get_historical_candles`, latest candle mirrored at the
top level for single-candle reads):
```json
{
"symbol": "EURUSD", "timeframe": "H1", "count": 1,
"candles": [{ "time": 1774112000, "open": 1.1000, "high": 1.1050,
"low": 1.0990, "close": 1.1020, "tick_volume": 500 }],
"time": 1774112000, "open": 1.1, "high": 1.105, "low": 1.099,
"close": 1.102, "tick_volume": 500
}
```
### Trading ⚡
| Tool | Parameters |
|------|-----------|
| `place_market_order` | `symbol`, `volume`, `action` (`BUY`/`SELL`), `sl?`, `tp?`, `max_allowed_lot?` |
| `place_pending_order` | `symbol`, `volume`, `action`, `price`, `order_type` (`LIMIT`/`STOP`), `sl?`, `tp?` |
| `modify_position` | `ticket`, `sl?`, `tp?`, `trailing?` |
| `close_position` | `ticket`, `volume?` (omit = close fully) |
Success payload (canonical):
```json
{ "status": "SUCCESS", "ticket": 99881122, "retcode": 10009, "comment": "Success" }
```
A rejected order is an exception payload, e.g. an oversize lot:
```json
{ "status": "ERROR", "code": "RISK_VIOLATION",
"message": "Volume target exceeds maximum allowed risk threshold: requested 100.0 lots > allowed 10.0 lots." }
```
### Backtesting ⚡
| Tool | Parameters |
|------|-----------|
| `trigger_backtest` | `expert`, `symbol`, `from_date`, `to_date` (`YYYY.MM.DD`), `timeframe?`, `deposit?`, `leverage?` |
| `fetch_backtest_report` | `run_id` |
`trigger_backtest` writes a Strategy Tester `.ini`, launches the terminal
headlessly (`ShutdownTerminal=1`) and returns a `run_id`;
`fetch_backtest_report` parses the report into
`{profit_factor, max_drawdown, win_rate, net_profit, total_trades}`.
## Trading safety
1. **Opt in deliberately.** `MTM_ENABLE_TRADING=true` (env / `.mcpb` config
toggle / `--enable-trading`). Until then every mutation returns
`TRADING_DISABLED`.
2. **Risk limits** (`MTM_MAX_LOT`, `MTM_MAX_DRAWDOWN_PCT`) are enforced on
every order, in front of the adapter — there is no code path around the
interceptor. Closing/reducing positions is always allowed; opening new
exposure past the drawdown ceiling is not.
3. **Start on a demo account.** Point `MT5_LOGIN`/`MT5_SERVER` at your
broker's demo server until you trust your setup end to end.
## Optional: always-on / autostart (advanced)
> Most users should skip this — the client-managed default already starts
> the server with your LLM app.
Needed only when the server must outlive the client (shared server, HTTP-only
client, headless VPS) or should track the MT5 terminal's lifecycle:
```bash
meta-trader-mcp install-autostart --on-boot # always-on HTTP on 127.0.0.1:8000
meta-trader-mcp install-autostart --with-mt5 # start/stop together with MT5
meta-trader-mcp uninstall-autostart # remove the artifact
meta-trader-mcp supervise --stop-with-mt5 # run the watcher in foreground
```
What gets written ([templates](packaging/autostart)):
* **Windows** — a Task Scheduler task at the least-privilege `LIMITED` level
* **macOS** — a user LaunchAgent `~/Library/LaunchAgents/com.metatradermcp.server.plist`
* **Linux** — a systemd *user* unit `~/.config/systemd/user/meta-trader-mcp.service`
(use `loginctl enable-linger` for always-on VPS boxes)
Autostart always serves **HTTP on loopback** (stdio has no client when the
OS launches it) and never writes credentials anywhere.
## Troubleshooting
| Symptom | Fix |
|---------|-----|
| `MT5_NOT_RUNNING` errors | Start the MT5 terminal, retry the call — no server restart needed. |
| `Cannot auto-select a runtime on 'darwin'` | You're not on Windows: pick `--mode local-wine` or `--mode remote-bridge --host …`. |
| `MetaTrader5 binding is not installed` | `pip install "meta-trader-mcp[windows]"` — on Windows only; the binding does not exist for macOS/Linux. |
| Client doesn't list the server | Check the client's MCP config path (table above), then restart the client; for `uvx`, confirm `uv` is on PATH. |
| Port 8000 already in use (HTTP) | `--port 9000` or `MTM_HTTP_PORT=9000`. |
| Wine: `terminal64.exe not found` | Install MT5 into the prefix or set `MT5_TERMINAL_PATH` to the exe inside `drive_c`. |
| Wine: bridge unreachable | Run the in-prefix bridge (local-wine setup step 4); the error message includes the exact command. |
| Orders rejected with `TRADING_DISABLED` | That's the safety default — see *Trading safety*. |
## Architecture & contributing
The codebase is hexagonal: role ports (`protocols.py`), pluggable registries
(`registry.py`), one composition root (`container.py`), three runtime
adapters behind one contract. Adding a tool/adapter/risk rule touches **zero**
core files. Read [docs/architecture.md](docs/architecture.md), then
[CONTRIBUTING.md](CONTRIBUTING.md).
```bash
git clone https://github.com/shubhvisputek/meta-trader-mcp
cd meta-trader-mcp
uv venv && uv pip install -e ".[dev]"
pytest tests/ -v # fully mocked; no MT5 or network needed
ruff check src tests
```
Releases are cut manually via the [Release workflow](.github/workflows/release.yml)
(`workflow_dispatch` or a `v*` tag) — wheel + sdist to PyPI (OIDC), the
`.mcpb` bundle and checksums to GitHub Releases.
## Credits & license
MIT © Meta Trader MCP Contributors — see [LICENSE](LICENSE).
This project deliberately **reuses proven open source** instead of
reinventing it. It incorporates MIT-licensed code from, and owes its design
to ([NOTICE](NOTICE), [THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md)):
* [ariadng/metatrader-mcp-server](https://github.com/ariadng/metatrader-mcp-server) — the modular MT5 client core and the remote bridge shapes
* [Qoyyuum/mcp-metatrader5-server](https://github.com/Qoyyuum/mcp-metatrader5-server) — FastMCP tool/resource schemas and packaging conventions
* [Cloudmeru/MetaTrader-5-MCP-Server](https://github.com/Cloudmeru/MetaTrader-5-MCP-Server) — risk guardrails, rate limiting and the error taxonomy
* [emerzon/mt-data-mcp](https://github.com/emerzon/mt-data-mcp) — fast market-data reads and indicator semantics
* [masdevid/mt5-quant](https://github.com/masdevid/mt5-quant) — conceptual reference for headless MT5 under Wine (no code copied)
*Not affiliated with MetaQuotes. MetaTrader is a trademark of MetaQuotes Ltd.*
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing