mt5ctl
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mt5ctlList all my configured terminals"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mt5ctl
An MCP server for operating headless MetaTrader 5 terminals — over SSH, from your agent.
Manage MetaTrader 5 terminals running under Wine + systemd on remote hosts (native Linux or WSL2) entirely through the Model Context Protocol: check status, read logs, capture screenshots, control the systemd lifecycle, and perform the tricky headless first-login — all as clean, typed tools.
⚠️ Port in progress. mt5ctl is a port of mt4ctl (MIT, © Pavel Volkov) from MetaTrader 4 to MetaTrader 5. The tool's own identity is already renamed, but the runtime logic still speaks MT4 (data paths, file encodings, log phrasing). See
docs/ANALISIS-VIABILIDAD.mdfor the feasibility analysis anddocs/PORT-TODO.mdfor the remaining MT5-specific work. Not yet usable against a real MT5 terminal.
Why
Algo traders increasingly run MetaTrader 4 headless on Linux — Wine under
Xvfb, supervised by systemd, no GUI. That's great for uptime and terrible for
day-to-day operations: every "is it connected?", "restart that one", or "log this
new account in" turns into a fragile chain of
ssh → (Windows cmd → wsl) → bash → systemctl → wine, with quoting hazards at
every hop.
mt5ctl collapses that chain into a handful of MCP tools. Point it at a registry
of your hosts and terminals, wire it into Claude (or any MCP client), and operate
the whole farm conversationally:
"Which demo terminals are down?" · "Restart demo2." · "Log demo2 into account 1000002 on ExampleBroker-Demo." · "Screenshot the live terminal so I can see the AutoTrading state."
Related MCP server: OpenTrading
Quickstart (5 minutes)
The init → list → doctor commands let you set up and verify everything
before wiring an MCP client:
# 1. write a starter registry, then fill in your hosts + terminals
uvx mt5ctl init # creates ~/.config/mt5ctl/terminals.yaml
$EDITOR ~/.config/mt5ctl/terminals.yaml
# 2. verify — offline, then over SSH (no MCP client needed)
uvx mt5ctl list # confirms the registry parses
uvx mt5ctl doctor # checks SSH, remote tools, units, data dirs
# 3. wire into Claude Code
claude mcp add --scope user mt5ctl \
--env MT5CTL_CONFIG="$HOME/.config/mt5ctl/terminals.yaml" \
-- uvx mt5ctlThen ask Claude: "Use mt5_list to show my configured terminals," then "mt5_status," and "mt5_doctor" if anything looks off. Full setup and other clients are below.
Features
Per-terminal connection detection — attributes established broker sockets to each terminal's
systemdcgroup, so terminals sharing a host (and a Wine prefix) are reported independently — not guessed from a host-wide count.Headless first-login — automates the one-time bootstrap a migrated terminal needs (MetaTrader's saved password is machine-bound), then hands control back to
systemdfor automatic reconnection on every restart.Idempotent strategy deploy — kubectl-apply for one terminal: push a local bundle of charts + experts and reconcile a terminal to it, touching only what mt5ctl deployed (foreign files like a watchdog's chart stay untouched), with a backup-and-restore-on-failure apply and a polling, report-only health verify that waits out the broker reconnect instead of guessing from a single snapshot.
Native and WSL2 hosts — one registry, two execution models; commands are base64-shipped so nothing breaks in the
cmd.exe → wsl.exe → bashgauntlet.Live-trading guardrails — terminals tagged
env: livereject mutating operations unless you passconfirm=true.Concurrent status — hosts are polled in parallel via
asyncio.Secrets stay secret — passwords resolve from arg → env → secrets file, are never logged, and the transient remote login config is
shred-ed after use.
How it works
┌────────────┐ MCP/stdio ┌──────────────────┐
│ MCP client │ ────────────► │ mt5ctl │
│ (Claude…) │ │ FastMCP server │
└────────────┘ └────────┬─────────┘
│ asyncio SSH (base64-framed)
┌─────────────────────┼─────────────────────┐
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ native Linux │ │ Windows + WSL2 │
│ sudo systemctl │ │ wsl -u root -- │
├─────────────────┤ ├──────────────────┤
│ mt5-live-main… │ systemd units running │ mt5-demo1… │
│ wine terminal.exe (Xvfb display) │ wine terminal.exe│
└─────────────────┘ └──────────────────┘A thin, typed core (models → config → ssh → scripts → deploy →
operations/login) sits under the server adapter, so the logic is testable
without a network and the MCP layer stays a one-line-per-tool shell.
Install
The fastest path needs no clone and no global install — uv
runs mt5ctl straight from the repo and fetches a matching Python itself:
uvx mt5ctl # runs the stdio serverNo uv yet? curl -LsSf https://astral.sh/uv/install.sh | sh — or skip it and use
the pipx path below.
Prefer a persistent mt5ctl command? Install it with uv or pipx:
uv tool install mt5ctl
# or
pipx install mt5ctlFor development:
git clone https://github.com/Chust-dev/mt5ctl.git && cd mt5ctl
python -m venv venv && source venv/bin/activate
pip install -e ".[dev]"The server machine needs either uv or Python 3.11+, plus SSH access to your
hosts. The remote hosts need the usual tools mt5ctl shells out to: systemctl,
ss, getent, (for screenshots) imagemagick/scrot + xdotool, and (for
deploy/adopt) GNU tar + a sha256 tool.
Configure
Copy the example registry and fill in your real hosts and terminals:
mkdir -p ~/.config/mt5ctl
cp examples/terminals.example.yaml ~/.config/mt5ctl/terminals.yamlThe registry is resolved from MT5CTL_CONFIG, then
~/.config/mt5ctl/terminals.yaml, then ./terminals.yaml. See
examples/terminals.example.yaml for the full
schema and docs/configuration.md for details.
Keep your populated registry private. It maps your accounts and infrastructure. The default
.gitignoreexcludesterminals.yaml.
Setting up terminal hosts
mt5ctl manages terminals; it doesn't install them. To stand up a host that runs
MT4 headless (Wine + Xvfb + systemd) so mt5ctl has something to drive:
Ubuntu / Linux server — Wine, the Xvfb + window-manager display, fonts (incl. the real Wingdings the MT4 smiley needs),
systemdunits, and the one-time headless login.Windows via WSL2 — the same stack inside WSL2, plus enabling WSL +
systemd, copying fonts from the Windows C: drive, boot autostart, and the WSL-specific gotchas.
Connect to an MCP client
Claude Code — one command wires it up (user scope = available in every project):
claude mcp add --scope user mt5ctl \
--env MT5CTL_CONFIG="$HOME/.config/mt5ctl/terminals.yaml" \
-- uvx mt5ctlOr commit a project .mcp.json to share with a team (Claude Code expands ${HOME}):
{
"mcpServers": {
"mt5ctl": {
"command": "uvx",
"args": ["mt5ctl"],
"env": { "MT5CTL_CONFIG": "${HOME}/.config/mt5ctl/terminals.yaml" }
}
}
}Claude Desktop — Settings → Developer → Edit Config (claude_desktop_config.json),
same shape but use an absolute config path (Desktop does not expand ${HOME}),
and an absolute command path if uvx is not on the GUI app's PATH (which uvx):
{
"mcpServers": {
"mt5ctl": {
"command": "uvx",
"args": ["mt5ctl"],
"env": { "MT5CTL_CONFIG": "/Users/you/.config/mt5ctl/terminals.yaml" }
}
}
}Installed
mt5ctlpersistently (uv/pipx)? Replacecommand/argswith just"command": "mt5ctl".
Tools
Tool | Mutates | Description |
| – | List configured terminals (offline). |
| – | Per-terminal service state + broker connection + log age. |
| – | Tail / grep a terminal's newest log file. |
| – | Capture a terminal window as PNG. |
| ✓ |
|
| ✓ | One-time headless login for auto-reconnect (live needs |
| – | Diagnose registry, SSH, remote tools, units, and data dirs. |
| – | List the experts (strategies) attached per terminal. |
| – | AutoTrading master switch + per-EA live-trading status. |
| – | Terminal build, broker server, and last broker ping. |
| ✓ | Reconcile a terminal to a local strategy bundle (live needs |
| ✓ | Record an already-running bundle as managed — the brownfield first cutover. |
| – | Poll a terminal until it is healthy after a restart (or report the failure). |
Full reference: docs/tools.md.
CLI
The subcommands mirror the MCP tool surface, so you can operate — and script — the whole farm without an MCP client:
# setup
mt5ctl init [path] # write a starter terminals.yaml (default: XDG config path)
mt5ctl list # list configured terminals (offline)
mt5ctl doctor # check registry, SSH, remote tools, units, data dirs
# read / inspect
mt5ctl status [terminal] # service + broker per terminal (exit 1 if unhealthy)
mt5ctl logs <terminal> [--pattern RE] [--lines N]
mt5ctl ea-list [terminal] # experts attached per terminal
mt5ctl autotrading [terminal] # AutoTrading master + per-EA live status
mt5ctl info [terminal] # build / broker server / last ping
mt5ctl screenshot <terminal> [--out-dir DIR]
# control / lifecycle (env=live needs --confirm)
mt5ctl control <terminal> {start|stop|restart} [--confirm]
mt5ctl login <terminal> <server> [--account A] [--password P] [--confirm]
mt5ctl verify <terminal> [--timeout SECONDS] # poll until healthy after a restart
mt5ctl deploy <terminal> <bundle> [--dry-run] [--confirm] [--reset-market-watch]
mt5ctl adopt <terminal> <bundle> [--confirm] # adopt an already-running farm
mt5ctl serve # run the MCP stdio server (the default with no subcommand)Health-oriented commands (status, verify, doctor) exit non-zero when
something is unhealthy, so a shell health-check can rely on the exit code rather
than grepping the output.
Deploy
Push a local bundle of charts + experts onto a terminal and reconcile it to that desired set — idempotently, touching only what mt5ctl deployed. The bundle mirrors the MT4 layout:
<bundle>/
profiles/default/<name>.chr # ready charts (one expert each)
MQL4/Experts/<folder>/<ea>.ex4 # the experts those charts referencemt5ctl deploy demo3 ./bundle --dry-run # preview the add/update/remove/foreign plan
mt5ctl deploy demo3 ./bundle # apply (env=live terminals need --confirm)It is apply-only (no selection, lot sizing, chart generation, or compilation —
you build the bundle), idempotent (a re-run is a no-op that still verifies health),
and managed-subset (foreign files like a watchdog's chart are never touched). The
write order is stop → drain → backup → apply → start; after the restart verify
polls until the terminal is healthy (report-only — it never reverts), and there
is no rollback command — recovery is to re-deploy the previous bundle. Add
--reset-market-watch to rebuild the terminal's Market Watch in the stopped window
(deletes symbols.sel, backed up first) and cap unbounded symbol carry-over.
Already running strategies on the farm? Take it under management first with
mt5ctl adopt <terminal> <bundle> (records the current footprint, changes
nothing), then deploy as usual. Full model and caveats: docs/deploy.md.
Security
Mutations on
env: liveterminals require explicitconfirm=true.Credentials resolve from argument →
MT5CTL_PASSWORD_<account>→ secrets file; they are never written to logs and the transient remote login config is shredded after use.All remote execution goes through your existing SSH config and key-based auth;
mt5ctlstores no credentials of its own.During
mt5_loginthe password is embedded in the base64-framed script handed tossh, so it is briefly visible in the local process list to your own user. On the remote side it is written only to a freshmktempconfig (mode 600) that a cleanup trapshreds on any exit path. On POSIX, the local secrets file is rejected if it is readable by group/other.
Deep dive
The MT4 "32 terminals per Windows user" limit — reproducing the cap on a clean box, locating the exact kernel object that enforces it (a per-instance Mutant in the session-local
\Sessions\<id>\BaseNamedObjects), and why running headless under Wine on Linux — whatmt5ctldrives — sidesteps it entirely.
Development
ruff check src tests # lint
mypy # type-check (strict)
pytest # testsSee docs/architecture.md for the module boundaries.
License
MIT © Pavel Volkov. See LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Chust-dev/mt5ctl'
If you have feedback or need assistance with the MCP directory API, please join our Discord server