mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-06 05:09:09 +08:00
feat: add mcp Execute Tool
This commit is contained in:
parent
a9c9224835
commit
f30f06f40f
@ -3985,7 +3985,36 @@
|
|||||||
},
|
},
|
||||||
"loadError": "Get tools Error",
|
"loadError": "Get tools Error",
|
||||||
"noToolsAvailable": "No tools available",
|
"noToolsAvailable": "No tools available",
|
||||||
"run": "Run"
|
"run": "Run",
|
||||||
|
"execute": {
|
||||||
|
"label": "Execute",
|
||||||
|
"button": "Execute",
|
||||||
|
"tooltip": "Execute tool with custom parameters",
|
||||||
|
"title": "Execute Tool: {{name}}",
|
||||||
|
"params": "Parameters (JSON)",
|
||||||
|
"paramsPlaceholder": "Enter JSON parameters...",
|
||||||
|
"execute": "Execute",
|
||||||
|
"copied": "Copied to clipboard",
|
||||||
|
"copyFailed": "Failed to copy",
|
||||||
|
"copy": "Copy",
|
||||||
|
"result": {
|
||||||
|
"success": "Result",
|
||||||
|
"error": "Error Result",
|
||||||
|
"text": "Text"
|
||||||
|
},
|
||||||
|
"view": {
|
||||||
|
"json": "JSON",
|
||||||
|
"formatted": "Formatted"
|
||||||
|
},
|
||||||
|
"table": {
|
||||||
|
"name": "Name",
|
||||||
|
"value": "Value"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"noToolOrServer": "Tool or server not found",
|
||||||
|
"invalidJson": "Invalid JSON format: {{error}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"types": {
|
"types": {
|
||||||
|
|||||||
@ -3985,7 +3985,36 @@
|
|||||||
},
|
},
|
||||||
"loadError": "获取工具失败",
|
"loadError": "获取工具失败",
|
||||||
"noToolsAvailable": "无可用工具",
|
"noToolsAvailable": "无可用工具",
|
||||||
"run": "运行"
|
"run": "运行",
|
||||||
|
"execute": {
|
||||||
|
"label": "执行",
|
||||||
|
"button": "执行",
|
||||||
|
"tooltip": "使用自定义参数执行工具",
|
||||||
|
"title": "执行工具: {{name}}",
|
||||||
|
"params": "参数 (JSON)",
|
||||||
|
"paramsPlaceholder": "输入 JSON 参数...",
|
||||||
|
"execute": "执行",
|
||||||
|
"copied": "已复制到剪贴板",
|
||||||
|
"copyFailed": "复制失败",
|
||||||
|
"copy": "复制",
|
||||||
|
"result": {
|
||||||
|
"success": "结果",
|
||||||
|
"error": "错误结果",
|
||||||
|
"text": "文本"
|
||||||
|
},
|
||||||
|
"view": {
|
||||||
|
"json": "JSON",
|
||||||
|
"formatted": "美化"
|
||||||
|
},
|
||||||
|
"table": {
|
||||||
|
"name": "名称",
|
||||||
|
"value": "值"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"noToolOrServer": "未找到工具或服务器",
|
||||||
|
"invalidJson": "无效的 JSON 格式: {{error}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"type": "类型",
|
"type": "类型",
|
||||||
"types": {
|
"types": {
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import type { MCPServer, MCPTool } from '@renderer/types'
|
import type { MCPServer, MCPTool } from '@renderer/types'
|
||||||
import { isToolAutoApproved } from '@renderer/utils/mcp-tools'
|
import { isToolAutoApproved } from '@renderer/utils/mcp-tools'
|
||||||
import { Badge, Descriptions, Empty, Flex, Switch, Table, Tag, Tooltip, Typography } from 'antd'
|
import { Badge, Button, Descriptions, Empty, Flex, Switch, Table, Tag, Tooltip, Typography } from 'antd'
|
||||||
import type { ColumnsType } from 'antd/es/table'
|
import type { ColumnsType } from 'antd/es/table'
|
||||||
import { Hammer, Info, Zap } from 'lucide-react'
|
import { Hammer, Info, Play, Zap } from 'lucide-react'
|
||||||
|
import { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import ExecuteToolModal from './ExecuteToolModal'
|
||||||
|
|
||||||
interface MCPToolsSectionProps {
|
interface MCPToolsSectionProps {
|
||||||
tools: MCPTool[]
|
tools: MCPTool[]
|
||||||
@ -14,6 +16,8 @@ interface MCPToolsSectionProps {
|
|||||||
|
|
||||||
const MCPToolsSection = ({ tools, server, onToggleTool, onToggleAutoApprove }: MCPToolsSectionProps) => {
|
const MCPToolsSection = ({ tools, server, onToggleTool, onToggleAutoApprove }: MCPToolsSectionProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const [executeModalOpen, setExecuteModalOpen] = useState(false)
|
||||||
|
const [selectedTool, setSelectedTool] = useState<MCPTool | null>(null)
|
||||||
|
|
||||||
// Check if a tool is enabled (not in the disabledTools array)
|
// Check if a tool is enabled (not in the disabledTools array)
|
||||||
const isToolEnabled = (tool: MCPTool) => {
|
const isToolEnabled = (tool: MCPTool) => {
|
||||||
@ -30,6 +34,12 @@ const MCPToolsSection = ({ tools, server, onToggleTool, onToggleAutoApprove }: M
|
|||||||
onToggleAutoApprove(tool, checked)
|
onToggleAutoApprove(tool, checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle execute tool
|
||||||
|
const handleExecuteTool = (tool: MCPTool) => {
|
||||||
|
setSelectedTool(tool)
|
||||||
|
setExecuteModalOpen(true)
|
||||||
|
}
|
||||||
|
|
||||||
// Render tool properties from the input schema
|
// Render tool properties from the input schema
|
||||||
const renderToolProperties = (tool: MCPTool) => {
|
const renderToolProperties = (tool: MCPTool) => {
|
||||||
if (!tool.inputSchema?.properties) return null
|
if (!tool.inputSchema?.properties) return null
|
||||||
@ -102,6 +112,7 @@ const MCPToolsSection = ({ tools, server, onToggleTool, onToggleAutoApprove }: M
|
|||||||
}
|
}
|
||||||
|
|
||||||
const columns: ColumnsType<MCPTool> = [
|
const columns: ColumnsType<MCPTool> = [
|
||||||
|
// 工具列表列定义:可用工具、启用工具、自动批准、执行工具
|
||||||
{
|
{
|
||||||
title: <Typography.Text strong>{t('settings.mcp.tools.availableTools')}</Typography.Text>,
|
title: <Typography.Text strong>{t('settings.mcp.tools.availableTools')}</Typography.Text>,
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
@ -141,7 +152,7 @@ const MCPToolsSection = ({ tools, server, onToggleTool, onToggleAutoApprove }: M
|
|||||||
</Flex>
|
</Flex>
|
||||||
),
|
),
|
||||||
key: 'enable',
|
key: 'enable',
|
||||||
width: 150, // Fixed width might be good for alignment
|
width: 130, // Fixed width might be good for alignment
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (_, tool) => (
|
render: (_, tool) => (
|
||||||
<Switch checked={isToolEnabled(tool)} onChange={(checked) => handleToggle(tool, checked)} size="small" />
|
<Switch checked={isToolEnabled(tool)} onChange={(checked) => handleToggle(tool, checked)} size="small" />
|
||||||
@ -155,7 +166,7 @@ const MCPToolsSection = ({ tools, server, onToggleTool, onToggleAutoApprove }: M
|
|||||||
</Flex>
|
</Flex>
|
||||||
),
|
),
|
||||||
key: 'autoApprove',
|
key: 'autoApprove',
|
||||||
width: 150, // Fixed width
|
width: 130, // Fixed width
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (_, tool) => (
|
render: (_, tool) => (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@ -175,21 +186,57 @@ const MCPToolsSection = ({ tools, server, onToggleTool, onToggleAutoApprove }: M
|
|||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: (
|
||||||
|
<Flex align="center" justify="center" gap={4}>
|
||||||
|
<Play size={14} color="green" />
|
||||||
|
<Typography.Text strong>{t('settings.mcp.tools.execute.label', 'Execute')}</Typography.Text>
|
||||||
|
</Flex>
|
||||||
|
),
|
||||||
|
key: 'execute',
|
||||||
|
width: 130,
|
||||||
|
align: 'center',
|
||||||
|
render: (_, tool) => (
|
||||||
|
<Tooltip title={t('settings.mcp.tools.execute.tooltip', 'Execute tool with custom parameters')}>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
icon={<Play size={12} />}
|
||||||
|
onClick={() => handleExecuteTool(tool)}
|
||||||
|
disabled={!isToolEnabled(tool)}>
|
||||||
|
{t('settings.mcp.tools.execute.button', 'Execute')}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
return tools.length > 0 ? (
|
return (
|
||||||
<Table
|
<>
|
||||||
rowKey="id"
|
{tools.length > 0 ? (
|
||||||
columns={columns}
|
<Table
|
||||||
dataSource={tools}
|
rowKey="id"
|
||||||
pagination={false}
|
columns={columns}
|
||||||
expandable={{
|
dataSource={tools}
|
||||||
expandedRowRender: (tool) => renderToolProperties(tool)
|
pagination={false}
|
||||||
}}
|
expandable={{
|
||||||
/>
|
expandedRowRender: (tool) => renderToolProperties(tool)
|
||||||
) : (
|
}}
|
||||||
<Empty description={t('settings.mcp.tools.noToolsAvailable')} image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
/>
|
||||||
|
) : (
|
||||||
|
<Empty description={t('settings.mcp.tools.noToolsAvailable')} image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||||
|
)}
|
||||||
|
<ExecuteToolModal
|
||||||
|
open={executeModalOpen}
|
||||||
|
tool={selectedTool}
|
||||||
|
server={server}
|
||||||
|
onClose={() => {
|
||||||
|
setExecuteModalOpen(false)
|
||||||
|
setSelectedTool(null)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user