oas-execute-mcp
oas-execute-mcp
An MCP server that puts a safety layer between a language model and a broker order.
A model calls order_submit. Before anything reaches the broker, the request passes six
independent checks, any one of which can refuse it — seven across the write paths, since the
stop-loss rule governs modifications rather than opens. Every attempt — allowed or refused — is
appended to an audit log with the reason. The broker itself sits behind a swappable backend, so the
same tool surface runs against an on-disk simulator or a live MetaTrader 5 terminal without the
model knowing which.
Built for an agent that, on its own channel, submitted orders against a prop-firm evaluation account without per-trade human approval, where a mis-sized order was not a failed test.
Why it exists
The interesting part of giving an agent a tool that spends money is not the happy path. It is:
what the tool returns when it half-succeeds — the order filled but the stop did not attach;
where a timeout lands — the broker never answered, and you do not know whether it filled;
how a failure is stopped from being reported as a success by the layer above it.
So the design rule here is that the model's own account of what happened is never trusted. Position state is re-read from the broker on every call. The refusals are explicit, few, and sit directly on the execution path rather than beside it in a prompt.
The safety layer
Seven checks, each able to refuse independently, all logged with a machine-readable reason.
Six of them stand between order_submit and the broker; check_sl_widen_block governs
modifications, so it never sees an open:
Check | Refuses when |
| A kill-switch file exists on disk. Trips instantly, no restart needed. |
| Orders are arriving faster than the configured ceiling. |
| The upstream decision record is stale — no order may ride an old approval. |
| Size, side or symbol disagree with what the broker reports. |
| A stop-loss modification would move the stop away from price. |
| Manual overrides this session exceed the allowed count. |
| Account equity has crossed the configured floor. |
The audit append runs after the gates on every path, allowed or refused — it is the record, not a check: a refusal that leaves no trace is treated as a failure of the system.
safety.py groups these into run_entry_safety_gates, run_modify_safety_gates and
run_close_safety_gates, so a close is never blocked by a rule that should only govern an open —
the failure mode where a safety system traps you in a position it was meant to protect.
Tool surface
Seven tools: order_submit · order_modify · order_close · close_all · position_list ·
account_info · health_check.
Architecture
model tool call
│
▼
server.py ── MCP stdio server, tool schemas + dispatch
│
▼
safety.py ── 7 gates, audit log, kill switch ◄── refuses here, before the broker
│
▼
backends/ ── swappable
├── stub.py on-disk simulation, no broker, deterministic
└── mt5_demo.py file bridge → MetaTrader 5 (Wine/macOS) via an MQL5 EA
localhost HTTP listener, shared-secret token on the firing routeThe MQL5 expert advisor (oas_execute_mcp/mql5/OAS_Bridge.mq5) polls a localhost endpoint and
executes on the terminal side. backends/base.py is the interface; adding a broker means
implementing it, and nothing above the backend changes.
Install
pip install -e ".[dev]"Point your MCP client at it:
{
"mcpServers": {
"oas-execute": {
"command": "/path/to/.venv/bin/python",
"args": ["-m", "oas_execute_mcp.server"],
"cwd": "/path/to/parent-of-this-package"
}
}
}Backend selection and paths are environment variables:
Variable | Default | Purpose |
|
|
|
|
| State, audit log, account record |
| MT5-under-Wine default | MT5 |
It ships defaulting to stub. You have to choose to point it at a broker.
No credentials live in this repository, and none should. The MT5 backend follows whatever terminal is already logged in; the account record it reads is documentary (login and server name), carries no password, and belongs outside version control.
Tests
PYTHONPATH=. python3 tests/test_smoke.py # full submit → modify → close cycle + failure modes
for t in tests/test_*.py; do PYTHONPATH=. python3 "$t"; done # the whole suite
python3 -m pytest tests/ -q # same suite, if you would rather type thisNine test files, all passing on a clean checkout. Each one is a self-contained
checker: it runs its assertions at module scope and exits non-zero on failure, so
the suite needs nothing but an interpreter. tests/suite_test.py drives the same
scripts as subprocesses so pytest is a working entry point too — it is a bridge,
not a second suite, and there is no version of the tests that only one runner sees. They cover the submit/modify/close cycle against
the stub, stop-loss anchoring and re-derivation after a charged fill, the bridge client-mode
handshake, quote and position routes, and the gate that stops an error-shaped payload from being
consumed as an empty position list — a real incident, where a timeout returned {"positions": []}
and a downstream reader believed it.
Two tests skip rather than pass when their subject is absent. They exercise a consumer of this
server, so they need the host project (OAS_HOST_REPO, OAS_RECONCILE_CMD). A check that silently
turns green when the thing it checks is missing is worse than no check.
Status and limits
The
stubbackend is complete and deterministic.mt5_demois in production use against a MetaTrader 5 terminal running under Wine on macOS.check_rate_limitis implemented but is not exercised by the test bench — the bench simulates broker timeouts and kill-switch fire, not rate-limit responses. Stated because the distinction between "implemented" and "tested" is the whole subject of this repository.The MT5 bridge is macOS/Wine-shaped. A native Windows install needs
OAS_MT5_COMMON_FILESset and has not been tested by me.Single-terminal by design: the listener is a singleton on one port, and a second server process detects the first and forwards to it rather than competing for the bind.
License
MIT — see LICENSE.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/zorionarrillaga/oas-execute-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server