fix: handle empty results in MCP keyword_search tool (#15058)

## Description

Fixes: #15038 — MCP keyword_search tool errors with "Unexpected response
type" when no results are found.

### Problem

When the MCP `keyword_search` tool returns no matching documents, the
access control `.docs()` method may return `undefined`/`null` for an
empty input array. Calling `.map()` on this value throws an error, and
the MCP framework wraps it as "Unexpected response type".

### Solution

Added a guard check after the permission filtering step. If the result
is empty or null, the tool now returns a proper informational response
instead of throwing.

### Changes

- `packages/backend/server/src/plugins/copilot/mcp/provider.ts`: Added
null/empty check before `docs.map()` in the keyword_search tool execute
function.

### Testing

- **Before**: `keyword_search` with a non-existent keyword throws
"Unexpected response type"
- **After**: `keyword_search` with a non-existent keyword returns `{
content: [{ type: 'text', text: 'No matching documents found.' }] }`


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Prevented errors when document data is missing, improving search
stability.
* Improved search feedback by displaying a clear "No matching documents
found." message instead of empty results.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Marsssssssssssdsss
2026-06-01 17:56:42 +08:00
committed by GitHub
parent ebd3e62ed9
commit 78cf402141
@@ -191,10 +191,10 @@ export class WorkspaceMcpProvider {
if (abortedAfterDocs) return abortedAfterDocs;
return {
content: docs.map(doc => ({
content: (docs?.map(doc => ({
type: 'text',
text: clearEmbeddingChunk(doc).content,
})),
})) ?? []),
};
},
});
@@ -230,11 +230,15 @@ export class WorkspaceMcpProvider {
const abortedAfterDocs = abortIfNeeded(options.signal);
if (abortedAfterDocs) return abortedAfterDocs;
if (!docs || docs.length === 0) {
return toolText('No matching documents found.');
}
return {
content: docs.map(doc => ({
content: (docs?.map(doc => ({
type: 'text',
text: JSON.stringify(pick(doc, 'docId', 'title', 'createdAt')),
})),
})) ?? []),
};
},
});