From a407870547465d87185d73ec38b84ffe958733e7 Mon Sep 17 00:00:00 2001 From: xiaoqu-ai Date: Wed, 21 Oct 2026 12:56:04 +0800 Subject: [PATCH] =?UTF-8?q?fix(mcp):=20=E7=BB=91=E5=AE=9A=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=90=8C=E6=97=B6=E5=90=AF=E7=94=A8=E8=A2=AB=E5=81=9C?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E5=B7=A5=E5=85=B7=EF=BC=88=E8=A7=A3=E9=87=8A?= =?UTF-8?q?"=E7=BB=91=E4=BA=86=E4=BB=8D=20PERMISSION=5FDENIED"=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现象:sync 作用域绑定 4 个工具后,3 个可用,district.paper.statistics.query 仍报 PERMISSION_DENIED。 原因推断:该工具在 tool 表 status != 1(停用),作用域解析会过滤掉它, 于是"绑定存在但工具不可用"。ToolSyncService 按设计保留管理员设置的状态, 所以不会纠正。 修复:ScopeToolSyncService 把绑定配置视为显式授权,遇到 status != 1 时 启用并 WARN 记录(原 status),避免静默失败。新增单测覆盖该场景(5 例全过)。 --- .../iiv/agent/mcp/ScopeToolSyncService.java | 9 ++++++++ .../agent/mcp/ScopeToolSyncServiceTest.java | 21 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/xiaoqu-agent-service/src/main/java/me/iiv/agent/mcp/ScopeToolSyncService.java b/xiaoqu-agent-service/src/main/java/me/iiv/agent/mcp/ScopeToolSyncService.java index 2d02fb4..c8e2b49 100644 --- a/xiaoqu-agent-service/src/main/java/me/iiv/agent/mcp/ScopeToolSyncService.java +++ b/xiaoqu-agent-service/src/main/java/me/iiv/agent/mcp/ScopeToolSyncService.java @@ -93,6 +93,15 @@ public class ScopeToolSyncService implements ApplicationRunner { skipped++; continue; } + // 绑定配置本身就是一次显式授权:若该工具在 tool 表被停用(status != 1), + // 作用域解析会把它过滤掉,表现为"绑了却仍 PERMISSION_DENIED"。 + // 这里按配置启用并告警,避免这种"看起来绑上了其实用不了"的静默失败。 + if (tool.getStatus() == null || tool.getStatus() != 1) { + Byte oldStatus = tool.getStatus(); + tool.setStatus((byte) 1); + toolMapper.updateById(tool); + log.warn("scope-tool binding 启用工具 name={} 原 status={}", toolName, oldStatus); + } Long existing = scopeToolMapper.selectCount(new LambdaQueryWrapper() .eq(ScopeTool::getScopeId, scope.getId()).eq(ScopeTool::getToolId, tool.getId())); if (existing != null && existing > 0) { diff --git a/xiaoqu-agent-service/src/test/java/me/iiv/agent/mcp/ScopeToolSyncServiceTest.java b/xiaoqu-agent-service/src/test/java/me/iiv/agent/mcp/ScopeToolSyncServiceTest.java index 466b356..acf1a2c 100644 --- a/xiaoqu-agent-service/src/test/java/me/iiv/agent/mcp/ScopeToolSyncServiceTest.java +++ b/xiaoqu-agent-service/src/test/java/me/iiv/agent/mcp/ScopeToolSyncServiceTest.java @@ -65,6 +65,27 @@ class ScopeToolSyncServiceTest { verify(scopeToolMapper, times(1)).insert(any(ScopeTool.class)); } + @Test + void enablesDisabledToolWhenBindingConfigDeclaresIt() { + service.rawBindings = "sync=tool.d"; + AgentScope scope = new AgentScope(); + scope.setId(4L); + scope.setCode("sync"); + when(scopeMapper.selectOne(any())).thenReturn(scope); + Tool toolD = new Tool(); + toolD.setId(13L); + toolD.setName("tool.d"); + toolD.setStatus((byte) 0); // 停用 + when(toolMapper.selectOne(any())).thenReturn(toolD); + when(scopeToolMapper.selectCount(any())).thenReturn(0L); + + service.run(null); + + assertEquals((byte) 1, toolD.getStatus(), "绑定配置应启用被停用的工具"); + verify(toolMapper, times(1)).updateById(toolD); + verify(scopeToolMapper, times(1)).insert(any(ScopeTool.class)); + } + @Test void bindsToolWhoseSoftDeleteColumnIsNull() { service.rawBindings = "sync=tool.c";