feat(engine): 添加MCP连接管理和工具集成功能

- 集成MCP连接管理器,支持MCP服务器连接
- 添加多种内置工具:ClarifyTool、CronTool、DelegateTool、ExecuteCodeTool、
  PatchFileTool、ProcessTool、SendMessageTool、SpawnTool、TerminalTool、
  TodoTool、WebFetchTool、WebSearchTool、WriteFileTool等
- 实现工具注册和装配功能
- 添加技能选择上下文参数
- 支持思考模式控制参数thinking_enabled

feat(coordinator): 重构任务执行计划器参数命名

- 将learning_candidate_enabled重命名为allow_candidate_generation
- 更新TeamGraphScheduler中的参数传递
- 修改LocalAgentRunner中的相关参数处理
- 更新README文档中的相应描述

refactor(context): 标准化工具调用参数格式

- 添加_json导入用于参数序列化
- 实现_provider_tool_calls方法标准化OpenAI兼容的工具调用载荷
- 修复工具调用中参数非字符串类型的序列化问题

refactor(session): 优化消息历史记录过滤逻辑

- 修改get_messages_as_conversation为基于运行状态过滤消息
- 排除未完成、失败或错误结束的运行记录
- 改进对话历史的可见性控制机制

fix(store): 修复FTS索引重建逻辑

- 添加异常处理防止FTS索引创建失败
- 实现_rebuild_fts_index方法重新构建全文搜索索引
- 优化索引触发器和表的维护流程
This commit is contained in:
2026-05-14 09:43:48 +08:00
parent 8a12c30141
commit 30ab74ffb2
149 changed files with 12293 additions and 2812 deletions

View File

@ -116,6 +116,7 @@ export default function MCPPage() {
const [form, setForm] = useState(createEmptyForm());
const [authzStatus, setAuthzStatus] = useState<AuthzStatus | null>(null);
const [selectedServerId, setSelectedServerId] = useState<string | null>(null);
const [toolTab, setToolTab] = useState<'local' | 'online'>('local');
const load = useCallback(async (background = false) => {
if (background) {
@ -262,6 +263,7 @@ export default function MCPPage() {
const showAuthzPreview = form.auth_mode === 'oauth_backend_token';
const selectedServer = selectedServerId ? servers.find((server) => server.id === selectedServerId) || null : null;
const selectedToolGroup = selectedServerId ? tools.find((group) => group.server_id === selectedServerId) || null : null;
const visibleServers = servers.filter((server) => (server.kind || (server.transport === 'stdio' ? 'local' : 'online')) === toolTab);
let authzHint = t(
'无需手动填写。Audience 会按 MCP ID 自动生成Scopes 按 AuthZ 当前权限动态决定。',
'No manual input is required. The audience is generated from the MCP ID and scopes follow current AuthZ permissions.'
@ -305,10 +307,10 @@ export default function MCPPage() {
<div>
<h1 className="text-2xl font-bold flex items-center gap-2">
<ServerCog className="w-6 h-6" />
{t('MCP 服务', 'MCP servers')}
{t('工具', 'Tools')}
</h1>
<p className="text-sm text-muted-foreground mt-1">
{t('管理 MCP 服务配置、连通性和当前已发现的工具。', 'Manage MCP server configuration, connectivity, and discovered tools.')}
{t('本地工具和在线工具都通过 MCP Server 暴露;本地工具按类别由真实 stdio MCP 子进程承载。', 'Local and online tools are both exposed through MCP servers. Local tool categories run as real stdio MCP subprocesses.')}
</p>
</div>
<div className="flex items-center gap-2">
@ -323,7 +325,7 @@ export default function MCPPage() {
<DialogTrigger asChild>
<Button size="sm">
<Plus className="w-4 h-4 mr-2" />
{t('新增 MCP', 'Add MCP')}
{t('新增工具服务', 'Add tool server')}
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-2xl">
@ -484,9 +486,19 @@ export default function MCPPage() {
</Card>
)}
<Tabs value={toolTab} onValueChange={(value) => {
setToolTab(value as 'local' | 'online');
setSelectedServerId(null);
}} className="space-y-4">
<TabsList>
<TabsTrigger value="local">{t('本地工具', 'Local tools')}</TabsTrigger>
<TabsTrigger value="online">{t('在线工具', 'Online tools')}</TabsTrigger>
</TabsList>
</Tabs>
<div className="grid grid-cols-1 xl:grid-cols-[minmax(0,1.3fr)_minmax(0,1fr)] gap-4">
<div className="space-y-4">
{servers.map((server) => (
{visibleServers.map((server) => (
<Card
key={server.id}
role="button"
@ -511,6 +523,8 @@ export default function MCPPage() {
</div>
<div className="flex items-center gap-2 flex-wrap justify-end">
<Badge variant="outline">{transportLabel(server.transport, locale)}</Badge>
<Badge variant="secondary">{server.category || (server.kind === 'local' ? 'local' : 'online')}</Badge>
{server.managed && <Badge variant="outline">{t('内置', 'Built-in')}</Badge>}
<Badge variant={server.status === 'connected' ? 'default' : server.status === 'error' ? 'destructive' : 'secondary'}>
{serverStatusLabel(server.status, locale)}
</Badge>
@ -534,12 +548,14 @@ export default function MCPPage() {
{server.last_error && <span className="text-rose-300">{server.last_error}</span>}
</div>
<div className="flex items-center gap-2 justify-end">
<Button variant="outline" size="sm" onClick={(event) => {
event.stopPropagation();
openEdit(server);
}}>
{t('编辑', 'Edit')}
</Button>
{!server.managed && (
<Button variant="outline" size="sm" onClick={(event) => {
event.stopPropagation();
openEdit(server);
}}>
{t('编辑', 'Edit')}
</Button>
)}
<Button variant="outline" size="sm" onClick={(event) => {
event.stopPropagation();
void handleTest(server.id);
@ -547,21 +563,23 @@ export default function MCPPage() {
{testingId === server.id ? <Loader2 className="w-4 h-4 animate-spin mr-2" /> : <TestTube2 className="w-4 h-4 mr-2" />}
{t('测试', 'Test')}
</Button>
<Button variant="outline" size="sm" onClick={(event) => {
event.stopPropagation();
void handleDelete(server.id);
}}>
<Trash2 className="w-4 h-4 mr-2" />
{t('删除', 'Delete')}
</Button>
{!server.managed && (
<Button variant="outline" size="sm" onClick={(event) => {
event.stopPropagation();
void handleDelete(server.id);
}}>
<Trash2 className="w-4 h-4 mr-2" />
{t('删除', 'Delete')}
</Button>
)}
</div>
</CardContent>
</Card>
))}
{servers.length === 0 && (
{visibleServers.length === 0 && (
<Card>
<CardContent className="py-12 text-center text-muted-foreground">
{t('暂无 MCP 服务。', 'There are no MCP servers yet.')}
{toolTab === 'local' ? t('暂无本地工具服务。', 'There are no local tool servers yet.') : t('暂无在线工具服务。', 'There are no online tool servers yet.')}
</CardContent>
</Card>
)}
@ -571,7 +589,7 @@ export default function MCPPage() {
<CardHeader>
<CardTitle className="text-base flex items-center gap-2">
<Wrench className="w-4 h-4" />
{selectedServer ? t(`${selectedServer.name} 的工具`, `${selectedServer.name} tools`) : t('MCP 工具', 'MCP tools')}
{selectedServer ? t(`${selectedServer.name} 的工具`, `${selectedServer.name} tools`) : t('工具详情', 'Tool details')}
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">