Skip to main content
Glama
mcp-server-worldquantbrain

mcp-server-worldquantbrain

MCP server and LangGraph tools for WorldQuant BRAIN

PyPI CI License: MIT

mcp-server-worldquantbrain is a Model Context Protocol (MCP) server for the WorldQuant BRAIN API, with the same tools packaged for LangGraph and LangChain. It lets an agent look up data fields, backtest Fast Expression (FASTEXPR) alphas and read the results. Unofficial, and not affiliated with WorldQuant.

Why this exists

Driving BRAIN from an agent goes wrong in a few predictable ways, and each one shaped this package.

  • A simulation takes minutes and clients give up sooner. A wait that runs out returns PENDING with an id, and get_simulation_status picks it up again. Nothing is resubmitted.

  • Agents repeat themselves, and simulations are metered. A local ledger remembers every expression and settings pair, so a repeat returns the earlier alpha instead of spending quota.

  • BRAIN responses are huge. Tools return trimmed, typed results: a PnL series becomes yearly figures, lists are paged and capped, and messages lose their embedded images.

  • Logging in is awkward. The session is saved to disk, so restarts and short-lived stdio processes reuse it. If BRAIN asks for a biometric check you get a URL to open, not a headless browser you cannot see.

  • Submission is permanent. submit_alpha does not exist unless you turn it on, and when it is on it runs BRAIN's checks and the self-correlation test first and refuses on any failure.

Related MCP server: QuantRisk

Quick start

Store your login once. Credentials go to ~/.config/mcp-server-worldquantbrain/credentials.json, readable only by you.

uvx mcp-server-worldquantbrain auth

Then add the server to your client.

Claude Code

claude mcp add brain -- uvx mcp-server-worldquantbrain

Claude Desktop, Cursor, VS Code and others

{
  "mcpServers": {
    "brain": { "command": "uvx", "args": ["mcp-server-worldquantbrain"] }
  }
}

Now ask for something like "Find a value signal in the fundamental datasets for USA TOP3000 and backtest it."

Prefer to pass credentials directly? Add "env": {"WQB_EMAIL": "...", "WQB_PASSWORD": "..."}.

LangGraph and LangChain

The langgraph extra gives you plain LangChain tools in the same process, with no MCP server to run. It also has a prebuilt agent.

uv add "mcp-server-worldquantbrain[langgraph]"
from mcp_server_worldquantbrain.integrations.langgraph import create_brain_agent, get_brain_tools

agent = create_brain_agent("anthropic:claude-sonnet-5")
result = await agent.ainvoke({"messages": [("user", "Backtest rank(-returns) and summarize it")]})

# Or take the tools and build your own graph:
tools = get_brain_tools()

The tools work from sync and async graphs. With WQB_ALLOW_SUBMIT=true the agent stops for human approval before submit_alpha. Invoke it with a thread_id in the config, and resume with Command(resume=...). get_brain_tools() leaves submit_alpha out, because a custom graph has no approval step; pass include_submit=True once yours does.

To keep BRAIN in a separate process, connect over MCP instead. This route needs langchain[mcp], which LangChain still marks as beta.

from langchain.agents import create_agent
from langchain.mcp import MCPAdapter

config = {
    "mcpServers": {
        "brain": {
            "command": "uvx",
            "args": ["mcp-server-worldquantbrain"],
            "timeout": 1_200_000,  # milliseconds; simulations block
        }
    }
}

async with MCPAdapter(config) as adapter:
    agent = create_agent("anthropic:claude-sonnet-5", await adapter.list_tools())

The subprocess inherits only HOME, PATH and a few others, so anything else, including WQB_* variables, has to go in env. Over this route a submission confirmation arrives as a LangGraph interrupt, so give the agent a checkpointer if you enable submission. A deployable example is in examples/langgraph_app.

draw_mermaid(agent) from mcp_server_worldquantbrain.integrations.langgraph returns the graph as a Mermaid flowchart, for the prebuilt agent or a graph of your own. Tools are grouped by area and colored by what they can change. This is the prebuilt agent with WQB_ALLOW_SUBMIT=true:

---
config:
  flowchart:
    nodeSpacing: 24
    rankSpacing: 12
    padding: 8
---
flowchart TB
    subgraph agent["Agent graph"]
        direction LR
        n0([start])
        n1["model"]
        n2["tools"]
        n3{{"human approval<br/>before submit_alpha"}}:::approval
        n4([end])
        n3 -.-> n4
        n3 -.->|"rejected"| n1
        n3 -.->|"approved"| n2
        n0 --> n1
        n1 --> n3
        n2 -.-> n1
    end
    subgraph tools["Tools"]
        direction TB
        subgraph tools_row0[" "]
            direction LR
            subgraph tools_auth["Login"]
                direction LR
                tools_auth_read["auth_status"]:::read
                tools_auth_write["authenticate<br/>complete_authentication"]:::write
            end
            subgraph tools_simulations["Simulate"]
                direction LR
                tools_simulations_read["get_simulation_status<br/>get_simulation_options"]:::read
                tools_simulations_write["simulate_alpha<br/>simulate_alphas_batch"]:::write
            end
            subgraph tools_submit["Submit"]
                direction LR
                tools_submit_irreversible["submit_alpha"]:::irreversible
            end
            tools_auth ~~~ tools_simulations ~~~ tools_submit
        end
        subgraph tools_row1[" "]
            direction LR
            subgraph tools_alphas["Alphas"]
                direction LR
                tools_alphas_read["get_alpha<br/>list_alphas<br/>get_alpha_pnl<br/>list_alpha_recordsets<br/>get_alpha_recordset<br/>check_alpha_submission<br/>get_alpha_self_correlation<br/>get_alpha_prod_correlation"]:::read
                tools_alphas_write["update_alpha"]:::write
            end
            subgraph tools_data["Data"]
                direction LR
                tools_data_read["list_datasets<br/>get_dataset<br/>list_datafields<br/>get_datafield<br/>list_data_categories<br/>list_operators"]:::read
            end
            subgraph tools_users["Account"]
                direction LR
                tools_users_read["get_user_profile<br/>get_user_activity<br/>list_messages"]:::read
            end
            tools_alphas ~~~ tools_data ~~~ tools_users
        end
        tools_row0 ~~~ tools_row1
    end
    agent -- tool calls --> tools
    subgraph legend["Legend"]
        direction TB
        legend_read["read-only"]:::read
        legend_write["changes account state"]:::write
        legend_irreversible["irreversible"]:::irreversible
    end
    brain["BRAIN API"]:::external
    tools -- HTTPS --> brain
    tools ~~~ legend
    classDef default fill:#64748b,fill-opacity:0.06,stroke:#64748b
    classDef read fill:#64748b,fill-opacity:0.14,stroke:#64748b
    classDef write fill:#d97706,fill-opacity:0.16,stroke:#d97706
    classDef irreversible,approval fill:#dc2626,fill-opacity:0.16,stroke:#dc2626,stroke-width:2px
    classDef external fill-opacity:0,stroke-dasharray:5 4
    classDef box fill:#64748b,fill-opacity:0.05,stroke:#64748b,stroke-opacity:0.45
    classDef row fill:none,stroke:none
    class agent,tools,tools_auth,tools_simulations,tools_submit,tools_alphas,tools_data,tools_users,legend box
    class tools_row0,tools_row1 row

Tools

Group

Tool

Notes

Login

authenticate, complete_authentication, auth_status

Other tools log in by themselves

Simulate

simulate_alpha

Blocks up to 15 minutes by default; wait=False returns at once

simulate_alphas_batch

Up to 30 expressions, in groups of 10; needs multi-simulation access

get_simulation_status

Check or resume a simulation

get_simulation_options

Regions, universes and delays your account can use

Alphas

get_alpha, list_alphas

Filter by Sharpe, fitness, turnover, date, tag and more

get_alpha_pnl, list_alpha_recordsets, get_alpha_recordset

PnL by year; other recordsets as rows

update_alpha

Name, description, tags, color, category

check_alpha_submission

BRAIN's pre-submission checks

get_alpha_self_correlation, get_alpha_prod_correlation

Production correlation depends on account tier

submit_alpha

Off unless WQB_ALLOW_SUBMIT=true

Data

list_datasets, get_dataset, list_datafields, get_datafield

list_data_categories, list_operators

Account

get_user_profile, get_user_activity, list_messages

Personal fields are withheld by default

Resources: brain://operators, brain://simulation-options, brain://alphas/{alpha_id}, and reference pages under brain://docs/ (fastexpr-cheatsheet, settings-guide, submission-criteria).

Prompts: design_alpha runs a short research loop. review_alpha assesses an existing alpha.

Configuration

All settings are environment variables. A .env file in the working directory also works, except for settings that decide where credentials go or that enable submission (WQB_BASE_URL, the file and directory paths, the WQB_SUBMIT_* and WQB_ALLOW_SUBMIT settings, and the bearer token). These have to be set in the real environment.

Variable

Default

Purpose

WQB_EMAIL, WQB_PASSWORD

Login. These win over the credentials file

WQB_CREDENTIALS_FILE

~/.config/mcp-server-worldquantbrain/credentials.json

JSON: ["email", "password"]

WQB_SESSION_FILE

~/.config/mcp-server-worldquantbrain/session.json

Saved session. Delete it to log out

WQB_CACHE_DIR

~/.cache/mcp-server-worldquantbrain

Catalogue cache and simulation ledger

WQB_CACHE_TTL

per catalogue

Seconds; 0 disables the cache

WQB_LEDGER

true

Reuse results of identical simulations

WQB_ALLOW_SUBMIT

false

Expose submit_alpha

WQB_SUBMIT_CONFIRM

elicit

Ask the user first where the client supports it; none skips asking

WQB_SUBMIT_CORRELATION_GATE

0.7

Refuse at or above this self-correlation; 0 disables

WQB_MAX_CONCURRENT_SIMULATIONS

2

Blocking simulation calls this process runs at once

WQB_SIMULATION_TIMEOUT

900

Seconds a blocking simulation waits

WQB_HTTP_TIMEOUT

30

Seconds per HTTP request

WQB_POLL_MAX_INTERVAL

30

Longest pause between status polls

WQB_HTTP_BEARER_TOKEN

Required by the HTTP transport on a non-local address

WQB_LOG_LEVEL

INFO

Logs go to stderr

WQB_DEFAULT_REGION, WQB_DEFAULT_UNIVERSE, _DELAY, _DECAY, _NEUTRALIZATION, _TRUNCATION, _PASTEURIZATION, _UNIT_HANDLING, _NAN_HANDLING, _TEST_PERIOD, _MAX_TRADE, _INSTRUMENT_TYPE

USA, TOP3000, 1, 0, INDUSTRY, 0.08, ON, VERIFY, OFF, none, OFF, EQUITY

Used when a call leaves a setting out. A call for another region must name its universe

On Windows the two directories are %APPDATA%\mcp-server-worldquantbrain and %LOCALAPPDATA%\mcp-server-worldquantbrain, and files are protected by your user profile rather than POSIX permissions.

To serve over HTTP:

WQB_HTTP_BEARER_TOKEN=change-me mcp-server-worldquantbrain serve --transport streamable-http --host 0.0.0.0

The server refuses a non-local address without a token. /health stays open for probes.

How it behaves

Long calls. Claude Desktop has been reported to cancel stdio tool calls after about a minute, so for that client each call is limited to 45 seconds of waiting and the agent resumes with get_simulation_status. Claude Code and LangGraph wait as long as you let them. Set WQB_SIMULATION_TIMEOUT to match whatever your client allows.

Concurrency. BRAIN limits simultaneous simulations per account and does not publish the number. The default of 2 is deliberately cautious. Raise it if your account allows more. The setting only counts blocking calls while they wait, and one batch group of up to 10 uses one slot. wait=False calls, simulations still running after a timeout, and other processes on the same account are not counted, and can hit BRAIN's own limit, which comes back as a rate-limit error with a suggested wait.

The ledger. Whitespace in an expression does not matter; every setting does. Pass force=True to run an identical simulation again. Failed simulations can be run again.

Writes are not retried. A POST that may have reached BRAIN is never repeated automatically, so a network failure cannot spend quota twice or submit twice. Reads retry with backoff and honour Retry-After.

Biometric login. authenticate returns a URL, the user finishes the check in a browser, and complete_authentication ends the login. The pending check is saved for 30 minutes, so it survives a restart. On a terminal, mcp-server-worldquantbrain auth does the same with a prompt.

What is cached. Operators and simulation options for a week, categories and dataset pages for a day. Alphas, simulations, checks, correlations and data fields are always fetched fresh.

What is never logged. Passwords, cookies, authorization headers and session tokens are masked, and email addresses are shortened, in logs and error messages.

Limitations

  • BRAIN's API documentation sits behind a login, and BRAIN can change the API without notice. Run WQB_LIVE=1 uv run pytest -m live to check it against your account.

  • Login, saved sessions, data catalogues, single simulations, alpha search, PnL, recordsets, submission checks and self-correlation have been run against a live account. Biometric completion, multi-simulation, update_alpha, submit_alpha and production correlation results have only been tested against responses documented by other BRAIN clients, so treat them as less proven. If a biometric completion fails, log in once on the BRAIN website and call authenticate with force=true.

  • The self-correlation gate fails closed: if BRAIN will not report the figure, submit_alpha refuses. Set WQB_SUBMIT_CORRELATION_GATE=0 on accounts where that endpoint is unavailable.

  • Simulations are REGULAR FASTEXPR alphas. SUPER and region-agnostic alphas, Python alphas, forum access, payments, competitions and pyramids are not covered.

  • There is no cancel tool, because no cancel endpoint is known.

  • credentials.json is plaintext protected by file permissions. Use WQB_EMAIL and WQB_PASSWORD from your own secret store if that is not enough.

  • Check that your use of automation complies with the BRAIN terms that apply to you.

Other WorldQuant BRAIN projects

  • cnhkmcp is on PyPI and covers far more of the platform, including the forum. It is a large install that bundles Selenium.

  • lavender1203/world-quant-brain-mcp has the deepest local analytics, such as correlation pools and an alpha history database. It runs with Docker and Redis over HTTP, and has no license.

  • QuantGPT is a full research agent with its own knowledge base, for when you want the loop rather than the tools.

  • worldquant-harness adds local backtests and a strict human submission boundary.

  • brainapi-go-sdk is a Go SDK and CLI with static binaries and tests built on captured API responses.

  • rocky-d/wqb is a plain Python client, if you do not need an agent interface.

No code in this repository was copied from those projects.

Development

To point a client at a checkout, use uvx --from /path/to/mcp-server-worldquantbrain mcp-server-worldquantbrain, or uv add --editable ../mcp-server-worldquantbrain from your LangGraph project. See CONTRIBUTING.md and RELEASING.md.

License

MIT

Available Tools

25 tools
authenticateLog in to BRAINA

Log in with the configured credentials, reusing a saved session when it is still valid.

Tools log in on their own, so this is only needed to start or restart a biometric check. When
state is biometric_required, have the user open biometric_url, then call
complete_authentication.

Inputs: force. Returns: state, user_id, next_step, biometric_url, +2 more

auth_statusCheck the BRAIN sessionA
Read-onlyIdempotent

Report whether a BRAIN session is active and when it expires. Never sends the password.

Inputs: no named parameters. Returns: state, user_id, next_step, biometric_url, +2 more

check_alpha_submissionRun submission checksB
Read-onlyIdempotent

Run BRAIN's pre-submission checks. verdict is PASS, WARNING, FAIL or PENDING.

Inputs: alpha_id (required), wait_seconds. Returns: checks, failed, pending, verdict, +4 more

complete_authenticationFinish a biometric loginA

Finish a login after the user completed the biometric check at biometric_url.

Inputs: no named parameters. Returns: state, user_id, next_step, biometric_url, +2 more

get_alphaGet an alphaB
Read-onlyIdempotent

Return an alpha's expression, settings, in-sample stats and submission checks.

Inputs: alpha_id (required). Returns: id, name, tags, type, +23 more

get_alpha_pnlGet alpha PnLB
Read-onlyIdempotent

Summarize an alpha's PnL by year, with optional recent daily cumulative values.

Inputs: alpha_id (required), last_n, include_daily. Returns: daily, yearly, alpha_id, end_date, +4 more

get_alpha_prod_correlationGet production correlationB
Read-onlyIdempotent

Return the alpha's correlation with the production pool. Some account tiers get a 403.

Inputs: alpha_id (required), wait_seconds. Returns: top, kind, count, passes, +6 more

get_alpha_recordsetGet an alpha recordsetA
Read-onlyIdempotent

Return one recordset as named rows. Prefer get_alpha_pnl for PnL.

Inputs: name (required), alpha_id (required), max_rows. Returns: name, rows, columns, alpha_id, +2 more

get_alpha_self_correlationGet self-correlationB
Read-onlyIdempotent

Return the alpha's highest correlation with the user's submitted alphas (limit 0.7).

Inputs: alpha_id (required), wait_seconds. Returns: top, kind, count, passes, +6 more

get_datafieldGet a data fieldC
Read-onlyIdempotent

Return one data field with its full description, for example field_id 'close'.

Inputs: field_id (required). Returns: id, type, delay, region, +9 more

get_datasetGet a datasetB
Read-onlyIdempotent

Return one dataset with its full description, for example dataset_id 'pv1'.

Inputs: dataset_id (required). Returns: id, name, delay, region, +10 more

get_simulation_optionsList valid simulation settingsA
Read-onlyIdempotent

List the regions, universes, delays and neutralizations this account may simulate.

by_context maps parent settings such as 'EQUITY:USA' to the values valid for them. Cached for
a week.

Inputs: no named parameters. Returns: raw, fields, parsed

get_simulation_statusGet simulation statusB
Read-onlyIdempotent

Check or resume a simulation. A finished one includes its alpha; a batch lists children.

Inputs: simulation_id (required), wait_seconds. Returns: alpha, quota, status, message, +7 more

get_user_activityGet my activityA
Read-onlyIdempotent

Return simulation or submission counts: yesterday, month to date, year to date, total.

Inputs: kind (required). Returns: ytd, kind, total, recent, +4 more

get_user_profileGet my profileA
Read-onlyIdempotent

Return the user's BRAIN profile. Personal fields are withheld by default.

Inputs: include_pii. Returns: id, approved, personal, verified, +3 more

list_alpha_recordsetsList alpha recordsetsA
Read-onlyIdempotent

List the recordset names available for an alpha, for use with get_alpha_recordset.

Inputs: alpha_id (required). Returns: names, alpha_id

list_alphasList my alphasB
Read-onlyIdempotent

Search the user's alphas. Use next_offset to page; BRAIN stops at offset 10,000.

Inputs: tag, name, color, delay, +16 more. Returns: count, items, next_offset, truncated_by_api

list_data_categoriesList data categoriesA
Read-onlyIdempotent

Return the data category tree. Cached for a day.

Inputs: no named parameters. Returns: items

list_datafieldsList data fieldsA
Read-onlyIdempotent

Find the data fields usable in expressions.

BRAIN stops paging at 10,000 rows, so when truncated_by_api is true narrow with dataset_id or
search.

Inputs: type, delay, limit, order, +7 more. Returns: count, items, next_offset, truncated_by_api

list_datasetsList datasetsB
Read-onlyIdempotent

List datasets available for a market. Cached for a day.

Inputs: delay, limit, order, theme, +6 more. Returns: count, items, next_offset, truncated_by_api

list_messagesList my messagesB
Read-onlyIdempotent

Return platform messages, newest first, as plain text capped at 2,000 characters each.

Inputs: type, limit, offset. Returns: count, items, next_offset, truncated_by_api

list_operatorsList operatorsA
Read-onlyIdempotent

List the FASTEXPR operators this account can use. Cached for a week.

Inputs: search, verbose, category. Returns: count, items

simulate_alphaSimulate an alphaA

Backtest one FASTEXPR expression and return its alpha with stats and checks.

A simulation usually takes 1 to 10 minutes. If it outlasts the timeout the result has status
PENDING and a simulation_id: call get_simulation_status to resume, never simulate again.
Identical expression and settings return the earlier result (from_ledger) without spending
quota. ERROR or FAIL results carry BRAIN's message, usually a syntax or field problem.

Inputs: expression (required), wait, decay, delay, +12 more. Returns: alpha, quota, status, message, +7 more

simulate_alphas_batchSimulate several alphasA

Backtest up to 30 expressions, sent to BRAIN in groups of at most 10.

All expressions must share one delay; different regions are sent as separate groups.
Multi-simulation needs a Consultant account. Expressions already in the ledger are returned
without spending quota. not_started lists anything that could not be sent; resubmit those later.

Inputs: alphas (required), wait, force, timeout_seconds. Returns: status, message, results, batch_ids, +2 more

update_alphaUpdate alpha propertiesC
Idempotent

Change an alpha's name, description, tags, color, category, favorite or hidden flag.

Inputs: alpha_id (required), name, tags, color, +4 more. Returns: id, name, tags, type, +23 more

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    B3.3/5.0

    Scored across 25 tools

    Disambiguation4/5

    Tools are grouped into clear resource families (datasets/datafields, alphas, simulations, auth, user) and each action is largely distinct. The only real overlap is get_alpha_pnl vs get_alpha_recordset and get_dataset vs get_datafield, and the descriptions explicitly steer callers ('Prefer get_alpha_pnl for PnL'), which resolves the ambiguity in practice.

    Naming Consistency4/5

    Almost everything follows a predictable snake_case verb_noun pattern (list_datasets, get_alpha, simulate_alpha, check_alpha_submission). Minor deviations: auth_status has no verb, and authenticate stands alone without a noun object, but the convention remains readable overall.

    Tool Count3/5

    25 tools is at the upper edge of well-scoped; each maps to a real BRAIN operation, but several niche read tools (get_alpha_self_correlation, get_alpha_prod_correlation, list_alpha_recordsets, get_alpha_recordset, list_messages) could be folded into broader getters without losing capability.

    Completeness3/5

    Simulation, discovery, and alpha inspection are well covered, including batch runs, resume-via-status, and pre-submission checks. However, there is no tool to actually submit an alpha (only check_alpha_submission), no delete_alpha, and no way to enumerate past simulations independent of alphas, leaving lifecycle dead ends.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Automates WorldQuant BRAIN alpha research workflows, including simulation, reference search, and alpha submission through MCP tools.
      2
      MIT
    • F
      license
      A
      quality
      C
      maintenance
      Enables agents to generate alpha signals, retrieve market snapshots, compute portfolio risk, validate and submit paper orders, and trigger a kill switch, all under deterministic pre-trade risk controls and audit logging.
      5
      -
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI agents to run WorldQuant BRAIN alpha backtests via MCP, supporting expression submission, status tracking, result analysis, and batch resumption.
      1
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables LLM agents to safely perform WorldQuant BRAIN research tasks such as account status checks, dataset/field/operator discovery, recent alpha retrieval, candidate writing, and guarded multi-simulation runs, while deliberately excluding alpha submission from the MCP layer.
      11
      MIT