@anyshift/mcp-proxy 0.3.0 → 0.3.1
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/fileWriter/index.d.ts +4 -4
- package/dist/fileWriter/index.js +1 -1
- package/dist/fileWriter/types.d.ts +1 -1
- package/dist/fileWriter/writer.d.ts +3 -3
- package/dist/fileWriter/writer.js +58 -39
- package/dist/index.js +134 -56
- package/dist/jq/tool.js +2 -2
- package/dist/types/index.d.ts +18 -0
- package/dist/utils/filename.d.ts +8 -0
- package/dist/utils/filename.js +14 -4
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FileWriterConfig,
|
|
1
|
+
import { FileWriterConfig, UnifiedToolResponse } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Create a file writer instance with the given configuration
|
|
4
4
|
* @param config - File writer configuration
|
|
@@ -10,9 +10,9 @@ export declare function createFileWriter(config: FileWriterConfig): {
|
|
|
10
10
|
* @param toolName - Name of the tool that generated the response
|
|
11
11
|
* @param args - Arguments passed to the tool
|
|
12
12
|
* @param responseData - The response data to potentially write to file
|
|
13
|
-
* @returns
|
|
13
|
+
* @returns UnifiedToolResponse with consistent structure
|
|
14
14
|
*/
|
|
15
|
-
handleResponse: (toolName: string, args: Record<string, unknown>, responseData: unknown) => Promise<
|
|
15
|
+
handleResponse: (toolName: string, args: Record<string, unknown>, responseData: unknown) => Promise<UnifiedToolResponse>;
|
|
16
16
|
};
|
|
17
|
-
export type { FileWriterConfig, FileWriterResult } from './types.js';
|
|
17
|
+
export type { FileWriterConfig, FileWriterResult, UnifiedToolResponse } from './types.js';
|
|
18
18
|
export { generateQueryAssistSchema } from './schema.js';
|
package/dist/fileWriter/index.js
CHANGED
|
@@ -11,7 +11,7 @@ export function createFileWriter(config) {
|
|
|
11
11
|
* @param toolName - Name of the tool that generated the response
|
|
12
12
|
* @param args - Arguments passed to the tool
|
|
13
13
|
* @param responseData - The response data to potentially write to file
|
|
14
|
-
* @returns
|
|
14
|
+
* @returns UnifiedToolResponse with consistent structure
|
|
15
15
|
*/
|
|
16
16
|
handleResponse: async (toolName, args, responseData) => {
|
|
17
17
|
return handleToolResponse(config, toolName, args, responseData);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { FileWriterConfig,
|
|
1
|
+
import { FileWriterConfig, UnifiedToolResponse } from '../types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Centralized response handler with file writing capability
|
|
4
4
|
* @param config - File writer configuration
|
|
5
5
|
* @param toolName - Name of the tool that generated the response
|
|
6
6
|
* @param args - Arguments passed to the tool
|
|
7
7
|
* @param responseData - The response data to potentially write to file
|
|
8
|
-
* @returns
|
|
8
|
+
* @returns UnifiedToolResponse with consistent structure
|
|
9
9
|
*/
|
|
10
|
-
export declare function handleToolResponse(config: FileWriterConfig, toolName: string, args: Record<string, unknown>, responseData: unknown): Promise<
|
|
10
|
+
export declare function handleToolResponse(config: FileWriterConfig, toolName: string, args: Record<string, unknown>, responseData: unknown): Promise<UnifiedToolResponse>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import {
|
|
3
|
+
import { generateToolId } from '../utils/filename.js';
|
|
4
4
|
import { generateQueryAssistSchema } from './schema.js';
|
|
5
5
|
// Default minimum character count to trigger file writing
|
|
6
6
|
const DEFAULT_MIN_CHARS = 1000;
|
|
@@ -115,14 +115,23 @@ const extractContentForFile = (responseData) => {
|
|
|
115
115
|
let parsedForSchema = null;
|
|
116
116
|
if (rawText) {
|
|
117
117
|
try {
|
|
118
|
-
// Try to parse the raw text as JSON
|
|
119
|
-
let
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
118
|
+
// Try to parse the raw text directly as JSON first
|
|
119
|
+
let parsed;
|
|
120
|
+
try {
|
|
121
|
+
parsed = JSON.parse(rawText);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// If direct parsing fails, try extracting JSON from prefixed patterns
|
|
125
|
+
// like "Listed incidents: {...}" or "Queried metrics data: [...]"
|
|
126
|
+
// Only match colon at the START, before any JSON content
|
|
127
|
+
const prefixMatch = rawText.match(/^[^[{]*?:\s*(\{.*\}|\[.*\])$/s);
|
|
128
|
+
if (prefixMatch) {
|
|
129
|
+
parsed = JSON.parse(prefixMatch[1]);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
throw new Error('Could not parse as JSON');
|
|
133
|
+
}
|
|
124
134
|
}
|
|
125
|
-
const parsed = JSON.parse(jsonText);
|
|
126
135
|
parsedForSchema = parsed;
|
|
127
136
|
// Remove pagination-related fields before writing
|
|
128
137
|
const { pagination, has_more, next_page, previous_page, page, page_size, total_pages, ...cleanData } = parsed;
|
|
@@ -157,77 +166,87 @@ const extractContentForFile = (responseData) => {
|
|
|
157
166
|
* @param toolName - Name of the tool that generated the response
|
|
158
167
|
* @param args - Arguments passed to the tool
|
|
159
168
|
* @param responseData - The response data to potentially write to file
|
|
160
|
-
* @returns
|
|
169
|
+
* @returns UnifiedToolResponse with consistent structure
|
|
161
170
|
*/
|
|
162
171
|
export async function handleToolResponse(config, toolName, args, responseData) {
|
|
172
|
+
// Generate tool_id for all responses
|
|
173
|
+
const tool_id = generateToolId(toolName, args, config.toolAbbreviations);
|
|
163
174
|
// Some tools should always return directly to AI (never write to file)
|
|
164
175
|
if (toolName === 'execute_jq_query' || toolName === 'get_label_schema') {
|
|
165
|
-
|
|
176
|
+
const { contentToWrite, parsedForSchema } = extractContentForFile(responseData);
|
|
177
|
+
return {
|
|
178
|
+
tool_id,
|
|
179
|
+
wroteToFile: false,
|
|
180
|
+
outputContent: parsedForSchema ?? contentToWrite,
|
|
181
|
+
};
|
|
166
182
|
}
|
|
167
|
-
// If there's an error, return
|
|
183
|
+
// If there's an error, return error in unified format
|
|
168
184
|
if (isErrorResponse(responseData)) {
|
|
169
185
|
const errorMessage = extractErrorMessage(responseData);
|
|
170
186
|
return {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
text: `Error: ${errorMessage}`,
|
|
175
|
-
},
|
|
176
|
-
],
|
|
177
|
-
isError: true,
|
|
187
|
+
tool_id,
|
|
188
|
+
wroteToFile: false,
|
|
189
|
+
error: errorMessage,
|
|
178
190
|
};
|
|
179
191
|
}
|
|
180
|
-
// If file writing is disabled, just return the response
|
|
181
|
-
if (!config.enabled || !config.outputPath) {
|
|
182
|
-
return responseData;
|
|
183
|
-
}
|
|
184
192
|
// Extract the content that will be written to file
|
|
185
193
|
// This ensures we count the EXACT same content that will be written
|
|
186
194
|
const { contentToWrite, parsedForSchema } = extractContentForFile(responseData);
|
|
195
|
+
// If file writing is disabled, return content directly
|
|
196
|
+
if (!config.enabled || !config.outputPath) {
|
|
197
|
+
return {
|
|
198
|
+
tool_id,
|
|
199
|
+
wroteToFile: false,
|
|
200
|
+
outputContent: parsedForSchema ?? contentToWrite,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
187
203
|
// Check character count threshold - if response is too short, return directly
|
|
188
204
|
const contentLength = contentToWrite.length;
|
|
189
205
|
const minChars = config.minCharsForWrite ?? DEFAULT_MIN_CHARS;
|
|
190
206
|
if (contentLength < minChars) {
|
|
191
|
-
return
|
|
207
|
+
return {
|
|
208
|
+
tool_id,
|
|
209
|
+
wroteToFile: false,
|
|
210
|
+
outputContent: parsedForSchema ?? contentToWrite,
|
|
211
|
+
};
|
|
192
212
|
}
|
|
193
213
|
// Success case: write to file
|
|
194
214
|
try {
|
|
195
|
-
|
|
196
|
-
const filename = generateCompactFilename(toolName, args, config.toolAbbreviations);
|
|
215
|
+
const filename = `${tool_id}.json`;
|
|
197
216
|
const filepath = path.join(config.outputPath, filename);
|
|
198
217
|
// Ensure output directory exists
|
|
199
218
|
await fs.mkdir(config.outputPath, { recursive: true });
|
|
200
219
|
// Write the exact content we counted
|
|
201
220
|
await fs.writeFile(filepath, contentToWrite);
|
|
202
221
|
// Generate query-assist schema if we have valid JSON
|
|
203
|
-
let
|
|
222
|
+
let fileSchema;
|
|
204
223
|
if (parsedForSchema) {
|
|
205
224
|
// Use the clean data (without pagination) for schema analysis
|
|
206
225
|
const { pagination, has_more, next_page, previous_page, page, page_size, total_pages, ...cleanData } = parsedForSchema;
|
|
207
226
|
// Generate compact query-assist schema using config values
|
|
208
227
|
// Pass contentLength to avoid re-stringifying large payloads
|
|
209
|
-
|
|
228
|
+
fileSchema = generateQueryAssistSchema(cleanData, {
|
|
210
229
|
maxDepth: config.schemaMaxDepth ?? 2,
|
|
211
230
|
maxPaths: config.schemaMaxPaths ?? 20,
|
|
212
231
|
maxKeys: config.schemaMaxKeys ?? 50,
|
|
213
232
|
dataSize: contentLength
|
|
214
|
-
})
|
|
233
|
+
});
|
|
215
234
|
}
|
|
216
|
-
// Count lines in the content
|
|
217
|
-
const lineCount = contentToWrite.split('\n').length;
|
|
218
|
-
// Return success message with file path, size, lines, and schema
|
|
219
235
|
return {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
},
|
|
225
|
-
],
|
|
236
|
+
tool_id,
|
|
237
|
+
wroteToFile: true,
|
|
238
|
+
filePath: filepath,
|
|
239
|
+
fileSchema,
|
|
226
240
|
};
|
|
227
241
|
}
|
|
228
242
|
catch (error) {
|
|
229
|
-
// If file writing fails, return the
|
|
243
|
+
// If file writing fails, return the content directly with error note
|
|
230
244
|
console.error(`[handleToolResponse] Error writing file:`, error);
|
|
231
|
-
return
|
|
245
|
+
return {
|
|
246
|
+
tool_id,
|
|
247
|
+
wroteToFile: false,
|
|
248
|
+
outputContent: parsedForSchema ?? contentToWrite,
|
|
249
|
+
error: `File write failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
250
|
+
};
|
|
232
251
|
}
|
|
233
252
|
}
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,36 @@ import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprot
|
|
|
22
22
|
import { createJqTool } from './jq/index.js';
|
|
23
23
|
import { truncateResponseIfNeeded } from './truncation/index.js';
|
|
24
24
|
import { createFileWriter } from './fileWriter/index.js';
|
|
25
|
+
import { generateToolId } from './utils/filename.js';
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// HELPER FUNCTIONS
|
|
28
|
+
// ============================================================================
|
|
29
|
+
/**
|
|
30
|
+
* Inject 'description' parameter into a tool's inputSchema
|
|
31
|
+
* This ensures LLMs explain why they're calling each tool
|
|
32
|
+
*/
|
|
33
|
+
function injectDescriptionParam(tool) {
|
|
34
|
+
// Clone the tool to avoid mutating the original
|
|
35
|
+
const modifiedTool = { ...tool };
|
|
36
|
+
if (!modifiedTool.inputSchema) {
|
|
37
|
+
modifiedTool.inputSchema = { type: 'object', properties: {} };
|
|
38
|
+
}
|
|
39
|
+
// Clone inputSchema
|
|
40
|
+
modifiedTool.inputSchema = { ...modifiedTool.inputSchema };
|
|
41
|
+
if (!modifiedTool.inputSchema.properties) {
|
|
42
|
+
modifiedTool.inputSchema.properties = {};
|
|
43
|
+
}
|
|
44
|
+
// Clone properties
|
|
45
|
+
modifiedTool.inputSchema.properties = { ...modifiedTool.inputSchema.properties };
|
|
46
|
+
// Only add if not already present
|
|
47
|
+
if (!modifiedTool.inputSchema.properties.description) {
|
|
48
|
+
modifiedTool.inputSchema.properties.description = {
|
|
49
|
+
type: 'string',
|
|
50
|
+
description: 'Brief explanation of why you are calling this tool and what you expect to learn/achieve'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return modifiedTool;
|
|
54
|
+
}
|
|
25
55
|
/**
|
|
26
56
|
* ENVIRONMENT VARIABLE CONTRACT
|
|
27
57
|
* =============================
|
|
@@ -267,11 +297,13 @@ async function main() {
|
|
|
267
297
|
});
|
|
268
298
|
}
|
|
269
299
|
// ------------------------------------------------------------------------
|
|
270
|
-
// 5. REGISTER ALL TOOLS (CHILD + PROXY)
|
|
300
|
+
// 5. REGISTER ALL TOOLS (CHILD + PROXY) WITH DESCRIPTION INJECTION
|
|
271
301
|
// ------------------------------------------------------------------------
|
|
302
|
+
// Inject 'description' parameter into all child tools
|
|
303
|
+
const enhancedChildTools = childToolsResponse.tools.map(injectDescriptionParam);
|
|
272
304
|
const allTools = [
|
|
273
|
-
...
|
|
274
|
-
...(jqTool ? [jqTool.toolDefinition] : [])
|
|
305
|
+
...enhancedChildTools,
|
|
306
|
+
...(jqTool ? [jqTool.toolDefinition] : []) // JQ tool already has description param
|
|
275
307
|
];
|
|
276
308
|
console.debug(`[mcp-proxy] Exposing ${allTools.length} tools total (${childToolsResponse.tools.length} from child${jqTool ? ' + 1 JQ' : ''})`);
|
|
277
309
|
// ------------------------------------------------------------------------
|
|
@@ -281,13 +313,16 @@ async function main() {
|
|
|
281
313
|
return { tools: allTools };
|
|
282
314
|
});
|
|
283
315
|
// ------------------------------------------------------------------------
|
|
284
|
-
// 7. HANDLE TOOL CALL REQUESTS (WITH
|
|
316
|
+
// 7. HANDLE TOOL CALL REQUESTS (WITH UNIFIED RESPONSE FORMAT)
|
|
285
317
|
// ------------------------------------------------------------------------
|
|
286
318
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
287
319
|
const toolName = request.params.name;
|
|
288
320
|
const toolArgs = request.params.arguments || {};
|
|
289
321
|
if (ENABLE_LOGGING) {
|
|
290
322
|
console.debug(`[mcp-proxy] Tool call: ${toolName}`);
|
|
323
|
+
if (toolArgs.description) {
|
|
324
|
+
console.debug(`[mcp-proxy] Description: ${toolArgs.description}`);
|
|
325
|
+
}
|
|
291
326
|
}
|
|
292
327
|
try {
|
|
293
328
|
let result;
|
|
@@ -299,73 +334,116 @@ async function main() {
|
|
|
299
334
|
result = await jqTool.handler({
|
|
300
335
|
params: { arguments: toolArgs }
|
|
301
336
|
});
|
|
337
|
+
// JQ tool returns directly, wrap in unified format
|
|
338
|
+
const tool_id = generateToolId(toolName, toolArgs, fileWriterConfig.toolAbbreviations);
|
|
339
|
+
const unifiedResponse = {
|
|
340
|
+
tool_id,
|
|
341
|
+
wroteToFile: false,
|
|
342
|
+
outputContent: result.content?.[0]?.text
|
|
343
|
+
};
|
|
344
|
+
return {
|
|
345
|
+
content: [{
|
|
346
|
+
type: 'text',
|
|
347
|
+
text: JSON.stringify(unifiedResponse, null, 2)
|
|
348
|
+
}],
|
|
349
|
+
isError: result.isError
|
|
350
|
+
};
|
|
302
351
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
});
|
|
352
|
+
// Forward all other tools to child MCP (if child exists)
|
|
353
|
+
if (!childClient) {
|
|
354
|
+
const tool_id = generateToolId(toolName, toolArgs, fileWriterConfig.toolAbbreviations);
|
|
355
|
+
const errorResponse = {
|
|
356
|
+
tool_id,
|
|
357
|
+
wroteToFile: false,
|
|
358
|
+
error: `Tool ${toolName} not available in standalone mode (no child MCP)`
|
|
359
|
+
};
|
|
360
|
+
return {
|
|
361
|
+
content: [{
|
|
362
|
+
type: 'text',
|
|
363
|
+
text: JSON.stringify(errorResponse, null, 2)
|
|
364
|
+
}],
|
|
365
|
+
isError: true
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
if (ENABLE_LOGGING) {
|
|
369
|
+
console.debug(`[mcp-proxy] Forwarding to child MCP: ${toolName}`);
|
|
321
370
|
}
|
|
322
|
-
|
|
371
|
+
result = await childClient.callTool({
|
|
372
|
+
name: toolName,
|
|
373
|
+
arguments: toolArgs
|
|
374
|
+
});
|
|
375
|
+
// Process result through file writer to get unified response
|
|
323
376
|
if (result.content && Array.isArray(result.content) && result.content.length > 0) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
if (
|
|
333
|
-
|
|
334
|
-
content: [{ type: 'text', text: item.text }]
|
|
335
|
-
});
|
|
336
|
-
// Check if file was actually written (file reference returned)
|
|
337
|
-
if (fileResult && fileResult.content && Array.isArray(fileResult.content) &&
|
|
338
|
-
fileResult.content.length > 0 && fileResult.content[0].type === 'text') {
|
|
339
|
-
const resultText = fileResult.content[0].text;
|
|
340
|
-
// File reference contains "📄 File:" - this means file was written
|
|
341
|
-
if (resultText.includes('📄 File:')) {
|
|
342
|
-
item.text = resultText;
|
|
343
|
-
fileWasWritten = true;
|
|
344
|
-
if (ENABLE_LOGGING) {
|
|
345
|
-
console.debug(`[mcp-proxy] File writing applied for ${toolName} (${originalLength} chars written to file)`);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
377
|
+
const item = result.content[0];
|
|
378
|
+
if (item.type === 'text' && typeof item.text === 'string') {
|
|
379
|
+
const originalLength = item.text.length;
|
|
380
|
+
// Get unified response from file writer
|
|
381
|
+
const unifiedResponse = await fileWriter.handleResponse(toolName, toolArgs, {
|
|
382
|
+
content: [{ type: 'text', text: item.text }]
|
|
383
|
+
});
|
|
384
|
+
if (ENABLE_LOGGING) {
|
|
385
|
+
if (unifiedResponse.wroteToFile) {
|
|
386
|
+
console.debug(`[mcp-proxy] File written for ${toolName} (${originalLength} chars) → ${unifiedResponse.filePath}`);
|
|
349
387
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
388
|
+
else {
|
|
389
|
+
console.debug(`[mcp-proxy] Response for ${toolName} (${originalLength} chars) returned directly`);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// If not written to file, apply truncation to outputContent
|
|
393
|
+
if (!unifiedResponse.wroteToFile && unifiedResponse.outputContent) {
|
|
394
|
+
const contentStr = typeof unifiedResponse.outputContent === 'string'
|
|
395
|
+
? unifiedResponse.outputContent
|
|
396
|
+
: JSON.stringify(unifiedResponse.outputContent);
|
|
397
|
+
const truncated = truncateResponseIfNeeded(truncationConfig, contentStr);
|
|
398
|
+
if (truncated.length < contentStr.length) {
|
|
399
|
+
if (ENABLE_LOGGING) {
|
|
400
|
+
console.debug(`[mcp-proxy] Truncated response: ${contentStr.length} → ${truncated.length} chars`);
|
|
401
|
+
}
|
|
402
|
+
// Re-parse if it was JSON, otherwise keep as string
|
|
403
|
+
try {
|
|
404
|
+
unifiedResponse.outputContent = JSON.parse(truncated);
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
unifiedResponse.outputContent = truncated;
|
|
356
408
|
}
|
|
357
409
|
}
|
|
358
410
|
}
|
|
411
|
+
// Return unified response as JSON
|
|
412
|
+
return {
|
|
413
|
+
content: [{
|
|
414
|
+
type: 'text',
|
|
415
|
+
text: JSON.stringify(unifiedResponse, null, 2)
|
|
416
|
+
}],
|
|
417
|
+
isError: !!unifiedResponse.error
|
|
418
|
+
};
|
|
359
419
|
}
|
|
360
420
|
}
|
|
361
|
-
return result
|
|
421
|
+
// Fallback: return result with generated tool_id
|
|
422
|
+
const tool_id = generateToolId(toolName, toolArgs, fileWriterConfig.toolAbbreviations);
|
|
423
|
+
const fallbackResponse = {
|
|
424
|
+
tool_id,
|
|
425
|
+
wroteToFile: false,
|
|
426
|
+
outputContent: result
|
|
427
|
+
};
|
|
428
|
+
return {
|
|
429
|
+
content: [{
|
|
430
|
+
type: 'text',
|
|
431
|
+
text: JSON.stringify(fallbackResponse, null, 2)
|
|
432
|
+
}]
|
|
433
|
+
};
|
|
362
434
|
}
|
|
363
435
|
catch (error) {
|
|
364
436
|
console.error(`[mcp-proxy] Error executing tool ${toolName}:`, error);
|
|
437
|
+
const tool_id = generateToolId(toolName, toolArgs, fileWriterConfig.toolAbbreviations);
|
|
438
|
+
const errorResponse = {
|
|
439
|
+
tool_id,
|
|
440
|
+
wroteToFile: false,
|
|
441
|
+
error: `Error executing ${toolName}: ${error.message || String(error)}`
|
|
442
|
+
};
|
|
365
443
|
return {
|
|
366
444
|
content: [{
|
|
367
445
|
type: 'text',
|
|
368
|
-
text:
|
|
446
|
+
text: JSON.stringify(errorResponse, null, 2)
|
|
369
447
|
}],
|
|
370
448
|
isError: true
|
|
371
449
|
};
|
package/dist/jq/tool.js
CHANGED
|
@@ -12,7 +12,7 @@ export const ExecuteJqQuerySchema = z.object({
|
|
|
12
12
|
description: z
|
|
13
13
|
.string()
|
|
14
14
|
.optional()
|
|
15
|
-
.describe('
|
|
15
|
+
.describe('Brief explanation of why you are calling this tool and what you expect to learn/achieve'),
|
|
16
16
|
});
|
|
17
17
|
/**
|
|
18
18
|
* Tool definition for JQ query execution with enhanced prompts
|
|
@@ -113,7 +113,7 @@ export const JQ_TOOL_DEFINITION = {
|
|
|
113
113
|
},
|
|
114
114
|
description: {
|
|
115
115
|
type: 'string',
|
|
116
|
-
description: '
|
|
116
|
+
description: 'Brief explanation of why you are calling this tool and what you expect to learn/achieve',
|
|
117
117
|
},
|
|
118
118
|
},
|
|
119
119
|
required: ['jq_query', 'file_path'],
|
package/dist/types/index.d.ts
CHANGED
|
@@ -56,3 +56,21 @@ export interface NullableFields {
|
|
|
56
56
|
/** Fields that can be null (mixed types) */
|
|
57
57
|
nullable: string[];
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Unified response format for all tool calls
|
|
61
|
+
* Provides a consistent structure for LLM consumption
|
|
62
|
+
*/
|
|
63
|
+
export interface UnifiedToolResponse {
|
|
64
|
+
/** LLM-friendly unique identifier for this tool call */
|
|
65
|
+
tool_id: string;
|
|
66
|
+
/** Whether the response was written to a file */
|
|
67
|
+
wroteToFile: boolean;
|
|
68
|
+
/** Path to the file (only present if wroteToFile is true) */
|
|
69
|
+
filePath?: string;
|
|
70
|
+
/** Schema/structure guide for the data (only present if wroteToFile is true) */
|
|
71
|
+
fileSchema?: string;
|
|
72
|
+
/** The actual response content (only present if wroteToFile is false) */
|
|
73
|
+
outputContent?: unknown;
|
|
74
|
+
/** Error message if the tool call failed */
|
|
75
|
+
error?: string;
|
|
76
|
+
}
|
package/dist/utils/filename.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate LLM-friendly tool ID (without file extension)
|
|
3
|
+
* @param toolName - Name of the tool that generated the data
|
|
4
|
+
* @param args - Arguments passed to the tool
|
|
5
|
+
* @param toolAbbreviations - Optional custom abbreviations for tool names
|
|
6
|
+
* @returns Tool ID like "1697834567123_met_qry_a3b4c5"
|
|
7
|
+
*/
|
|
8
|
+
export declare const generateToolId: (toolName: string, args: Record<string, unknown>, toolAbbreviations?: Record<string, string>) => string;
|
|
1
9
|
/**
|
|
2
10
|
* Generate LLM-friendly compact filename
|
|
3
11
|
* @param toolName - Name of the tool that generated the data
|
package/dist/utils/filename.js
CHANGED
|
@@ -28,15 +28,25 @@ const hashArgs = (args) => {
|
|
|
28
28
|
.substring(0, 6);
|
|
29
29
|
};
|
|
30
30
|
/**
|
|
31
|
-
* Generate LLM-friendly
|
|
31
|
+
* Generate LLM-friendly tool ID (without file extension)
|
|
32
32
|
* @param toolName - Name of the tool that generated the data
|
|
33
33
|
* @param args - Arguments passed to the tool
|
|
34
34
|
* @param toolAbbreviations - Optional custom abbreviations for tool names
|
|
35
|
-
* @returns
|
|
35
|
+
* @returns Tool ID like "1697834567123_met_qry_a3b4c5"
|
|
36
36
|
*/
|
|
37
|
-
export const
|
|
37
|
+
export const generateToolId = (toolName, args, toolAbbreviations) => {
|
|
38
38
|
const timestamp = generateCompactTimestamp();
|
|
39
39
|
const toolAbbrev = toolAbbreviations?.[toolName] || toolName.substring(0, 6);
|
|
40
40
|
const argsHash = hashArgs(args);
|
|
41
|
-
return `${timestamp}_${toolAbbrev}_${argsHash}
|
|
41
|
+
return `${timestamp}_${toolAbbrev}_${argsHash}`;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Generate LLM-friendly compact filename
|
|
45
|
+
* @param toolName - Name of the tool that generated the data
|
|
46
|
+
* @param args - Arguments passed to the tool
|
|
47
|
+
* @param toolAbbreviations - Optional custom abbreviations for tool names
|
|
48
|
+
* @returns Compact filename like "1697834567123_met_qry_a3b4c5.json"
|
|
49
|
+
*/
|
|
50
|
+
export const generateCompactFilename = (toolName, args, toolAbbreviations) => {
|
|
51
|
+
return `${generateToolId(toolName, args, toolAbbreviations)}.json`;
|
|
42
52
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anyshift/mcp-proxy",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
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",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"README.md"
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
16
|
+
"@modelcontextprotocol/sdk": "^1.24.0",
|
|
17
17
|
"zod": "^3.24.2"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|