Spaces:
Sleeping
Sleeping
File size: 4,364 Bytes
0d1138e 42c6967 0d1138e 8aac38c 0d1138e 59ba69c 0d1138e 8aac38c 0d1138e 8aac38c 59ba69c 0d1138e 8aac38c 0d1138e 59ba69c 0d1138e 8aac38c 0d1138e 59ba69c 0d1138e d78f12e 0d1138e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
import gradio as gr
import config
import utils
# Import obb (don't reload it)
if gr.NO_RELOAD:
from openbb import obb
# A set of submodules to include when searching for tools, registering
# them to the MCP server, and dynamically building the Gradio interface
# List of valid values: https://docs.openbb.co/platform/reference
INCLUDE = {"currency", "equity", "news"}
# Get tool names and guides
print("Getting tool names and guides...")
ARGS = "obb", obb # type: ignore
tool_names = utils.get_callable_names(*ARGS, include=INCLUDE)
tool_guides = utils.generate_callable_guides(*ARGS, tool_names)
# Build the demo interface
print("Building the demo...")
with gr.Blocks() as demo:
gr.Markdown("# OpenBB MCP")
# Reference guide
with gr.Accordion("Tool Reference Guide 📃", open=False):
for tool_name, tool_guide in zip(tool_names, tool_guides):
# Create a collapsible for each tool
with gr.Accordion(f"{tool_name}", open=False):
gr.Markdown(f"```\n{tool_guide}```")
# Dynamically generate tool test UI
tool_params = utils.get_callable_params(*ARGS, tool_name)
tool_param_inputs = []
tool_param_kinds = []
with gr.Row():
for param in tool_params:
tool_param_inputs.append(
gr.Textbox(
label=param["name"],
value=str(param["default"]) if param["default"] else ""
)
)
tool_param_kinds.append(param["kind"])
output = gr.Textbox(label="Output", lines=10)
test_btn = gr.Button("Run")
# Format vars for dynamic function generation
t = tool_name
tool_name = tool_name.replace(".", "_")
tool_guide = tool_guide.replace(t, tool_name)
tool_param_names = [
param["name"] for param in tool_params
]
csv_tool_names = ", ".join(tool_param_names)
# Dynamically generate function
# TODO: Fragile. Refactor if possible
namespace = { # Create a local namespace
"utils": utils,
"ARGS": ARGS,
"tool_param_kinds": tool_param_kinds
}
exec(f"""\
import inspect
import json
def {tool_name}({csv_tool_names}) -> str:
\"\"\"
{tool_guide}
\"\"\"
print("{tool_name}:", locals())
args = []
try:
kwargs = json.loads(kwargs)
except Exception:
kwargs = {{}}
for kind, name, value in zip(
tool_param_kinds,
{tool_param_names},
[{csv_tool_names}],
):
if kind in {{
inspect.Parameter.POSITIONAL_ONLY,
inspect.Parameter.POSITIONAL_OR_KEYWORD,
}}:
args.append(value if value else None)
return utils.test_callable(*ARGS, "{tool_name}", *args, **kwargs)
""", namespace)
# Extract tool from namespace and register to the MCP server
test_btn.click(
fn=namespace[tool_name], # type: ignore
inputs=tool_param_inputs,
outputs=output,
)
# Usage instructions
with gr.Accordion("Use via MCP 🛠️", open=False):
gr.Markdown("""\
**SSE support**: To add this MCP to clients that support SSE (e.g. Cursor, Windsurf, Cline), simply add the following configuration to your MCP config:
```
{
"mcpServers": {
"OpenBB-MCP": {
"url": "http://xarical-openbb-mcp.hf.space/gradio_api/mcp/sse"
}
}
}
```
**Stdio support**: For clients that only support stdio, first install Node.js. Then, you can use the following command:
```
{
"mcpServers": {
"OpenBB-MCP": {
"command": "npx",
"args": [
"mcp-remote",
"http://xarical-openbb-mcp.hf.space/gradio_api/mcp/sse",
"--transport",
"sse-only"
]
}
}
}
```
""")
# Launch the demo
if __name__ == "__main__":
print("Starting the demo...")
demo.launch(
server_port=7860,
show_api=False,
mcp_server=True,
)
|