feat: Add cleanInputSchema function to remove $schema field from inputSchema (#255)

This commit is contained in:
samanhappy
2025-08-05 13:45:52 +08:00
committed by GitHub
parent f63f06d879
commit 48bcf9f5f0
2 changed files with 118 additions and 4 deletions

View File

@@ -0,0 +1,102 @@
describe('Schema Cleanup Tests', () => {
describe('cleanInputSchema functionality', () => {
// Helper function to simulate the cleanInputSchema behavior
const cleanInputSchema = (schema: any): any => {
if (!schema || typeof schema !== 'object') {
return schema;
}
const cleanedSchema = { ...schema };
delete cleanedSchema.$schema;
return cleanedSchema;
};
test('should remove $schema field from inputSchema', () => {
const schemaWithDollarSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'object',
properties: {
name: {
type: 'string',
description: 'Test property',
},
},
required: ['name'],
};
const cleanedSchema = cleanInputSchema(schemaWithDollarSchema);
expect(cleanedSchema).not.toHaveProperty('$schema');
expect(cleanedSchema.type).toBe('object');
expect(cleanedSchema.properties).toEqual({
name: {
type: 'string',
description: 'Test property',
},
});
expect(cleanedSchema.required).toEqual(['name']);
});
test('should handle null and undefined schemas', () => {
expect(cleanInputSchema(null)).toBe(null);
expect(cleanInputSchema(undefined)).toBe(undefined);
});
test('should handle non-object schemas', () => {
expect(cleanInputSchema('string')).toBe('string');
expect(cleanInputSchema(42)).toBe(42);
expect(cleanInputSchema(true)).toBe(true);
});
test('should preserve other properties while removing $schema', () => {
const complexSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'object',
title: 'Test Schema',
description: 'A test schema',
properties: {
name: { type: 'string' },
age: { type: 'number' },
},
required: ['name'],
additionalProperties: false,
};
const cleanedSchema = cleanInputSchema(complexSchema);
expect(cleanedSchema).not.toHaveProperty('$schema');
expect(cleanedSchema.type).toBe('object');
expect(cleanedSchema.title).toBe('Test Schema');
expect(cleanedSchema.description).toBe('A test schema');
expect(cleanedSchema.properties).toEqual({
name: { type: 'string' },
age: { type: 'number' },
});
expect(cleanedSchema.required).toEqual(['name']);
expect(cleanedSchema.additionalProperties).toBe(false);
});
test('should handle schemas without $schema field', () => {
const schemaWithoutDollarSchema = {
type: 'object',
properties: {
name: { type: 'string' },
},
};
const cleanedSchema = cleanInputSchema(schemaWithoutDollarSchema);
expect(cleanedSchema).toEqual(schemaWithoutDollarSchema);
expect(cleanedSchema).not.toHaveProperty('$schema');
});
test('should handle empty objects', () => {
const emptySchema = {};
const cleanedSchema = cleanInputSchema(emptySchema);
expect(cleanedSchema).toEqual({});
expect(cleanedSchema).not.toHaveProperty('$schema');
});
});
});

View File

@@ -99,6 +99,18 @@ export const syncToolEmbedding = async (serverName: string, toolName: string) =>
saveToolsAsVectorEmbeddings(serverName, [tool]);
};
// Helper function to clean $schema field from inputSchema
const cleanInputSchema = (schema: any): any => {
if (!schema || typeof schema !== 'object') {
return schema;
}
const cleanedSchema = { ...schema };
delete cleanedSchema.$schema;
return cleanedSchema;
};
// Store all server information
let serverInfos: ServerInfo[] = [];
@@ -272,7 +284,7 @@ const callToolWithReconnect = async (
serverInfo.tools = tools.tools.map((tool) => ({
name: `${serverInfo.name}-${tool.name}`,
description: tool.description || '',
inputSchema: tool.inputSchema || {},
inputSchema: cleanInputSchema(tool.inputSchema || {}),
}));
// Save tools as vector embeddings for search
@@ -391,7 +403,7 @@ export const initializeClientsFromSettings = async (isInit: boolean): Promise<Se
const mcpTools: ToolInfo[] = openApiTools.map((tool) => ({
name: `${name}-${tool.name}`,
description: tool.description,
inputSchema: tool.inputSchema,
inputSchema: cleanInputSchema(tool.inputSchema),
}));
// Update server info with successful initialization
@@ -472,7 +484,7 @@ export const initializeClientsFromSettings = async (isInit: boolean): Promise<Se
serverInfo.tools = tools.tools.map((tool) => ({
name: `${name}-${tool.name}`,
description: tool.description || '',
inputSchema: tool.inputSchema || {},
inputSchema: cleanInputSchema(tool.inputSchema || {}),
}));
serverInfo.status = 'connected';
serverInfo.error = null;
@@ -924,7 +936,7 @@ export const handleCallToolRequest = async (request: any, extra: any) => {
return {
name: result.toolName,
description: result.description || '',
inputSchema: result.inputSchema || {},
inputSchema: cleanInputSchema(result.inputSchema || {}),
};
})
.filter((tool) => {