@aiconnect/agentjobs-mcp 1.0.8 → 1.1.0
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/.env.example +7 -0
- package/README.md +82 -12
- package/build/config.js +8 -3
- package/build/debug.js +86 -0
- package/build/index.js +81 -22
- package/build/lib/agentJobsClient.js +79 -0
- package/build/test-tools.js +53 -0
- package/build/tools/cancel_job.js +58 -0
- package/build/tools/create_job.js +76 -0
- package/build/tools/get_job.js +55 -0
- package/build/tools/get_job_type.js +66 -0
- package/build/tools/get_jobs_stats.js +57 -0
- package/build/tools/list_jobs.js +79 -0
- package/build/utils/debugger.js +74 -0
- package/build/utils/formatters.js +498 -0
- package/build/utils/formatters.test.js +387 -0
- package/build/utils/schemas.js +20 -0
- package/build/utils/schemas.test.js +40 -0
- package/docs/debug-guide.md +203 -0
- package/package.json +12 -4
- package/build/cancel_job.js +0 -71
- package/build/create_job.js +0 -151
- package/build/get_job.js +0 -62
- package/build/list_jobs.js +0 -88
package/.env.example
CHANGED
|
@@ -9,3 +9,10 @@ AICONNECT_API_KEY=your-api-key-here
|
|
|
9
9
|
|
|
10
10
|
# Optional: Default organization ID (defaults to 'aiconnect' if not set)
|
|
11
11
|
# DEFAULT_ORG_ID=your-organization-id
|
|
12
|
+
|
|
13
|
+
# Debug Settings
|
|
14
|
+
MCP_DEBUG=false
|
|
15
|
+
NODE_ENV=development
|
|
16
|
+
|
|
17
|
+
# HTTP Debug (opcional - para ver requisições HTTP detalhadas)
|
|
18
|
+
DEBUG=axios
|
package/README.md
CHANGED
|
@@ -153,9 +153,9 @@ This MCP server is designed to work out-of-the-box with minimal configuration. I
|
|
|
153
153
|
- `AICONNECT_API_KEY`: `""` (empty - you must provide this)
|
|
154
154
|
|
|
155
155
|
**Error Handling:**
|
|
156
|
-
-
|
|
157
|
-
- If `AICONNECT_API_URL`
|
|
158
|
-
- If `DEFAULT_ORG_ID` is not set, it defaults to "aiconnect"
|
|
156
|
+
- The server will always start, even if environment variables are missing.
|
|
157
|
+
- If `AICONNECT_API_KEY` or `AICONNECT_API_URL` are not provided, each tool will return a clear error message upon execution, guiding the user to configure the environment correctly.
|
|
158
|
+
- If `DEFAULT_ORG_ID` is not set, it defaults to "aiconnect".
|
|
159
159
|
|
|
160
160
|
### Running the MCP server
|
|
161
161
|
|
|
@@ -185,8 +185,39 @@ To use this MCP server with Claude Desktop, add the following configuration to y
|
|
|
185
185
|
}
|
|
186
186
|
```
|
|
187
187
|
|
|
188
|
+
### Local Development with Claude Code
|
|
189
|
+
|
|
190
|
+
For development and testing, you can add this MCP server directly to your Claude Code project:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Prerequisites: build the project first
|
|
194
|
+
npm install
|
|
195
|
+
npm run build
|
|
196
|
+
|
|
197
|
+
# Configure your .env file
|
|
198
|
+
cp .env.example .env
|
|
199
|
+
# Edit .env with your API credentials
|
|
200
|
+
|
|
201
|
+
# Add MCP server to Claude Code (project scope)
|
|
202
|
+
claude mcp add --scope project agentjobs -- ./mcp-agentjobs.sh
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
This allows you to test and use the AgentJobs tools directly within Claude Code during development, providing immediate feedback and easier debugging.
|
|
206
|
+
|
|
188
207
|
## Available Tools
|
|
189
208
|
|
|
209
|
+
### 📊 `get_jobs_stats`
|
|
210
|
+
Get aggregated statistics for agent jobs without retrieving individual job data. Optimized for dashboards and monitoring with minimal network overhead.
|
|
211
|
+
|
|
212
|
+
**Parameters:**
|
|
213
|
+
- `scheduled_at_gte`: Start of period (ISO 8601)
|
|
214
|
+
- `scheduled_at_lte`: End of period (ISO 8601)
|
|
215
|
+
- `org_id`: Organization filter
|
|
216
|
+
- `job_type_id`: Job type filter
|
|
217
|
+
- `tags`: Tags filter (comma-separated)
|
|
218
|
+
- `status`: Status filter
|
|
219
|
+
- `channel_code`: Channel filter
|
|
220
|
+
|
|
190
221
|
### 🔧 `list_jobs`
|
|
191
222
|
Lists all jobs with filtering and pagination options.
|
|
192
223
|
|
|
@@ -260,11 +291,14 @@ Agent: "Cancel job job-456 because it's no longer needed"
|
|
|
260
291
|
```
|
|
261
292
|
agentjobs-mcp/
|
|
262
293
|
├── src/ # TypeScript source code
|
|
263
|
-
│ ├── index.ts # Main MCP server
|
|
264
|
-
│ ├──
|
|
265
|
-
│
|
|
266
|
-
│
|
|
267
|
-
│
|
|
294
|
+
│ ├── index.ts # Main MCP server entry point
|
|
295
|
+
│ ├── config.ts # Configuration loader
|
|
296
|
+
│ └── tools/ # Directory for all MCP tools
|
|
297
|
+
│ ├── get_jobs_stats.ts # Tool for getting job statistics
|
|
298
|
+
│ ├── list_jobs.ts # Tool for listing jobs
|
|
299
|
+
│ ├── get_job.ts # Tool for getting a job
|
|
300
|
+
│ ├── create_job.ts # Tool for creating a job
|
|
301
|
+
│ └── cancel_job.ts # Tool for canceling a job
|
|
268
302
|
├── build/ # Compiled JavaScript code
|
|
269
303
|
├── docs/ # Documentation
|
|
270
304
|
│ └── agent-jobs-api.md # API documentation
|
|
@@ -280,13 +314,49 @@ agentjobs-mcp/
|
|
|
280
314
|
|
|
281
315
|
- `npm run build`: Compiles TypeScript
|
|
282
316
|
- `npm start`: Runs the compiled server
|
|
317
|
+
- `npm run debug`: Runs server in debug mode with detailed logging
|
|
318
|
+
- `npm run test:tools`: Tests tool loading without starting server
|
|
319
|
+
- `npm run cli:config`: Shows current configuration
|
|
320
|
+
- `npm run cli:version`: Shows version information
|
|
321
|
+
- `npm run cli:help`: Shows help information
|
|
322
|
+
|
|
323
|
+
### Debugging
|
|
324
|
+
|
|
325
|
+
For detailed debugging information, see [Debug Guide](docs/debug-guide.md).
|
|
326
|
+
|
|
327
|
+
**Quick Debug Commands:**
|
|
328
|
+
```bash
|
|
329
|
+
# Test configuration
|
|
330
|
+
npm run cli:config
|
|
331
|
+
|
|
332
|
+
# Test tool loading
|
|
333
|
+
npm run test:tools
|
|
334
|
+
|
|
335
|
+
# Run in debug mode
|
|
336
|
+
MCP_DEBUG=true npm run debug
|
|
337
|
+
|
|
338
|
+
# Use debug helper script (Fish shell)
|
|
339
|
+
./debug.fish help
|
|
340
|
+
./debug.fish quick
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Debug Environment:**
|
|
344
|
+
```bash
|
|
345
|
+
# Copy debug environment template
|
|
346
|
+
cp .env.debug .env
|
|
347
|
+
# Edit .env with your API credentials
|
|
348
|
+
# Run with debug environment
|
|
349
|
+
./debug.fish debug-with-env
|
|
350
|
+
```
|
|
283
351
|
|
|
284
352
|
### Adding new tools
|
|
285
353
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
354
|
+
Adding a new tool is simple:
|
|
355
|
+
|
|
356
|
+
1. Create a new TypeScript file inside the `src/tools/` directory (e.g., `my_new_tool.ts`).
|
|
357
|
+
2. Implement your tool logic following the existing pattern. The server will automatically detect and register it on startup.
|
|
358
|
+
3. Recompile the project with `npm run build`.
|
|
359
|
+
4. Test with `npm run test:tools` to verify loading.
|
|
290
360
|
|
|
291
361
|
## Contributing
|
|
292
362
|
|
package/build/config.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
// Configuration
|
|
1
|
+
// Configuration for the MCP server
|
|
2
2
|
export const config = {
|
|
3
|
-
|
|
3
|
+
apiUrl: process.env.AICONNECT_API_URL || 'https://api.aiconnect.cloud/api/v0',
|
|
4
|
+
apiKey: process.env.AICONNECT_API_KEY || '',
|
|
5
|
+
defaultOrgId: process.env.DEFAULT_ORG_ID || 'aiconnect',
|
|
6
|
+
debugMode: process.env.DEBUG === 'true',
|
|
7
|
+
// Legacy compatibility
|
|
8
|
+
AICONNECT_API_URL: process.env.AICONNECT_API_URL || 'https://api.aiconnect.cloud/api/v0',
|
|
4
9
|
AICONNECT_API_KEY: process.env.AICONNECT_API_KEY || '',
|
|
5
|
-
|
|
10
|
+
DEFAULT_ORG_ID: process.env.DEFAULT_ORG_ID || 'aiconnect'
|
|
6
11
|
};
|
package/build/debug.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as dotenv from 'dotenv';
|
|
3
|
+
dotenv.config();
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import fs from "fs/promises";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
import { config } from './config.js';
|
|
10
|
+
// Enable debug mode
|
|
11
|
+
const DEBUG = true;
|
|
12
|
+
function debugLog(message, data) {
|
|
13
|
+
if (DEBUG) {
|
|
14
|
+
const timestamp = new Date().toISOString();
|
|
15
|
+
console.error(`[DEBUG ${timestamp}] ${message}`);
|
|
16
|
+
if (data) {
|
|
17
|
+
console.error('[DEBUG DATA]', JSON.stringify(data, null, 2));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Get package version
|
|
22
|
+
const packageJson = JSON.parse(await import('fs').then(fs => fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8')));
|
|
23
|
+
debugLog('Starting MCP Server in DEBUG mode');
|
|
24
|
+
debugLog('Configuration loaded', {
|
|
25
|
+
DEFAULT_ORG_ID: config.DEFAULT_ORG_ID,
|
|
26
|
+
AICONNECT_API_URL: config.AICONNECT_API_URL,
|
|
27
|
+
AICONNECT_API_KEY: config.AICONNECT_API_KEY ? '[SET]' : '[NOT SET]',
|
|
28
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
29
|
+
version: packageJson.version
|
|
30
|
+
});
|
|
31
|
+
// Initialize server with debug logging
|
|
32
|
+
const server = new McpServer({
|
|
33
|
+
name: "agentjobs-mcp-debug",
|
|
34
|
+
version: packageJson.version
|
|
35
|
+
});
|
|
36
|
+
debugLog('MCP Server initialized');
|
|
37
|
+
// Dynamically load and register tools with debug info
|
|
38
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
39
|
+
const toolsDir = path.join(__dirname, 'tools');
|
|
40
|
+
try {
|
|
41
|
+
debugLog(`Loading tools from: ${toolsDir}`);
|
|
42
|
+
const toolFiles = await fs.readdir(toolsDir);
|
|
43
|
+
debugLog(`Found tool files:`, toolFiles);
|
|
44
|
+
for (const file of toolFiles) {
|
|
45
|
+
if (file.endsWith('.js')) {
|
|
46
|
+
debugLog(`Loading tool: ${file}`);
|
|
47
|
+
try {
|
|
48
|
+
const toolModule = await import(`./tools/${file}`);
|
|
49
|
+
if (typeof toolModule.default === 'function') {
|
|
50
|
+
toolModule.default(server);
|
|
51
|
+
debugLog(`✅ Successfully registered tool: ${file}`);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
debugLog(`❌ Tool ${file} does not export a default function`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
debugLog(`❌ Error loading tool ${file}:`, error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
debugLog("❌ Error loading tools directory:", error);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
// Start server with debug transport
|
|
68
|
+
const transport = new StdioServerTransport();
|
|
69
|
+
debugLog('Starting transport connection...');
|
|
70
|
+
// Add connection event handling
|
|
71
|
+
transport.onclose = () => {
|
|
72
|
+
debugLog('Transport connection closed');
|
|
73
|
+
};
|
|
74
|
+
transport.onerror = (error) => {
|
|
75
|
+
debugLog('Transport error:', error);
|
|
76
|
+
};
|
|
77
|
+
console.error(`🔍 AI Connect Agent Jobs MCP Server v${packageJson.version} (DEBUG MODE)`);
|
|
78
|
+
console.error('🚀 Server ready and listening for MCP connections');
|
|
79
|
+
try {
|
|
80
|
+
await server.connect(transport);
|
|
81
|
+
debugLog('✅ Server connected successfully');
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
debugLog('❌ Error connecting MCP server:', error);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
package/build/index.js
CHANGED
|
@@ -3,10 +3,10 @@ import * as dotenv from 'dotenv';
|
|
|
3
3
|
dotenv.config();
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
6
|
+
import { InitializeRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import fs from "fs/promises";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { fileURLToPath } from "url";
|
|
10
10
|
// Get package version
|
|
11
11
|
const packageJson = JSON.parse(await import('fs').then(fs => fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8')));
|
|
12
12
|
// CLI argument parsing
|
|
@@ -55,29 +55,88 @@ if (args.includes('--config') || args.includes('-c')) {
|
|
|
55
55
|
console.log(` MCP Server Version: ${packageJson.version}`);
|
|
56
56
|
process.exit(0);
|
|
57
57
|
}
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
console.error('Use --help for more information');
|
|
67
|
-
process.exit(1);
|
|
68
|
-
}
|
|
69
|
-
// Initialize server
|
|
58
|
+
// Protocol version tracking
|
|
59
|
+
let clientProtocolVersion = "2024-11-05"; // Default fallback
|
|
60
|
+
let serverCapabilities = {
|
|
61
|
+
tools: { listChanged: true },
|
|
62
|
+
resources: {},
|
|
63
|
+
prompts: {}
|
|
64
|
+
};
|
|
65
|
+
// Initialize server with dynamic capabilities based on protocol version
|
|
70
66
|
const server = new McpServer({
|
|
71
67
|
name: "agentjobs-mcp",
|
|
72
68
|
version: packageJson.version
|
|
69
|
+
}, {
|
|
70
|
+
capabilities: serverCapabilities
|
|
71
|
+
});
|
|
72
|
+
console.error(`[DEBUG] MCP Server initialized with name: agentjobs-mcp`);
|
|
73
|
+
console.error(`[DEBUG] Server version: ${packageJson.version}`);
|
|
74
|
+
console.error(`[DEBUG] Default capabilities: tools, resources, prompts`);
|
|
75
|
+
// Intercept initialization to detect protocol version
|
|
76
|
+
const originalSetRequestHandler = server.server.setRequestHandler.bind(server.server);
|
|
77
|
+
// Override initialization handler to capture protocol version
|
|
78
|
+
server.server.setRequestHandler(InitializeRequestSchema, async (request) => {
|
|
79
|
+
const initParams = request.params;
|
|
80
|
+
clientProtocolVersion = initParams.protocolVersion || "2024-11-05";
|
|
81
|
+
console.error(`[VERSION-NEGOTIATION] Client requested protocol: ${clientProtocolVersion}`);
|
|
82
|
+
// Always use minimal capabilities to prevent loops
|
|
83
|
+
console.error(`[VERSION-NEGOTIATION] Client requested: ${clientProtocolVersion}`);
|
|
84
|
+
console.error(`[VERSION-NEGOTIATION] Using minimal capabilities to prevent infinite loops`);
|
|
85
|
+
// Use only tools capability - no resources/prompts to avoid repeated calls
|
|
86
|
+
serverCapabilities = {
|
|
87
|
+
tools: {}
|
|
88
|
+
};
|
|
89
|
+
console.error(`[VERSION-NEGOTIATION] Responding with our supported version: 2025-03-26`);
|
|
90
|
+
console.error(`[VERSION-NEGOTIATION] Updated capabilities:`, JSON.stringify(serverCapabilities, null, 2));
|
|
91
|
+
// Return initialization response with our supported version
|
|
92
|
+
return {
|
|
93
|
+
protocolVersion: "2025-03-26", // Our SDK version
|
|
94
|
+
capabilities: serverCapabilities,
|
|
95
|
+
serverInfo: {
|
|
96
|
+
name: "agentjobs-mcp",
|
|
97
|
+
version: packageJson.version
|
|
98
|
+
}
|
|
99
|
+
};
|
|
73
100
|
});
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
101
|
+
// Dynamically load and register tools
|
|
102
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
103
|
+
const toolsDir = path.join(__dirname, 'tools');
|
|
104
|
+
try {
|
|
105
|
+
const toolFiles = await fs.readdir(toolsDir);
|
|
106
|
+
for (const file of toolFiles) {
|
|
107
|
+
if (file.endsWith('.js')) { // In production, files will be .js
|
|
108
|
+
try {
|
|
109
|
+
const toolModule = await import(`./tools/${file}`);
|
|
110
|
+
if (typeof toolModule.default === 'function') {
|
|
111
|
+
toolModule.default(server);
|
|
112
|
+
console.error(`-> Registered tool: ${file}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
console.error(`-> Failed to register tool ${file}:`, error);
|
|
117
|
+
// Continue loading other tools
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
console.error("Error loading tools:", error);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
console.error(`[DEBUG] Only tools capability enabled - no resources/prompts handlers needed`);
|
|
79
127
|
// Start server with stdio transport
|
|
80
128
|
const transport = new StdioServerTransport();
|
|
81
129
|
console.error(`Starting AI Connect Agent Jobs MCP Server v${packageJson.version}...`);
|
|
130
|
+
console.error('Configuration:');
|
|
131
|
+
console.error(` API URL: ${process.env.AICONNECT_API_URL || 'Using default'}`);
|
|
132
|
+
console.error(` API Key: ${process.env.AICONNECT_API_KEY ? '[SET]' : '[NOT SET]'}`);
|
|
133
|
+
console.error(` Default Org: ${process.env.DEFAULT_ORG_ID || 'aiconnect'}`);
|
|
82
134
|
console.error('Server ready and listening for MCP connections');
|
|
83
|
-
|
|
135
|
+
// Add error handling for the server connection
|
|
136
|
+
try {
|
|
137
|
+
await server.connect(transport);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
console.error('Error connecting MCP server:', error);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { config } from '../config.js';
|
|
3
|
+
class AgentJobsClient {
|
|
4
|
+
client = null;
|
|
5
|
+
getClient() {
|
|
6
|
+
if (!this.client) {
|
|
7
|
+
const { AICONNECT_API_URL, AICONNECT_API_KEY } = config;
|
|
8
|
+
if (!AICONNECT_API_URL || !AICONNECT_API_KEY) {
|
|
9
|
+
throw new Error('API URL or Key is not configured. Please set AICONNECT_API_URL and AICONNECT_API_KEY environment variables.');
|
|
10
|
+
}
|
|
11
|
+
this.client = axios.create({
|
|
12
|
+
baseURL: AICONNECT_API_URL,
|
|
13
|
+
headers: {
|
|
14
|
+
'Authorization': `Bearer ${AICONNECT_API_KEY}`,
|
|
15
|
+
'X-Client-Type': 'mcp',
|
|
16
|
+
'Content-Type': 'application/json'
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return this.client;
|
|
21
|
+
}
|
|
22
|
+
async get(endpoint, params) {
|
|
23
|
+
return this.request(() => this.getClient().get(endpoint, { params }), params);
|
|
24
|
+
}
|
|
25
|
+
async getWithMeta(endpoint, params) {
|
|
26
|
+
try {
|
|
27
|
+
const response = await this.getClient().get(endpoint, { params });
|
|
28
|
+
return response.data; // Return the full API response including data and meta
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
this.handleError(error);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async getStats(filters = {}) {
|
|
35
|
+
const params = {
|
|
36
|
+
...filters,
|
|
37
|
+
include: 'stats',
|
|
38
|
+
limit: 1
|
|
39
|
+
};
|
|
40
|
+
return this.get('/services/agent-jobs', params);
|
|
41
|
+
}
|
|
42
|
+
async post(endpoint, data) {
|
|
43
|
+
return this.request(() => this.getClient().post(endpoint, data));
|
|
44
|
+
}
|
|
45
|
+
async patch(endpoint, data) {
|
|
46
|
+
return this.request(() => this.getClient().patch(endpoint, data));
|
|
47
|
+
}
|
|
48
|
+
async delete(endpoint, data) {
|
|
49
|
+
return this.request(() => this.getClient().delete(endpoint, { data }));
|
|
50
|
+
}
|
|
51
|
+
async request(requestFn, params) {
|
|
52
|
+
try {
|
|
53
|
+
const response = await requestFn();
|
|
54
|
+
if (params?.include === 'stats') {
|
|
55
|
+
// @ts-expect-error axios response typing varies per call in this client
|
|
56
|
+
return response.data;
|
|
57
|
+
}
|
|
58
|
+
// @ts-expect-error axios response typing varies per call in this client
|
|
59
|
+
return response.data?.data || response.data;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
this.handleError(error);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
handleError(error) {
|
|
66
|
+
if (axios.isAxiosError(error)) {
|
|
67
|
+
const axiosError = error;
|
|
68
|
+
const apiError = axiosError.response?.data?.message || axiosError.response?.data?.error || JSON.stringify(axiosError.response?.data);
|
|
69
|
+
throw new Error(`API Error (${axiosError.response?.status}): ${apiError || axiosError.message}`);
|
|
70
|
+
}
|
|
71
|
+
else if (error instanceof Error) {
|
|
72
|
+
throw new Error(`Error: ${error.message}`);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
throw new Error('An unknown error occurred.');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export default new AgentJobsClient();
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as dotenv from 'dotenv';
|
|
3
|
+
// Load debug environment
|
|
4
|
+
dotenv.config({ path: '.env.debug' });
|
|
5
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
+
import fs from 'fs/promises';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
// Test specific tools
|
|
10
|
+
async function testTools() {
|
|
11
|
+
console.log('🧪 Testing MCP Tools...\n');
|
|
12
|
+
// Initialize server
|
|
13
|
+
const server = new McpServer({
|
|
14
|
+
name: 'agentjobs-mcp-test',
|
|
15
|
+
version: 'test'
|
|
16
|
+
});
|
|
17
|
+
// Load tools
|
|
18
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const toolsDir = path.join(__dirname, 'tools');
|
|
20
|
+
try {
|
|
21
|
+
const toolFiles = await fs.readdir(toolsDir);
|
|
22
|
+
console.log(`📁 Found ${toolFiles.length} tool files`);
|
|
23
|
+
for (const file of toolFiles) {
|
|
24
|
+
if (file.endsWith('.js')) {
|
|
25
|
+
try {
|
|
26
|
+
console.log(`⚙️ Loading tool: ${file}`);
|
|
27
|
+
const toolModule = await import(`./tools/${file}`);
|
|
28
|
+
if (typeof toolModule.default === 'function') {
|
|
29
|
+
toolModule.default(server);
|
|
30
|
+
console.log(`✅ Successfully registered: ${file}`);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.log(`❌ Invalid tool format: ${file}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.log(`❌ Error loading ${file}:`, error?.message || error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Show success message
|
|
42
|
+
console.log('\n✅ Tool testing completed!');
|
|
43
|
+
console.log('💡 To run in debug mode: MCP_DEBUG=true npm run debug');
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.error('❌ Error during tool testing:', error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Run if this script is executed directly
|
|
50
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
51
|
+
testTools().catch(console.error);
|
|
52
|
+
}
|
|
53
|
+
export { testTools };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import agentJobsClient from "../lib/agentJobsClient.js";
|
|
3
|
+
import { formatJobSummary } from '../utils/formatters.js';
|
|
4
|
+
import { mcpDebugger, withTiming } from '../utils/debugger.js';
|
|
5
|
+
export default (server) => {
|
|
6
|
+
server.registerTool("cancel_job", {
|
|
7
|
+
description: "Cancels an agent job by its ID.",
|
|
8
|
+
annotations: {
|
|
9
|
+
title: "Cancel Agent Job"
|
|
10
|
+
},
|
|
11
|
+
inputSchema: {
|
|
12
|
+
job_id: z.string({
|
|
13
|
+
description: "The unique identifier of the job to be canceled. Example: 'job-12345'.",
|
|
14
|
+
}),
|
|
15
|
+
reason: z.string().optional().describe("An optional reason explaining why the job is being canceled."),
|
|
16
|
+
}
|
|
17
|
+
}, async (params) => {
|
|
18
|
+
mcpDebugger.toolCall("cancel_job", params);
|
|
19
|
+
const { job_id, reason } = params;
|
|
20
|
+
const endpoint = `/services/agent-jobs/${job_id}`;
|
|
21
|
+
let requestBody;
|
|
22
|
+
if (reason) {
|
|
23
|
+
requestBody = { reason };
|
|
24
|
+
}
|
|
25
|
+
mcpDebugger.debug("Job cancellation request", {
|
|
26
|
+
endpoint,
|
|
27
|
+
job_id,
|
|
28
|
+
reason,
|
|
29
|
+
hasRequestBody: !!requestBody
|
|
30
|
+
});
|
|
31
|
+
try {
|
|
32
|
+
const canceledJob = await withTiming(() => agentJobsClient.delete(endpoint, requestBody), "cancel_job API call");
|
|
33
|
+
mcpDebugger.debug("Job cancellation response", { canceledJob });
|
|
34
|
+
const summary = formatJobSummary(canceledJob);
|
|
35
|
+
const result = {
|
|
36
|
+
content: [{
|
|
37
|
+
type: "text",
|
|
38
|
+
text: `Successfully canceled job:\n\n${summary}`,
|
|
39
|
+
}]
|
|
40
|
+
};
|
|
41
|
+
mcpDebugger.toolResponse("cancel_job", {
|
|
42
|
+
jobId: job_id,
|
|
43
|
+
reason,
|
|
44
|
+
resultLength: result.content[0].text.length
|
|
45
|
+
});
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
mcpDebugger.toolError("cancel_job", error);
|
|
50
|
+
return {
|
|
51
|
+
content: [{
|
|
52
|
+
type: "text",
|
|
53
|
+
text: `Error canceling job: ${error.message}`,
|
|
54
|
+
}],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import agentJobsClient from '../lib/agentJobsClient.js';
|
|
3
|
+
import { config } from '../config.js';
|
|
4
|
+
import { flexibleDateTimeSchema } from '../utils/schemas.js';
|
|
5
|
+
import { mcpDebugger, withTiming } from '../utils/debugger.js';
|
|
6
|
+
export default (server) => {
|
|
7
|
+
server.registerTool('create_job', {
|
|
8
|
+
description: 'Create a new Agent Job with the minimal set of fields.',
|
|
9
|
+
annotations: {
|
|
10
|
+
title: 'Create Agent Job'
|
|
11
|
+
},
|
|
12
|
+
inputSchema: {
|
|
13
|
+
// Required fields
|
|
14
|
+
job_type_id: z
|
|
15
|
+
.string()
|
|
16
|
+
.describe('ID of the job type (e.g. "mood-monitor")'),
|
|
17
|
+
target_channel: z
|
|
18
|
+
.object({
|
|
19
|
+
platform: z
|
|
20
|
+
.enum(['whatsapp', 'slack', 'web'])
|
|
21
|
+
.describe('Destination platform.'),
|
|
22
|
+
code: z
|
|
23
|
+
.string()
|
|
24
|
+
.describe('Channel identifier, phone number, or user ID.'),
|
|
25
|
+
org_id: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('Org ID – defaults to config.DEFAULT_ORG_ID')
|
|
29
|
+
})
|
|
30
|
+
.describe('Where the agent will communicate.'),
|
|
31
|
+
params: z
|
|
32
|
+
.record(z.any())
|
|
33
|
+
.optional()
|
|
34
|
+
.describe('Free‑form params passed to the agent'),
|
|
35
|
+
scheduled_at: flexibleDateTimeSchema
|
|
36
|
+
.optional()
|
|
37
|
+
.describe('Schedule the job to run later')
|
|
38
|
+
}
|
|
39
|
+
}, async (params) => {
|
|
40
|
+
mcpDebugger.toolCall("create_job", params);
|
|
41
|
+
// Fall back to default org if none supplied.
|
|
42
|
+
params.target_channel.org_id ??= config.DEFAULT_ORG_ID;
|
|
43
|
+
mcpDebugger.debug("Job creation payload", {
|
|
44
|
+
job_type_id: params.job_type_id,
|
|
45
|
+
target_channel: params.target_channel,
|
|
46
|
+
scheduled_at: params.scheduled_at,
|
|
47
|
+
paramsCount: params.params ? Object.keys(params.params).length : 0
|
|
48
|
+
});
|
|
49
|
+
try {
|
|
50
|
+
const res = await withTiming(() => agentJobsClient.post('/services/agent-jobs', params), "create_job API call");
|
|
51
|
+
const jobId = res.id ?? 'unknown';
|
|
52
|
+
mcpDebugger.debug("Job creation response", { jobId, fullResponse: res });
|
|
53
|
+
const result = {
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: 'text',
|
|
57
|
+
text: `✅ Job created (id: ${jobId}).`
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
};
|
|
61
|
+
mcpDebugger.toolResponse("create_job", { jobId });
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
mcpDebugger.toolError("create_job", error);
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: 'text',
|
|
70
|
+
text: `Error creating job: ${error.message}`
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
};
|