agent-orchestrator-mcp-server 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -9,7 +9,7 @@ MCP server for PulseMCP's agent-orchestrator: a Claude Code + MCP-powered agent-
9
9
 
10
10
  - Simplified 4-tool interface for full agent session management
11
11
  - Search, filter, and retrieve sessions with optional logs and transcripts
12
- - Session lifecycle actions (pause, restart, archive, unarchive, follow_up)
12
+ - Session lifecycle actions (pause, restart, archive, unarchive, follow_up, change_mcp_servers)
13
13
  - Tool grouping system for permission-based access control
14
14
  - TypeScript with strict type checking
15
15
  - Comprehensive testing setup (functional, integration, manual)
@@ -18,12 +18,12 @@ MCP server for PulseMCP's agent-orchestrator: a Claude Code + MCP-powered agent-
18
18
 
19
19
  ### Tools
20
20
 
21
- | Tool | Group | Description |
22
- | ----------------- | -------- | ---------------------------------------------------------------------- |
23
- | `search_sessions` | readonly | Search/list sessions with optional ID lookup, query, and status filter |
24
- | `get_session` | readonly | Get detailed session info with optional logs and transcripts |
25
- | `start_session` | write | Create and start a new agent session |
26
- | `action_session` | write | Perform actions: follow_up, pause, restart, archive, unarchive |
21
+ | Tool | Group | Description |
22
+ | ----------------- | -------- | ---------------------------------------------------------------------------------- |
23
+ | `search_sessions` | readonly | Search/list sessions with optional ID lookup, query, and status filter |
24
+ | `get_session` | readonly | Get detailed session info with optional logs and transcripts |
25
+ | `start_session` | write | Create and start a new agent session |
26
+ | `action_session` | write | Perform actions: follow_up, pause, restart, archive, unarchive, change_mcp_servers |
27
27
 
28
28
  ### Resources
29
29
 
@@ -47,51 +47,45 @@ Control which tools are available via the `ENABLED_TOOLGROUPS` environment varia
47
47
  - `ENABLED_TOOLGROUPS="readonly,write"` - Read and write, no admin
48
48
  - Not set - All tools enabled (default)
49
49
 
50
- ## Quick Start
50
+ ## Setup
51
51
 
52
- ### Installation
52
+ ### Prerequisites
53
53
 
54
- ```bash
55
- npm run install-all
56
- npm run build
57
- ```
54
+ - Node.js (use `nvm use` if you have nvm installed)
55
+ - An Agent Orchestrator instance with API access
58
56
 
59
- ### Configuration
57
+ ### Environment Variables
60
58
 
61
- Set the required environment variables:
59
+ | Variable | Required | Description | Default |
60
+ | ----------------------------- | -------- | -------------------------------------- | ----------- |
61
+ | `AGENT_ORCHESTRATOR_BASE_URL` | Yes | Base URL for the orchestrator API | - |
62
+ | `AGENT_ORCHESTRATOR_API_KEY` | Yes | API key for authentication | - |
63
+ | `ENABLED_TOOLGROUPS` | No | Comma-separated tool groups | All enabled |
64
+ | `SKIP_HEALTH_CHECKS` | No | Skip API connectivity check at startup | `false` |
65
+ | `HEALTH_CHECK_TIMEOUT` | No | Health check timeout in milliseconds | `10000` |
62
66
 
63
- ```bash
64
- export AGENT_ORCHESTRATOR_BASE_URL="http://localhost:3000"
65
- export AGENT_ORCHESTRATOR_API_KEY="your_api_key_here"
66
- ```
67
+ ### Claude Desktop
67
68
 
68
- ### Running
69
+ Make sure you have your Agent Orchestrator base URL and API key ready.
69
70
 
70
- ```bash
71
- npm start
72
- ```
71
+ Then proceed to the setup instructions below. If this is your first time using MCP Servers, you'll want to make sure you have the [Claude Desktop application](https://claude.ai/download) and follow the [official MCP setup instructions](https://modelcontextprotocol.io/quickstart/user).
73
72
 
74
- ## Environment Variables
73
+ #### Manual Setup
75
74
 
76
- | Variable | Required | Description | Default |
77
- | ----------------------------- | -------- | --------------------------------- | ----------- |
78
- | `AGENT_ORCHESTRATOR_BASE_URL` | Yes | Base URL for the orchestrator API | - |
79
- | `AGENT_ORCHESTRATOR_API_KEY` | Yes | API key for authentication | - |
80
- | `ENABLED_TOOLGROUPS` | No | Comma-separated tool groups | All enabled |
81
- | `SKIP_HEALTH_CHECKS` | No | Skip API validation at startup | `false` |
75
+ You're going to need Node working on your machine so you can run `npx` commands in your terminal. If you don't have Node, you can install it from [nodejs.org](https://nodejs.org/en/download).
82
76
 
83
- ### Claude Desktop Configuration
77
+ macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
84
78
 
85
- #### macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
79
+ Windows: `%APPDATA%\Claude\claude_desktop_config.json`
86
80
 
87
- #### Windows: `%APPDATA%\Claude\claude_desktop_config.json`
81
+ Modify your `claude_desktop_config.json` file to add the following:
88
82
 
89
83
  ```json
90
84
  {
91
85
  "mcpServers": {
92
86
  "agent-orchestrator": {
93
- "command": "node",
94
- "args": ["/path/to/agent-orchestrator/local/build/index.js"],
87
+ "command": "npx",
88
+ "args": ["-y", "agent-orchestrator-mcp-server"],
95
89
  "env": {
96
90
  "AGENT_ORCHESTRATOR_BASE_URL": "http://localhost:3000",
97
91
  "AGENT_ORCHESTRATOR_API_KEY": "your-api-key-here",
@@ -102,6 +96,8 @@ npm start
102
96
  }
103
97
  ```
104
98
 
99
+ Restart Claude Desktop and you should be ready to go!
100
+
105
101
  ## Development
106
102
 
107
103
  ### Running in Development Mode
package/build/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
- import { createMCPServer } from '../shared/index.js';
4
- import { logServerStart, logError, logWarning } from '../shared/logging.js';
3
+ import { createMCPServer, checkApiHealth, getErrorHint, parseHealthCheckTimeout, } from '../shared/index.js';
4
+ import { logServerStart, logError, logWarning, logDebug } from '../shared/logging.js';
5
5
  // =============================================================================
6
6
  // ENVIRONMENT VALIDATION
7
7
  // =============================================================================
@@ -28,9 +28,14 @@ function validateEnvironment() {
28
28
  },
29
29
  {
30
30
  name: 'SKIP_HEALTH_CHECKS',
31
- description: 'Skip API validation at startup',
31
+ description: 'Skip API connectivity check at startup (set to "true" to skip)',
32
32
  defaultValue: 'false',
33
33
  },
34
+ {
35
+ name: 'HEALTH_CHECK_TIMEOUT',
36
+ description: 'Health check timeout in milliseconds',
37
+ defaultValue: '10000',
38
+ },
34
39
  ];
35
40
  const missing = required.filter(({ name }) => !process.env[name]);
36
41
  if (missing.length > 0) {
@@ -71,8 +76,28 @@ async function performHealthChecks() {
71
76
  logWarning('healthcheck', 'Health checks skipped (SKIP_HEALTH_CHECKS=true)');
72
77
  return;
73
78
  }
74
- // For agent-orchestrator, we could add a health check by calling the sessions endpoint
75
- // For now, we skip complex validation since the API might not always be available
79
+ logDebug('healthcheck', 'Performing API connectivity health check...');
80
+ // Parse health check timeout using shared utility
81
+ const healthCheckTimeout = parseHealthCheckTimeout(process.env.HEALTH_CHECK_TIMEOUT, (msg) => logWarning('healthcheck', msg));
82
+ const baseUrl = process.env.AGENT_ORCHESTRATOR_BASE_URL;
83
+ const apiKey = process.env.AGENT_ORCHESTRATOR_API_KEY;
84
+ try {
85
+ await checkApiHealth(baseUrl, apiKey, healthCheckTimeout);
86
+ logDebug('healthcheck', `Health check passed - connected to ${baseUrl}`);
87
+ }
88
+ catch (error) {
89
+ const errorMessage = error instanceof Error ? error.message : String(error);
90
+ // Provide helpful error messages based on common failure scenarios
91
+ const hint = getErrorHint(errorMessage, healthCheckTimeout);
92
+ logError('healthcheck', `API connectivity health check failed: ${errorMessage}${hint}`);
93
+ console.error('\n----------------------------------------');
94
+ console.error('API connectivity health check failed!');
95
+ console.error(`Error: ${errorMessage}${hint}`);
96
+ console.error('\nTo skip health checks, set:');
97
+ console.error(' SKIP_HEALTH_CHECKS=true');
98
+ console.error('----------------------------------------\n');
99
+ process.exit(1);
100
+ }
76
101
  }
77
102
  // =============================================================================
78
103
  // MAIN ENTRY POINT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-orchestrator-mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Local implementation of agent-orchestrator MCP server",
5
5
  "main": "build/index.js",
6
6
  "type": "module",
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Health check utilities for Agent Orchestrator MCP server.
3
+ * These are exported separately for testing.
4
+ */
5
+ export declare const DEFAULT_HEALTH_CHECK_TIMEOUT = 10000;
6
+ export declare const MAX_HEALTH_CHECK_TIMEOUT = 300000;
7
+ /**
8
+ * Get a helpful hint based on the error message to guide users in troubleshooting.
9
+ */
10
+ export declare function getErrorHint(errorMessage: string, timeout: number): string;
11
+ /**
12
+ * Parse and validate health check timeout from environment variable.
13
+ * Returns validated timeout value or default.
14
+ */
15
+ export declare function parseHealthCheckTimeout(envValue: string | undefined, warnFn?: (message: string) => void): number;
16
+ /**
17
+ * Perform a health check against the Agent Orchestrator API.
18
+ * Makes a lightweight request to verify connectivity and authentication.
19
+ */
20
+ export declare function checkApiHealth(baseUrl: string, apiKey: string, timeoutMs?: number): Promise<void>;
21
+ //# sourceMappingURL=health-check.d.ts.map
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Health check utilities for Agent Orchestrator MCP server.
3
+ * These are exported separately for testing.
4
+ */
5
+ export const DEFAULT_HEALTH_CHECK_TIMEOUT = 10000;
6
+ export const MAX_HEALTH_CHECK_TIMEOUT = 300000; // 5 minutes max
7
+ /**
8
+ * Get a helpful hint based on the error message to guide users in troubleshooting.
9
+ */
10
+ export function getErrorHint(errorMessage, timeout) {
11
+ // Check for authentication errors first (most common initial setup issue)
12
+ if (errorMessage.includes('401') ||
13
+ errorMessage.includes('403') ||
14
+ errorMessage.toLowerCase().includes('unauthorized') ||
15
+ errorMessage.toLowerCase().includes('forbidden')) {
16
+ return '\nHint: Authentication failed. Check that AGENT_ORCHESTRATOR_API_KEY is correct.';
17
+ }
18
+ // Check for timeout errors
19
+ if (errorMessage.toLowerCase().includes('timeout')) {
20
+ return `\nHint: Connection timed out after ${timeout}ms. Check that the API server is running and reachable.`;
21
+ }
22
+ // Check for connection refused (specific error codes)
23
+ if (errorMessage.includes('ECONNREFUSED')) {
24
+ return '\nHint: Connection refused. Check that the API server is running and AGENT_ORCHESTRATOR_BASE_URL is correct.';
25
+ }
26
+ // Check for DNS resolution errors
27
+ if (errorMessage.includes('ENOTFOUND') || errorMessage.includes('getaddrinfo')) {
28
+ return '\nHint: Could not resolve hostname. Check that AGENT_ORCHESTRATOR_BASE_URL is correct.';
29
+ }
30
+ // Check for other connection errors (more specific patterns)
31
+ if (errorMessage.includes('ECONNRESET') ||
32
+ errorMessage.includes('EHOSTUNREACH') ||
33
+ errorMessage.includes('ENETUNREACH')) {
34
+ return '\nHint: Network error. Check that the API server is reachable and there are no firewall issues.';
35
+ }
36
+ // Check for invalid URL errors
37
+ if (errorMessage.includes('Invalid URL') || errorMessage.includes('ERR_INVALID_URL')) {
38
+ return '\nHint: Invalid URL. Check that AGENT_ORCHESTRATOR_BASE_URL is a valid URL (e.g., http://localhost:3000).';
39
+ }
40
+ return '';
41
+ }
42
+ /**
43
+ * Parse and validate health check timeout from environment variable.
44
+ * Returns validated timeout value or default.
45
+ */
46
+ export function parseHealthCheckTimeout(envValue, warnFn) {
47
+ if (!envValue) {
48
+ return DEFAULT_HEALTH_CHECK_TIMEOUT;
49
+ }
50
+ const parsed = parseInt(envValue, 10);
51
+ if (!isNaN(parsed) && parsed > 0 && parsed <= MAX_HEALTH_CHECK_TIMEOUT) {
52
+ return parsed;
53
+ }
54
+ if (warnFn) {
55
+ warnFn(`Invalid HEALTH_CHECK_TIMEOUT: ${envValue}. Must be between 1 and ${MAX_HEALTH_CHECK_TIMEOUT}. Using default: ${DEFAULT_HEALTH_CHECK_TIMEOUT}ms`);
56
+ }
57
+ return DEFAULT_HEALTH_CHECK_TIMEOUT;
58
+ }
59
+ /**
60
+ * Perform a health check against the Agent Orchestrator API.
61
+ * Makes a lightweight request to verify connectivity and authentication.
62
+ */
63
+ export async function checkApiHealth(baseUrl, apiKey, timeoutMs = DEFAULT_HEALTH_CHECK_TIMEOUT) {
64
+ // Validate inputs
65
+ if (!baseUrl || baseUrl.trim().length === 0) {
66
+ throw new Error('Base URL cannot be empty');
67
+ }
68
+ if (!apiKey || apiKey.trim().length === 0) {
69
+ throw new Error('API key cannot be empty');
70
+ }
71
+ // Remove trailing slash if present
72
+ const normalizedBaseUrl = baseUrl.trim().replace(/\/$/, '');
73
+ // Use the sessions endpoint with minimal data to verify connectivity
74
+ let url;
75
+ try {
76
+ url = new URL(`${normalizedBaseUrl}/api/v1/sessions`);
77
+ }
78
+ catch {
79
+ throw new Error('Invalid URL: Check that AGENT_ORCHESTRATOR_BASE_URL is a valid URL (e.g., http://localhost:3000)');
80
+ }
81
+ url.searchParams.set('per_page', '1');
82
+ const controller = new AbortController();
83
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
84
+ try {
85
+ const response = await fetch(url.toString(), {
86
+ method: 'GET',
87
+ headers: {
88
+ 'X-API-Key': apiKey.trim(),
89
+ 'Content-Type': 'application/json',
90
+ },
91
+ signal: controller.signal,
92
+ });
93
+ if (!response.ok) {
94
+ const errorText = await response.text();
95
+ let errorMessage;
96
+ try {
97
+ const errorJson = JSON.parse(errorText);
98
+ errorMessage = errorJson.message || errorJson.error || errorText;
99
+ }
100
+ catch {
101
+ errorMessage = errorText || `HTTP ${response.status}`;
102
+ }
103
+ throw new Error(`API Error (${response.status}): ${errorMessage}`);
104
+ }
105
+ }
106
+ catch (error) {
107
+ if (error instanceof Error && error.name === 'AbortError') {
108
+ throw new Error(`Request timeout after ${timeoutMs}ms`);
109
+ }
110
+ throw error;
111
+ }
112
+ finally {
113
+ clearTimeout(timeoutId);
114
+ }
115
+ }
package/shared/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { registerResources } from './resources.js';
2
2
  export { registerTools, createRegisterTools, type ToolGroup, parseEnabledToolGroups, } from './tools.js';
3
3
  export { createMCPServer, type ClientFactory, type IAgentOrchestratorClient } from './server.js';
4
4
  export { AgentOrchestratorClient, type IAgentOrchestratorClient as AgentOrchestratorClientInterface, } from './orchestrator-client/orchestrator-client.js';
5
+ export { checkApiHealth, getErrorHint, parseHealthCheckTimeout, DEFAULT_HEALTH_CHECK_TIMEOUT, MAX_HEALTH_CHECK_TIMEOUT, } from './health-check.js';
5
6
  export type { Session, Log, SubagentTranscript, SessionStatus, LogLevel, SubagentStatus, Pagination, SessionsResponse, SearchSessionsResponse, SessionResponse, SessionActionResponse, LogsResponse, LogResponse, SubagentTranscriptsResponse, SubagentTranscriptResponse, CreateSessionRequest, UpdateSessionRequest, CreateLogRequest, UpdateLogRequest, CreateSubagentTranscriptRequest, UpdateSubagentTranscriptRequest, } from './types.js';
6
7
  export { logServerStart, logError, logWarning, logDebug } from './logging.js';
7
8
  //# sourceMappingURL=index.d.ts.map
package/shared/index.js CHANGED
@@ -4,5 +4,7 @@ export { registerTools, createRegisterTools, parseEnabledToolGroups, } from './t
4
4
  export { createMCPServer } from './server.js';
5
5
  // Client exports
6
6
  export { AgentOrchestratorClient, } from './orchestrator-client/orchestrator-client.js';
7
+ // Health check exports
8
+ export { checkApiHealth, getErrorHint, parseHealthCheckTimeout, DEFAULT_HEALTH_CHECK_TIMEOUT, MAX_HEALTH_CHECK_TIMEOUT, } from './health-check.js';
7
9
  // Logging exports (re-exported for convenience)
8
10
  export { logServerStart, logError, logWarning, logDebug } from './logging.js';
@@ -33,6 +33,7 @@ export interface IAgentOrchestratorClient {
33
33
  followUp(id: string | number, prompt: string): Promise<SessionActionResponse>;
34
34
  pauseSession(id: string | number): Promise<SessionActionResponse>;
35
35
  restartSession(id: string | number): Promise<SessionActionResponse>;
36
+ changeMcpServers(id: string | number, mcp_servers: string[]): Promise<Session>;
36
37
  listLogs(sessionId: string | number, options?: {
37
38
  level?: LogLevel;
38
39
  page?: number;
@@ -86,6 +87,7 @@ export declare class AgentOrchestratorClient implements IAgentOrchestratorClient
86
87
  followUp(id: string | number, prompt: string): Promise<SessionActionResponse>;
87
88
  pauseSession(id: string | number): Promise<SessionActionResponse>;
88
89
  restartSession(id: string | number): Promise<SessionActionResponse>;
90
+ changeMcpServers(id: string | number, mcp_servers: string[]): Promise<Session>;
89
91
  listLogs(sessionId: string | number, options?: {
90
92
  level?: LogLevel;
91
93
  page?: number;
@@ -171,6 +171,8 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
171
171
  session.slug = data.slug;
172
172
  if (data.stop_condition !== undefined)
173
173
  session.stop_condition = data.stop_condition;
174
+ if (data.mcp_servers !== undefined)
175
+ session.mcp_servers = data.mcp_servers;
174
176
  if (data.custom_metadata !== undefined)
175
177
  session.custom_metadata = data.custom_metadata;
176
178
  session.updated_at = new Date().toISOString();
@@ -237,6 +239,15 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
237
239
  session.updated_at = new Date().toISOString();
238
240
  return { session, message: 'Session restarted' };
239
241
  },
242
+ async changeMcpServers(id, mcp_servers) {
243
+ const session = mockData.sessions?.find((s) => s.id === Number(id) || s.slug === String(id));
244
+ if (!session) {
245
+ throw new Error(`API Error (404): Session not found`);
246
+ }
247
+ session.mcp_servers = mcp_servers;
248
+ session.updated_at = new Date().toISOString();
249
+ return session;
250
+ },
240
251
  async listLogs(sessionId, options) {
241
252
  let logs = (mockData.logs || []).filter((l) => l.session_id === Number(sessionId));
242
253
  if (options?.level) {
@@ -125,6 +125,12 @@ export class AgentOrchestratorClient {
125
125
  async restartSession(id) {
126
126
  return this.request('POST', `/sessions/${id}/restart`);
127
127
  }
128
+ async changeMcpServers(id, mcp_servers) {
129
+ const response = await this.request('PATCH', `/sessions/${id}`, {
130
+ mcp_servers,
131
+ });
132
+ return response.session;
133
+ }
128
134
  // Logs
129
135
  async listLogs(sessionId, options) {
130
136
  return this.request('GET', `/sessions/${sessionId}/logs`, undefined, options);
@@ -3,16 +3,19 @@ import { z } from 'zod';
3
3
  import type { IAgentOrchestratorClient } from '../orchestrator-client/orchestrator-client.js';
4
4
  export declare const ActionSessionSchema: z.ZodObject<{
5
5
  session_id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
6
- action: z.ZodEnum<["follow_up", "pause", "restart", "archive", "unarchive"]>;
6
+ action: z.ZodEnum<["follow_up", "pause", "restart", "archive", "unarchive", "change_mcp_servers"]>;
7
7
  prompt: z.ZodOptional<z.ZodString>;
8
+ mcp_servers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
8
9
  }, "strip", z.ZodTypeAny, {
9
10
  session_id: string | number;
10
- action: "follow_up" | "pause" | "restart" | "archive" | "unarchive";
11
+ action: "follow_up" | "pause" | "restart" | "archive" | "unarchive" | "change_mcp_servers";
11
12
  prompt?: string | undefined;
13
+ mcp_servers?: string[] | undefined;
12
14
  }, {
13
15
  session_id: string | number;
14
- action: "follow_up" | "pause" | "restart" | "archive" | "unarchive";
16
+ action: "follow_up" | "pause" | "restart" | "archive" | "unarchive" | "change_mcp_servers";
15
17
  prompt?: string | undefined;
18
+ mcp_servers?: string[] | undefined;
16
19
  }>;
17
20
  export declare function actionSessionTool(_server: Server, clientFactory: () => IAgentOrchestratorClient): {
18
21
  name: string;
@@ -28,13 +31,20 @@ export declare function actionSessionTool(_server: Server, clientFactory: () =>
28
31
  };
29
32
  action: {
30
33
  type: string;
31
- enum: readonly ["follow_up", "pause", "restart", "archive", "unarchive"];
32
- description: "Action to perform: \"follow_up\" (send prompt to paused session), \"pause\" (pause running session), \"restart\" (restart paused/failed session), \"archive\" (archive session), \"unarchive\" (restore archived session)";
34
+ enum: readonly ["follow_up", "pause", "restart", "archive", "unarchive", "change_mcp_servers"];
35
+ description: "Action to perform: \"follow_up\" (send prompt to paused session), \"pause\" (pause running session), \"restart\" (restart paused/failed session), \"archive\" (archive session), \"unarchive\" (restore archived session), \"change_mcp_servers\" (update MCP servers for session)";
33
36
  };
34
37
  prompt: {
35
38
  type: string;
36
39
  description: "Required for \"follow_up\" action. The prompt to send to the agent. Not used for other actions.";
37
40
  };
41
+ mcp_servers: {
42
+ type: string;
43
+ items: {
44
+ type: string;
45
+ };
46
+ description: "Required for \"change_mcp_servers\" action. Array of MCP server names to set for the session.";
47
+ };
38
48
  };
39
49
  required: string[];
40
50
  };
@@ -1,14 +1,23 @@
1
1
  import { z } from 'zod';
2
2
  const PARAM_DESCRIPTIONS = {
3
3
  session_id: 'Session ID (numeric) or slug (string) to perform the action on.',
4
- action: 'Action to perform: "follow_up" (send prompt to paused session), "pause" (pause running session), "restart" (restart paused/failed session), "archive" (archive session), "unarchive" (restore archived session)',
4
+ action: 'Action to perform: "follow_up" (send prompt to paused session), "pause" (pause running session), "restart" (restart paused/failed session), "archive" (archive session), "unarchive" (restore archived session), "change_mcp_servers" (update MCP servers for session)',
5
5
  prompt: 'Required for "follow_up" action. The prompt to send to the agent. Not used for other actions.',
6
+ mcp_servers: 'Required for "change_mcp_servers" action. Array of MCP server names to set for the session.',
6
7
  };
7
- const ACTION_ENUM = ['follow_up', 'pause', 'restart', 'archive', 'unarchive'];
8
+ const ACTION_ENUM = [
9
+ 'follow_up',
10
+ 'pause',
11
+ 'restart',
12
+ 'archive',
13
+ 'unarchive',
14
+ 'change_mcp_servers',
15
+ ];
8
16
  export const ActionSessionSchema = z.object({
9
17
  session_id: z.union([z.string(), z.number()]).describe(PARAM_DESCRIPTIONS.session_id),
10
18
  action: z.enum(ACTION_ENUM).describe(PARAM_DESCRIPTIONS.action),
11
19
  prompt: z.string().optional().describe(PARAM_DESCRIPTIONS.prompt),
20
+ mcp_servers: z.array(z.string()).optional().describe(PARAM_DESCRIPTIONS.mcp_servers),
12
21
  });
13
22
  const TOOL_DESCRIPTION = `Perform an action on an agent session.
14
23
 
@@ -18,6 +27,7 @@ const TOOL_DESCRIPTION = `Perform an action on an agent session.
18
27
  - **restart**: Restart a paused or failed session without providing new input
19
28
  - **archive**: Archive a session (marks as completed)
20
29
  - **unarchive**: Restore an archived session to "needs_input" status
30
+ - **change_mcp_servers**: Update the MCP servers for a session (requires "mcp_servers" parameter)
21
31
 
22
32
  **Status requirements:**
23
33
  - follow_up: Session must be "needs_input"
@@ -25,11 +35,13 @@ const TOOL_DESCRIPTION = `Perform an action on an agent session.
25
35
  - restart: Session must be "needs_input" or "failed"
26
36
  - archive: Session can be in any status except "archived"
27
37
  - unarchive: Session must be "archived"
38
+ - change_mcp_servers: Session can be in any status except "archived"
28
39
 
29
40
  **Use cases:**
30
41
  - Provide additional instructions to an agent
31
42
  - Control session lifecycle (pause, restart)
32
- - Organize sessions (archive, unarchive)`;
43
+ - Organize sessions (archive, unarchive)
44
+ - Reconfigure session MCP server access`;
33
45
  export function actionSessionTool(_server, clientFactory) {
34
46
  return {
35
47
  name: 'action_session',
@@ -50,6 +62,11 @@ export function actionSessionTool(_server, clientFactory) {
50
62
  type: 'string',
51
63
  description: PARAM_DESCRIPTIONS.prompt,
52
64
  },
65
+ mcp_servers: {
66
+ type: 'array',
67
+ items: { type: 'string' },
68
+ description: PARAM_DESCRIPTIONS.mcp_servers,
69
+ },
53
70
  },
54
71
  required: ['session_id', 'action'],
55
72
  },
@@ -57,7 +74,7 @@ export function actionSessionTool(_server, clientFactory) {
57
74
  try {
58
75
  const validatedArgs = ActionSessionSchema.parse(args);
59
76
  const client = clientFactory();
60
- const { session_id, action, prompt } = validatedArgs;
77
+ const { session_id, action, prompt, mcp_servers } = validatedArgs;
61
78
  // Validate that prompt is provided for follow_up action
62
79
  if (action === 'follow_up' && !prompt) {
63
80
  return {
@@ -70,6 +87,18 @@ export function actionSessionTool(_server, clientFactory) {
70
87
  isError: true,
71
88
  };
72
89
  }
90
+ // Validate that mcp_servers is provided for change_mcp_servers action
91
+ if (action === 'change_mcp_servers' && !mcp_servers) {
92
+ return {
93
+ content: [
94
+ {
95
+ type: 'text',
96
+ text: 'Error: The "mcp_servers" parameter is required for the "change_mcp_servers" action.',
97
+ },
98
+ ],
99
+ isError: true,
100
+ };
101
+ }
73
102
  let result;
74
103
  switch (action) {
75
104
  case 'follow_up': {
@@ -148,6 +177,18 @@ export function actionSessionTool(_server, clientFactory) {
148
177
  result = lines.join('\n');
149
178
  break;
150
179
  }
180
+ case 'change_mcp_servers': {
181
+ const session = await client.changeMcpServers(session_id, mcp_servers);
182
+ const lines = [
183
+ `## MCP Servers Updated`,
184
+ '',
185
+ `- **Session ID:** ${session.id}`,
186
+ `- **Title:** ${session.title}`,
187
+ `- **MCP Servers:** ${session.mcp_servers.length > 0 ? session.mcp_servers.join(', ') : '(none)'}`,
188
+ ];
189
+ result = lines.join('\n');
190
+ break;
191
+ }
151
192
  default: {
152
193
  // This should never happen due to Zod validation
153
194
  const _exhaustiveCheck = action;
@@ -11,20 +11,20 @@ export declare const SearchSessionsSchema: z.ZodObject<{
11
11
  page: z.ZodOptional<z.ZodNumber>;
12
12
  per_page: z.ZodOptional<z.ZodNumber>;
13
13
  }, "strip", z.ZodTypeAny, {
14
+ per_page?: number | undefined;
14
15
  status?: "waiting" | "running" | "needs_input" | "failed" | "archived" | undefined;
15
16
  agent_type?: string | undefined;
16
17
  show_archived?: boolean | undefined;
17
18
  page?: number | undefined;
18
- per_page?: number | undefined;
19
19
  search_contents?: boolean | undefined;
20
20
  id?: number | undefined;
21
21
  query?: string | undefined;
22
22
  }, {
23
+ per_page?: number | undefined;
23
24
  status?: "waiting" | "running" | "needs_input" | "failed" | "archived" | undefined;
24
25
  agent_type?: string | undefined;
25
26
  show_archived?: boolean | undefined;
26
27
  page?: number | undefined;
27
- per_page?: number | undefined;
28
28
  search_contents?: boolean | undefined;
29
29
  id?: number | undefined;
30
30
  query?: string | undefined;
package/shared/types.d.ts CHANGED
@@ -116,6 +116,7 @@ export interface UpdateSessionRequest {
116
116
  title?: string;
117
117
  slug?: string;
118
118
  stop_condition?: string;
119
+ mcp_servers?: string[];
119
120
  custom_metadata?: Record<string, unknown>;
120
121
  }
121
122
  export interface CreateLogRequest {