mcp_ / app.py
eienmojiki's picture
Update app.py
0c0cf30 verified
raw
history blame
5.95 kB
import gradio as gr
import typing as ty
# Importing the tool files automatically registers them with the mcp_tool registry
# This assumes all tool files are in the 'tools' directory and end with '_tool.py'
# A more robust approach might explicitly import each tool file.
# For this example, we explicitly import the one tool file.
import tools.time_tool
# Import the mcp_tool registry instance
from utils.mcp_decorator import mcp_tool
def update_tool_info(selected_api_name: str) -> ty.List[ty.Union[gr.update, dict]]:
"""
Updates the displayed docstring and the visibility of tool UI groups
based on the selected tool from the dropdown.
Args:
selected_api_name: The api_name of the tool selected in the dropdown.
Returns:
A list of gr.update objects for the docstring and each tool UI group.
The list must match the order of outputs specified in the dropdown.change call.
"""
updates = []
# 1. Update Docstring
docstring_value = ""
docstring_visible = False
if selected_api_name:
tool_info = mcp_tool.get_tool_info(selected_api_name)
if tool_info and tool_info.get('tool_func') and tool_info['tool_func'].__doc__:
docstring_value = f"### Tool Documentation\n---\n{tool_info['tool_func'].__doc__}\n---"
docstring_visible = True
# Correct way to generate an update for the docstring component
updates.append(gr.update(visible=docstring_visible, value=docstring_value))
# 2. Update Visibility of Tool UI Groups
all_tools_api_names = [api_name for _, api_name in mcp_tool.get_tools_list()]
# Generate visibility updates for each tool group
for api_name_in_list in all_tools_api_names:
is_selected_tool = (api_name_in_list == selected_api_name)
# Correct way to generate an update for a Group component
updates.append(gr.update(visible=is_selected_tool))
# The total number of updates must match the number of outputs in the dropdown.change call.
# outputs = [doc_display, *tool_ui_groups_list]
# inputs = [dropdown]
return updates
# --- Gradio App Layout ---
with gr.Blocks(title="MCP Server Demo") as demo:
gr.Markdown("# Gradio MCP Server Demo")
gr.Markdown("Select a tool to view its documentation and UI controls.")
# Get defined tools
tool_options = mcp_tool.get_tools_list() # Returns list of (name, api_name)
if not tool_options:
gr.Warning("No tools defined. Please check the 'tools' directory.")
gr.Markdown("No tools available.")
else:
# Dropdown to select tool. Using api_name as value for easier lookup.
dropdown = gr.Dropdown(
choices=[(name, api_name) for name, api_name in tool_options],
label="Select a Tool",
interactive=True,
value=None # Start with no tool selected
)
# Markdown component to display tool documentation
# Needs a specific elem_id or be directly referenced as an output
doc_display = gr.Markdown(label="Tool Documentation", visible=False)
# Container to hold dynamic UI controls.
tool_uis_container = gr.Column()
# List to hold the UI groups for each tool.
# The order in this list MUST match the order in the outputs list of dropdown.change
tool_ui_groups_list = []
# Dynamically create UI components for each tool
with tool_uis_container:
for tool_name, api_name in tool_options:
ui_builder = mcp_tool.get_tool_ui_builder(api_name)
if ui_builder:
# Call the UI builder function to get the components (should be a gr.Group/Column)
tool_ui_group = ui_builder()
# Ensure the group is initially hidden (build_ui_control should ideally do this, but reinforce here)
tool_ui_group.visible = False # Overwrite potential builder default if needed
# Add the group to our list for output mapping
tool_ui_groups_list.append(tool_ui_group)
else:
# If a tool has no UI builder, we still need a placeholder in the outputs list
# to keep the order consistent for the updates list.
# An empty hidden Group works as a placeholder.
with gr.Group(visible=False) as empty_group_placeholder:
# Optional: add a tiny markdown saying no UI
gr.Markdown(f"No UI defined for {tool_name} ({api_name})", visible=False)
tool_ui_groups_list.append(empty_group_placeholder)
# --- Event Handling ---
# When the dropdown selection changes, update the displayed info and controls
# The outputs list defines which components will be updated by update_tool_info,
# and their order must match the order of elements in the list returned by update_tool_info.
outputs_list = [doc_display] + tool_ui_groups_list
dropdown.change(
fn=update_tool_info,
inputs=[dropdown], # Input is the selected api_name from the dropdown
outputs=outputs_list, # Outputs are the doc display and all the tool UI groups
)
# Trigger an initial update after the layout is built if you want
# a default tool's UI to show on load. If dropdown value is None,
# calling this will hide everything initially, which is also a valid state.
# demo.load(fn=update_tool_info, inputs=[dropdown], outputs=outputs_list)
# --- Launch the Gradio App as an MCP Server ---
if __name__ == "__main__":
print("Launching Gradio app with MCP server enabled...")
demo.launch(
server_name="0.0.0.0", # Required for Spaces
mcp_server=True, # Enable the MCP server endpoint
)
print("Gradio app launched.")