Spaces:
Runtime error
Runtime error
Upload 3 files
Browse files
ui_components/add_mcp_server_button.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import modelscope_studio.components.antd as antd
|
| 2 |
+
import modelscope_studio.components.base as ms
|
| 3 |
+
import gradio as gr
|
| 4 |
+
import json
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def AddMcpServerButton():
|
| 8 |
+
with antd.Button("添加 MCP Server", type="primary",
|
| 9 |
+
size="small") as add_mcp_server_btn:
|
| 10 |
+
with ms.Slot("icon"):
|
| 11 |
+
antd.Icon("PlusOutlined")
|
| 12 |
+
with antd.Modal(
|
| 13 |
+
title="添加 MCP Server",
|
| 14 |
+
footer=False,
|
| 15 |
+
styles=dict(footer=dict(display="none"))) as add_mcp_server_modal:
|
| 16 |
+
with antd.Tabs():
|
| 17 |
+
with antd.Tabs.Item(label="表单添加"):
|
| 18 |
+
with antd.Form(layout="vertical") as add_mcp_server_form:
|
| 19 |
+
with antd.Form.Item(form_name="name",
|
| 20 |
+
label="名称",
|
| 21 |
+
rules=[{
|
| 22 |
+
"required": True
|
| 23 |
+
}]):
|
| 24 |
+
antd.Input(placeholder="MCP Server 名称,如 fetch、time 等")
|
| 25 |
+
with antd.Form.Item(form_name="url",
|
| 26 |
+
label="SSE 链接",
|
| 27 |
+
rules=[{
|
| 28 |
+
"required": True
|
| 29 |
+
}]):
|
| 30 |
+
antd.Input(placeholder="MCP Server SSE 链接")
|
| 31 |
+
with antd.Flex(gap="small", justify="end"):
|
| 32 |
+
add_mcp_server_modal_cancel_btn = antd.Button("取消")
|
| 33 |
+
antd.Button("确定", html_type="submit", type="primary")
|
| 34 |
+
with antd.Tabs.Item(label="JSON 添加"):
|
| 35 |
+
with antd.Form(layout="vertical") as add_mcp_server_json_form:
|
| 36 |
+
with antd.Form.Item(form_name="json",
|
| 37 |
+
label="JSON",
|
| 38 |
+
rules=[{
|
| 39 |
+
"required":
|
| 40 |
+
True,
|
| 41 |
+
"validator":
|
| 42 |
+
"""(_, value) => {
|
| 43 |
+
if (!value) {
|
| 44 |
+
return Promise.reject('请输入 JSON 值');
|
| 45 |
+
}
|
| 46 |
+
try {
|
| 47 |
+
const parsedValue = JSON.parse(value);
|
| 48 |
+
if (!parsedValue.mcpServers || typeof parsedValue.mcpServers !== 'object') {
|
| 49 |
+
return Promise.reject('配置必须包含正确的 mcpServers 字段');
|
| 50 |
+
}
|
| 51 |
+
return Promise.resolve()
|
| 52 |
+
} catch {
|
| 53 |
+
return Promise.reject('请输入有效的 JSON 值');
|
| 54 |
+
}
|
| 55 |
+
} """
|
| 56 |
+
}]):
|
| 57 |
+
antd.Input.Textarea(
|
| 58 |
+
auto_size=dict(minRows=4, maxRows=8),
|
| 59 |
+
placeholder=json.dumps(
|
| 60 |
+
{
|
| 61 |
+
"mcpServers": {
|
| 62 |
+
"fetch": {
|
| 63 |
+
"type": "sse",
|
| 64 |
+
"url": "mcp server sse url"
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
},
|
| 68 |
+
indent=4))
|
| 69 |
+
with antd.Flex(gap="small", justify="end"):
|
| 70 |
+
add_mcp_server_modal_json_cancel_btn = antd.Button(
|
| 71 |
+
"取消")
|
| 72 |
+
antd.Button("确定", html_type="submit", type="primary")
|
| 73 |
+
add_mcp_server_btn.click(fn=lambda: gr.update(open=True),
|
| 74 |
+
outputs=[add_mcp_server_modal],
|
| 75 |
+
queue=False)
|
| 76 |
+
gr.on(triggers=[
|
| 77 |
+
add_mcp_server_modal_cancel_btn.click,
|
| 78 |
+
add_mcp_server_modal_json_cancel_btn.click, add_mcp_server_modal.cancel
|
| 79 |
+
],
|
| 80 |
+
queue=False,
|
| 81 |
+
fn=lambda: gr.update(open=False),
|
| 82 |
+
outputs=[add_mcp_server_modal])
|
| 83 |
+
add_mcp_server_form.finish(
|
| 84 |
+
lambda: (gr.update(value={
|
| 85 |
+
"name": "",
|
| 86 |
+
"url": "",
|
| 87 |
+
}), gr.update(open=False)),
|
| 88 |
+
outputs=[add_mcp_server_form, add_mcp_server_modal])
|
| 89 |
+
add_mcp_server_json_form.finish(
|
| 90 |
+
lambda: (gr.update(value={"json": ""}), gr.update(open=False)),
|
| 91 |
+
outputs=[add_mcp_server_json_form, add_mcp_server_modal])
|
| 92 |
+
return add_mcp_server_form, add_mcp_server_json_form
|
ui_components/config_form.py
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import gradio as gr
|
| 3 |
+
import modelscope_studio.components.antd as antd
|
| 4 |
+
import modelscope_studio.components.base as ms
|
| 5 |
+
|
| 6 |
+
from .add_mcp_server_button import AddMcpServerButton
|
| 7 |
+
from config import default_mcp_config, model_options, default_sys_prompt
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def ConfigForm():
|
| 11 |
+
with antd.Form(layout="vertical",
|
| 12 |
+
value={
|
| 13 |
+
"sys_prompt": default_sys_prompt,
|
| 14 |
+
"model": model_options[0]["value"]
|
| 15 |
+
}) as config_form:
|
| 16 |
+
with antd.Form.Item(label_col=24):
|
| 17 |
+
with ms.Slot("extra"):
|
| 18 |
+
with antd.Flex(justify="end", elem_style=dict(marginTop=10)):
|
| 19 |
+
mcp_config_confirm_btn = antd.Button("保存配置",
|
| 20 |
+
type="primary")
|
| 21 |
+
with antd.Flex(wrap=True,
|
| 22 |
+
justify="space-between",
|
| 23 |
+
gap="middle",
|
| 24 |
+
elem_style=dict(paddingBottom=8)):
|
| 25 |
+
with antd.Flex(gap="middle", wrap=True):
|
| 26 |
+
with antd.Flex(gap="small", align="center"):
|
| 27 |
+
antd.Typography.Text("MCP Servers",
|
| 28 |
+
elem_style=dict(fontSize=14))
|
| 29 |
+
antd.Typography.Text("编辑以下内容以修改运行中的 MCP Servers",
|
| 30 |
+
elem_style=dict(fontSize=12),
|
| 31 |
+
type="secondary")
|
| 32 |
+
with antd.Tooltip(title="目前只支持 SSE 类型的 MCP Server"):
|
| 33 |
+
with antd.Typography.Text(type="warning"):
|
| 34 |
+
antd.Icon("InfoCircleOutlined")
|
| 35 |
+
add_mcp_server_form, add_mcp_server_json_form = AddMcpServerButton(
|
| 36 |
+
)
|
| 37 |
+
|
| 38 |
+
with antd.Button("重置默认配置",
|
| 39 |
+
size="small") as reset_mcp_config_btn:
|
| 40 |
+
with ms.Slot("icon"):
|
| 41 |
+
antd.Icon("ReloadOutlined")
|
| 42 |
+
with ms.Div():
|
| 43 |
+
with antd.Tooltip("在 MCP Inspector 中测试待连接的 MCP Server"):
|
| 44 |
+
with antd.Button(
|
| 45 |
+
"前往 MCP Inspector 测试",
|
| 46 |
+
color="primary",
|
| 47 |
+
variant="outlined",
|
| 48 |
+
size="small",
|
| 49 |
+
href_target="_blank",
|
| 50 |
+
href=
|
| 51 |
+
"https://modelscope.cn/studios/modelscope/mcp-inspector"
|
| 52 |
+
):
|
| 53 |
+
with ms.Slot("icon"):
|
| 54 |
+
antd.Icon("ExportOutlined")
|
| 55 |
+
mcp_config = gr.Code(default_mcp_config,
|
| 56 |
+
show_label=False,
|
| 57 |
+
container=False,
|
| 58 |
+
max_lines=20,
|
| 59 |
+
lines=3,
|
| 60 |
+
language="json")
|
| 61 |
+
with antd.Form.Item(form_name="model", label="模型"):
|
| 62 |
+
with ms.Slot("extra"):
|
| 63 |
+
with ms.Fragment(visible=False) as thought_tip:
|
| 64 |
+
antd.Typography.Text("Note: 推理模式在调用工具前,会有较长的思考过程,需耐心等待。",
|
| 65 |
+
elem_style=dict(fontSize=12),
|
| 66 |
+
type="warning")
|
| 67 |
+
|
| 68 |
+
with antd.Flex(align="center",
|
| 69 |
+
gap=4,
|
| 70 |
+
elem_style=dict(marginTop=4)):
|
| 71 |
+
ms.Text("Powered by")
|
| 72 |
+
with antd.Typography.Link(
|
| 73 |
+
href=
|
| 74 |
+
"https://modelscope.cn/docs/model-service/API-Inference/intro",
|
| 75 |
+
href_target="_blank",
|
| 76 |
+
elem_style=dict(display="flex",
|
| 77 |
+
alignItems="center")):
|
| 78 |
+
antd.Image(
|
| 79 |
+
"https://gw.alicdn.com/imgextra/i4/O1CN01dCJ2sA1OHUQJFyCRm_!!6000000001680-2-tps-200-200.png",
|
| 80 |
+
preview=False,
|
| 81 |
+
width=20,
|
| 82 |
+
height=20)
|
| 83 |
+
ms.Text("ModelScope API-Inference")
|
| 84 |
+
with antd.Select(options=model_options) as model_select:
|
| 85 |
+
with ms.Slot("labelRender",
|
| 86 |
+
params_mapping="""(option) => {
|
| 87 |
+
const tag = window.MODEL_OPTIONS_MAP[option.value].tag
|
| 88 |
+
return {
|
| 89 |
+
label: option.label,
|
| 90 |
+
link: { href: `https://modelscope.cn/models/${option.value.split(':')[0]}` },
|
| 91 |
+
tag: tag ? { value: tag.label, style: { display: 'inline-block', color: tag.color } } : undefined
|
| 92 |
+
}
|
| 93 |
+
}"""):
|
| 94 |
+
with antd.Flex(gap="small"):
|
| 95 |
+
antd.Typography.Text(as_item="label")
|
| 96 |
+
antd.Tag(elem_style=dict(display="none"),
|
| 97 |
+
as_item="tag")
|
| 98 |
+
antd.Typography.Link("模型链接",
|
| 99 |
+
href_target="_blank",
|
| 100 |
+
as_item="link")
|
| 101 |
+
with ms.Slot("optionRender",
|
| 102 |
+
params_mapping="""(option) => ({
|
| 103 |
+
label: option.data.label.split(':')[0],
|
| 104 |
+
tag: option.data.tag ? { value: option.data.tag.label, style: { display: 'inline-block', color: option.data.tag.color } } : undefined
|
| 105 |
+
})"""):
|
| 106 |
+
|
| 107 |
+
with antd.Flex(gap="small"):
|
| 108 |
+
antd.Typography.Text(as_item="label")
|
| 109 |
+
antd.Tag(elem_style=dict(display="none"),
|
| 110 |
+
as_item="tag")
|
| 111 |
+
|
| 112 |
+
with antd.Form.Item(form_name="sys_prompt", label="系统提示"):
|
| 113 |
+
antd.Input.Textarea(auto_size=dict(minRows=2, maxRows=4))
|
| 114 |
+
|
| 115 |
+
def add_mcp_server(mcp_config_value, add_mcp_server_form_value):
|
| 116 |
+
if not mcp_config_value:
|
| 117 |
+
mcp_config_value = "{}"
|
| 118 |
+
mcp_config = json.loads(mcp_config_value)
|
| 119 |
+
name = add_mcp_server_form_value["name"]
|
| 120 |
+
url = add_mcp_server_form_value["url"]
|
| 121 |
+
if "mcpServers" not in mcp_config:
|
| 122 |
+
mcp_config["mcpServers"] = {}
|
| 123 |
+
mcp_config["mcpServers"][name] = {"type": "sse", "url": url}
|
| 124 |
+
|
| 125 |
+
return gr.update(value=json.dumps(mcp_config, indent=4))
|
| 126 |
+
|
| 127 |
+
def add_mcp_server_by_json(mcp_config_value,
|
| 128 |
+
add_mcp_server_json_form_value):
|
| 129 |
+
if not mcp_config_value:
|
| 130 |
+
mcp_config_value = "{}"
|
| 131 |
+
mcp_config = json.loads(mcp_config_value)
|
| 132 |
+
json_value = add_mcp_server_json_form_value["json"]
|
| 133 |
+
json_config = json.loads(json_value)
|
| 134 |
+
if "mcpServers" not in mcp_config:
|
| 135 |
+
mcp_config["mcpServers"] = {}
|
| 136 |
+
|
| 137 |
+
mcp_config["mcpServers"].update(json_config.get("mcpServers", {}))
|
| 138 |
+
|
| 139 |
+
return gr.update(value=json.dumps(mcp_config, indent=4))
|
| 140 |
+
|
| 141 |
+
def select_model(e: gr.EventData):
|
| 142 |
+
return gr.update(visible=e._data["payload"][1].get("thought", False))
|
| 143 |
+
|
| 144 |
+
add_mcp_server_form.finish(fn=add_mcp_server,
|
| 145 |
+
inputs=[mcp_config, add_mcp_server_form],
|
| 146 |
+
outputs=[mcp_config],
|
| 147 |
+
queue=False)
|
| 148 |
+
add_mcp_server_json_form.finish(
|
| 149 |
+
fn=add_mcp_server_by_json,
|
| 150 |
+
inputs=[mcp_config, add_mcp_server_json_form],
|
| 151 |
+
outputs=[mcp_config],
|
| 152 |
+
queue=False)
|
| 153 |
+
model_select.change(fn=select_model, outputs=[thought_tip], queue=False)
|
| 154 |
+
|
| 155 |
+
return config_form, mcp_config_confirm_btn, reset_mcp_config_btn, mcp_config
|
ui_components/mcp_servers_button.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import List
|
| 2 |
+
import modelscope_studio.components.antd as antd
|
| 3 |
+
import modelscope_studio.components.base as ms
|
| 4 |
+
import gradio as gr
|
| 5 |
+
from config import max_mcp_server_count
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def McpServersButton(data_source: List[dict]):
|
| 9 |
+
state = gr.State({"data_source": data_source})
|
| 10 |
+
with antd.Button(value=None, variant="text",
|
| 11 |
+
color="primary") as mcp_servers_btn:
|
| 12 |
+
with ms.Slot("icon"):
|
| 13 |
+
antd.Icon("ToolOutlined")
|
| 14 |
+
with antd.Modal(
|
| 15 |
+
width=420,
|
| 16 |
+
footer=False,
|
| 17 |
+
centered=True,
|
| 18 |
+
styles=dict(footer=dict(display="none"))) as mcp_servers_modal:
|
| 19 |
+
with ms.Slot("title"):
|
| 20 |
+
with antd.Flex(gap="small", align="center"):
|
| 21 |
+
ms.Text("MCP Servers")
|
| 22 |
+
mcp_servers_switch = antd.Switch(True)
|
| 23 |
+
antd.Typography.Text(
|
| 24 |
+
f"最大 MCP Server 连接数:{max_mcp_server_count}",
|
| 25 |
+
type="secondary",
|
| 26 |
+
elem_style=dict(fontSize=12, fontWeight="normal"))
|
| 27 |
+
with antd.List(
|
| 28 |
+
data_source=data_source,
|
| 29 |
+
pagination=dict(pageSize=10,
|
| 30 |
+
hideOnSinglePage=True)) as mcp_servers_list:
|
| 31 |
+
with ms.Slot(
|
| 32 |
+
"renderItem",
|
| 33 |
+
params_mapping=
|
| 34 |
+
"(item) => ({ text: { value: item.name, disabled: item.disabled }, tag: { style: { display: item.internal ? undefined: 'none' } }, switch: { value: item.enabled, mcp: item.name, disabled: item.disabled }})"
|
| 35 |
+
):
|
| 36 |
+
with antd.List.Item():
|
| 37 |
+
with antd.Flex(justify="space-between",
|
| 38 |
+
elem_style=dict(width="100%")):
|
| 39 |
+
with antd.Flex(gap="small"):
|
| 40 |
+
antd.Typography.Text(as_item="text")
|
| 41 |
+
antd.Tag("官方示例", color="green", as_item="tag")
|
| 42 |
+
mcp_server_switch = antd.Switch(as_item="switch")
|
| 43 |
+
|
| 44 |
+
def change_mcp_servers_switch(mcp_servers_switch_value, state_value):
|
| 45 |
+
state_value["data_source"] = [{
|
| 46 |
+
**item, "disabled":
|
| 47 |
+
not mcp_servers_switch_value
|
| 48 |
+
} for item in state_value["data_source"]]
|
| 49 |
+
return gr.update(value=state_value)
|
| 50 |
+
|
| 51 |
+
def change_mcp_server_switch(state_value, e: gr.EventData):
|
| 52 |
+
mcp = e._data["component"]["mcp"]
|
| 53 |
+
|
| 54 |
+
enabled = e._data["payload"][0]
|
| 55 |
+
|
| 56 |
+
state_value["data_source"] = [{
|
| 57 |
+
**item, "enabled": enabled
|
| 58 |
+
} if item["name"] == mcp else item
|
| 59 |
+
for item in state_value["data_source"]]
|
| 60 |
+
return gr.update(value=state_value)
|
| 61 |
+
|
| 62 |
+
def apply_state_change(state_value):
|
| 63 |
+
has_tool_use = False
|
| 64 |
+
disabled_tool_use = False
|
| 65 |
+
enabled_server_count = 0
|
| 66 |
+
for item in state_value["data_source"]:
|
| 67 |
+
if item.get("enabled"):
|
| 68 |
+
if enabled_server_count >= max_mcp_server_count:
|
| 69 |
+
item["enabled"] = False
|
| 70 |
+
else:
|
| 71 |
+
enabled_server_count += 1
|
| 72 |
+
if item.get("disabled"):
|
| 73 |
+
disabled_tool_use = True
|
| 74 |
+
else:
|
| 75 |
+
has_tool_use = True
|
| 76 |
+
|
| 77 |
+
if not disabled_tool_use:
|
| 78 |
+
for item in state_value["data_source"]:
|
| 79 |
+
if enabled_server_count >= max_mcp_server_count:
|
| 80 |
+
item["disabled"] = not item.get("enabled", False)
|
| 81 |
+
else:
|
| 82 |
+
item["disabled"] = False
|
| 83 |
+
|
| 84 |
+
return gr.update(
|
| 85 |
+
data_source=state_value["data_source"],
|
| 86 |
+
footer="没有可用的 MCP Server"
|
| 87 |
+
if len(state_value["data_source"]) == 0 else ""), gr.update(
|
| 88 |
+
color="primary" if has_tool_use else "default"), gr.update(
|
| 89 |
+
value=not disabled_tool_use), gr.update(value=state_value)
|
| 90 |
+
|
| 91 |
+
mcp_servers_btn.click(fn=lambda: gr.update(open=True),
|
| 92 |
+
outputs=[mcp_servers_modal],
|
| 93 |
+
queue=False)
|
| 94 |
+
mcp_servers_switch.change(fn=change_mcp_servers_switch,
|
| 95 |
+
inputs=[mcp_servers_switch, state],
|
| 96 |
+
outputs=[state])
|
| 97 |
+
mcp_server_switch.change(fn=change_mcp_server_switch,
|
| 98 |
+
inputs=[state],
|
| 99 |
+
outputs=[state])
|
| 100 |
+
state.change(
|
| 101 |
+
fn=apply_state_change,
|
| 102 |
+
inputs=[state],
|
| 103 |
+
outputs=[mcp_servers_list, mcp_servers_btn, mcp_servers_switch, state],
|
| 104 |
+
queue=False)
|
| 105 |
+
mcp_servers_modal.cancel(fn=lambda: gr.update(open=False),
|
| 106 |
+
outputs=[mcp_servers_modal],
|
| 107 |
+
queue=False)
|
| 108 |
+
return state
|