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 +31 -35
- package/build/index.js +30 -5
- package/package.json +1 -1
- package/shared/health-check.d.ts +21 -0
- package/shared/health-check.js +115 -0
- package/shared/index.d.ts +1 -0
- package/shared/index.js +2 -0
- package/shared/orchestrator-client/orchestrator-client.d.ts +2 -0
- package/shared/orchestrator-client/orchestrator-client.integration-mock.js +11 -0
- package/shared/orchestrator-client/orchestrator-client.js +6 -0
- package/shared/tools/action-session.d.ts +15 -5
- package/shared/tools/action-session.js +45 -4
- package/shared/tools/search-sessions.d.ts +2 -2
- package/shared/types.d.ts +1 -0
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
|
-
##
|
|
50
|
+
## Setup
|
|
51
51
|
|
|
52
|
-
###
|
|
52
|
+
### Prerequisites
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
###
|
|
57
|
+
### Environment Variables
|
|
60
58
|
|
|
61
|
-
|
|
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
|
-
|
|
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
|
-
|
|
69
|
+
Make sure you have your Agent Orchestrator base URL and API key ready.
|
|
69
70
|
|
|
70
|
-
|
|
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
|
-
|
|
73
|
+
#### Manual Setup
|
|
75
74
|
|
|
76
|
-
|
|
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
|
-
|
|
77
|
+
macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
84
78
|
|
|
85
|
-
|
|
79
|
+
Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
86
80
|
|
|
87
|
-
|
|
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": "
|
|
94
|
-
"args": ["
|
|
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
|
|
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
|
-
|
|
75
|
-
//
|
|
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
|
@@ -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 = [
|
|
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