这是indexloc提供的服务,不要输入任何密码
Skip to content

[Feature] Add mcp_server to openbb_core api #7094

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jul 3, 2025

Conversation

MagnusS0
Copy link
Contributor

@MagnusS0 MagnusS0 commented Apr 20, 2025

MCP for OpenBB Platform

Edit (June 1, 2025): Based on feedback from maintainers, this is now implemented as a standalone extension following OpenBB's extension architecture.

Description

  • Summary of the change/feature:
    This PR adds support for the Model Context Protocol (MCP) to the OpenBB Platform by mounting an MCP server to the REST FastAPI application. Using FastAPI-MCP, every REST endpoint is automatically exposed as an MCP tool, enabling seamless integration with LLM agents and tool-using frameworks. This creates a SSE endpoint and communicate over ASGI-transport layer by default.

  • Motivation and context:
    With MCP, agents and LLMs can discover and invoke OpenBB API endpoints as tools, making it easy to build advanced workflows and automations. The extension provides configurable tool filtering by categories and providers, with helper endpoints for dynamic tool management: get_available_tool_categories, activate_tool_categories, get_available_tools, and activate_tools. This allows agents to dynamically control their toolset and avoid being overloaded with too many tools at once.

  • Dependencies:

    • Adds a dependency on fastapi-mcp (MIT License).

How has this been tested?

  • Manual testing:

    • Verified that the MCP server is mounted and exposes all endpoints as tools.
    • Tested the get_available_tool_categories, activate_tool_categories, get_available_tools, and activate_tools` endpoints for dynamic tool filtering.
    • Connected to the MCP server using Cursor and Pydantic AI as clients.
    • With Cursor, confirmed that tools are discovered and can be invoked (note: after updating tags, a manual refresh is required in Cursor).
    • With Pydantic AI, confirmed that the agent can programmatically discover tags, update active tools, and invoke endpoints without manual intervention.
  • Known problem

    • Won't shutdown correctly due to SSE connection. If someone knows how to fix this please let me know.
  • Reproduction steps:

    1. Install the extension:
      pip install -e openbb_platform/extensions/mcp_server/
    2. Start the MCP server:
      openbb-mcp --host 127.0.0.1 --port 8001
    3. Connect to http://localhost:8001/mcp using an MCP-compatible client
    4. Use the following Pydantic AI example to verify agent interaction:
      import asyncio
      from pydantic_ai import Agent
      from pydantic_ai.mcp import MCPServerHTTP
      
      server = MCPServerHTTP(url='http://localhost:8001/mcp')
      system_prompt = """
       You are a financial analyst.
       You have access to the OpenBB MCP server.
       
       A MCP server allows you access to a ton of useful finacial tools.
       They are listed in categories by calling `get_available_tool_categories`.
       Use the `activate_tools` to update the active tools.
       
       ## Workflow
       
       1. Get the available categories by calling `get_available_tool_categories`
       2. Update the active tool by calling `activate_tools`.
       3. Use the tool by calling the function with the right arguments.
       4. Repeat until you have the answer.
       
       ALWAYS use one of the following data providers:
       "federal_reserve", "fmp", "imf", "oecd", "sec", "yfinance"
       You do not have API access to any other data provider.
      """
      
      agent = Agent('openai:gpt-4.1-mini', mcp_servers=[server], system_prompt=system_prompt)  
      
      async def main():
          async with agent.run_mcp_servers():
              result = await agent.run('What is the latest price of APPL?')
          print(result.all_messages())
          #> The latest price of Apple Inc. (AAPL) is $196.98.
      
      if __name__ == "__main__":
          asyncio.run(main())
  • Test configuration:

    • Python 3.10+ (3.9 is not supported by fast_mcp)
    • fastapi-mcp (v0.3.3)
    • OpenBB Platform API running locally
  • If you modified/added command(s):

    • Ensure the command(s) execute with the expected output.
      • API.
      • Python Interface.
    • If applicable, please add new tests for the command (see CONTRIBUTING.md to leverage semi-automated testing).

Checklist

  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have adhered to the GitFlow naming convention and my branch name is in the format of feature/feature-name or hotfix/hotfix-name.
  • I ensure that I am following the CONTRIBUTING guidelines.

@CLAassistant
Copy link

CLAassistant commented Apr 20, 2025

CLA assistant check
All committers have signed the CLA.

@DidierRLopes
Copy link
Collaborator

@piiq is this what you were looking for? 👀

@deeleeramone
Copy link
Contributor

Thanks for the PR, @MagnusS0, and great idea!

Can you look at incorporating this, either as an extra here, as a keyword argument in the openbb-api command line launcher; or, as a standalone extension with a dedicated launcher?

A similar pattern can be established where the FastAPI instance is being imported from openbb-core, ultimately using uvicorn to target that specific instance for starting the server.

Some degree of separation is going to be desirable and we'll need to expose the complete configurations for this server somewhere, potentially under, "system_settings:mcp_settings". The system_settings.json file can be read by the specific implementation at runtime and these definitions will not impact the main application.

BTW this, system_service.system_settings.python_settings.docstring_max_length = 1024, won't actually do anything as that only affects the Python docstrings, which is a completely independent from the API interface.

@piiq
Copy link
Member

piiq commented Apr 21, 2025

Hi @MagnusS0 this indeed is a nice addition. I can only second @deeleeramone that it would be better if this is a standalone extension or a part of the openbb-platform-api. If the latter I personally would prefer that it will have it's own launch command like openbb-mcp similarly to how openbb-api is defined here. If the former feel free to create a folder in openbb_platform/extensions.

I've taken a look at the fastapi-mcp package and apart from the mcp itself it does not seem to pull any new dependencies (which is a good thing)

Regarding the problem of the server not shutting down - I thing it is going to be best to debug this once we separate the mcp from the openbb_core codebase. It would make it easier to focus.

Thanks for the PR and let us know if you need any guidance

@MagnusS0
Copy link
Contributor Author

Thanks for the feedback. I'll look at how to implement it as an extension.

Btw, does all endpoints have operation IDs?

I noticed it's used to get schemas for widgets here. Might be able to use this as an another layer of filtering before the agent gets the tools. Fetching all equity tools at once for example cost a lot of tokens. So reducing this to just a specific needed operations would be great.

@deeleeramone
Copy link
Contributor

Thanks for the feedback. I'll look at how to implement it as an extension.

Btw, does all endpoints have operation IDs?

I noticed it's used to get schemas for widgets here. Might be able to use this as an another layer of filtering before the agent gets the tools. Fetching all equity tools at once for example cost a lot of tokens. So reducing this to just a specific needed operations would be great.

Operation IDs are assigned when openapi.json is built. That is first moment when the APIs endpoints are known.

@MagnusS0
Copy link
Contributor Author

MagnusS0 commented May 4, 2025

Just an update on this, I have a master thesis to deliver in 10 days so will probably not contribute anything before after that. In case someone else wants to give it a go 🚀

@piiq
Copy link
Member

piiq commented May 4, 2025

Good luck with your thesis. This PR will be waiting for you

@MagnusS0 MagnusS0 force-pushed the feature/mcp-server branch from 1a4b979 to 6d09ead Compare June 1, 2025 14:40
@MagnusS0
Copy link
Contributor Author

MagnusS0 commented Jun 1, 2025

@piiq @deeleeramone I have now made the MCP as a standalone extension, and added a new MCPSettings following how the OpenBB Platform API settings are set up. Let me know if this is closer to what you had in mind and any feedback.

I have tested with GPT-4.1 and it is surprisingly good at finding the right tools, with minimal instructions 😄

Know limitations:
The dynamic update of tools works well with one agent connected. But, if you have multiple agents (or useres) connected and one decides to activate some tool it also becomes available to all other connected agents, same goes the other way, if an agent deactivates a tool this deactivates the tool for all other connected agents.

@deeleeramone
Copy link
Contributor

@MagnusS0, did you happen to try out this library already? It offers considerably more functionality and tooling at the developer level - and supports the current MCP transport protocol.

@DidierRLopes
Copy link
Collaborator

Fwiw this worked for me - good job @MagnusS0 !!!

image

But ya, I wonder if the library that @deeleeramone suggested is more indicated!

Copy link
Member

@piiq piiq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @MagnusS0, sorry for the delay, just got my hands on this.

Thanks again for the thoughtful work. I wanted to flag a few points that could help make this extension more future-proof and reduce maintenance overhead:

  1. HTTP+SSE deprecation in MCP
    The fastapi-mcp package currently uses HTTP+SSE as the transport layer, but SSE has been deprecated by the MCP spec in favor of Streamable HTTP.
    This is already being tracked as an open issue in the fastapi-mcp repo (tadata-org/fastapi_mcp#61), but it’s been somewhat stale. Given that the repo itself hasn’t seen much activity during last month apart from promotional README edits, I’d be cautious about depending on it long-term. A different library, pointed out by @deeleeramone (https://github.com/jlowin/fastmcp) seems to be both actively maintained, implements all transport layers of the protocol and provides the tooling to spin up the mcp server from an existing FastAPI instance (or from an openapi spec). This migration is worth exploring, especially since this could also address the issue you mention in the PR description related to the server failing to shut down due to lingering SSE connections.
  2. Global tool state = single-user design
    The current behavior of tool activation being global to all connected agents effectively makes this a single-user server. That’s fine, but it should probably be made explicit in the docs so that users/integrators know not to deploy this for shared use in teams or networks without proper isolation. Long-term, a per-session or per-agent context might be needed, but that’s a bigger lift.
  3. MCPSettings placement
    Currently, the MCPSettings are part of SystemSettings, which requires users to modify their global system_settings.json to enable the extension. I’d recommend scoping all configuration for this extension to the extension itself, so it remains fully self-contained. If a user installs the platform without the MCP extension, they shouldn’t have to deal with leftover configuration or errors related to unused settings.
  4. Use argparse instead of click
    In main.py, the CLI entrypoint uses click to parse arguments. While this works and doesn’t introduce a new dependency, click isn’t used anywhere else in the OpenBB's codebase. For consistency and maintainability, it would be better to use argparse, which is already used elsewhere in the platform.

Let me know if you’d like help adjusting any of these. Really excited to see where this goes. Nice work overall!!!❤️🚀

@MagnusS0
Copy link
Contributor Author

Hey @piiq

Thanks for looking through this!

Agree on migrating to use FastMCP. Started looking into it after @deeleeramone mentioned it. More active and follows MCP standards more closely. It also supports Prompt templates and Resources which there might be some cool use-cases for.

I started on a rewrite today, but have to figure out how to implement the "management" tools, aka how to hot-swap tools at runtime without restarting the server. Any ideas here would be very helpful. It is supposed to be possible based on the original documentation (https://modelcontextprotocol.io/docs/concepts/tools#python)

I'll make sure to also move the configs and switch to argparse before pushing an update 🚀

- Also moves settings into the extention
- Refactors the management tool
- Add tool registry
- Use Argpars
@MagnusS0
Copy link
Contributor Author

MagnusS0 commented Jun 26, 2025

Okey so fully refactored to use FastMCP 2.0! Streamable HTTP is now supported in addition to SSE and stdio. Also future support for Resources and PrompTemplates when clients start supporting it.

For multiple users it can be run with the discovery tools disabled, then the tools are set, so no dynamic changes. Then you can either limit the number of tools at startup or manually enable/disable e.g. in Cursor or Claud Desktop.

There is also no longer a problem with shutting it down when clients are connected. And settings has been integrated in the extension and swapped to argparse

Next is to implement unit tests, and probably look into authentication

@DidierRLopes
Copy link
Collaborator

I was able to access this data on Cursor. However, I would add some instructions on how to add it to a few of the popular MCP Clients, e.g. https://docs.financialdatasets.ai/mcp-server#cursor

Also - I wasn't able to add it to the OpenBB workspace running locally due to CORS. I solved the issue by creating a proxy. I pushed the code here for context: #7156

But @MagnusS0 suggested having a look at https://gofastmcp.com/deployment/asgi instead

@piiq
Copy link
Member

piiq commented Jun 29, 2025

@deeleeramone can the mcp potentially utilize the same cors settings that we set for the platform rest api from system settings json?
If you look at the code, how big is the gap? Will it be a good design decision?

@piiq
Copy link
Member

piiq commented Jun 29, 2025

@deeleeramone can the mcp potentially utilize the same cors settings that we set for the platform rest api from system settings json?
If you look at the code, how big is the gap? Will it be a good design decision?

Sorry, I guess it's already doing that.

@DidierRLopes what do you have in the cors section of your system_settings.json?

https://docs.openbb.co/platform/settings_and_environment_variables#api-settings

@deeleeramone
Copy link
Contributor

deeleeramone commented Jun 29, 2025

@deeleeramone can the mcp potentially utilize the same cors settings that we set for the platform rest api from system settings json? If you look at the code, how big is the gap? Will it be a good design decision?

I don't see why not, the default configuration is available via SystemService and just needs to be imported.

from openbb_core.app.service.system_service import SystemService

In [3]: SystemService().system_settings.api_settings
Out[3]: 
APISettings

version: 1
title: OpenBB Platform API
description: Investment research for everyone, anywhere.
terms_of_service: http://example.com/terms/
contact_name: OpenBB Team
contact_url: https://openbb.co
contact_email: hello@openbb.co
license_name: AGPLv3
license_url: https://github.com/OpenBB-finance/OpenBB/blob/develop/LICENSE
servers: [{'url': '', 'description': 'Local OpenBB development server'}]
cors: {'allow_origins': ['*'], 'allow_methods': ['*'], 'allow_headers': ['*']}
custom_headers: None
prefix: /api/v1

class Cors(BaseModel):
    """Cors model for FastAPI configuration."""

    model_config = ConfigDict(frozen=True)

    allow_origins: List[str] = Field(default_factory=lambda: ["*"])
    allow_methods: List[str] = Field(default_factory=lambda: ["*"])
    allow_headers: List[str] = Field(default_factory=lambda: ["*"])

@deeleeramone
Copy link
Contributor

I was able to access this data on Cursor. However, I would add some instructions on how to add it to a few of the popular MCP Clients, e.g. https://docs.financialdatasets.ai/mcp-server#cursor

Also - I wasn't able to add it to the OpenBB workspace running locally due to CORS. I solved the issue by creating a proxy. I pushed the code here for context: #7156

But @MagnusS0 suggested having a look at https://gofastmcp.com/deployment/asgi instead

This is because the Middleware is not being added to the FastMCP server.

Screenshot 2025-06-29 at 12 42 32 PM

@MagnusS0
Copy link
Contributor Author

I was able to access this data on Cursor. However, I would add some instructions on how to add it to a few of the popular MCP Clients, e.g. https://docs.financialdatasets.ai/mcp-server#cursor
Also - I wasn't able to add it to the OpenBB workspace running locally due to CORS. I solved the issue by creating a proxy. I pushed the code here for context: #7156
But @MagnusS0 suggested having a look at https://gofastmcp.com/deployment/asgi instead

This is because the Middleware is not being added to the FastMCP server.

Screenshot 2025-06-29 at 12 42 32 PM

I tested this and it works for SSE, but I get a sesssion ID error when using streamable-http. They mention this is due to some lifespan issue, but following their docs didn't fix it...

My understanding was that it adopts the CORS settings from the underlying OpenBB platform FastAPI, but it seems that this is not the case and it needs to be set manually for the mcp server. So either add CORS settings to the mcp settings or use settings from the systems settings.

@deeleeramone
Copy link
Contributor

I tested this and it works for SSE, but I get a sesssion ID error when using streamable-http. They mention this is due to some lifespan issue, but following their docs didn't fix it...

The existing FastAPI app has a lifespan context, so perhaps related to "nested lifespans". Perhaps needs to be replaced explicitly?

For Streamable HTTP transport, you must pass the lifespan context from the FastMCP app to the resulting Starlette app, as nested lifespans are not recognized. Otherwise, the FastMCP server’s session manager will not be properly initialized.

@MagnusS0
Copy link
Contributor Author

MagnusS0 commented Jun 29, 2025

Got it working by setting stateless_http=True

@DidierRLopes
Copy link
Collaborator

THAT WORKED 🔥 🔥 🔥

CleanShot 2025-06-29 at 21 51 43@2x

Copy link
Member

@piiq piiq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MagnusS0 this is the most valuable and meaningful external contribution to the repo I've seen in a while.

Thank you for investing time into this. This is a very good addition to OpenBB

@MagnusS0
Copy link
Contributor Author

MagnusS0 commented Jul 1, 2025

@MagnusS0 this is the most valuable and meaningful external contribution to the repo I've seen in a while.

Thank you for investing time into this. This is a very good addition to OpenBB

Thanks! Really appreciate that, and I'm happy to contribute 🫡

@DidierRLopes
Copy link
Collaborator

@MagnusS0 this is the most valuable and meaningful external contribution to the repo I've seen in a while.

Thank you for investing time into this. This is a very good addition to OpenBB

I second this! 💪

@piiq
Copy link
Member

piiq commented Jul 2, 2025

@MagnusS0 can you fix the linters please? 😂😅

Once we get all checks to pass this will be good to go

@MagnusS0
Copy link
Contributor Author

MagnusS0 commented Jul 2, 2025

@MagnusS0 can you fix the linters please? 😂😅

Once we get all checks to pass this will be good to go

Should pass now, ran the pre hooks 10x

@piiq piiq added this pull request to the merge queue Jul 3, 2025
Merged via the queue into OpenBB-finance:develop with commit e00cf0f Jul 3, 2025
12 of 13 checks passed
@deeleeramone
Copy link
Contributor

Thank you very much for the contribution!

@MagnusS0
Copy link
Contributor Author

MagnusS0 commented Jul 3, 2025

Uploaded to PyPI https://pypi.org/project/openbb-mcp-server/

Should be able to start the server by running:

uvx --from openbb-mcp-server --with openbb openbb-mcp

@piiq
Copy link
Member

piiq commented Jul 3, 2025

@MagnusS0 since you own the pypi project we'll be tagging you for patches and uploads. If you want, you can add @deeleeramone or the openbb account to the project maintainers so that we can push updates. This is going to happen once in a while and most likely be related to patches of vulnerabilities in the package dependency tree.

Let me know how you prefer to handle this

@MagnusS0
Copy link
Contributor Author

MagnusS0 commented Jul 3, 2025

@piiq Invited both opnebb and @deeleeramone as maintainers 🫡 Feel free to tag me anytime as well!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants