@anyshift/mcp-proxy 0.6.1 → 0.6.3
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 +58 -4
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -417,6 +417,51 @@ async function main() {
|
|
|
417
417
|
console.debug('[mcp-proxy] Standalone mode - no child MCP');
|
|
418
418
|
}
|
|
419
419
|
// ------------------------------------------------------------------------
|
|
420
|
+
// 2.5. STORE ORIGINAL TOOL SCHEMAS FOR SMART PARAMETER SANITIZATION
|
|
421
|
+
// ------------------------------------------------------------------------
|
|
422
|
+
// Create a map of original tool schemas (before proxy param injection)
|
|
423
|
+
// This allows us to detect if description/isRetryAttempt/originalToolId were
|
|
424
|
+
// originally part of the child tool's schema (to handle parameter name collisions)
|
|
425
|
+
const originalToolSchemas = new Map();
|
|
426
|
+
if (childToolsResponse.tools) {
|
|
427
|
+
for (const tool of childToolsResponse.tools) {
|
|
428
|
+
const originalParams = new Set();
|
|
429
|
+
if (tool.inputSchema?.properties) {
|
|
430
|
+
for (const paramName of Object.keys(tool.inputSchema.properties)) {
|
|
431
|
+
originalParams.add(paramName);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
originalToolSchemas.set(tool.name, originalParams);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Sanitize tool arguments before forwarding to child MCP.
|
|
439
|
+
* Removes proxy parameters (description, isRetryAttempt, originalToolId)
|
|
440
|
+
* ONLY if they weren't originally part of the child tool's schema.
|
|
441
|
+
* This handles parameter name collisions gracefully.
|
|
442
|
+
*/
|
|
443
|
+
function sanitizeToolArgs(toolName, args) {
|
|
444
|
+
const originalParams = originalToolSchemas.get(toolName);
|
|
445
|
+
if (!originalParams) {
|
|
446
|
+
// If we don't have schema info, pass through all args (safer than stripping)
|
|
447
|
+
return args;
|
|
448
|
+
}
|
|
449
|
+
const sanitized = {};
|
|
450
|
+
const proxyParamNames = Object.keys(PROXY_PARAMS);
|
|
451
|
+
for (const [key, value] of Object.entries(args)) {
|
|
452
|
+
// Keep the parameter if:
|
|
453
|
+
// 1. It's NOT a proxy parameter, OR
|
|
454
|
+
// 2. It WAS in the original tool's schema (collision case)
|
|
455
|
+
if (!proxyParamNames.includes(key) || originalParams.has(key)) {
|
|
456
|
+
sanitized[key] = value;
|
|
457
|
+
}
|
|
458
|
+
else if (ENABLE_LOGGING) {
|
|
459
|
+
console.debug(`[mcp-proxy] Stripping proxy parameter '${key}' from ${toolName} call`);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return sanitized;
|
|
463
|
+
}
|
|
464
|
+
// ------------------------------------------------------------------------
|
|
420
465
|
// 3. CREATE PROXY SERVER
|
|
421
466
|
// ------------------------------------------------------------------------
|
|
422
467
|
const server = new Server({
|
|
@@ -641,12 +686,18 @@ async function main() {
|
|
|
641
686
|
if (ENABLE_LOGGING) {
|
|
642
687
|
console.debug(`[mcp-proxy] Forwarding to child MCP: ${toolName}`);
|
|
643
688
|
}
|
|
689
|
+
// Sanitize arguments: remove proxy parameters that weren't in original tool schema
|
|
690
|
+
const sanitizedArgs = sanitizeToolArgs(toolName, toolArgs);
|
|
644
691
|
result = await childClient.callTool({
|
|
645
692
|
name: toolName,
|
|
646
|
-
arguments:
|
|
693
|
+
arguments: sanitizedArgs
|
|
647
694
|
});
|
|
648
695
|
// Check if child MCP returned an error
|
|
649
696
|
const childReturnedError = !!result.isError;
|
|
697
|
+
// Preserve _meta from child response (e.g. parsed_commands) for passthrough
|
|
698
|
+
const childMeta = result._meta && typeof result._meta === 'object' && Object.keys(result._meta).length > 0
|
|
699
|
+
? result._meta
|
|
700
|
+
: undefined;
|
|
650
701
|
// Process result through file writer to get unified response
|
|
651
702
|
if (result.content && Array.isArray(result.content) && result.content.length > 0) {
|
|
652
703
|
// Extract text content and embedded resources from all content items
|
|
@@ -709,7 +760,8 @@ async function main() {
|
|
|
709
760
|
type: 'text',
|
|
710
761
|
text: JSON.stringify(createErrorResponse(tool_id, contentStr, toolArgs), null, 2)
|
|
711
762
|
}],
|
|
712
|
-
isError: true
|
|
763
|
+
isError: true,
|
|
764
|
+
...(childMeta ? { _meta: childMeta } : {})
|
|
713
765
|
};
|
|
714
766
|
}
|
|
715
767
|
// Get unified response from file writer
|
|
@@ -750,7 +802,8 @@ async function main() {
|
|
|
750
802
|
type: 'text',
|
|
751
803
|
text: JSON.stringify(unifiedResponse, null, 2)
|
|
752
804
|
}],
|
|
753
|
-
isError: !!unifiedResponse.error
|
|
805
|
+
isError: !!unifiedResponse.error,
|
|
806
|
+
...(childMeta ? { _meta: childMeta } : {})
|
|
754
807
|
};
|
|
755
808
|
}
|
|
756
809
|
}
|
|
@@ -761,7 +814,8 @@ async function main() {
|
|
|
761
814
|
type: 'text',
|
|
762
815
|
text: JSON.stringify(createContentResponse(tool_id, result, toolArgs), null, 2)
|
|
763
816
|
}],
|
|
764
|
-
isError: childReturnedError
|
|
817
|
+
isError: childReturnedError,
|
|
818
|
+
...(childMeta ? { _meta: childMeta } : {})
|
|
765
819
|
};
|
|
766
820
|
}
|
|
767
821
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anyshift/mcp-proxy",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "Generic MCP proxy that adds truncation, file writing, and JQ capabilities to any MCP server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@jest/globals": "^30.2.0",
|
|
22
|
+
"@types/glob": "^9.0.0",
|
|
22
23
|
"@types/jest": "^30.0.0",
|
|
23
24
|
"@types/node": "^22.0.0",
|
|
24
25
|
"jest": "^30.2.0",
|