@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.
Files changed (2) hide show
  1. package/index.js +38 -9
  2. 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 -> dispose
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((tool) => {
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
- warn(`会话 ${sessionId} 工具门控失败:`, e?.message ?? e);
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 = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wfm-cn/dsh-mcp-connectors",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.js",