Skip to main content
Workflows Library MCP Directory Realtime AI News Sponsor Tier Subscribe
Front Page / AI Tools / Deep Dive

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

Deepak Bagada

CEO, SaaSNext

Aug 15, 2026 Published
|
Aug 15, 2026 Updated
|
15 Minutes Reading Time
Core Takeaways for Founders & Builders
  • 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.

Executive Briefing

Enjoyed this breakdown? Get our morning dispatch in your inbox.

Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.

Frequently Asked Questions
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.
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.
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.
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.
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.
Deepak Bagada
Author Profile

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.

Related Intelligence Analysis

Briefing AI Tools

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

Deepak Bagada Deepak Bagada
12m read
Breaking AI Tools

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

Deepak Bagada Deepak Bagada
4m read
Audio Briefing
Accessibility Preferences
High Contrast Mode
Accessible Reading Font

Keyboard Shortcuts

Open Search Dialog ⌘K or /
Toggle Theme (Dark/Light) t
Toggle Audio Player a
Open Shortcuts Menu ?
Close Active Dialog Esc