Skip to main content
Glama
tivojn

ibkr-mcp-guard

by tivojn

ibkr-mcp-guard

IBKR (guarded): a small local MCP server that lets your AI assistant use Interactive Brokers' official MCP server through a safety guard. The assistant can read your account and market data and create order drafts. It can never send an order to the market.

An opt-in paper trading mode lets the assistant submit orders to an IBKR paper (simulated) account, so you can test strategies. Live accounts can never receive orders.

Unofficial. This project is not affiliated with, endorsed by, or supported by Interactive Brokers. It connects to IBKR's official public MCP server (https://api.ibkr.com/v1/api/mcp-public), announced on 28 July 2026, using IBKR's own browser sign-in.

  • Runs locally over stdio. Needs Node.js 20 or newer and has no npm dependencies.

  • Installs by URL as a plugin in EnConvo, Claude Code and Codex, or runs with npx.

Safety guarantees

Never requests order submission

It asks for the scopes openid account-ids mcp.read mcp.write and nothing else. If code ever asks for mcp.orders.submit, an assertion throws, and a test checks this. If IBKR grants that scope anyway, ibkr_status reports it. The only exception is the opt-in paper trading mode, which you must turn on yourself.

Submit tools removed

Any upstream tool that places, submits, transmits or executes an order, or that requires mcp.orders.submit, is removed from the tool list and refused if called by name. This also covers buy/sell tools, replies to order confirmations, and changes to live orders.

Drafts only

Order instructions (create_order_instruction, delete_order_instruction) are IBKR's order drafts. They are listed with the warning "Creates/changes an order DRAFT (order instruction) only — nothing is sent to the market; you approve drafts inside IBKR." and marked destructiveHint: true. A draft becomes an order only when you approve it inside IBKR.

Asks before drafting

If your MCP client supports elicitation, the guard asks you to Approve or Cancel each draft before sending it. Otherwise your host's own tool-approval prompt applies, which is triggered by destructiveHint.

Tokens stay local

macOS: stored in your login Keychain. Elsewhere: stored in a file with mode 0600. Tokens are never logged.

Nothing else leaves your machine

The guard connects only to api.ibkr.com, plus 127.0.0.1 for the sign-in callback. There is no telemetry and no third-party server.

Tool classes:

Class

Examples

Behaviour

read

get_account_balances, get_account_positions, get_account_summary, get_account_orders, get_account_trades, get_price_snapshot, get_price_history, get_option_data, search_contracts, whats_new

Listed with readOnlyHint: true.

write

create_alert, set_alert_status, watchlist create/update/delete, provide_customer_feedback

Listed with readOnlyHint: false, destructiveHint: false.

draft

create_order_instruction, delete_order_instruction

Listed with the DRAFT prefix and destructiveHint: true; asks first when the client supports elicitation.

block

place_order, submit_order, transmit_order, any tool requiring mcp.orders.submit

Never listed, never called.

Set IBKR_MCP_GUARD_READONLY=1 to hide the write and draft tools as well.

Related MCP server: IBKR MCP Server

Install

EnConvo

Open Plugins → Install from URL and paste:

https://github.com/tivojn/ibkr-mcp-guard

EnConvo reads .mcp.json and expands ${CLAUDE_PLUGIN_ROOT}.

Claude Code

As a plugin (this repo is its own marketplace):

claude plugin marketplace add https://github.com/tivojn/ibkr-mcp-guard
claude plugin install ibkr-mcp-guard@ibkr-mcp-guard

Inside Claude Code, the same commands are /plugin marketplace add tivojn/ibkr-mcp-guard followed by /plugin install ibkr-mcp-guard@ibkr-mcp-guard.

Or as a plain MCP server:

claude mcp add ibkr -- npx -y github:tivojn/ibkr-mcp-guard

Codex

Add to ~/.codex/config.toml:

[mcp_servers.ibkr]
command = "npx"
args = ["-y", "github:tivojn/ibkr-mcp-guard"]
startup_timeout_sec = 60   # the first npx run downloads the package

If you use a local clone, set command = "node" and args = ["/path/to/ibkr-mcp-guard/server/index.mjs"]. The repo also ships a .codex-plugin/plugin.json manifest for hosts that install Codex-format plugins by URL.

Any other MCP client

npx -y github:tivojn/ibkr-mcp-guard        # stdio MCP server
# or from a clone:
node server/index.mjs

First use

  1. Ask your assistant to "sign in to IBKR", or ask any IBKR question, such as "what are my positions?".

  2. Your browser opens IBKR's sign-in page. The consent screen should list read access and order-instruction (draft) access only, not order submission. Approve it.

  3. The tab says Signed in to IBKR. Go back to the assistant and ask again.

The guard's own tools work before you sign in:

  • ibkr_sign_in opens the browser sign-in. It returns immediately and finishes in the background, and does nothing if you are already signed in.

  • ibkr_status shows whether you are signed in, your account ids (if IBKR reports them), the granted scopes, when the token expires, and whether order submission was granted (it should say no).

  • ibkr_sign_out revokes the tokens at IBKR and deletes them locally.

  • ibkr_paper_log (only in paper trading mode) shows the latest paper-order audit entries.

Before you first sign in, the tool list shows only these three tools. After that, the guard caches IBKR's tool list, so the tools still appear when you are signed out. Calling one while signed out starts a sign-in.

Environment variables

Variable

Effect

IBKR_MCP_GUARD_READONLY=1

Hide and refuse write and draft tools; reads only. Also turns paper mode off.

IBKR_MCP_GUARD_PAPER=1

Paper trading mode: order submission to IBKR paper accounts only.

IBKR_MCP_GUARD_PAPER_NO_CONFIRM=1

In paper mode, skip the guard's Approve/Cancel prompt before each paper order (for automated strategy runs). Has no effect outside paper mode.

IBKR_MCP_GUARD_STORE=file

Use the 0600 file instead of the macOS Keychain.

IBKR_MCP_GUARD_NO_BROWSER=1

Don't open a browser; the sign-in result includes the link to open yourself (useful over SSH).

CLAUDE_PLUGIN_DATA / PLUGIN_DATA

Data directory (set by plugin hosts). Otherwise $XDG_CONFIG_HOME/ibkr-mcp-guard or ~/.config/ibkr-mcp-guard.

IBKR_MCP_GUARD_UPSTREAM

Testing only: a different upstream MCP URL. A warning is logged to stderr.

The data directory holds the token file (non-macOS, or with STORE=file), tools-cache.json (the last tool list, which contains no secrets) and, in paper mode, paper-orders.log.

Paper trading mode

Paper trading mode is for testing strategies on an IBKR paper trading account through IBKR's official connector. It is off by default. When it is off, nothing on this page applies and the guard behaves exactly as described above.

What it does

With IBKR_MCP_GUARD_PAPER=1:

  • The sign-in also asks for order submission. The guard requests openid account-ids mcp.read mcp.write mcp.orders.submit. Only this code path can ask for mcp.orders.submit; the default path still throws if anything asks for it.

  • Changing modes needs a new sign-in. Each saved sign-in remembers which scopes it was made with. If you turn paper mode on or off, the old sign-in is not used, and the guard asks you to sign in again.

  • Order submission is gated to paper accounts. The tools that the default mode removes (place, submit, cancel or modify orders, and so on) are allowed only when every account the sign-in can see is a paper account, meaning its id starts with DU or DF. Before every submit, the guard:

    1. reads the account ids again from IBKR, by calling the account tools (get_account_positions, get_account_balances, get_account_summary, get_account_orders and any other read tool whose name mentions accounts) and scanning their answers for account ids;

    2. refuses if it sees any non-paper id (U…, F…, I…), or if it cannot find any account id at all;

    3. refuses if the order's arguments name an account that is not one of those paper accounts.

    The result of this check is never cached. Each submit makes its own check.

  • Submit tools are shown only while the session is paper-only. They are listed with the description prefix "PAPER ACCOUNT ONLY — submits a simulated order to your IBKR paper account (DU…). Refused for live accounts." and destructiveHint: true. The guard checks again on every tools/list and after each sign-in, and sends notifications/tools/list_changed when the answer changes. At other times the submit tools are hidden, and they are refused if called by name.

  • Every order is confirmed. If your MCP client supports elicitation, the guard shows a plain read-back (account, side, quantity, symbol, order type, price if given, time in force) and asks you to Approve or Cancel. After you approve, it checks the accounts again before sending. Without elicitation, your host's own approval prompt applies, which is triggered by destructiveHint. For automated strategy runs, IBKR_MCP_GUARD_PAPER_NO_CONFIRM=1 skips the guard's prompt. Even then, orders still go only to paper accounts.

  • Every attempt is logged. Each paper submit attempt (submitted, failed, refused or cancelled) is added as one JSON line to paper-orders.log in the data directory (file mode 0600). Each line records the time, the tool, the decision and reason, the accounts seen, a read-back of the order and its arguments. Tokens are never written to the log. Use the ibkr_paper_log tool (optional limit, default 20) to see recent entries.

  • ibkr_status shows the paper state: whether paper mode is on, the accounts seen in a fresh read (each labelled paper or LIVE), whether mcp.orders.submit was granted, and whether submits are allowed right now and why.

IBKR_MCP_GUARD_READONLY=1 overrides paper mode: the guard does not request the submit scope and no orders are submitted.

Get a paper login

  1. In IBKR's Client Portal, open Settings → Paper Trading Account. Create (or reset) your paper account there and note its username. Paper accounts start with simulated funds, normally USD 1,000,000.

  2. When the guard opens IBKR's sign-in page, set the login page's Live / Paper switch to Paper, then sign in with the paper username.

IBKR's official MCP connector does accept paper logins. A paper sign-in through this guard has been checked: the account summary showed the paper account's USD 1,000,000 net liquidation value and no positions. If you sign in with a live login while paper mode is on, the guard sees the live account id and refuses every submit.

Turn it on

Paper mode is set by an environment variable on the MCP server, so set it in your host's server configuration.

EnConvo: in the plugin's MCP server settings, add the environment variable IBKR_MCP_GUARD_PAPER with value 1 (and, if you want, IBKR_MCP_GUARD_PAPER_NO_CONFIRM = 1). Then restart the server.

Claude Code: add it as a separate MCP server with the variable set:

claude mcp add -e IBKR_MCP_GUARD_PAPER=1 ibkr-paper -- npx -y github:tivojn/ibkr-mcp-guard

Codex (~/.codex/config.toml):

[mcp_servers.ibkr-paper]
command = "npx"
args = ["-y", "github:tivojn/ibkr-mcp-guard"]
env = { IBKR_MCP_GUARD_PAPER = "1" }
startup_timeout_sec = 60

After you turn it on, ask the assistant to "sign in to IBKR", sign in with your paper login, and then run ibkr_status. It should show your DU… account labelled paper and "Paper order submission allowed now: yes".

Paper trading is simulated. Paper fills, prices and margin can differ from what would happen in a live account, and results in paper trading do not predict live results. This is not financial advice.

Troubleshooting

  • The browser didn't open. Use the link in the tool result, or set IBKR_MCP_GUARD_NO_BROWSER=1. The sign-in must finish on the same machine, because IBKR redirects to http://127.0.0.1:<port>/callback.

  • "Sign-in timed out". The flow waits 10 minutes. Ask to sign in again.

  • "Sign-in did not match". You opened an old sign-in tab. Start a new sign-in.

  • No IBKR tools after signing in. Your client may ignore notifications/tools/list_changed. Restart the MCP server or reload tools.

  • Signed out unexpectedly. IBKR refused to renew the token (for example, it was revoked or expired). Sign in again.

  • Reset everything. Run ibkr_sign_out. Then:

    • On macOS, delete the Keychain items with service ibkr-mcp-guard (Keychain Access, or security delete-generic-password -s ibkr-mcp-guard -a https://api.ibkr.com/v1/api/mcp-public).

    • Elsewhere, delete the data directory.

  • Logs. The server logs to stderr only. stdout carries MCP JSON-RPC.

  • Paper mode refuses every submit. Run ibkr_status. "This sign-in can see non-paper (live) account(s)" means you signed in with a live login: sign out and sign in with your paper login. "No account ids could be read" means IBKR's account tools did not return any account id, so the guard cannot confirm that only paper accounts are visible.

  • "You need to sign in again" after changing paper mode. This is expected: a sign-in made in one mode is not used in the other.

  • Why Node's fetch? api.ibkr.com asks for an optional TLS client certificate. Chromium-based HTTP stacks treat that as fatal, but Node's fetch handles it.

How it works

your AI host ──stdio (MCP)──▶ ibkr-mcp-guard ──HTTPS (MCP Streamable HTTP + OAuth bearer)──▶ api.ibkr.com/v1/api/mcp-public
                                   │ policy: block / draft / write / read
                                   └─ tokens: macOS Keychain or 0600 file
  • MCP server (stdio): newline-delimited JSON-RPC 2.0 with initialize, ping, tools/list and tools/call.

    • Protocol versions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05 are supported; 2025-06-18 is the default.

    • It sends notifications/tools/list_changed after sign-in and sign-out.

    • When the client supports it, it uses elicitation/create to confirm drafts.

  • Upstream client: MCP Streamable HTTP. It accepts JSON or SSE answers, tracks Mcp-Session-Id, follows tools/list paging and applies timeouts. A 401 triggers one token refresh, and a second 401 starts a new sign-in.

  • Sign-in (MCP authorization, OAuth 2.1):

    • Discovery from the WWW-Authenticate resource_metadata value (RFC 9728), then the authorization-server metadata (RFC 8414, path-inserted URL first).

    • Dynamic Client Registration (RFC 7591) as a public native client, with a loopback redirect http://127.0.0.1:<port>/callback. The registered port is reused when it is free; otherwise the guard registers again.

    • PKCE S256 (RFC 7636), plus a random state that is checked on the callback.

    • The resource parameter (RFC 8707) is sent.

    • Refresh tokens are rotated, and tokens are revoked on sign-out.

Development

npm test                 # node --test: offline, fake upstream + fake OAuth server

The tests cover:

  • discovery using IBKR's real metadata strings

  • the DCR body, PKCE (RFC 7636 test vector), state mismatch, and the scope assertion

  • policy classification of the real tool names

  • paper mode: the default path never asking for mcp.orders.submit, the paper scopes, mode changes needing a new sign-in, the DU/DF gate (live ids, unknown ids, accounts named in the order), tool visibility and list_changed, Approve/Cancel, NO_CONFIRM, the audit log and status

  • tools/list filtering and the draft prefix

  • the signed-out call and the 401 refresh

  • SSE parsing

  • the 0600 token file

  • an end-to-end stdio round trip (sign-in, list, call, block, elicitation) against a local fake MCP server

Disclaimer

This software is provided as is, under the MIT License, without warranty of any kind. It is not financial advice, and nothing it or your assistant outputs is a recommendation to buy or sell anything. AI assistants make mistakes: check every number and every draft yourself in IBKR before acting. You use it at your own risk and remain responsible for every action taken in your account. Interactive Brokers, IBKR and related marks belong to their owners.

License

MIT © 2026 Adam Cohen

Available Tools

3 tools
ibkr_sign_inSign in to Interactive BrokersA
Idempotent

Start signing in to Interactive Brokers in the user's browser (read + order-draft access only; order submission is never requested). Returns immediately; the user approves in the browser and then asks again.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantive context beyond the annotations: it discloses the requested permission scope (read + order-draft only, never order submission) and the asynchronous return behavior. With openWorldHint and non-destructive already declared, this covers the main agent concerns, though it says nothing about session lifetime or failure modes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences. The action and permission scope are front-loaded, and the follow-up workflow ('user approves... then asks again') is placed where it is needed. No wasted text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, no-output-schema authentication trigger, the description covers the essentials: what starts, what access is granted, that it returns immediately, and what the agent should do next. Nothing needed to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4. The description correctly implies no input is required and adds no misleading parameter claims.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Start signing in to Interactive Brokers') and scopes it to browser-based authentication. It is clearly distinct from ibkr_sign_out and ibkr_status by action, though it never names those siblings explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The final clause explains the execution model: the call returns immediately, the user approves in the browser, and the agent must 'ask again' afterwards. That is real usage guidance for an async tool, but it offers no explicit when-not condition or named alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ibkr_sign_outSign out of Interactive BrokersA
Idempotent

Sign out of Interactive Brokers: revoke the tokens at IBKR and delete them from this computer.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotent, open-world, non-read-only, non-destructive; the description adds the substantive detail that the tool operates on both sides (remote revocation plus local credential deletion), which is the key behavioral fact an agent needs. It does not clarify what happens if no session exists or that re-authentication is required afterwards, keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with a colon that front-loads the action and then enumerates the two effects. No filler, nothing to trim.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter tool with no output schema and full annotation coverage, the description covers the essential effects. Minor omissions are the post-condition (agent must sign in again) and error behavior when not signed in.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline 4 applies. The description adds no parameter noise either.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names the exact operation (sign out of Interactive Brokers) and specifies the two concrete effects: token revocation at IBKR and local token deletion. This clearly distinguishes it from ibkr_sign_in and ibkr_status, which are the only siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The purpose makes the use case obvious (when you want to end the IBKR session), but the description never states when this should be preferred over simply letting a session lapse, nor does it mention prerequisites such as requiring an active session. Usage is implied rather than guided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ibkr_statusIBKR connection statusA
Read-onlyIdempotent

Show whether the user is signed in to Interactive Brokers, the account ids, granted scopes, token expiry, and confirm that order submission was not granted.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the tool read-only, idempotent, non-destructive, and closed-world, so the safety profile is covered. The description adds behavioral value by specifying the returned status data and explicitly confirming that order submission was not granted, which is meaningful context beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition is a single, front-loaded sentence that enumerates the returned fields without filler. Every clause contributes to describing the tool's output and scope.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of explaining return values and does so thoroughly: sign-in state, account ids, scopes, token expiry, and order-submission permission. For a zero-parameter status tool with full annotation coverage, nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero input parameters, so there are no parameter semantics to explain; the baseline score of 4 applies. The schema and description are consistent, and no missing parameter information exists.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Show') and resource ('signed in to Interactive Brokers') and enumerates the exact status fields returned: account ids, scopes, token expiry, and order-submission permission. This inherently distinguishes it from the sibling sign-in and sign-out tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the status-check nature of the tool, but the description does not explicitly say when to call it versus ibkr_sign_in or ibkr_sign_out, nor does it state prerequisites or exclusions. An agent can infer the use case, but the definition leaves the routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.2.0
    • First observedibkr_sign_in
    • First observedibkr_sign_out
    • First observedibkr_status

TDQS

A4.4/5.0

Scored across 3 tools

Disambiguation5/5

The three tools map cleanly to distinct authentication lifecycle actions: sign in, inspect status, and sign out. There is no overlap in purpose, and the descriptions make the boundaries clear.

Naming Consistency5/5

All tools use the same predictable prefix and verb pattern: ibkr_sign_in, ibkr_status, ibkr_sign_out. The convention is consistent and readable.

Tool Count5/5

For an authentication/guard server, three tools are sufficient and each earns its place. There are no redundant or filler tools.

Completeness5/5

The server covers the full auth lifecycle: sign in, check current status and scopes, and sign out/revoke tokens. No obvious operations are missing for its stated purpose as a guard around IBKR access.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    Enables AI assistants to interact with Interactive Brokers trading accounts to retrieve market data, check positions, and place trades. Includes pre-configured IB Gateway and handles OAuth authentication automatically.
    14
    60 npm
    226
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides AI models with secure access to Interactive Brokers trading data and functionality, enabling account management, market data retrieval, and trading operations through natural language interactions.
    18
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Connects AI assistants to Interactive Brokers for intelligent portfolio management, options analysis, risk monitoring, and automated trading strategy suggestions. Enables real-time account tracking, Greeks calculations, option chain analysis, and playbook-based risk adjustments through natural language.
    5
    -
  • A
    license
    B
    quality
    D
    maintenance
    Gives AI assistants real-time access to Interactive Brokers accounts via the Client Portal Web API, with 26 read-only tools for portfolio, market data, options, and scanner.
    32
    14 npm
    2
    MIT