openbb-mcp
The openbb-mcp-server package installs the openbb-mcp command, which serves the routes of a FastAPI app as Model Context Protocol tools through FastMCP. By default the app is the OpenBB REST API built from the installed extensions. --app serves any other FastAPI app, and --spec serves a proxy built from an openbb-cli .spec file.
Installation
pip install openbb-mcp-server openbb-cboe openbb-imf
The package requires Python 3.10 or newer and openbb-core 2.x. The tools come from whatever provider and extension packages are installed alongside it. The cli extra installs openbb-cli and enables four more tools:
pip install "openbb-mcp-server[cli]"
Launch
openbb-mcp
The default transport is streamable-http at http://127.0.0.1:8001/mcp. Run openbb-mcp --help to print the flags and a commented openbb.toml example.
| Flag | Default | Description |
|---|---|---|
--app | Installed REST API | FastAPI app whose routes become tools: a Python file, file.py:name, or package.module:name. |
--name | app | Name of the app instance or factory function. A :name suffix on --app sets it too. |
--factory | Off | Call --name to create the app. |
--spec | None | .spec file to serve as a proxy. Cannot be combined with --app. |
--config-file | None | TOML file applied on top of the discovered openbb.toml files. Also read from OPENBB_MCP_CONFIG, OPENBB_API_CONFIG, or OPENBB_CONFIG. |
--transport | streamable-http | streamable-http, sse, or stdio. |
--host | 127.0.0.1 | Bind address for the HTTP transports. |
--port | 8001 | Bind port for the HTTP transports. |
--allowed-categories | All | Comma-separated categories to serve. Routes in other categories are never registered. |
--default-categories | all | With tool discovery off, the categories whose tools are listed and callable. |
--tool-discovery | Off | Hide the command tools behind the discovery tools. |
--system-prompt | None | Text file used as the system prompt. |
--server-prompts | None | JSON file of prompt definitions. |
Every other --key value pair is routed by name. A key that matches a setting, with hyphens or underscores, sets it, as in --enable-cli-tools false or --server-auth '["user", "pass"]'. A key starting with httpx- sets an option of the httpx client that sends tool calls to the app, as in --httpx-verify false. Anything else goes to uvicorn with hyphens converted to underscores, as in --log-level debug or --ssl-keyfile key.pem. The values true and false become booleans, and a value wrapped in [] or {} is parsed as JSON.
Configuration
Settings are resolved from four sources. Each overrides the ones below it:
- Command-line flags.
- The
[mcp]table of theopenbb.tomlfiles, applied as if its keys were flags. OPENBB_MCP_*environment variables.~/.openbb_platform/mcp_settings.json, which the server writes with the defaults on its first run.
For some data providers, the API key must be set in the OpenBB credentials, not in the MCP settings.
Settings
| Setting | Environment variable | Type | Default | Description |
|---|---|---|---|---|
name | OPENBB_MCP_NAME | str | "OpenBB MCP" | Server name reported to clients. |
description | OPENBB_MCP_DESCRIPTION | str | Built-in text | Server description. |
version | OPENBB_MCP_VERSION | str | None | Server version. |
instructions | OPENBB_MCP_INSTRUCTIONS | str | None | Text sent to the client during the MCP initialize handshake. When unset, the system prompt fills it. |
api_prefix | OPENBB_MCP_API_PREFIX | str | None | Prefix stripped from route paths when naming tools. None uses the OpenBB API prefix, /api/v1. |
default_tool_categories | OPENBB_MCP_DEFAULT_TOOL_CATEGORIES | list[str] | ["all"] | With tool discovery off, the categories served. Other tools are registered but disabled, unless a route sets enable. Ignored with tool discovery on. |
allowed_tool_categories | OPENBB_MCP_ALLOWED_TOOL_CATEGORIES | list[str] | None | The only categories served, with or without discovery. None or ["all"] serves every category. |
enable_tool_discovery | OPENBB_MCP_ENABLE_TOOL_DISCOVERY | bool | False | Hide the command tools behind available_categories, available_tools, search_tools, and call_tool. |
list_page_size | OPENBB_MCP_LIST_PAGE_SIZE | int | None | Maximum items per page in MCP list responses. None returns everything in one page. |
describe_responses | OPENBB_MCP_DESCRIBE_RESPONSES | bool | False | Keep the query parameter and response documentation in tool descriptions. When False, descriptions stop before it. |
system_prompt_file | OPENBB_MCP_SYSTEM_PROMPT_FILE | str | None | Path to a text file used as the system prompt. |
server_prompts_file | OPENBB_MCP_SERVER_PROMPTS_FILE | str | None | Path to a JSON file of prompt definitions. |
default_skills_dir | OPENBB_MCP_DEFAULT_SKILLS_DIR | str | Bundled skills | Directory of skills, one subdirectory with a SKILL.md per skill. null or an empty string disables it. |
skills_reload | OPENBB_MCP_SKILLS_RELOAD | bool | False | Re-read skill files on every read. |
skills_providers | OPENBB_MCP_SKILLS_PROVIDERS | list[str] | None | Vendor skill directories to load: claude, cursor, vscode, copilot, codex, gemini, goose, opencode. |
enable_cli_tools | OPENBB_MCP_ENABLE_CLI_TOOLS | bool | True | Register the openbb-cli dispatcher tools when openbb-cli is installed. |
on_duplicate | OPENBB_MCP_ON_DUPLICATE | str | None | What to do when a tool, resource, or prompt is registered twice: warn, error, replace, or ignore. |
mask_error_details | OPENBB_MCP_MASK_ERROR_DETAILS | bool | None | Hide exception details from clients. |
module_exclusion_map | OPENBB_MCP_MODULE_EXCLUSION_MAP | dict[str, str] | None | Route path segments mapped to Python modules. Routes under a segment are hidden while its module is imported. None uses {"coverage": "openbb_core"}; {} hides nothing. |
uvicorn_config | OPENBB_MCP_UVICORN_CONFIG | dict | {"host": "127.0.0.1", "port": "8001"} | Keyword arguments for uvicorn on the HTTP transports. Keys use underscores. |
httpx_client_kwargs | OPENBB_MCP_HTTPX_CLIENT_KWARGS | dict | {} | Options for the httpx client that sends tool calls to the app, such as headers, timeout, or verify. |
client_auth | OPENBB_MCP_CLIENT_AUTH | [str, str] | None | Username and password sent as httpx auth on requests to the app. |
server_auth | OPENBB_MCP_SERVER_AUTH | [str, str] | None | Username and password that HTTP clients must send as a Bearer token. |
Lists and dictionaries
List settings accept a comma-separated string or a JSON array, on the command line and in environment variables. Dictionary settings accept a JSON object on the command line; environment variables also accept comma-separated key:value pairs. Wrap JSON in single quotes in the shell so the double quotes reach the server intact.
openbb-mcp --default-categories cboe,imf
openbb-mcp --default-categories '["cboe", "imf"]'
openbb-mcp --uvicorn-config '{"host": "0.0.0.0", "port": 9000}'
OPENBB_MCP_DEFAULT_TOOL_CATEGORIES="cboe,imf"
OPENBB_MCP_UVICORN_CONFIG="host:0.0.0.0,port:9000"
OPENBB_MCP_HTTPX_CLIENT_KWARGS='{"timeout": 30}'
openbb.toml
At startup openbb-mcp merges the layered openbb.toml files, lowest priority first: the [tool.openbb] table of the nearest pyproject.toml (so [tool.openbb.mcp] there), ~/.openbb_platform/openbb.toml, the nearest openbb.toml walking up from the working directory, and the file given by --config-file, OPENBB_MCP_CONFIG, OPENBB_API_CONFIG, or OPENBB_CONFIG. .openbb.toml works in place of openbb.toml, and a syntax error in the explicit file stops the server at startup. The [system] table and the top-level shortcuts apply to the system settings of the server process, as described in openbb.toml.
[mcp]
host = "0.0.0.0"
port = 8005
default-categories = "cboe,imf"
tool-discovery = true
enable_cli_tools = false
[mcp.auth]
hooks = ["my_pkg.auth:check_bearer_token"]
[mcp.middleware]
hooks = ["my_pkg.middleware:log_requests"]
[env]
OPENBB_MCP_NAME = "Research MCP"
[mcp] holds defaults for any flag or setting, with hyphens or underscores. [env] sets environment variables before the server starts, without replacing variables already set in the shell, and expands $VAR or ${VAR} references. An entry that references an unset variable is skipped with a warning.
[mcp.auth] and [mcp.middleware] list module:attribute references to async def hook(request, call_next) functions. They wrap the streamable-http and sse transports, not stdio. Auth hooks run before middleware hooks, and each list runs in order. A reference that cannot be imported, is not async, or takes fewer than two arguments stops the server at startup.
[mcp.spec] configures spec proxy mode. When it is absent, a top-level [spec] table is used instead, so one openbb.toml can configure the same proxy for openbb-api and openbb-mcp.
Authentication
Server authentication
server_auth requires every HTTP request to carry Authorization: Bearer <token>, where the token is the Base64 encoding of username:password. Requests without a valid token are rejected. Set it in mcp_settings.json, in the environment, or on the command line:
{
"server_auth": ["admin", "secretpass"]
}
OPENBB_MCP_SERVER_AUTH='["admin", "secretpass"]'
A client then sends the encoded pair, here base64("admin:secretpass"):
{
"mcpServers": {
"openbb-mcp": {
"url": "http://127.0.0.1:8001/mcp",
"headers": {
"Authorization": "Bearer YWRtaW46c2VjcmV0cGFzcw=="
}
}
}
}
Client authentication
client_auth is the credential the MCP server sends to the app it wraps, as httpx auth. A username and password pair is sent as HTTP Basic authentication, which matches the login of an OpenBB API started with OPENBB_API_AUTH enabled.
OPENBB_MCP_CLIENT_AUTH='["client_user", "client_pass"]'
In code
create_mcp_server builds the FastMCP server from settings and an app. Its auth argument accepts any FastMCP AuthProvider, a (username, password) pair with the same meaning as server_auth, or None; anything else raises TypeError.
from fastapi import FastAPI
from fastmcp.server.auth.providers.jwt import JWTVerifier
from openbb_mcp_server.app.app import create_mcp_server
from openbb_mcp_server.models.settings import MCPSettings
auth = JWTVerifier(
jwks_uri="https://auth.example.com/.well-known/jwks.json",
issuer="https://auth.example.com",
audience="openbb-mcp",
)
mcp = create_mcp_server(MCPSettings(), FastAPI(), auth=auth)
mcp.run(transport="streamable-http")
Spec proxy mode
A .spec file, written by openbb --generate-spec, records the routes and address of an OpenBB API server. Codegen covers generating one. With --spec, the server builds a FastAPI app whose routes forward each request to the spec's base_url, and serves those routes as tools. The MCP process then needs no provider packages; the data comes from the upstream server.
openbb --generate-spec --server https://api.example.com --output api.spec
openbb-mcp --spec api.spec
The spec is checked at startup: it must be version 5, have a base_url and a commands table, and carry a content_sha256 that matches its contents. [mcp.spec] adds what the file cannot hold:
[mcp.spec]
path = "/etc/openbb/api.spec"
base_url = "https://upstream.example.com"
content_sha256 = "<expected sha256>"
[mcp.spec.headers]
Authorization = "Bearer $OPENBB_UPSTREAM_TOKEN"
base_url replaces the recorded address, content_sha256 pins the expected revision, and [mcp.spec.headers] adds headers to every upstream request with $VAR substitution, replacing any header of the same name. To serve several specs, give each a [mcp.spec.NAME] table with its own path, an optional mount that defaults to /NAME, and its own base_url, content_sha256, headers, auth, and middleware. The openbb-api reference describes the same tables for the REST launcher in more detail.
Tools
Names and categories
A tool's name is built from its route path after the API prefix, skipping {placeholder} segments. /api/v1/cboe/equity/quote is cboe_equity_quote, a two-segment path such as /demo/items is demo_items, and a single-segment path repeats the segment, so /hello is hello_hello. When one path serves several methods, the non-GET tools get a _<method> suffix, as in demo_items_post. A route's mcp_config.name replaces the generated name.
The first path segment is the tool's category, and the second, on paths with three or more segments, its subcategory; other tools fall in the subcategory general. For the default app, categories are the provider namespaces such as cboe, imf, and fred, plus news, econometrics, quantitative, and technical when those packages are installed.
Built-in tools
These tools are registered next to the command tools:
| Tool | Purpose |
|---|---|
run_pipeline | Run several tools in sequence on the server, feeding earlier results into later arguments. |
list_prompts | List prompts with their arguments. |
get_prompt | Render a prompt by name with optional arguments. |
list_resources | List resources, including skills. |
read_resource | Read a resource by uri. |
install_skill | Write a skill into the bundled or a vendor skills directory. |
openbb_dispatch | Run one command through openbb-cli. Requires the cli extra. |
openbb_batch_dispatch | Run a list of commands concurrently through openbb-cli. Requires the cli extra. |
openbb_list_commands | List every command with a one-line description. Requires the cli extra. |
openbb_describe_command | Describe one command's parameters and output schema. Requires the cli extra. |
The four openbb_* tools take an optional server_url. Without one they use OPENBB_SERVER_URL, and without that they run in process. Set enable_cli_tools to false to leave them out.
install_skill writes files to the server's disk for any connected client. When clients are not trusted, keep the skills directories read-only for the server process or require server_auth.
Tool discovery
With --tool-discovery, the command tools are left out of the tool list and reached through four more tools:
| Tool | Purpose |
|---|---|
available_categories | Categories and subcategories with tool counts. |
available_tools | Tools in a category, optionally one subcategory, with one-sentence descriptions. |
search_tools | Full definitions, including input schemas, of the tools that best match a natural-language query. |
call_tool | Run any tool by name with its arguments. |
A hidden tool can also be called directly by name. Discovery keeps no per-session state, so every client and transport sees the same tool list and several clients can share one server.
Without discovery, default_tool_categories limits the tools that are listed and callable, and tools outside those categories fail as unknown tools. With discovery, default_tool_categories is ignored. allowed_tool_categories applies in both modes: routes outside it are never registered and cannot be reached by name, through call_tool, or through run_pipeline.
Pipelines
openbb-econometrics, openbb-quantitative, and openbb-technical commands take the rows to analyze as a data argument. run_pipeline passes rows between steps on the server, so a price history does not travel through the conversation. Each step has an optional id, a tool, its arguments, and inputs, which map an argument name to an earlier step's id. The input is that step's results, the rows of a chart artifact, a lone wrapped result, or the whole output when it has none of these. outputs selects the steps to return and defaults to the last one.
{
"steps": [
{
"id": "prices",
"tool": "cboe_equity_historical",
"arguments": {"symbol": "AAPL", "provider": "cboe"}
},
{
"id": "rsi",
"tool": "technical_rsi",
"arguments": {"length": 14},
"inputs": {"data": "prices"}
}
],
"outputs": ["rsi"]
}
The pipeline is validated before any step runs, a step cannot call run_pipeline, and a failing step is reported by its id. run_pipeline calls only tools the server serves.
Parameter choices
Tool input schemas state the valid values of each parameter, taken from the provider choices and x-widget_config options declared on the command. A parameter with one fixed set of values gets an enum. When providers accept different values, the description lists them by provider, and multi-value or partially declared choices are listed in the description. A parameter whose options come from an optionsEndpoint names the tool that lists them.
Charts
A Plotly figure in a tool result, returned directly or as an OBBject chart when the call passes chart: true, is replaced by an OpenBB Workspace artifact. Line, bar, scatter, pie, and donut figures become a chart artifact whose content rows and chart_params redraw the figure. Other figures become a table artifact of their data. Tool output schemas declare the artifact in place of the figure.
Prompts
System prompt
--system-prompt, system_prompt_file, or OPENBB_MCP_SYSTEM_PROMPT_FILE points to a text file. Its content is served as the system_prompt prompt and the resource://system_prompt resource, and fills instructions when that setting is empty. Clients do not apply it automatically; instruct them to read it.
When skills are loaded and no system prompt file is set, the server adds a short system_prompt that points the agent to the skills.
Server prompts
--server-prompts, server_prompts_file, or OPENBB_MCP_SERVER_PROMPTS_FILE points to a JSON list of prompts. Each prompt has a name, a description, and a content string with {placeholder} arguments, plus optional arguments and tags. Each argument has a name, a type (str, int, float, bool, list, dict, or any), and an optional default and description. An argument without a default is required. An invalid prompt or argument is logged as an error and skipped.
[
{
"name": "options_review",
"description": "Review the options market for one symbol.",
"content": "Review the options market for {symbol}. Get the quote with cboe_equity_quote, then summarize the implied volatility term structure with cboe_options_term_structure. Focus on {focus}.",
"arguments": [
{
"name": "symbol",
"type": "str",
"description": "Ticker symbol, such as AAPL."
},
{
"name": "focus",
"type": "str",
"default": "near-term expirations",
"description": "What the summary should emphasize."
}
],
"tags": ["options"]
}
]
Inline prompts
A route can carry prompts in openapi_extra["mcp_config"]["prompts"]. Each {placeholder} in content becomes an argument: a prompt argument of the same name, else the endpoint parameter, else a required string. The rendered prompt starts by naming the route's tool, and the tool's description lists its prompts.
from typing import Literal
from fastapi import FastAPI
app = FastAPI()
@app.get(
"/macro/gdp",
openapi_extra={
"mcp_config": {
"prompts": [
{
"name": "gdp_summary_prompt",
"description": "Generate a brief summary of GDP for a country.",
"content": "Provide a concise summary of the GDP for {country} over the last {years} years.",
"arguments": [
{
"name": "years",
"type": "int",
"default": 5,
"description": "Number of years to summarize.",
}
],
"tags": ["gdp", "summary"],
}
]
}
},
)
def get_gdp_data(country: str, period: Literal["annual", "quarterly"] = "annual"):
"""Get GDP data for a specific country."""
return {"country": country, "period": period}
The description of the macro_gdp tool then ends with:
**Associated Prompts:**
- **gdp_summary_prompt**: Generate a brief summary of GDP for a country.
- Arguments: `country`, `years`
MCP passes prompt arguments as strings, so quote every value in a get_prompt call:
{
"name": "gdp_summary_prompt",
"arguments": {"years": "10", "country": "Japan"}
}
{
"messages": [
{
"role": "user",
"content": "Use the tool, macro_gdp, to perform the following task.\n\nProvide a concise summary of the GDP for Japan over the last 10 years."
}
]
}
Skills
Skills are Markdown guides served as MCP resources at skill://<name>/SKILL.md and listed by list_resources. The server ships five:
| Skill | Covers |
|---|---|
develop_extension | Creating a new OpenBB extension from scratch. |
build_workspace_app | Building, running, and serving a Workspace application from an extension project. |
configure_mcp_server | Installing, configuring, and connecting openbb-mcp-server. |
work_with_server | Calling tools, reading responses, and handling errors as an agent. |
use_openbb_cli | The openbb command line, .spec files, and spec proxy mode. |
Set default_skills_dir to another directory to replace them, or to null or an empty string to turn them off. skills_providers also loads skill directories from other tools, such as ["claude", "cursor"], and skills_reload re-reads skill files on every read while you edit them.
Per-route configuration
openapi_extra["mcp_config"] controls how one route becomes a tool. If mcp_config is absent, openapi_extra["x-mcp"] is read instead. Values are validated with MCPConfigModel; an invalid configuration is logged as an error and ignored for that route.
| Key | Type | Effect |
|---|---|---|
expose | bool | False hides the route from the server. |
mcp_type | str | Serve the route as a tool, resource, or resource_template. |
methods | list[str] | HTTP methods of the route to serve, or ["*"] for all. The others are left out. |
exclude_args | list[str] | Arguments left out of the tool's input schema. Each needs a default, which is then used. |
name | str | Tool name, replacing the generated one. |
tags | list[str] | Tags added next to the category. |
enable | bool | With discovery off, serve (True) or hide (False) the tool regardless of default_tool_categories. |
describe_responses | bool | Override describe_responses for this tool. |
mime_type | str | MIME type of a route served as a resource. |
prompts | list[dict] | Inline prompts. |
@app.get(
"/some/route",
openapi_extra={
"mcp_config": {
"mcp_type": "tool",
"methods": ["GET"],
"exclude_args": ["internal_param"],
"name": "some_route",
}
},
)
def some_route(param1: str, internal_param: str = "default"):
"""An example route with MCP configuration."""
return {"param1": param1}
In OpenBB routers, pass the dictionary as the mcp_config argument of @router.command, which stores it in openapi_extra.
Connect a client
Claude Desktop
Claude Desktop starts the server itself over stdio. With uv installed, uvx creates the environment on demand; add a --with pair for each provider package:
{
"mcpServers": {
"openbb-mcp": {
"command": "uvx",
"args": [
"--from",
"openbb-mcp-server",
"--with",
"openbb-cboe",
"--with",
"openbb-imf",
"openbb-mcp",
"--transport",
"stdio"
]
}
}
}
Restart Claude Desktop after editing its configuration.
Cursor
Start the server with openbb-mcp, then add it to the mcpServers object in Cursor's mcp.json:
{
"mcpServers": {
"openbb-mcp": {
"url": "http://127.0.0.1:8001/mcp"
}
}
}
VS Code
Enable MCP support in the user settings: open Preferences: Open User Settings from the command palette, search for mcp, and check the option under Chat.
Start the server with openbb-mcp, then run MCP: Add Server from the command palette and choose HTTP.
Enter the URL the server prints at startup, http://127.0.0.1:8001/mcp by default, give the server a name, and save it globally or for the workspace. VS Code writes the entry to an mcp.json file, and the tools become available in chat.
For the Cline extension, start the server with --transport sse.
OpenBB Workspace
Follow the MCP tools guide to add the server URL to Workspace.
Changes from V4
Compared with openbb-mcp-server 1.4.1, the version on the V4 main branch, discovery no longer activates tools per session. activate_tools, deactivate_tools, and activate_category were removed; hidden tools are found with search_tools and run with call_tool or by name. run_pipeline, the openbb-cli dispatcher tools, chart artifacts, openbb.toml support, --config-file, and --spec are new.
on_duplicate replaces on_duplicate_tools, on_duplicate_resources, and on_duplicate_prompts. cache_expiration_seconds, resource_prefix_format, dependencies, and deprecation_warnings were removed, and enable_cli_tools was added.