Metadata-Version: 2.4
Name: meta-trader-mcp
Version: 1.0.0
Summary: A production-grade, cross-platform MCP Server for MetaTrader 5
Project-URL: Homepage, https://github.com/shubhvisputek/meta-trader-mcp
Project-URL: Repository, https://github.com/shubhvisputek/meta-trader-mcp
Project-URL: Issues, https://github.com/shubhvisputek/meta-trader-mcp/issues
Author: Meta Trader MCP Contributors
License: MIT
License-File: LICENSE
License-File: NOTICE
Keywords: ai-agents,llm,mcp,metatrader,model-context-protocol,mt5,trading
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial :: Investment
Requires-Python: >=3.10
Requires-Dist: fastmcp>=0.4.0
Requires-Dist: mcp>=1.0.0
Requires-Dist: numpy>=1.26.0
Requires-Dist: pandas>=2.0.0
Requires-Dist: pydantic-settings>=2.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: requests>=2.31.0
Requires-Dist: websockets>=12.0
Provides-Extra: autostart
Requires-Dist: psutil>=5.9.0; extra == 'autostart'
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Provides-Extra: remote
Requires-Dist: fastapi>=0.110.0; extra == 'remote'
Requires-Dist: uvicorn>=0.29.0; extra == 'remote'
Provides-Extra: windows
Requires-Dist: metatrader5>=5.0.45; extra == 'windows'
Description-Content-Type: text/markdown

# 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.

[![CI](https://github.com/shubhvisputek/meta-trader-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/shubhvisputek/meta-trader-mcp/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![PyPI](https://img.shields.io/pypi/v/meta-trader-mcp.svg)](https://pypi.org/project/meta-trader-mcp/)
[![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue)](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.*
