Build a cTrader MCP Server for Agentic Trading, Backtesting & cBot Automation
Spotware launched cTrader CLI on August 13, 2026, giving AI agents direct command access to accounts, cBots, backtests, and market data — and letting third-party AI apps turn natural language into trading commands. This guide builds a production FastMCP TypeScript server that wraps cTrader into risk-gated agent tools: positions, backtests, cBot management, and market data, wired into Claude Desktop with strict risk controls.
Deepak Bagada
CEO, SaaSNext
- Spotware launched cTrader CLI on August 13, 2026, giving AI agents direct command access to accounts, cBots, backtests, and market data, with third-party AI apps turning natural language into trading commands.
- A risk-gated FastMCP TypeScript gateway wraps cTrader into a narrow approved surface: positions, orders, backtests, and cBot management, with dry-run mode as the default for agent traffic.
- Order-size caps, allowlisted symbols, and human approval gates on live orders turn the same system that can move money into one that cannot move it without a human.
- The CLI + MCP pattern generalizes: any platform exposing a CLI can expose the same surface to agents with the same risk controls.
By Deepak Bagada, CEO at SaaSNext & Principal AI Architect.
On August 13, 2026, Spotware launched cTrader CLI — and with it, AI-controlled trading became an official access path. The CLI lets AI agents place trading commands and run cBots from local machines, and third-party AI apps can turn natural-language instructions into trading commands against the same accounts, backtests, and market data. The launch is a milestone in the agentic finance wave: for the first time, a major retail-trading platform ships a first-class control path designed for software agents, not just humans. This guide builds a production-grade TypeScript FastMCP server, ctrader-mcp, that wraps cTrader into a narrow, risk-gated set of agent tools — positions, backtests, cBot management, and market data — and wires it into Claude Desktop with the risk controls that make agentic trading defensible. The same CLI-to-MCP pattern generalizes to any platform exposing a command interface, so the architecture is worth studying even if you never touch forex. If you are building agent tool surfaces in finance, the MCP directory is the reference map.
Why agentic trading needs a gateway, not just the CLI
The cTrader CLI is the raw access path — exactly what you want for a human operator and exactly what you do not want a general-purpose agent pointing at directly. A gateway between the agent and the CLI is where risk control lives:
- A narrow, audited surface. The gateway exposes reads and backtests by default and keeps order placement behind explicit risk gates. A trading agent that cannot place live orders without approval computes less risk than one that can.
- Dry-run as the default. The gateway's order tools default to simulation; live mode is an explicit, per-request opt-in.
- Order-size caps and symbol allowlists. Even in live mode, the gateway clamps every order to a configured maximum and rejects anything outside an approved symbol list — the machine cannot size itself into a loss.
- Full audit. Every command is logged with the agent identity that issued it, the exact payload, and the verdict, so a bad decision is reconstructable after the fact.
The tool surface and architecture
The gateway exposes eight tools against the cTrader CLI:
| Tool | Type | What it does |
|---|---|---|
get_account_info |
R | Account balance, equity, margin, open positions |
get_positions |
R | Open positions with entry, size, P/L |
get_market_data |
R | Price data for a symbol over a window |
run_backtest |
R | Run a cBot backtest and return performance metrics |
list_cbots |
R | List available cBots and their status |
start_cbot |
W | Start a cBot on a symbol (gated) |
stop_cbot |
W | Stop a running cBot (gated) |
place_order |
W | Place an order — dry-run by default, live only with approval |
Writes are not disabled; they are policed. Every W tool passes through the risk gate first.
Step 1: Scaffold the TypeScript FastMCP server
mkdir ctrader-mcp && cd ctrader-mcp
npm init -y
npm install @modelcontextprotocol/sdk fastmcp zod
// server.ts
import { FastMCP } from "fastmcp";
import { z } from "zod";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
const exec = promisify(execFile);
const CLI = process.env.CTRADER_CLI_PATH ?? "ctrader-cli";
const TOKEN = process.env.CTRADER_API_TOKEN;
const LIVE_MODE = process.env.CTRADER_LIVE_MODE === "true";
const MAX_ORDER_SIZE = parseFloat(process.env.CTRADER_MAX_ORDER_SIZE ?? "0.01");
const ALLOWED_SYMBOLS = (process.env.CTRADER_ALLOWED_SYMBOLS ?? "EURUSD,GBPUSD").split(",");
const mcp = new FastMCP("ctrader-mcp", {
instructions: "Risk-gated cTrader tools. All order placement defaults to dry-run; live orders require explicit approval.",
});
async function run(args: string[]) {
const { stdout } = await exec(CLI, [...args, "--token", TOKEN!], { timeout: 30_000 });
return stdout;
}
const riskGate = (symbol: string, size: number) => {
if (!ALLOWED_SYMBOLS.includes(symbol)) return `blocked: symbol ${symbol} not allowlisted`;
if (size > MAX_ORDER_SIZE) return `blocked: size ${size} exceeds cap ${MAX_ORDER_SIZE}`;
return null;
};
mcp.addTool({
name: "get_account_info",
description: "Return account balance, equity, margin, and open positions.",
inputSchema: { type: "object", properties: {} },
execute: async () => run(["account", "info"]),
});
mcp.addTool({
name: "get_positions",
description: "Return open positions with entry, size, and unrealized P/L.",
inputSchema: { type: "object", properties: {} },
execute: async () => run(["positions", "list"]),
});
mcp.addTool({
name: "get_market_data",
description: "Return price data for a symbol over a window (candles).",
inputSchema: z.object({
symbol: z.string(),
timeframe: z.enum(["M1", "M5", "H1", "D1"]).default("H1"),
bars: z.number().int().max(500).default(100),
}),
execute: async (args) => run(["market", "data", args.symbol, args.timeframe, String(args.bars)]),
});
mcp.addTool({
name: "run_backtest",
description: "Run a cBot backtest and return performance metrics.",
inputSchema: z.object({
cbot: z.string(),
symbol: z.string(),
timeframe: z.enum(["M1", "M5", "H1", "D1"]).default("H1"),
days: z.number().int().positive().max(365).default(30),
}),
execute: async (args) => run(["cbot", "backtest", args.cbot, args.symbol, args.timeframe, String(args.days)]),
});
mcp.addTool({
name: "list_cbots",
description: "List available cBots and their running status.",
inputSchema: { type: "object", properties: {} },
execute: async () => run(["cbot", "list"]),
});
mcp.addTool({
name: "place_order",
description: "Place an order. Dry-run by default; live only when approved and live mode is enabled.",
inputSchema: z.object({
symbol: z.string(),
side: z.enum(["buy", "sell"]),
size: z.number().positive(),
approve_live: z.boolean().default(false),
}),
execute: async (args) => {
const gate = riskGate(args.symbol, args.size);
if (gate) return gate;
if (!LIVE_MODE || !args.approve_live) {
return run(["order", "dry-run", args.side, args.symbol, String(args.size)]);
}
return run(["order", "live", args.side, args.symbol, String(args.size)]);
},
});
mcp.start({ transport: "stdio" });
The critical detail is place_order: it runs the risk gate first, defaults to dry-run, and only reaches a live order when live mode is enabled and the agent explicitly requests approval. A trading agent that hits a 5x-size order on an unallowlisted symbol gets a blocked verdict, not an order.
Step 2: inputSchema definitions published to agents
{
"place_order": {
"type": "object",
"properties": {
"symbol": { "type": "string", "description": "Symbol; must be in the allowlist" },
"side": { "type": "string", "enum": ["buy", "sell"] },
"size": { "type": "number", "description": "Order size in lots; capped by the server" },
"approve_live": { "type": "boolean", "default": false, "description": "Explicit opt-in to a live order" }
},
"required": ["symbol", "side", "size"]
},
"run_backtest": {
"type": "object",
"properties": {
"cbot": { "type": "string" },
"symbol": { "type": "string" },
"timeframe": { "type": "string", "enum": ["M1", "M5", "H1", "D1"], "default": "H1" },
"days": { "type": "integer", "maximum": 365, "default": 30 }
},
"required": ["cbot", "symbol"]
}
}
Descriptions in agent-facing schemas decide which tool the model picks and how it fills arguments — say what each tool returns and what the risk gates are, so a model does not discover the cap by hitting it.
Step 3: Wire into Claude Desktop and Cursor
{
"mcpServers": {
"ctrader-mcp": {
"command": "node",
"args": ["/absolute/path/to/ctrader-mcp/dist/server.js"],
"env": {
"CTRADER_CLI_PATH": "/usr/local/bin/ctrader-cli",
"CTRADER_API_TOKEN": "short-lived-token",
"CTRADER_LIVE_MODE": "false",
"CTRADER_MAX_ORDER_SIZE": "0.01",
"CTRADER_ALLOWED_SYMBOLS": "EURUSD,GBPUSD"
}
}
}
}
Note CTRADER_LIVE_MODE: "false" — the default deployment cannot place live orders at all. Flip it to true only after you have proven the agent's decision quality in dry-run and added a human approval gate upstream. The token belongs in a secret manager, rotated frequently, scoped to the minimum permissions the CLI requires.
Risk controls and the human approval gate
- Dry-run by default. Every order tool returns a simulated fill with slippage assumptions, so the agent learns order behavior without moving money.
- Order-size caps and symbol allowlists. Enforced at the gateway, in addition to any platform-level limits — defense in depth for the single most dangerous action an agent can take.
- Short-lived tokens. Issue tokens that expire hourly and rotate them; an agent with a leaked credential is a liability, an agent with an expiring one is an incident to investigate.
- Human approval for live. In production, route live orders through a LangGraph human-in-the-loop node — the agent prepares the order, a human approves or rejects it, and the gateway executes only the approved payload. The same pattern we document across the AI workflows library.
- Full audit. Every command, agent identity, payload, and verdict goes to the audit log. When something goes wrong, you can reconstruct exactly which agent did what — the discipline the latest AI news coverage of agent governance keeps returning to.
Step 4: Wire into a LangGraph research-and-trade agent
from langchain_mcp_adapters.tools import load_mcp_tools
from langgraph.prebuilt import ToolNode
async def trading_tools():
# stdio client for ctrader-mcp
return ToolNode(await load_mcp_tools(read, write))
# Graph: research -> backtest -> propose -> human_approve -> execute
The realistic pattern is research first: the agent pulls get_market_data, runs run_backtest on candidate cBots, and produces a proposal. place_order sits at the end of the graph behind a human approval node, so the agent's output is a reviewed trade, not an autonomous one. That is the difference between agentic trading and reckless automation — and it is exactly why Spotware's CLI launch is exciting but the gateway is what makes it deployable.
Testing the server end to end
npx fastmcp inspect "$(pwd)/dist/server.js"
> get_account_info()
→ balance: 10,250.00, equity: 10,180.00, margin: 410.00, positions: 2
> run_backtest("ma-cross", "EURUSD", "H1", 30)
→ trades: 42, win_rate: 58.1%, max_dd: 3.2%, net: +1.9%
> place_order("BTCUSD", "buy", 1.0)
→ blocked: symbol BTCUSD not allowlisted
The last call is the most important test: the gateway blocked an unallowlisted symbol before anything touched the CLI. Try a capped size and a live-mode attempt next, and confirm both are rejected — those three tests prove the risk gate is actually in the execution path, not painted on the README.
Frequently Asked Questions
What did Spotware announce on August 13, 2026?
Spotware launched cTrader CLI, giving AI agents direct command access to accounts, cBots, backtests, and market data from local machines. Third-party AI apps can also turn natural-language instructions into trading commands.
Which tools should a production cTrader MCP server expose?
A conservative production surface is get_positions, get_account_info, run_backtest, list_cbots, start_cbot, stop_cbot, and get_market_data — with all order placement behind dry-run mode or a human approval gate.
How do you keep an agentic trading server safe?
Default to dry-run mode, enforce order-size caps and allowlisted symbols at the gateway, require a human approval gate for live orders, use short-lived API tokens, and log every command with the agent identity that issued it.
Does the cTrader CLI replace the existing cTrader platform?
No — it is a new access path. The CLI gives AI agents and third-party apps a command interface to the same accounts, cBots, backtests, and market data, complementing the platform's native tools.
What is the realistic use case for an agentic trading server?
Research and validation first: agents run backtests, analyze market data, and manage cBot lifecycle. Live order placement stays behind dry-run and human approval until the agent's decisions are proven against your own risk framework.
Closing thoughts
Spotware's cTrader CLI is the most concrete sign yet that trading platforms are building for agents, not just humans. The gateway pattern — narrow surface, dry-run default, hard risk caps, human approval on live orders, and full audit — is what turns that access path into something a compliance team can sign off on. Build the research-and-backtest loop first, keep live orders behind the gate, and the same CLI that scares people today becomes your most productive research assistant tomorrow. Track more finance agent builds in the MCP directory and watch AI news for the next platform to follow Spotware's lead.
Enjoyed this breakdown? Get our morning dispatch in your inbox.
Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.
Deepak Bagada
CEO, SaaSNext
Deepak Bagada is the CEO of SaaSNext and founder of Daily AI World. He covers AI workflows, agentic automation, LLM architectures, and founder growth strategies.
Build a Kaiterra MCP Server for Agentic Indoor Environmental Quality Monitoring
Next Story →Build a Cross-Tool Agent Handoff Workflow with the DeepJudge Agent Handoff Protocol
Related Intelligence Analysis
Vercel AI SDK Tool Calling React: 5 Steps (2026)
Vercel AI SDK tool calling React integration is a programming pattern that executes server-side functions based on large language model decisions and streams the results to a React frontend. By combining streamText with...
Fact-Density vs. Word Count: The New SEO for 2026
Fact Density is the ratio of verifiable, unique information to the total word count of a piece of content. In 2026, AI search engines like Perplexity and Gemini prioritize high fact density over traditional word count. A...
NVIDIA Audex vs Qwen3.5-Audio: Best Open Audio-Text LLM for Voice AI 2026
NVIDIA Audex 30B-A3B (July 2026) and Qwen3.5-35B-A3B are the two leading open audio-text LLMs. Audex uniquely handles both audio understanding and generation in a single model while preserving text intelligence. Qwen3.5-...