@aiconnect/agentjobs-mcp 1.0.9 → 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.
@@ -1,71 +1,56 @@
1
1
  import { z } from 'zod';
2
- import axios from 'axios';
2
+ import agentJobsClient from '../lib/agentJobsClient.js';
3
3
  import { config } from '../config.js';
4
- /**
5
- * Lightweight Agent‑Jobs creator.
6
- * Only the essentials are required to keep the contract LLM‑friendly.
7
- */
4
+ import { flexibleDateTimeSchema } from '../utils/schemas.js';
5
+ import { mcpDebugger, withTiming } from '../utils/debugger.js';
8
6
  export default (server) => {
9
- server.tool('create_job', 'Create a new Agent Job with the minimal set of fields.', {
10
- // ─────────────────────────────────────────────────────────────────────────┐
11
- // Required
12
- // ─────────────────────────────────────────────────────────────────────────┘
13
- job_type_id: z
14
- .string()
15
- .describe('ID of the job type (e.g. "mood-monitor")'),
16
- target_channel: z
17
- .object({
18
- platform: z
19
- .enum(['whatsapp', 'slack', 'web'])
20
- .describe('Destination platform.'),
21
- code: z
22
- .string()
23
- .describe('Channel identifier, phone number, or user ID.'),
24
- org_id: z
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
25
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())
26
33
  .optional()
27
- .describe('Org ID defaults to config.DEFAULT_ORG_ID')
28
- })
29
- .describe('Where the agent will communicate.'),
30
- params: z
31
- .record(z.any())
32
- .optional()
33
- .describe('Free‑form params passed to the agent'),
34
- scheduled_at: z
35
- .string()
36
- .datetime({ message: 'Use ISO‑8601' })
37
- .optional()
38
- .describe('Schedule the job to run later')
39
- },
40
- // ───────────────────────────────────────────────────────────────────────────┐
41
- // Implementation │
42
- // ───────────────────────────────────────────────────────────────────────────┘
43
- async (params) => {
44
- const { AICONNECT_API_URL: apiUrl, AICONNECT_API_KEY: apiKey, DEFAULT_ORG_ID } = config;
45
- if (!apiUrl) {
46
- return {
47
- content: [{
48
- type: "text",
49
- text: "Error: API URL is not configured. Please set AICONNECT_API_URL environment variable."
50
- }]
51
- };
52
- }
53
- if (!apiKey) {
54
- return {
55
- content: [{
56
- type: "text",
57
- text: "Error: API Key is not configured. Please set AICONNECT_API_KEY environment variable."
58
- }]
59
- };
34
+ .describe('Free‑form params passed to the agent'),
35
+ scheduled_at: flexibleDateTimeSchema
36
+ .optional()
37
+ .describe('Schedule the job to run later')
60
38
  }
39
+ }, async (params) => {
40
+ mcpDebugger.toolCall("create_job", params);
61
41
  // Fall back to default org if none supplied.
62
- params.target_channel.org_id ??= DEFAULT_ORG_ID;
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
+ });
63
49
  try {
64
- const res = await axios.post(`${apiUrl}/services/agent-jobs`, params, {
65
- headers: { Authorization: `Bearer ${apiKey}` }
66
- });
67
- const jobId = res.data?.data?.id ?? res.data?.id ?? 'unknown';
68
- return {
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 = {
69
54
  content: [
70
55
  {
71
56
  type: 'text',
@@ -73,21 +58,16 @@ export default (server) => {
73
58
  }
74
59
  ]
75
60
  };
61
+ mcpDebugger.toolResponse("create_job", { jobId });
62
+ return result;
76
63
  }
77
64
  catch (error) {
78
- let errorMessage = `Failed to create job.`;
79
- if (axios.isAxiosError(error) && error.response) {
80
- const apiError = error.response.data?.message || error.response.data?.error || JSON.stringify(error.response.data);
81
- errorMessage = `API Error (${error.response.status}): ${apiError || error.message}`;
82
- }
83
- else if (error instanceof Error) {
84
- errorMessage = `Error: ${error.message}`;
85
- }
65
+ mcpDebugger.toolError("create_job", error);
86
66
  return {
87
67
  content: [
88
68
  {
89
69
  type: 'text',
90
- text: errorMessage
70
+ text: `Error creating job: ${error.message}`
91
71
  }
92
72
  ]
93
73
  };
@@ -1,51 +1,32 @@
1
1
  import { z } from 'zod';
2
- import axios from 'axios';
3
- import { config } from '../config.js';
2
+ import agentJobsClient from '../lib/agentJobsClient.js';
4
3
  import { formatJobDetails } from '../utils/formatters.js';
4
+ import { mcpDebugger, withTiming } from '../utils/debugger.js';
5
5
  export default (server) => {
6
- server.tool('get_job', 'Retrieves an agent job by its ID.', {
7
- job_id: z.string({
8
- description: "The unique identifier of the job you want to retrieve. Example: 'job-12345'."
9
- }),
10
- org_id: z
11
- .string({
12
- description: "The organization ID. Example: 'aiconnect'."
13
- })
14
- .optional()
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
+ }
15
21
  }, async (params) => {
22
+ mcpDebugger.toolCall("get_job", params);
16
23
  const { job_id } = params;
17
- const apiUrl = config.AICONNECT_API_URL;
18
- const apiKey = config.AICONNECT_API_KEY;
19
- if (!apiUrl) {
20
- return {
21
- content: [
22
- {
23
- type: 'text',
24
- text: 'Error: API URL is not configured. Please set AICONNECT_API_URL environment variable.'
25
- }
26
- ]
27
- };
28
- }
29
- if (!apiKey) {
30
- return {
31
- content: [
32
- {
33
- type: 'text',
34
- text: 'Error: API Key is not configured. Please set AICONNECT_API_KEY environment variable.'
35
- }
36
- ]
37
- };
38
- }
39
- const endpoint = `${apiUrl}/services/agent-jobs/${job_id}${params.org_id ? `?org_id=${params.org_id}` : ''}`;
40
- const headers = {
41
- Authorization: `Bearer ${apiKey}`
42
- };
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 });
43
26
  try {
44
- const response = await axios.get(endpoint, {
45
- headers
46
- });
47
- const job = response.data?.data || response.data;
48
- return {
27
+ const job = await withTiming(() => agentJobsClient.get(endpoint), "get_job API call");
28
+ mcpDebugger.debug("Raw API response", { job });
29
+ const result = {
49
30
  content: [
50
31
  {
51
32
  type: 'text',
@@ -53,28 +34,19 @@ export default (server) => {
53
34
  }
54
35
  ]
55
36
  };
37
+ mcpDebugger.toolResponse("get_job", {
38
+ jobId: job_id,
39
+ resultLength: result.content[0].text.length
40
+ });
41
+ return result;
56
42
  }
57
43
  catch (error) {
58
- let errorMessage = `Failed to retrieve job ${job_id}.`;
59
- let errorDetails = {};
60
- if (axios.isAxiosError(error) && error.response) {
61
- const apiError = error.response.data?.message ||
62
- error.response.data?.error ||
63
- JSON.stringify(error.response.data);
64
- errorMessage = `API Error (${error.response.status}): ${apiError || error.message}`;
65
- errorDetails = {
66
- status: error.response.status,
67
- data: error.response.data
68
- };
69
- }
70
- else if (error instanceof Error) {
71
- errorMessage = `Error: ${error.message}`;
72
- }
44
+ mcpDebugger.toolError("get_job", error);
73
45
  return {
74
46
  content: [
75
47
  {
76
48
  type: 'text',
77
- text: errorMessage
49
+ text: `Error getting job: ${error.message}`
78
50
  }
79
51
  ]
80
52
  };
@@ -1,79 +1,63 @@
1
1
  import { z } from 'zod';
2
- import axios from 'axios';
2
+ import agentJobsClient from '../lib/agentJobsClient.js';
3
3
  import { config } from '../config.js';
4
4
  import { formatJobTypeDetails } from '../utils/formatters.js';
5
+ import { mcpDebugger, withTiming } from '../utils/debugger.js';
5
6
  export default (server) => {
6
- server.tool('get_job_type', 'Retrieves an agent job type by its ID.', {
7
- job_type_id: z.string({
8
- description: "The unique identifier of the job type you want to retrieve. Example: 'mood-monitor'."
9
- }),
10
- org_id: z.string({
11
- description: "The organization ID. Example: 'aiconnect'."
12
- }).optional()
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
+ }
13
20
  }, async (params) => {
21
+ mcpDebugger.toolCall("get_job_type", params);
14
22
  const { job_type_id } = params;
15
23
  const org_id = params.org_id || config.DEFAULT_ORG_ID;
16
- const apiUrl = config.AICONNECT_API_URL;
17
- const apiKey = config.AICONNECT_API_KEY;
18
- if (!apiUrl) {
19
- return {
20
- content: [
21
- {
22
- type: 'text',
23
- text: 'Error: API URL is not configured. Please set AICONNECT_API_URL environment variable.'
24
- }
25
- ]
26
- };
27
- }
28
- if (!apiKey) {
29
- return {
30
- content: [
31
- {
32
- type: 'text',
33
- text: 'Error: API Key is not configured. Please set AICONNECT_API_KEY environment variable.'
34
- }
35
- ]
36
- };
37
- }
38
- const endpoint = `${apiUrl}/organizations/${org_id}/agent-jobs-type/${job_type_id}`;
39
- const headers = {
40
- Authorization: `Bearer ${apiKey}`
41
- };
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
+ });
42
31
  try {
43
- const response = await axios.get(endpoint, {
44
- headers
45
- });
46
- const jobType = response.data?.data || response.data;
47
- return {
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 = {
48
39
  content: [
49
40
  {
50
41
  type: 'text',
51
- text: formatJobTypeDetails(jobType)
42
+ text: formatJobTypeDetails(jobTypeData)
52
43
  }
53
44
  ]
54
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;
55
53
  }
56
54
  catch (error) {
57
- let errorMessage = `Failed to retrieve job type ${job_type_id}.`;
58
- let errorDetails = {};
59
- if (axios.isAxiosError(error) && error.response) {
60
- const apiError = error.response.data?.message ||
61
- error.response.data?.error ||
62
- JSON.stringify(error.response.data);
63
- errorMessage = `API Error (${error.response.status}): ${apiError || error.message}`;
64
- errorDetails = {
65
- status: error.response.status,
66
- data: error.response.data
67
- };
68
- }
69
- else if (error instanceof Error) {
70
- errorMessage = `Error: ${error.message}`;
71
- }
55
+ mcpDebugger.toolError("get_job_type", error);
72
56
  return {
73
57
  content: [
74
58
  {
75
59
  type: 'text',
76
- text: errorMessage
60
+ text: `Error getting job type: ${error.message}`
77
61
  }
78
62
  ]
79
63
  };
@@ -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
+ };
@@ -1,7 +1,8 @@
1
1
  import { z } from "zod";
2
- import axios from 'axios';
3
- import { config } from '../config.js';
2
+ import agentJobsClient from "../lib/agentJobsClient.js";
4
3
  import { formatJobList } from "../utils/formatters.js";
4
+ import { flexibleDateTimeSchema } from "../utils/schemas.js";
5
+ import { mcpDebugger, withTiming } from "../utils/debugger.js";
5
6
  // Define the schema for job status based on docs/agent-jobs-api.md:246-251
6
7
  const jobStatusSchema = z.enum([
7
8
  "waiting",
@@ -12,42 +13,28 @@ const jobStatusSchema = z.enum([
12
13
  "canceled"
13
14
  ]);
14
15
  export default (server) => {
15
- server.tool("list_jobs", "Retrieves a list of agent jobs, with optional filters and pagination.", {
16
- org_id: z.string().optional().describe("Filter by organization ID. If not provided, the default from the environment is used."),
17
- status: jobStatusSchema.optional().describe("Filter by job status. Possible values are: 'waiting', 'scheduled', 'running', 'completed', 'failed', 'canceled'."),
18
- scheduled_at: z.string().datetime().optional().describe("Filter by the exact scheduled time in ISO 8601 format (e.g., '2024-07-23T10:00:00Z')."),
19
- scheduled_at_gte: z.string().datetime().optional().describe("Filter for jobs scheduled at or after a specific time (ISO 8601)."),
20
- scheduled_at_lte: z.string().datetime().optional().describe("Filter for jobs scheduled at or before a specific time (ISO 8601)."),
21
- created_at_gte: z.string().datetime().optional().describe("Filter for jobs created at or after a specific time (ISO 8601)."),
22
- created_at_lte: z.string().datetime().optional().describe("Filter for jobs created at or before a specific time (ISO 8601)."),
23
- job_type_id: z.string().optional().describe("Filter by the specific job type ID (e.g., 'daily-report')."),
24
- channel_code: z.string().optional().describe("Filter by the channel code (e.g., 'C123456' for a Slack channel)."),
25
- limit: z.number().int().positive().optional().describe("Maximum number of jobs to return (e.g.,20). Default is 20."),
26
- offset: z.number().int().nonnegative().optional().describe("Number of jobs to skip, used for pagination. Default is 0."),
27
- sort: z.string().optional().describe("Field to sort by and direction. Format is 'field:direction'. Example: 'created_at:desc'."),
28
- }, async (params) => {
29
- const apiUrl = config.AICONNECT_API_URL;
30
- const apiKey = config.AICONNECT_API_KEY;
31
- if (!apiUrl) {
32
- return {
33
- content: [{
34
- type: "text",
35
- text: "Error: API URL is not configured. Please set AICONNECT_API_URL environment variable."
36
- }]
37
- };
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'.")
38
34
  }
39
- if (!apiKey) {
40
- return {
41
- content: [{
42
- type: "text",
43
- text: "Error: API Key is not configured. Please set AICONNECT_API_KEY environment variable."
44
- }]
45
- };
46
- }
47
- const endpoint = `${apiUrl}/services/agent-jobs`;
48
- const headers = {
49
- "Authorization": `Bearer ${apiKey}`,
50
- };
35
+ }, async (params) => {
36
+ mcpDebugger.toolCall("list_jobs", params);
37
+ const endpoint = `/services/agent-jobs`;
51
38
  // Build query parameters object from provided params
52
39
  const queryParams = {};
53
40
  for (const [key, value] of Object.entries(params)) {
@@ -55,38 +42,36 @@ export default (server) => {
55
42
  queryParams[key] = value;
56
43
  }
57
44
  }
45
+ mcpDebugger.debug("Built query parameters", { endpoint, queryParams });
58
46
  try {
59
- const response = await axios.get(endpoint, {
60
- headers,
61
- params: queryParams,
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
62
56
  });
63
- const jobs = response.data?.data || [];
64
- const meta = response.data?.meta || {};
65
- return {
57
+ const result = {
66
58
  content: [{
67
59
  type: "text",
68
60
  text: formatJobList(jobs, meta),
69
61
  }]
70
62
  };
63
+ mcpDebugger.toolResponse("list_jobs", {
64
+ jobsReturned: jobs.length,
65
+ resultLength: result.content[0].text.length
66
+ });
67
+ return result;
71
68
  }
72
69
  catch (error) {
73
- let errorMessage = `Failed to list jobs.`;
74
- let errorDetails = {};
75
- if (axios.isAxiosError(error) && error.response) {
76
- const apiError = error.response.data?.message || error.response.data?.error || JSON.stringify(error.response.data);
77
- errorMessage = `API Error (${error.response.status}): ${apiError || error.message}`;
78
- errorDetails = {
79
- status: error.response.status,
80
- data: error.response.data
81
- };
82
- }
83
- else if (error instanceof Error) {
84
- errorMessage = `Error: ${error.message}`;
85
- }
70
+ mcpDebugger.toolError("list_jobs", error);
86
71
  return {
87
72
  content: [{
88
73
  type: "text",
89
- text: errorMessage,
74
+ text: `Error listing jobs: ${error.message}`,
90
75
  }],
91
76
  };
92
77
  }
@@ -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
+ }