mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 06:52:47 +00:00
🪨 fix: Normalize Empty MCP Tool Descriptions to undefined for Bedrock Compat. (#13217)
* fix(agents): normalize empty MCP tool descriptions to undefined MCP servers (e.g. Asana MCP) can return tools with an empty string description. AWS Bedrock's converse API rejects toolSpec.description with length < 1, so any empty-description MCP tool caused the entire request to fail with a validation error. Convert empty strings to undefined at the two sites in loadToolDefinitions where MCP tool definitions are built. An undefined description is omitted from JSON serialization, so Bedrock never sees the empty value. OpenAI and Anthropic direct APIs are unaffected. Fixes #13209 * test(agents): add coverage for empty MCP tool description normalization Verify that loadToolDefinitions converts '' descriptions to undefined for both the sys__all__sys pattern and directly named MCP tools.
This commit is contained in:
parent
6d6ea08da4
commit
7f0fde2d98
2 changed files with 74 additions and 2 deletions
|
|
@ -553,6 +553,78 @@ describe('definitions.ts', () => {
|
|||
expect(toolDef.name).toBe('list_items_mcp_my-server');
|
||||
expect((toolDef as { serverName?: string }).serverName).toBe('my-server');
|
||||
});
|
||||
|
||||
it('should convert empty MCP tool descriptions to undefined', async () => {
|
||||
const mockServerTools = {
|
||||
no_desc_tool_mcp_asana: {
|
||||
function: {
|
||||
name: 'no_desc_tool_mcp_asana',
|
||||
description: '',
|
||||
parameters: { type: 'object', properties: {} },
|
||||
},
|
||||
},
|
||||
has_desc_tool_mcp_asana: {
|
||||
function: {
|
||||
name: 'has_desc_tool_mcp_asana',
|
||||
description: 'List tasks',
|
||||
parameters: { type: 'object', properties: {} },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
mockGetOrFetchMCPServerTools.mockResolvedValue(mockServerTools);
|
||||
|
||||
const params: LoadToolDefinitionsParams = {
|
||||
userId: 'user-123',
|
||||
agentId: 'agent-123',
|
||||
tools: ['sys__all__sys_mcp_asana'],
|
||||
};
|
||||
|
||||
const deps: LoadToolDefinitionsDeps = {
|
||||
getOrFetchMCPServerTools: mockGetOrFetchMCPServerTools,
|
||||
isBuiltInTool: mockIsBuiltInTool,
|
||||
};
|
||||
|
||||
const result = await loadToolDefinitions(params, deps);
|
||||
|
||||
const noDef = result.toolDefinitions.find((d) => d.name === 'no_desc_tool_mcp_asana');
|
||||
expect(noDef).toBeDefined();
|
||||
expect(noDef?.description).toBeUndefined();
|
||||
|
||||
const hasDef = result.toolDefinitions.find((d) => d.name === 'has_desc_tool_mcp_asana');
|
||||
expect(hasDef).toBeDefined();
|
||||
expect(hasDef?.description).toBe('List tasks');
|
||||
});
|
||||
|
||||
it('should convert empty description to undefined for directly named MCP tool', async () => {
|
||||
const toolName = 'no_desc_tool_mcp_asana';
|
||||
mockGetOrFetchMCPServerTools.mockResolvedValue({
|
||||
[toolName]: {
|
||||
function: {
|
||||
name: toolName,
|
||||
description: '',
|
||||
parameters: { type: 'object', properties: {} },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const params: LoadToolDefinitionsParams = {
|
||||
userId: 'user-123',
|
||||
agentId: 'agent-123',
|
||||
tools: [toolName],
|
||||
};
|
||||
|
||||
const deps: LoadToolDefinitionsDeps = {
|
||||
getOrFetchMCPServerTools: mockGetOrFetchMCPServerTools,
|
||||
isBuiltInTool: mockIsBuiltInTool,
|
||||
};
|
||||
|
||||
const result = await loadToolDefinitions(params, deps);
|
||||
|
||||
const def = result.toolDefinitions.find((d) => d.name === toolName);
|
||||
expect(def).toBeDefined();
|
||||
expect(def?.description).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('toolkit expansion', () => {
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ export async function loadToolDefinitions(
|
|||
if (toolDef?.function) {
|
||||
mcpToolDefs.push({
|
||||
name: actualToolName,
|
||||
description: toolDef.function.description,
|
||||
description: toolDef.function.description || undefined,
|
||||
parameters: toolDef.function.parameters
|
||||
? normalizeJsonSchema(resolveJsonSchemaRefs(toolDef.function.parameters))
|
||||
: undefined,
|
||||
|
|
@ -173,7 +173,7 @@ export async function loadToolDefinitions(
|
|||
if (toolDef?.function) {
|
||||
mcpToolDefs.push({
|
||||
name: toolName,
|
||||
description: toolDef.function.description,
|
||||
description: toolDef.function.description || undefined,
|
||||
parameters: toolDef.function.parameters
|
||||
? normalizeJsonSchema(resolveJsonSchemaRefs(toolDef.function.parameters))
|
||||
: undefined,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue