@wfm-cn/dsh-mcp-connectors 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +38 -9
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -711,30 +711,59 @@ export async function apply(ctx, config = {}) {
|
|
|
711
711
|
for (const [sn, w] of want) {
|
|
712
712
|
if (!MOUNTED.has(sn)) await mount(w);
|
|
713
713
|
}
|
|
714
|
+
// 工具集变化后重新计算各会话的门控(deny 依赖已注册的工具名)
|
|
715
|
+
reapplyGates();
|
|
714
716
|
};
|
|
715
717
|
|
|
716
718
|
/* ---------------- 每会话工具门控 ---------------- */
|
|
717
719
|
|
|
718
|
-
const RESTRICTORS = new Map(); // agentId ->
|
|
720
|
+
const RESTRICTORS = new Map(); // agentId -> disposer
|
|
721
|
+
const GATE_PENDING = new Set(); // 因工具尚未注册而待重试的 agentId
|
|
722
|
+
|
|
723
|
+
/** 当前已挂载连接器的公开工具名(含 mcp__server__ 前缀)。 */
|
|
724
|
+
function mountedToolNamesByServer() {
|
|
725
|
+
const out = new Map(); // serverName -> string[]
|
|
726
|
+
for (const [serverName, rec] of MOUNTED) {
|
|
727
|
+
const names = (rec.tools ?? []).map((raw) => publicToolName(serverName, raw));
|
|
728
|
+
if (names.length) out.set(serverName, names);
|
|
729
|
+
}
|
|
730
|
+
return out;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/** 对单个 agent 应用会话级门控:禁用连接器的工具全部 deny。 */
|
|
719
734
|
const applyGate = (agent) => {
|
|
720
735
|
const agentCtx = agent?.ctx;
|
|
721
736
|
if (!agentCtx?.tools?.restrict) return;
|
|
722
737
|
const sessionId = String(agent.session?.id ?? agent.id ?? '');
|
|
723
|
-
try { RESTRICTORS.get(agent.id)?.(); } catch { /* ignore */ }
|
|
724
738
|
const allowed = enabledServersOf(currentConfig(), sessionId);
|
|
739
|
+
const byServer = mountedToolNamesByServer();
|
|
740
|
+
// 还没挂载完(工具尚未注册)时调用 restrict 会因 unknown name 抛错:留到挂载后再试
|
|
741
|
+
const deny = [];
|
|
742
|
+
for (const [serverName, names] of byServer) {
|
|
743
|
+
if (!allowed.has(serverName)) deny.push(...names);
|
|
744
|
+
}
|
|
745
|
+
try { RESTRICTORS.get(agent.id)?.(); } catch { /* ignore */ }
|
|
746
|
+
RESTRICTORS.delete(agent.id);
|
|
747
|
+
if (deny.length === 0) { GATE_PENDING.delete(agent.id); return; }
|
|
725
748
|
try {
|
|
726
|
-
const dispose = agentCtx.tools.restrict(
|
|
727
|
-
const name = typeof tool === 'string' ? tool : tool?.name ?? tool?.definition?.name;
|
|
728
|
-
if (typeof name !== 'string') return true;
|
|
729
|
-
const m = /^mcp__([A-Za-z0-9_-]+)__/.exec(name);
|
|
730
|
-
return m === null || allowed.has(m[1]);
|
|
731
|
-
});
|
|
749
|
+
const dispose = agentCtx.tools.restrict({ deny });
|
|
732
750
|
RESTRICTORS.set(agent.id, dispose);
|
|
751
|
+
GATE_PENDING.delete(agent.id);
|
|
733
752
|
} catch (e) {
|
|
734
|
-
|
|
753
|
+
// 工具名尚未生效(挂载中):记下,稍后重试
|
|
754
|
+
if (/unknown global tool/i.test(String(e?.message ?? ''))) {
|
|
755
|
+
GATE_PENDING.add(agent.id);
|
|
756
|
+
} else {
|
|
757
|
+
warn(`会话 ${sessionId} 工具门控失败:`, e?.message ?? e);
|
|
758
|
+
}
|
|
735
759
|
}
|
|
736
760
|
};
|
|
737
761
|
|
|
762
|
+
/** 挂载/卸载后重新应用所有 agent 的门控(门控依赖已注册的工具名)。 */
|
|
763
|
+
const reapplyGates = () => {
|
|
764
|
+
for (const agent of AGENTS?.list?.() ?? []) applyGate(agent);
|
|
765
|
+
};
|
|
766
|
+
|
|
738
767
|
/* ---------------- HTTP 路由 ---------------- */
|
|
739
768
|
|
|
740
769
|
const state = () => {
|