@anyshift/mcp-proxy 0.3.4 → 0.3.5
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/dist/index.js +59 -21
- package/dist/jq/index.d.ts +12 -4
- package/dist/jq/tool.d.ts +18 -4
- package/dist/jq/tool.js +5 -8
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.js +18 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23,14 +23,15 @@ import { createJqTool } from './jq/index.js';
|
|
|
23
23
|
import { truncateResponseIfNeeded } from './truncation/index.js';
|
|
24
24
|
import { createFileWriter } from './fileWriter/index.js';
|
|
25
25
|
import { generateToolId } from './utils/filename.js';
|
|
26
|
+
import { PROXY_PARAMS } from './types/index.js';
|
|
26
27
|
// ============================================================================
|
|
27
28
|
// HELPER FUNCTIONS
|
|
28
29
|
// ============================================================================
|
|
29
30
|
/**
|
|
30
|
-
* Inject
|
|
31
|
-
*
|
|
31
|
+
* Inject proxy-specific parameters into a tool's inputSchema
|
|
32
|
+
* Uses centralized PROXY_PARAMS definitions
|
|
32
33
|
*/
|
|
33
|
-
function
|
|
34
|
+
function injectProxyParams(tool) {
|
|
34
35
|
// Clone the tool to avoid mutating the original
|
|
35
36
|
const modifiedTool = { ...tool };
|
|
36
37
|
if (!modifiedTool.inputSchema) {
|
|
@@ -43,15 +44,26 @@ function injectDescriptionParam(tool) {
|
|
|
43
44
|
}
|
|
44
45
|
// Clone properties
|
|
45
46
|
modifiedTool.inputSchema.properties = { ...modifiedTool.inputSchema.properties };
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
modifiedTool.inputSchema.properties
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
};
|
|
47
|
+
// Inject all proxy params if not already present
|
|
48
|
+
for (const [key, value] of Object.entries(PROXY_PARAMS)) {
|
|
49
|
+
if (!modifiedTool.inputSchema.properties[key]) {
|
|
50
|
+
modifiedTool.inputSchema.properties[key] = value;
|
|
51
|
+
}
|
|
52
52
|
}
|
|
53
53
|
return modifiedTool;
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Add retry metadata to a unified response if present in tool args
|
|
57
|
+
*/
|
|
58
|
+
function addRetryMetadata(response, toolArgs) {
|
|
59
|
+
if (toolArgs.isRetryAttempt) {
|
|
60
|
+
response.isRetryAttempt = true;
|
|
61
|
+
if (toolArgs.originalToolId) {
|
|
62
|
+
response.originalToolId = toolArgs.originalToolId;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return response;
|
|
66
|
+
}
|
|
55
67
|
/**
|
|
56
68
|
* ENVIRONMENT VARIABLE CONTRACT
|
|
57
69
|
* =============================
|
|
@@ -299,8 +311,8 @@ async function main() {
|
|
|
299
311
|
// ------------------------------------------------------------------------
|
|
300
312
|
// 5. REGISTER ALL TOOLS (CHILD + PROXY) WITH DESCRIPTION INJECTION
|
|
301
313
|
// ------------------------------------------------------------------------
|
|
302
|
-
// Inject
|
|
303
|
-
const enhancedChildTools = childToolsResponse.tools.map(
|
|
314
|
+
// Inject proxy parameters (description, isRetryAttempt, originalToolId) into all child tools
|
|
315
|
+
const enhancedChildTools = childToolsResponse.tools.map(injectProxyParams);
|
|
304
316
|
const allTools = [
|
|
305
317
|
...enhancedChildTools,
|
|
306
318
|
...(jqTool ? [jqTool.toolDefinition] : []) // JQ tool already has description param
|
|
@@ -323,6 +335,9 @@ async function main() {
|
|
|
323
335
|
if (toolArgs.description) {
|
|
324
336
|
console.debug(`[mcp-proxy] Description: ${toolArgs.description}`);
|
|
325
337
|
}
|
|
338
|
+
if (toolArgs.isRetryAttempt) {
|
|
339
|
+
console.debug(`[mcp-proxy] Retry of: ${toolArgs.originalToolId}`);
|
|
340
|
+
}
|
|
326
341
|
}
|
|
327
342
|
try {
|
|
328
343
|
let result;
|
|
@@ -336,11 +351,11 @@ async function main() {
|
|
|
336
351
|
});
|
|
337
352
|
// JQ tool returns directly, wrap in unified format
|
|
338
353
|
const tool_id = generateToolId(toolName, toolArgs, fileWriterConfig.toolAbbreviations);
|
|
339
|
-
const unifiedResponse = {
|
|
354
|
+
const unifiedResponse = addRetryMetadata({
|
|
340
355
|
tool_id,
|
|
341
356
|
wroteToFile: false,
|
|
342
357
|
outputContent: result.content?.[0]?.text
|
|
343
|
-
};
|
|
358
|
+
}, toolArgs);
|
|
344
359
|
return {
|
|
345
360
|
content: [{
|
|
346
361
|
type: 'text',
|
|
@@ -352,11 +367,11 @@ async function main() {
|
|
|
352
367
|
// Forward all other tools to child MCP (if child exists)
|
|
353
368
|
if (!childClient) {
|
|
354
369
|
const tool_id = generateToolId(toolName, toolArgs, fileWriterConfig.toolAbbreviations);
|
|
355
|
-
const errorResponse = {
|
|
370
|
+
const errorResponse = addRetryMetadata({
|
|
356
371
|
tool_id,
|
|
357
372
|
wroteToFile: false,
|
|
358
373
|
error: `Tool ${toolName} not available in standalone mode (no child MCP)`
|
|
359
|
-
};
|
|
374
|
+
}, toolArgs);
|
|
360
375
|
return {
|
|
361
376
|
content: [{
|
|
362
377
|
type: 'text',
|
|
@@ -372,11 +387,32 @@ async function main() {
|
|
|
372
387
|
name: toolName,
|
|
373
388
|
arguments: toolArgs
|
|
374
389
|
});
|
|
390
|
+
// Check if child MCP returned an error
|
|
391
|
+
const childReturnedError = !!result.isError;
|
|
375
392
|
// Process result through file writer to get unified response
|
|
376
393
|
if (result.content && Array.isArray(result.content) && result.content.length > 0) {
|
|
377
394
|
const item = result.content[0];
|
|
378
395
|
if (item.type === 'text' && typeof item.text === 'string') {
|
|
379
396
|
const originalLength = item.text.length;
|
|
397
|
+
// If child returned error, pass through directly without file writing
|
|
398
|
+
if (childReturnedError) {
|
|
399
|
+
const tool_id = generateToolId(toolName, toolArgs, fileWriterConfig.toolAbbreviations);
|
|
400
|
+
const errorResponse = addRetryMetadata({
|
|
401
|
+
tool_id,
|
|
402
|
+
wroteToFile: false,
|
|
403
|
+
error: item.text
|
|
404
|
+
}, toolArgs);
|
|
405
|
+
if (ENABLE_LOGGING) {
|
|
406
|
+
console.debug(`[mcp-proxy] Child MCP returned error for ${toolName}: ${item.text.substring(0, 100)}...`);
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
content: [{
|
|
410
|
+
type: 'text',
|
|
411
|
+
text: JSON.stringify(errorResponse, null, 2)
|
|
412
|
+
}],
|
|
413
|
+
isError: true
|
|
414
|
+
};
|
|
415
|
+
}
|
|
380
416
|
// Get unified response from file writer
|
|
381
417
|
const unifiedResponse = await fileWriter.handleResponse(toolName, toolArgs, {
|
|
382
418
|
content: [{ type: 'text', text: item.text }]
|
|
@@ -408,7 +444,8 @@ async function main() {
|
|
|
408
444
|
}
|
|
409
445
|
}
|
|
410
446
|
}
|
|
411
|
-
//
|
|
447
|
+
// Add retry metadata and return unified response as JSON
|
|
448
|
+
addRetryMetadata(unifiedResponse, toolArgs);
|
|
412
449
|
return {
|
|
413
450
|
content: [{
|
|
414
451
|
type: 'text',
|
|
@@ -420,26 +457,27 @@ async function main() {
|
|
|
420
457
|
}
|
|
421
458
|
// Fallback: return result with generated tool_id
|
|
422
459
|
const tool_id = generateToolId(toolName, toolArgs, fileWriterConfig.toolAbbreviations);
|
|
423
|
-
const fallbackResponse = {
|
|
460
|
+
const fallbackResponse = addRetryMetadata({
|
|
424
461
|
tool_id,
|
|
425
462
|
wroteToFile: false,
|
|
426
463
|
outputContent: result
|
|
427
|
-
};
|
|
464
|
+
}, toolArgs);
|
|
428
465
|
return {
|
|
429
466
|
content: [{
|
|
430
467
|
type: 'text',
|
|
431
468
|
text: JSON.stringify(fallbackResponse, null, 2)
|
|
432
|
-
}]
|
|
469
|
+
}],
|
|
470
|
+
isError: childReturnedError
|
|
433
471
|
};
|
|
434
472
|
}
|
|
435
473
|
catch (error) {
|
|
436
474
|
console.error(`[mcp-proxy] Error executing tool ${toolName}:`, error);
|
|
437
475
|
const tool_id = generateToolId(toolName, toolArgs, fileWriterConfig.toolAbbreviations);
|
|
438
|
-
const errorResponse = {
|
|
476
|
+
const errorResponse = addRetryMetadata({
|
|
439
477
|
tool_id,
|
|
440
478
|
wroteToFile: false,
|
|
441
479
|
error: `Error executing ${toolName}: ${error.message || String(error)}`
|
|
442
|
-
};
|
|
480
|
+
}, toolArgs);
|
|
443
481
|
return {
|
|
444
482
|
content: [{
|
|
445
483
|
type: 'text',
|
package/dist/jq/index.d.ts
CHANGED
|
@@ -14,6 +14,18 @@ export declare function createJqTool(config: JqConfig): {
|
|
|
14
14
|
inputSchema: {
|
|
15
15
|
type: string;
|
|
16
16
|
properties: {
|
|
17
|
+
description: {
|
|
18
|
+
readonly type: "string";
|
|
19
|
+
readonly description: "Brief explanation of why you are calling this tool and what you expect to learn/achieve";
|
|
20
|
+
};
|
|
21
|
+
isRetryAttempt: {
|
|
22
|
+
readonly type: "boolean";
|
|
23
|
+
readonly description: "Set to true if this call is a follow-up attempt after a previous failure. This includes: (1) exact retries for transient errors, (2) corrected attempts fixing typos or parameters based on error feedback. Any call attempting to achieve the same goal as a failed call is a retry.";
|
|
24
|
+
};
|
|
25
|
+
originalToolId: {
|
|
26
|
+
readonly type: "string";
|
|
27
|
+
readonly description: "The tool_id from the FIRST failed attempt in this retry chain. Always reference the original tool_id, not intermediate failures. Example: if tool_id_1 fails, tool_id_2 (retry) fails, tool_id_3 (retry) succeeds - both tool_id_2 and tool_id_3 should reference tool_id_1. Required when isRetryAttempt is true.";
|
|
28
|
+
};
|
|
17
29
|
jq_query: {
|
|
18
30
|
type: string;
|
|
19
31
|
description: string;
|
|
@@ -22,10 +34,6 @@ export declare function createJqTool(config: JqConfig): {
|
|
|
22
34
|
type: string;
|
|
23
35
|
description: string;
|
|
24
36
|
};
|
|
25
|
-
description: {
|
|
26
|
-
type: string;
|
|
27
|
-
description: string;
|
|
28
|
-
};
|
|
29
37
|
};
|
|
30
38
|
required: string[];
|
|
31
39
|
};
|
package/dist/jq/tool.d.ts
CHANGED
|
@@ -6,14 +6,20 @@ export declare const ExecuteJqQuerySchema: z.ZodObject<{
|
|
|
6
6
|
jq_query: z.ZodString;
|
|
7
7
|
file_path: z.ZodString;
|
|
8
8
|
description: z.ZodOptional<z.ZodString>;
|
|
9
|
+
isRetryAttempt: z.ZodOptional<z.ZodBoolean>;
|
|
10
|
+
originalToolId: z.ZodOptional<z.ZodString>;
|
|
9
11
|
}, "strip", z.ZodTypeAny, {
|
|
10
12
|
jq_query: string;
|
|
11
13
|
file_path: string;
|
|
12
14
|
description?: string | undefined;
|
|
15
|
+
isRetryAttempt?: boolean | undefined;
|
|
16
|
+
originalToolId?: string | undefined;
|
|
13
17
|
}, {
|
|
14
18
|
jq_query: string;
|
|
15
19
|
file_path: string;
|
|
16
20
|
description?: string | undefined;
|
|
21
|
+
isRetryAttempt?: boolean | undefined;
|
|
22
|
+
originalToolId?: string | undefined;
|
|
17
23
|
}>;
|
|
18
24
|
/**
|
|
19
25
|
* Tool definition for JQ query execution with enhanced prompts
|
|
@@ -25,6 +31,18 @@ export declare const JQ_TOOL_DEFINITION: {
|
|
|
25
31
|
inputSchema: {
|
|
26
32
|
type: string;
|
|
27
33
|
properties: {
|
|
34
|
+
description: {
|
|
35
|
+
readonly type: "string";
|
|
36
|
+
readonly description: "Brief explanation of why you are calling this tool and what you expect to learn/achieve";
|
|
37
|
+
};
|
|
38
|
+
isRetryAttempt: {
|
|
39
|
+
readonly type: "boolean";
|
|
40
|
+
readonly description: "Set to true if this call is a follow-up attempt after a previous failure. This includes: (1) exact retries for transient errors, (2) corrected attempts fixing typos or parameters based on error feedback. Any call attempting to achieve the same goal as a failed call is a retry.";
|
|
41
|
+
};
|
|
42
|
+
originalToolId: {
|
|
43
|
+
readonly type: "string";
|
|
44
|
+
readonly description: "The tool_id from the FIRST failed attempt in this retry chain. Always reference the original tool_id, not intermediate failures. Example: if tool_id_1 fails, tool_id_2 (retry) fails, tool_id_3 (retry) succeeds - both tool_id_2 and tool_id_3 should reference tool_id_1. Required when isRetryAttempt is true.";
|
|
45
|
+
};
|
|
28
46
|
jq_query: {
|
|
29
47
|
type: string;
|
|
30
48
|
description: string;
|
|
@@ -33,10 +51,6 @@ export declare const JQ_TOOL_DEFINITION: {
|
|
|
33
51
|
type: string;
|
|
34
52
|
description: string;
|
|
35
53
|
};
|
|
36
|
-
description: {
|
|
37
|
-
type: string;
|
|
38
|
-
description: string;
|
|
39
|
-
};
|
|
40
54
|
};
|
|
41
55
|
required: string[];
|
|
42
56
|
};
|
package/dist/jq/tool.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { PROXY_PARAMS } from '../types/index.js';
|
|
2
3
|
/**
|
|
3
4
|
* Zod schema for JQ query execution
|
|
4
5
|
*/
|
|
@@ -9,10 +10,9 @@ export const ExecuteJqQuerySchema = z.object({
|
|
|
9
10
|
file_path: z
|
|
10
11
|
.string()
|
|
11
12
|
.describe('Absolute path starting with "/" pointing to the JSON or JSONL file to process. Must be a valid, existing file with .json or .jsonl extension. The file will be validated for existence and readability before processing.'),
|
|
12
|
-
description: z
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.describe('Brief explanation of why you are calling this tool and what you expect to learn/achieve'),
|
|
13
|
+
description: z.string().optional().describe(PROXY_PARAMS.description.description),
|
|
14
|
+
isRetryAttempt: z.boolean().optional().describe(PROXY_PARAMS.isRetryAttempt.description),
|
|
15
|
+
originalToolId: z.string().optional().describe(PROXY_PARAMS.originalToolId.description),
|
|
16
16
|
});
|
|
17
17
|
/**
|
|
18
18
|
* Tool definition for JQ query execution with enhanced prompts
|
|
@@ -111,10 +111,7 @@ export const JQ_TOOL_DEFINITION = {
|
|
|
111
111
|
type: 'string',
|
|
112
112
|
description: 'Absolute path starting with "/" pointing to the JSON or JSONL file to process. Must be a valid, existing file with .json or .jsonl extension. The file will be validated for existence and readability before processing.',
|
|
113
113
|
},
|
|
114
|
-
|
|
115
|
-
type: 'string',
|
|
116
|
-
description: 'Brief explanation of why you are calling this tool and what you expect to learn/achieve',
|
|
117
|
-
},
|
|
114
|
+
...PROXY_PARAMS,
|
|
118
115
|
},
|
|
119
116
|
required: ['jq_query', 'file_path'],
|
|
120
117
|
},
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized proxy parameter definitions
|
|
3
|
+
* Used by both injectProxyParams and JQ tool definitions
|
|
4
|
+
*/
|
|
5
|
+
export declare const PROXY_PARAMS: {
|
|
6
|
+
readonly description: {
|
|
7
|
+
readonly type: "string";
|
|
8
|
+
readonly description: "Brief explanation of why you are calling this tool and what you expect to learn/achieve";
|
|
9
|
+
};
|
|
10
|
+
readonly isRetryAttempt: {
|
|
11
|
+
readonly type: "boolean";
|
|
12
|
+
readonly description: "Set to true if this call is a follow-up attempt after a previous failure. This includes: (1) exact retries for transient errors, (2) corrected attempts fixing typos or parameters based on error feedback. Any call attempting to achieve the same goal as a failed call is a retry.";
|
|
13
|
+
};
|
|
14
|
+
readonly originalToolId: {
|
|
15
|
+
readonly type: "string";
|
|
16
|
+
readonly description: "The tool_id from the FIRST failed attempt in this retry chain. Always reference the original tool_id, not intermediate failures. Example: if tool_id_1 fails, tool_id_2 (retry) fails, tool_id_3 (retry) succeeds - both tool_id_2 and tool_id_3 should reference tool_id_1. Required when isRetryAttempt is true.";
|
|
17
|
+
};
|
|
18
|
+
};
|
|
1
19
|
/**
|
|
2
20
|
* Configuration for the file writer module
|
|
3
21
|
*/
|
|
@@ -73,4 +91,8 @@ export interface UnifiedToolResponse {
|
|
|
73
91
|
outputContent?: unknown;
|
|
74
92
|
/** Error message if the tool call failed */
|
|
75
93
|
error?: string;
|
|
94
|
+
/** Whether this was a retry attempt */
|
|
95
|
+
isRetryAttempt?: boolean;
|
|
96
|
+
/** The original tool_id this call is retrying */
|
|
97
|
+
originalToolId?: string;
|
|
76
98
|
}
|
package/dist/types/index.js
CHANGED
|
@@ -1 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Centralized proxy parameter definitions
|
|
3
|
+
* Used by both injectProxyParams and JQ tool definitions
|
|
4
|
+
*/
|
|
5
|
+
export const PROXY_PARAMS = {
|
|
6
|
+
description: {
|
|
7
|
+
type: 'string',
|
|
8
|
+
description: 'Brief explanation of why you are calling this tool and what you expect to learn/achieve'
|
|
9
|
+
},
|
|
10
|
+
isRetryAttempt: {
|
|
11
|
+
type: 'boolean',
|
|
12
|
+
description: 'Set to true if this call is a follow-up attempt after a previous failure. This includes: (1) exact retries for transient errors, (2) corrected attempts fixing typos or parameters based on error feedback. Any call attempting to achieve the same goal as a failed call is a retry.'
|
|
13
|
+
},
|
|
14
|
+
originalToolId: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'The tool_id from the FIRST failed attempt in this retry chain. Always reference the original tool_id, not intermediate failures. Example: if tool_id_1 fails, tool_id_2 (retry) fails, tool_id_3 (retry) succeeds - both tool_id_2 and tool_id_3 should reference tool_id_1. Required when isRetryAttempt is true.'
|
|
17
|
+
}
|
|
18
|
+
};
|