@agenticmail/enterprise 0.5.248 → 0.5.249

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.
@@ -0,0 +1,45 @@
1
+ import {
2
+ AgentRuntime,
3
+ EmailChannel,
4
+ FollowUpScheduler,
5
+ SessionManager,
6
+ SubAgentManager,
7
+ ToolRegistry,
8
+ callLLM,
9
+ createAgentRuntime,
10
+ createNoopHooks,
11
+ createRuntimeHooks,
12
+ estimateMessageTokens,
13
+ estimateTokens,
14
+ executeTool,
15
+ runAgentLoop,
16
+ toolsToDefinitions
17
+ } from "./chunk-RNREJCPG.js";
18
+ import {
19
+ PROVIDER_REGISTRY,
20
+ listAllProviders,
21
+ resolveApiKeyForProvider,
22
+ resolveProvider
23
+ } from "./chunk-UF3ZJMJO.js";
24
+ import "./chunk-KFQGP6VL.js";
25
+ export {
26
+ AgentRuntime,
27
+ EmailChannel,
28
+ FollowUpScheduler,
29
+ PROVIDER_REGISTRY,
30
+ SessionManager,
31
+ SubAgentManager,
32
+ ToolRegistry,
33
+ callLLM,
34
+ createAgentRuntime,
35
+ createNoopHooks,
36
+ createRuntimeHooks,
37
+ estimateMessageTokens,
38
+ estimateTokens,
39
+ executeTool,
40
+ listAllProviders,
41
+ resolveApiKeyForProvider,
42
+ resolveProvider,
43
+ runAgentLoop,
44
+ toolsToDefinitions
45
+ };
@@ -0,0 +1,15 @@
1
+ import {
2
+ createServer
3
+ } from "./chunk-XWVKQO6P.js";
4
+ import "./chunk-OF4MUWWS.js";
5
+ import "./chunk-UF3ZJMJO.js";
6
+ import "./chunk-3OC6RH7W.js";
7
+ import "./chunk-2DDKGTD6.js";
8
+ import "./chunk-YVK6F5OD.js";
9
+ import "./chunk-MKRNEM5A.js";
10
+ import "./chunk-DRXMYYKN.js";
11
+ import "./chunk-6WSX7QXF.js";
12
+ import "./chunk-KFQGP6VL.js";
13
+ export {
14
+ createServer
15
+ };
@@ -0,0 +1,20 @@
1
+ import {
2
+ promptCompanyInfo,
3
+ promptDatabase,
4
+ promptDeployment,
5
+ promptDomain,
6
+ promptRegistration,
7
+ provision,
8
+ runSetupWizard
9
+ } from "./chunk-PNBWEEJZ.js";
10
+ import "./chunk-ULRBF2T7.js";
11
+ import "./chunk-KFQGP6VL.js";
12
+ export {
13
+ promptCompanyInfo,
14
+ promptDatabase,
15
+ promptDeployment,
16
+ promptDomain,
17
+ promptRegistration,
18
+ provision,
19
+ runSetupWizard
20
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/enterprise",
3
- "version": "0.5.248",
3
+ "version": "0.5.249",
4
4
  "description": "AgenticMail Enterprise — cloud-hosted AI agent identity, email, auth & compliance for organizations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -401,6 +401,25 @@ export async function createAllTools(options?: AllToolsOptions): Promise<AnyAgen
401
401
  }
402
402
  }
403
403
 
404
+ // ─── External MCP Server Tools ───
405
+ // Tools from MCP servers registered via Dashboard → Integrations & MCP
406
+ var mcpServerTools: AnyAgentTool[] = [];
407
+ if ((options as any)?.mcpProcessManager) {
408
+ try {
409
+ var { createMcpServerTools } = await import('./tools/mcp-server-tools.js');
410
+ mcpServerTools = createMcpServerTools({
411
+ mcpManager: (options as any).mcpProcessManager,
412
+ agentId: options?.agentId,
413
+ permissionEngine: (options as any)?.permissionEngine,
414
+ });
415
+ if (mcpServerTools.length > 0) {
416
+ console.log(`[tools] Loaded ${mcpServerTools.length} MCP server tools for agent ${options?.agentId || 'all'}`);
417
+ }
418
+ } catch (e: any) {
419
+ console.warn(`[tools] MCP server tools load failed: ${e.message}`);
420
+ }
421
+ }
422
+
404
423
  // ─── Messaging Tools (WhatsApp, Telegram) ───
405
424
  var messagingTools: AnyAgentTool[] = [];
406
425
  try {
@@ -461,6 +480,7 @@ export async function createAllTools(options?: AllToolsOptions): Promise<AnyAgen
461
480
  .concat(workspaceTools)
462
481
  .concat(enterpriseBrowserTools)
463
482
  .concat(integrationTools)
483
+ .concat(mcpServerTools)
464
484
  .concat(messagingTools)
465
485
  .concat(managementTools);
466
486
 
@@ -0,0 +1,91 @@
1
+ /**
2
+ * MCP Server Tools Bridge
3
+ *
4
+ * Converts tools from external MCP servers (registered via Dashboard → Integrations & MCP)
5
+ * into native AnyAgentTool[] that the agent loop can use directly.
6
+ *
7
+ * This bridges the McpProcessManager (which manages MCP server lifecycles)
8
+ * to the agent's tool system. Each discovered MCP tool becomes a callable agent tool.
9
+ *
10
+ * Flow:
11
+ * McpProcessManager.getToolsForAgent(agentId)
12
+ * → McpDiscoveredTool[] (name, description, inputSchema, serverId)
13
+ * → createMcpServerTools() wraps each in AnyAgentTool with execute()
14
+ * → execute() calls McpProcessManager.callTool(name, args)
15
+ * → proxied to MCP server via stdio/HTTP → result returned to agent
16
+ */
17
+
18
+ import type { AnyAgentTool } from '../types.js';
19
+ import { jsonResult, errorResult } from '../common.js';
20
+ import type { McpProcessManager } from '../../engine/mcp-process-manager.js';
21
+
22
+ export interface McpServerToolsConfig {
23
+ mcpManager: McpProcessManager;
24
+ agentId?: string;
25
+ /** Optional permission engine for dynamic tool registration */
26
+ permissionEngine?: any;
27
+ }
28
+
29
+ /**
30
+ * Create agent tools from all connected MCP servers for a given agent.
31
+ * Returns empty array if no MCP servers are connected or none assigned to this agent.
32
+ */
33
+ export function createMcpServerTools(config: McpServerToolsConfig): AnyAgentTool[] {
34
+ const { mcpManager, agentId } = config;
35
+ const discoveredTools = mcpManager.getToolsForAgent(agentId);
36
+
37
+ if (discoveredTools.length === 0) return [];
38
+
39
+ console.log(`[mcp-server-tools] Creating ${discoveredTools.length} tools from MCP servers for agent ${agentId || 'all'}`);
40
+
41
+ // Register with permission engine
42
+ if (config.permissionEngine && discoveredTools.length > 0) {
43
+ try {
44
+ const toolDefs = discoveredTools.map(t => ({
45
+ id: `mcp_${t.name}`,
46
+ name: `mcp_${t.name}`,
47
+ description: t.description || t.name,
48
+ category: 'utility' as any,
49
+ risk: 'medium' as any,
50
+ skillId: 'mcp-servers',
51
+ sideEffects: ['external_api'] as any[],
52
+ }));
53
+ config.permissionEngine.registerDynamicTools('mcp-servers', toolDefs);
54
+ } catch (e: any) {
55
+ console.warn(`[mcp-server-tools] Permission engine registration failed: ${e.message}`);
56
+ }
57
+ }
58
+
59
+ return discoveredTools.map(tool => {
60
+ // Prefix tool names with mcp_ to avoid collisions with built-in tools
61
+ const toolName = `mcp_${tool.name}`;
62
+
63
+ return {
64
+ name: toolName,
65
+ description: `[${tool.serverName}] ${tool.description || tool.name}`,
66
+ category: 'utility' as const,
67
+ parameters: {
68
+ type: 'object' as const,
69
+ properties: tool.inputSchema?.properties || {},
70
+ required: tool.inputSchema?.required || [],
71
+ },
72
+ async execute(_callId: string, params: any) {
73
+ try {
74
+ const result = await mcpManager.callTool(tool.name, params, agentId);
75
+ if (result.isError) {
76
+ return errorResult(result.content);
77
+ }
78
+ // Try to parse JSON for structured output
79
+ try {
80
+ const parsed = JSON.parse(result.content);
81
+ return jsonResult(parsed);
82
+ } catch {
83
+ return { content: [{ type: 'text' as const, text: result.content }] };
84
+ }
85
+ } catch (e: any) {
86
+ return errorResult(`MCP tool ${tool.name} error: ${e.message}`);
87
+ }
88
+ },
89
+ };
90
+ });
91
+ }
package/src/cli-agent.ts CHANGED
@@ -567,6 +567,25 @@ export async function runAgent(_args: string[]) {
567
567
  resumeOnStartup: false, // Disabled: zombie sessions exhaust Supabase pool on restart
568
568
  });
569
569
 
570
+ // ─── MCP Process Manager ───────────────────────────
571
+ // Manages external MCP servers registered via Dashboard → Integrations & MCP
572
+ try {
573
+ const { McpProcessManager } = await import('./engine/mcp-process-manager.js');
574
+ const mcpManager = new McpProcessManager({ engineDb, orgId: 'default' });
575
+ await mcpManager.start();
576
+ (runtime as any).config.mcpProcessManager = mcpManager;
577
+ console.log(`[agent] MCP Process Manager started`);
578
+
579
+ // Graceful shutdown
580
+ const origStop = runtime.stop?.bind(runtime);
581
+ (runtime as any).stop = async () => {
582
+ await mcpManager.stop();
583
+ if (origStop) await origStop();
584
+ };
585
+ } catch (e: any) {
586
+ console.warn(`[agent] MCP Process Manager init failed (non-fatal): ${e.message}`);
587
+ }
588
+
570
589
  await runtime.start();
571
590
  const runtimeApp = runtime.getApp();
572
591
 
@@ -1,4 +1,4 @@
1
- import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall } from '../components/utils.js';
1
+ import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall, adminCall } from '../components/utils.js';
2
2
  import { I } from '../components/icons.js';
3
3
  import { Modal } from '../components/modal.js';
4
4
  import { HelpButton } from '../components/help-button.js';
@@ -44,9 +44,10 @@ function McpServersSection() {
44
44
  var _showAdd = useState(false); var showAdd = _showAdd[0]; var setShowAdd = _showAdd[1];
45
45
  var _editServer = useState(null); var editServer = _editServer[0]; var setEditServer = _editServer[1];
46
46
  var _testing = useState(null); var testing = _testing[0]; var setTesting = _testing[1];
47
+ var _agents = useState([]); var agents = _agents[0]; var setAgents = _agents[1];
47
48
 
48
49
  // Add/edit form
49
- var _form = useState({ name: '', type: 'stdio', command: '', args: '', url: '', apiKey: '', headers: '{}', env: '{}', enabled: true, description: '', autoRestart: true, timeout: 30 });
50
+ var _form = useState({ name: '', type: 'stdio', command: '', args: '', url: '', apiKey: '', headers: '{}', env: '{}', enabled: true, description: '', autoRestart: true, timeout: 30, assignedAgents: [] });
50
51
  var form = _form[0]; var setForm = _form[1];
51
52
 
52
53
  var load = useCallback(function() {
@@ -58,9 +59,12 @@ function McpServersSection() {
58
59
  }, []);
59
60
 
60
61
  useEffect(function() { load(); }, [load]);
62
+ useEffect(function() {
63
+ adminCall('/agents').then(function(d) { setAgents((d.agents || d || []).filter(function(a) { return a.status !== 'archived'; })); }).catch(function() {});
64
+ }, []);
61
65
 
62
66
  var resetForm = function() {
63
- setForm({ name: '', type: 'stdio', command: '', args: '', url: '', apiKey: '', headers: '{}', env: '{}', enabled: true, description: '', autoRestart: true, timeout: 30 });
67
+ setForm({ name: '', type: 'stdio', command: '', args: '', url: '', apiKey: '', headers: '{}', env: '{}', enabled: true, description: '', autoRestart: true, timeout: 30, assignedAgents: [] });
64
68
  };
65
69
 
66
70
  var openAdd = function() { resetForm(); setEditServer(null); setShowAdd(true); };
@@ -79,6 +83,7 @@ function McpServersSection() {
79
83
  description: server.description || '',
80
84
  autoRestart: server.autoRestart !== false,
81
85
  timeout: server.timeout || 30,
86
+ assignedAgents: server.assignedAgents || [],
82
87
  });
83
88
  setEditServer(server);
84
89
  setShowAdd(true);
@@ -92,6 +97,7 @@ function McpServersSection() {
92
97
  description: form.description.trim(),
93
98
  autoRestart: form.autoRestart,
94
99
  timeout: parseInt(form.timeout) || 30,
100
+ assignedAgents: form.assignedAgents || [],
95
101
  };
96
102
  if (form.type === 'stdio') {
97
103
  payload.command = form.command.trim();
@@ -210,7 +216,13 @@ function McpServersSection() {
210
216
  ? (server.command + ' ' + (server.args || []).join(' ')).trim()
211
217
  : server.url || ''
212
218
  ),
213
- server.description && h('div', { style: { fontSize: 11, color: 'var(--text-secondary)', marginTop: 2 } }, server.description)
219
+ server.description && h('div', { style: { fontSize: 11, color: 'var(--text-secondary)', marginTop: 2 } }, server.description),
220
+ server.assignedAgents && server.assignedAgents.length > 0 && h('div', { style: { fontSize: 10, color: 'var(--text-muted)', marginTop: 3 } },
221
+ 'Agents: ' + server.assignedAgents.map(function(aid) {
222
+ var a = agents.find(function(x) { return x.id === aid; });
223
+ return a ? (a.display_name || a.name) : aid.slice(0, 8);
224
+ }).join(', ')
225
+ )
214
226
  ),
215
227
  h('div', { style: { display: 'flex', gap: 4, flexShrink: 0 } },
216
228
  h('button', { className: 'btn btn-ghost btn-sm', title: 'Test connection', disabled: isTesting, onClick: function() { testServer(server); } },
@@ -400,6 +412,38 @@ function McpServersSection() {
400
412
  h('p', { style: { marginTop: 8 } }, 'Keep this on unless you have a reason to disable it.')
401
413
  )
402
414
  )
415
+ ),
416
+ // Agent assignment
417
+ agents.length > 0 && h('div', { className: 'form-group', style: { marginTop: 16 } },
418
+ h('label', { className: 'form-label', style: { display: 'flex', alignItems: 'center' } }, 'Agent Access', h(HelpButton, { label: 'Agent Access' },
419
+ h('p', null, 'Choose which agents can use this MCP server\'s tools. If none are selected, ALL agents can use it.'),
420
+ h('p', { style: { marginTop: 8 } }, 'Use this to restrict sensitive tools (like database access) to specific agents only.')
421
+ )),
422
+ h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 6 } },
423
+ agents.map(function(a) {
424
+ var isSelected = (form.assignedAgents || []).includes(a.id);
425
+ return h('button', {
426
+ key: a.id,
427
+ type: 'button',
428
+ style: {
429
+ padding: '4px 10px', borderRadius: 6, fontSize: 12, cursor: 'pointer',
430
+ border: '1px solid ' + (isSelected ? 'var(--primary)' : 'var(--border)'),
431
+ background: isSelected ? 'var(--primary)' : 'var(--bg-secondary)',
432
+ color: isSelected ? '#fff' : 'var(--text-primary)',
433
+ },
434
+ onClick: function() {
435
+ var current = form.assignedAgents || [];
436
+ var next = isSelected ? current.filter(function(x) { return x !== a.id; }) : current.concat(a.id);
437
+ setForm(Object.assign({}, form, { assignedAgents: next }));
438
+ }
439
+ }, a.display_name || a.name);
440
+ })
441
+ ),
442
+ h('div', { style: { fontSize: 11, color: 'var(--text-muted)', marginTop: 4 } },
443
+ form.assignedAgents && form.assignedAgents.length > 0
444
+ ? form.assignedAgents.length + ' agent(s) selected — only they can use this server'
445
+ : 'No agents selected — all agents can use this server'
446
+ )
403
447
  )
404
448
  ),
405
449
  // Preset templates