@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
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import agentJobsClient from '../lib/agentJobsClient.js';
|
|
3
|
+
import { formatJobDetails } from '../utils/formatters.js';
|
|
4
|
+
import { mcpDebugger, withTiming } from '../utils/debugger.js';
|
|
5
|
+
export default (server) => {
|
|
6
|
+
server.registerTool('get_job', {
|
|
7
|
+
description: 'Retrieves an agent job by its ID.',
|
|
8
|
+
annotations: {
|
|
9
|
+
title: 'Get Agent Job'
|
|
10
|
+
},
|
|
11
|
+
inputSchema: {
|
|
12
|
+
job_id: z.string({
|
|
13
|
+
description: "The unique identifier of the job you want to retrieve. Example: 'job-12345'."
|
|
14
|
+
}),
|
|
15
|
+
org_id: z
|
|
16
|
+
.string({
|
|
17
|
+
description: "The organization ID. Example: 'aiconnect'."
|
|
18
|
+
})
|
|
19
|
+
.optional()
|
|
20
|
+
}
|
|
21
|
+
}, async (params) => {
|
|
22
|
+
mcpDebugger.toolCall("get_job", params);
|
|
23
|
+
const { job_id } = params;
|
|
24
|
+
const endpoint = `/services/agent-jobs/${job_id}${params.org_id ? `?org_id=${params.org_id}` : ''}`;
|
|
25
|
+
mcpDebugger.debug("Built endpoint", { endpoint, job_id, org_id: params.org_id });
|
|
26
|
+
try {
|
|
27
|
+
const job = await withTiming(() => agentJobsClient.get(endpoint), "get_job API call");
|
|
28
|
+
mcpDebugger.debug("Raw API response", { job });
|
|
29
|
+
const result = {
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: 'text',
|
|
33
|
+
text: formatJobDetails(job)
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
};
|
|
37
|
+
mcpDebugger.toolResponse("get_job", {
|
|
38
|
+
jobId: job_id,
|
|
39
|
+
resultLength: result.content[0].text.length
|
|
40
|
+
});
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
mcpDebugger.toolError("get_job", error);
|
|
45
|
+
return {
|
|
46
|
+
content: [
|
|
47
|
+
{
|
|
48
|
+
type: 'text',
|
|
49
|
+
text: `Error getting job: ${error.message}`
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import agentJobsClient from '../lib/agentJobsClient.js';
|
|
3
|
+
import { config } from '../config.js';
|
|
4
|
+
import { formatJobTypeDetails } from '../utils/formatters.js';
|
|
5
|
+
import { mcpDebugger, withTiming } from '../utils/debugger.js';
|
|
6
|
+
export default (server) => {
|
|
7
|
+
server.registerTool('get_job_type', {
|
|
8
|
+
description: 'Retrieves an agent job type by its ID.',
|
|
9
|
+
annotations: {
|
|
10
|
+
title: 'Get Job Type Configuration'
|
|
11
|
+
},
|
|
12
|
+
inputSchema: {
|
|
13
|
+
job_type_id: z.string({
|
|
14
|
+
description: "The unique identifier of the job type you want to retrieve. Example: 'mood-monitor'."
|
|
15
|
+
}),
|
|
16
|
+
org_id: z.string({
|
|
17
|
+
description: "The organization ID. Example: 'aiconnect'."
|
|
18
|
+
}).optional()
|
|
19
|
+
}
|
|
20
|
+
}, async (params) => {
|
|
21
|
+
mcpDebugger.toolCall("get_job_type", params);
|
|
22
|
+
const { job_type_id } = params;
|
|
23
|
+
const org_id = params.org_id || config.DEFAULT_ORG_ID;
|
|
24
|
+
const endpoint = `/organizations/${org_id}/agent-jobs-type/${job_type_id}`;
|
|
25
|
+
mcpDebugger.debug("Job type request", {
|
|
26
|
+
endpoint,
|
|
27
|
+
job_type_id,
|
|
28
|
+
org_id,
|
|
29
|
+
usingDefaultOrg: !params.org_id
|
|
30
|
+
});
|
|
31
|
+
try {
|
|
32
|
+
const response = await withTiming(() => agentJobsClient.get(endpoint), "get_job_type API call");
|
|
33
|
+
mcpDebugger.debug("Job type raw response", { response });
|
|
34
|
+
// The API returns { data: {...}, meta: {...} } but agentJobsClient should extract data
|
|
35
|
+
// However, let's be defensive and handle both cases
|
|
36
|
+
const jobTypeData = response?.data ? response.data : response;
|
|
37
|
+
mcpDebugger.debug("Job type extracted data", { jobTypeData });
|
|
38
|
+
const result = {
|
|
39
|
+
content: [
|
|
40
|
+
{
|
|
41
|
+
type: 'text',
|
|
42
|
+
text: formatJobTypeDetails(jobTypeData)
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
};
|
|
46
|
+
mcpDebugger.toolResponse("get_job_type", {
|
|
47
|
+
job_type_id,
|
|
48
|
+
org_id,
|
|
49
|
+
resultLength: result.content[0].text.length,
|
|
50
|
+
hasData: !!jobTypeData
|
|
51
|
+
});
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
mcpDebugger.toolError("get_job_type", error);
|
|
56
|
+
return {
|
|
57
|
+
content: [
|
|
58
|
+
{
|
|
59
|
+
type: 'text',
|
|
60
|
+
text: `Error getting job type: ${error.message}`
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import agentJobsClient from "../lib/agentJobsClient.js";
|
|
3
|
+
import { formatJobStats } from "../utils/formatters.js";
|
|
4
|
+
import { flexibleDateTimeSchema } from "../utils/schemas.js";
|
|
5
|
+
import { mcpDebugger, withTiming } from "../utils/debugger.js";
|
|
6
|
+
const jobStatusSchema = z.enum([
|
|
7
|
+
"waiting",
|
|
8
|
+
"scheduled",
|
|
9
|
+
"running",
|
|
10
|
+
"completed",
|
|
11
|
+
"failed",
|
|
12
|
+
"canceled"
|
|
13
|
+
]);
|
|
14
|
+
export default (server) => {
|
|
15
|
+
server.registerTool("get_jobs_stats", {
|
|
16
|
+
description: "Get aggregated statistics for agent jobs without retrieving individual job data. Optimized for dashboards and monitoring with minimal network overhead.",
|
|
17
|
+
annotations: {
|
|
18
|
+
title: "Get Job Statistics"
|
|
19
|
+
},
|
|
20
|
+
inputSchema: {
|
|
21
|
+
org_id: z.string().optional().describe("Filter by organization ID."),
|
|
22
|
+
scheduled_at_gte: flexibleDateTimeSchema.optional().describe("Start of period (ISO 8601)"),
|
|
23
|
+
scheduled_at_lte: flexibleDateTimeSchema.optional().describe("End of period (ISO 8601)"),
|
|
24
|
+
created_at_gte: flexibleDateTimeSchema.optional().describe("Filter for jobs created at or after a specific time (ISO 8601)."),
|
|
25
|
+
created_at_lte: flexibleDateTimeSchema.optional().describe("Filter for jobs created at or before a specific time (ISO 8601)."),
|
|
26
|
+
job_type_id: z.string().optional().describe("Job type filter"),
|
|
27
|
+
channel_code: z.string().optional().describe("Channel filter"),
|
|
28
|
+
tags: z.string().optional().describe("Tags filter (comma-separated)"),
|
|
29
|
+
status: jobStatusSchema.optional().describe("Status filter"),
|
|
30
|
+
}
|
|
31
|
+
}, async (params) => {
|
|
32
|
+
mcpDebugger.toolCall("get_jobs_stats", params);
|
|
33
|
+
try {
|
|
34
|
+
const response = await withTiming(() => agentJobsClient.getStats(params), "get_jobs_stats API call");
|
|
35
|
+
const stats = response.meta?.stats || {};
|
|
36
|
+
const filters = response.meta?.filters || {};
|
|
37
|
+
mcpDebugger.debug("Raw API response", { stats, filters });
|
|
38
|
+
const result = {
|
|
39
|
+
content: [{
|
|
40
|
+
type: "text",
|
|
41
|
+
text: formatJobStats(stats, filters),
|
|
42
|
+
}]
|
|
43
|
+
};
|
|
44
|
+
mcpDebugger.toolResponse("get_jobs_stats", result);
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
mcpDebugger.toolError("get_jobs_stats", error);
|
|
49
|
+
return {
|
|
50
|
+
content: [{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: `Error getting job stats: ${error.message}`,
|
|
53
|
+
}],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import agentJobsClient from "../lib/agentJobsClient.js";
|
|
3
|
+
import { formatJobList } from "../utils/formatters.js";
|
|
4
|
+
import { flexibleDateTimeSchema } from "../utils/schemas.js";
|
|
5
|
+
import { mcpDebugger, withTiming } from "../utils/debugger.js";
|
|
6
|
+
// Define the schema for job status based on docs/agent-jobs-api.md:246-251
|
|
7
|
+
const jobStatusSchema = z.enum([
|
|
8
|
+
"waiting",
|
|
9
|
+
"scheduled",
|
|
10
|
+
"running",
|
|
11
|
+
"completed",
|
|
12
|
+
"failed",
|
|
13
|
+
"canceled"
|
|
14
|
+
]);
|
|
15
|
+
export default (server) => {
|
|
16
|
+
server.registerTool("list_jobs", {
|
|
17
|
+
description: "Retrieves a list of agent jobs, with optional filters and pagination.",
|
|
18
|
+
annotations: {
|
|
19
|
+
title: "List Agent Jobs"
|
|
20
|
+
},
|
|
21
|
+
inputSchema: {
|
|
22
|
+
org_id: z.string().optional().describe("Filter by organization ID. If not provided, the default from the environment is used."),
|
|
23
|
+
status: jobStatusSchema.optional().describe("Filter by job status. Possible values are: 'waiting', 'scheduled', 'running', 'completed', 'failed', 'canceled'."),
|
|
24
|
+
scheduled_at: flexibleDateTimeSchema.optional().describe("Filter by the exact scheduled time in ISO 8601 format (e.g., '2024-07-23T10:00:00Z')."),
|
|
25
|
+
scheduled_at_gte: flexibleDateTimeSchema.optional().describe("Filter for jobs scheduled at or after a specific time (ISO 8601)."),
|
|
26
|
+
scheduled_at_lte: flexibleDateTimeSchema.optional().describe("Filter for jobs scheduled at or before a specific time (ISO 8601)."),
|
|
27
|
+
created_at_gte: flexibleDateTimeSchema.optional().describe("Filter for jobs created at or after a specific time (ISO 8601)."),
|
|
28
|
+
created_at_lte: flexibleDateTimeSchema.optional().describe("Filter for jobs created at or before a specific time (ISO 8601)."),
|
|
29
|
+
job_type_id: z.string().optional().describe("Filter by the specific job type ID (e.g., 'daily-report')."),
|
|
30
|
+
channel_code: z.string().optional().describe("Filter by the channel code (e.g., 'C123456' for a Slack channel)."),
|
|
31
|
+
limit: z.number().int().positive().optional().describe("Maximum number of jobs to return (e.g.,20). Default is 20."),
|
|
32
|
+
offset: z.number().int().nonnegative().optional().describe("Number of jobs to skip, used for pagination. Default is 0."),
|
|
33
|
+
sort: z.string().optional().describe("Field to sort by and direction. Format is 'field:direction'. Example: 'created_at:desc'.")
|
|
34
|
+
}
|
|
35
|
+
}, async (params) => {
|
|
36
|
+
mcpDebugger.toolCall("list_jobs", params);
|
|
37
|
+
const endpoint = `/services/agent-jobs`;
|
|
38
|
+
// Build query parameters object from provided params
|
|
39
|
+
const queryParams = {};
|
|
40
|
+
for (const [key, value] of Object.entries(params)) {
|
|
41
|
+
if (value !== undefined) {
|
|
42
|
+
queryParams[key] = value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
mcpDebugger.debug("Built query parameters", { endpoint, queryParams });
|
|
46
|
+
try {
|
|
47
|
+
const apiResponse = await withTiming(() => agentJobsClient.getWithMeta(endpoint, queryParams), "list_jobs API call");
|
|
48
|
+
// Access the full API response structure
|
|
49
|
+
const jobs = apiResponse.data || [];
|
|
50
|
+
const meta = apiResponse.meta || {};
|
|
51
|
+
mcpDebugger.debug("Raw API response", {
|
|
52
|
+
fullResponse: apiResponse,
|
|
53
|
+
jobsCount: jobs.length,
|
|
54
|
+
meta,
|
|
55
|
+
firstJob: jobs[0] || null
|
|
56
|
+
});
|
|
57
|
+
const result = {
|
|
58
|
+
content: [{
|
|
59
|
+
type: "text",
|
|
60
|
+
text: formatJobList(jobs, meta),
|
|
61
|
+
}]
|
|
62
|
+
};
|
|
63
|
+
mcpDebugger.toolResponse("list_jobs", {
|
|
64
|
+
jobsReturned: jobs.length,
|
|
65
|
+
resultLength: result.content[0].text.length
|
|
66
|
+
});
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
mcpDebugger.toolError("list_jobs", error);
|
|
71
|
+
return {
|
|
72
|
+
content: [{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: `Error listing jobs: ${error.message}`,
|
|
75
|
+
}],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export class MCPDebugger {
|
|
2
|
+
isDebugEnabled;
|
|
3
|
+
constructor(enabled = process.env.MCP_DEBUG === 'true') {
|
|
4
|
+
this.isDebugEnabled = enabled;
|
|
5
|
+
}
|
|
6
|
+
formatLog(level, message, data) {
|
|
7
|
+
if (!this.isDebugEnabled)
|
|
8
|
+
return;
|
|
9
|
+
const timestamp = new Date().toISOString();
|
|
10
|
+
const prefix = `[MCP-DEBUG ${timestamp}] [${level.toUpperCase()}]`;
|
|
11
|
+
console.error(`${prefix} ${message}`);
|
|
12
|
+
if (data !== undefined) {
|
|
13
|
+
console.error(`${prefix} Data:`, JSON.stringify(data, null, 2));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
info(message, data) {
|
|
17
|
+
this.formatLog('info', message, data);
|
|
18
|
+
}
|
|
19
|
+
warn(message, data) {
|
|
20
|
+
this.formatLog('warn', message, data);
|
|
21
|
+
}
|
|
22
|
+
error(message, data) {
|
|
23
|
+
this.formatLog('error', message, data);
|
|
24
|
+
}
|
|
25
|
+
debug(message, data) {
|
|
26
|
+
this.formatLog('debug', message, data);
|
|
27
|
+
}
|
|
28
|
+
// Helper para debugar chamadas de tools
|
|
29
|
+
toolCall(toolName, args) {
|
|
30
|
+
this.info(`Tool called: ${toolName}`, { args });
|
|
31
|
+
}
|
|
32
|
+
toolResponse(toolName, response, duration) {
|
|
33
|
+
this.info(`Tool response: ${toolName}`, {
|
|
34
|
+
response: typeof response === 'object' ? response : { value: response },
|
|
35
|
+
duration: duration ? `${duration}ms` : undefined
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
toolError(toolName, error) {
|
|
39
|
+
this.error(`Tool error: ${toolName}`, {
|
|
40
|
+
error: error.message || error,
|
|
41
|
+
stack: error.stack
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
// Helper para debugar requisições HTTP
|
|
45
|
+
httpRequest(method, url, data) {
|
|
46
|
+
this.debug(`HTTP ${method.toUpperCase()} ${url}`, data);
|
|
47
|
+
}
|
|
48
|
+
httpResponse(method, url, status, data) {
|
|
49
|
+
this.debug(`HTTP Response ${method.toUpperCase()} ${url} [${status}]`, data);
|
|
50
|
+
}
|
|
51
|
+
httpError(method, url, error) {
|
|
52
|
+
this.error(`HTTP Error ${method.toUpperCase()} ${url}`, error);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Instância global do debugger
|
|
56
|
+
export const mcpDebugger = new MCPDebugger();
|
|
57
|
+
// Helper function para medir tempo de execução
|
|
58
|
+
export function withTiming(fn, name) {
|
|
59
|
+
return new Promise(async (resolve, reject) => {
|
|
60
|
+
const start = Date.now();
|
|
61
|
+
mcpDebugger.debug(`Starting ${name}`);
|
|
62
|
+
try {
|
|
63
|
+
const result = await fn();
|
|
64
|
+
const duration = Date.now() - start;
|
|
65
|
+
mcpDebugger.debug(`Completed ${name} in ${duration}ms`);
|
|
66
|
+
resolve(result);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
const duration = Date.now() - start;
|
|
70
|
+
mcpDebugger.error(`Failed ${name} after ${duration}ms`, error);
|
|
71
|
+
reject(error);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|