@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 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
- - If `AICONNECT_API_KEY` is not provided, tools will return helpful error messages
157
- - If `AICONNECT_API_URL` is not set, it defaults to the production API
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
- │ ├── cancel_job.ts # Tool for canceling jobs
265
- ├── create_job.ts # Tool for creating jobs
266
- ├── get_job.ts # Tool for querying job
267
- └── list_jobs.ts # Tool for listing jobs
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
- 1. Create a new file in the `src/` folder (e.g., `new_tool.ts`)
287
- 2. Implement the tool following the pattern of existing files
288
- 3. Register the tool in `src/index.ts`
289
- 4. Recompile with `npm run build`
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 with fallback to .env.example defaults
1
+ // Configuration for the MCP server
2
2
  export const config = {
3
- DEFAULT_ORG_ID: process.env.DEFAULT_ORG_ID || 'aiconnect',
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
- AICONNECT_API_URL: process.env.AICONNECT_API_URL || 'https://api.aiconnect.cloud/api/v0'
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 cancel_job from "./cancel_job.js";
7
- import get_job from "./get_job.js";
8
- import list_jobs from "./list_jobs.js";
9
- import create_job from "./create_job.js";
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
- // Validate required environment variables
59
- if (!process.env.AICONNECT_API_URL) {
60
- console.error('Error: AICONNECT_API_URL environment variable is required');
61
- console.error('Use --help for more information');
62
- process.exit(1);
63
- }
64
- if (!process.env.AICONNECT_API_KEY) {
65
- console.error('Error: AICONNECT_API_KEY environment variable is required');
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
- // Initialize components
75
- cancel_job(server);
76
- get_job(server);
77
- list_jobs(server);
78
- create_job(server);
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
- await server.connect(transport);
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
+ };