Skip to content

Commit 6fbfa7e

Browse files
Copilotdata-douser
andauthored
Remove grep from cache tools; fix annotation_search API to FTS semantics; always apply SARIF path for SARIF format
Agent-Logs-Url: https://github.com/advanced-security/codeql-development-mcp-server/sessions/219712ee-4c28-4b51-9da5-961020112e6e Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com>
1 parent 1adaf6d commit 6fbfa7e

File tree

6 files changed

+30
-43
lines changed

6 files changed

+30
-43
lines changed

server/dist/codeql-development-mcp-server.js

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -185639,7 +185639,7 @@ var SqliteStore = class _SqliteStore {
185639185639
return null;
185640185640
}
185641185641
/**
185642-
* Retrieve a subset of cached result content via line range, grep, or maxLines.
185642+
* Retrieve a subset of cached result content via line range or maxLines.
185643185643
*/
185644185644
getCacheContentSubset(cacheKey2, options) {
185645185645
const fullContent = this.getCacheContent(cacheKey2);
@@ -185654,10 +185654,6 @@ var SqliteStore = class _SqliteStore {
185654185654
const endIdx = Math.min(totalLines, end);
185655185655
selectedLines = selectedLines.slice(startIdx, endIdx);
185656185656
}
185657-
if (options.grep) {
185658-
const term = options.grep.toLowerCase();
185659-
selectedLines = selectedLines.filter((line) => line.toLowerCase().includes(term));
185660-
}
185661185657
const truncated = selectedLines.length > maxLines;
185662185658
if (truncated) {
185663185659
selectedLines = selectedLines.slice(0, maxLines);
@@ -195400,16 +195396,16 @@ function registerAnnotationDeleteTool(server) {
195400195396
function registerAnnotationSearchTool(server) {
195401195397
server.tool(
195402195398
"annotation_search",
195403-
"Substring search across annotation content, metadata, and labels (case-insensitive SQL LIKE matching).",
195399+
'Full-text search across annotation content, metadata, and labels using SQLite FTS (token-based MATCH; use * suffix for prefix matching, e.g. "vulnerab*").',
195404195400
{
195405-
query: external_exports.string().describe("Search term \u2014 matched as a substring against content, metadata, and label."),
195401+
search: external_exports.string().describe("Full-text search query matched against annotation content, metadata, and label (SQLite FTS MATCH syntax; use * for prefix matching)."),
195406195402
category: external_exports.string().optional().describe("Restrict search to a specific category."),
195407195403
limit: external_exports.number().optional().describe("Maximum number of results (default: 50).")
195408195404
},
195409-
async ({ query, category, limit }) => {
195405+
async ({ search, category, limit }) => {
195410195406
const store = sessionDataManager.getStore();
195411195407
const results = store.listAnnotations({
195412-
search: query,
195408+
search,
195413195409
category,
195414195410
limit: limit ?? 50
195415195411
});
@@ -195625,24 +195621,23 @@ function registerQueryResultsCacheLookupTool(server) {
195625195621
function registerQueryResultsCacheRetrieveTool(server) {
195626195622
server.tool(
195627195623
"query_results_cache_retrieve",
195628-
"Retrieve cached query results with optional subset selection. Supports line ranges (for graphtext/CSV), SARIF result indices, file filtering, and text search to return only the relevant portion.",
195624+
"Retrieve cached query results with optional subset selection. Supports line ranges (for graphtext/CSV) and SARIF result indices and file filtering to return only the relevant portion.",
195629195625
{
195630195626
cacheKey: external_exports.string().describe("The cache key of the result to retrieve."),
195631-
lineRange: external_exports.tuple([external_exports.number(), external_exports.number()]).optional().describe("Line range [start, end] (1-indexed). For graphtext/CSV output."),
195632-
resultIndices: external_exports.tuple([external_exports.number(), external_exports.number()]).optional().describe("SARIF result index range [start, end] (0-indexed, inclusive)."),
195627+
lineRange: external_exports.tuple([external_exports.number(), external_exports.number()]).optional().describe("Line range [start, end] (1-indexed, inclusive). For graphtext/CSV output only."),
195628+
resultIndices: external_exports.tuple([external_exports.number(), external_exports.number()]).optional().describe("SARIF result index range [start, end] (0-indexed, inclusive). For SARIF output only."),
195633195629
fileFilter: external_exports.string().optional().describe("For SARIF: only include results whose file path contains this string."),
195634-
grep: external_exports.string().optional().describe("Text search filter: only include lines/results containing this term."),
195635195630
maxLines: external_exports.number().optional().describe("Maximum number of lines to return for line-based formats (default: 500)."),
195636195631
maxResults: external_exports.number().optional().describe("Maximum number of SARIF results to return (default: 100).")
195637195632
},
195638-
async ({ cacheKey: cacheKey2, lineRange, resultIndices, fileFilter, grep, maxLines, maxResults }) => {
195633+
async ({ cacheKey: cacheKey2, lineRange, resultIndices, fileFilter, maxLines, maxResults }) => {
195639195634
const store = sessionDataManager.getStore();
195640195635
const meta = store.getCacheEntryMeta(cacheKey2);
195641195636
if (!meta) {
195642195637
return { content: [{ type: "text", text: `No cached result found for key: ${cacheKey2}` }] };
195643195638
}
195644195639
const isSarif = meta.outputFormat.includes("sarif");
195645-
if (isSarif && (resultIndices || fileFilter)) {
195640+
if (isSarif) {
195646195641
const subset2 = store.getCacheSarifSubset(cacheKey2, {
195647195642
resultIndices,
195648195643
fileFilter,
@@ -195676,7 +195671,6 @@ function registerQueryResultsCacheRetrieveTool(server) {
195676195671
}
195677195672
const subset = store.getCacheContentSubset(cacheKey2, {
195678195673
lineRange,
195679-
grep,
195680195674
maxLines: maxLines ?? 500
195681195675
});
195682195676
if (!subset) {

server/dist/codeql-development-mcp-server.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/src/lib/sqlite-store.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -662,13 +662,12 @@ export class SqliteStore {
662662
}
663663

664664
/**
665-
* Retrieve a subset of cached result content via line range, grep, or maxLines.
665+
* Retrieve a subset of cached result content via line range or maxLines.
666666
*/
667667
getCacheContentSubset(
668668
cacheKey: string,
669669
options: {
670670
lineRange?: [number, number];
671-
grep?: string;
672671
maxLines?: number;
673672
},
674673
): { content: string; totalLines: number; returnedLines: number; truncated: boolean } | null {
@@ -687,11 +686,6 @@ export class SqliteStore {
687686
selectedLines = selectedLines.slice(startIdx, endIdx);
688687
}
689688

690-
if (options.grep) {
691-
const term = options.grep.toLowerCase();
692-
selectedLines = selectedLines.filter(line => line.toLowerCase().includes(term));
693-
}
694-
695689
const truncated = selectedLines.length > maxLines;
696690
if (truncated) {
697691
selectedLines = selectedLines.slice(0, maxLines);

server/src/tools/annotation-tools.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,16 @@ function registerAnnotationDeleteTool(server: McpServer): void {
166166
function registerAnnotationSearchTool(server: McpServer): void {
167167
server.tool(
168168
'annotation_search',
169-
'Substring search across annotation content, metadata, and labels (case-insensitive SQL LIKE matching).',
169+
'Full-text search across annotation content, metadata, and labels using SQLite FTS (token-based MATCH; use * suffix for prefix matching, e.g. "vulnerab*").',
170170
{
171-
query: z.string().describe('Search term — matched as a substring against content, metadata, and label.'),
171+
search: z.string().describe('Full-text search query matched against annotation content, metadata, and label (SQLite FTS MATCH syntax; use * for prefix matching).'),
172172
category: z.string().optional().describe('Restrict search to a specific category.'),
173173
limit: z.number().optional().describe('Maximum number of results (default: 50).'),
174174
},
175-
async ({ query, category, limit }) => {
175+
async ({ search, category, limit }) => {
176176
const store = sessionDataManager.getStore();
177177
const results = store.listAnnotations({
178-
search: query,
178+
search,
179179
category,
180180
limit: limit ?? 50,
181181
});

server/src/tools/cache-tools.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,27 +80,27 @@ function registerQueryResultsCacheLookupTool(server: McpServer): void {
8080
function registerQueryResultsCacheRetrieveTool(server: McpServer): void {
8181
server.tool(
8282
'query_results_cache_retrieve',
83-
'Retrieve cached query results with optional subset selection. Supports line ranges (for graphtext/CSV), SARIF result indices, file filtering, and text search to return only the relevant portion.',
83+
'Retrieve cached query results with optional subset selection. Supports line ranges (for graphtext/CSV) and SARIF result indices and file filtering to return only the relevant portion.',
8484
{
8585
cacheKey: z.string().describe('The cache key of the result to retrieve.'),
86-
lineRange: z.tuple([z.number(), z.number()]).optional().describe('Line range [start, end] (1-indexed). For graphtext/CSV output.'),
87-
resultIndices: z.tuple([z.number(), z.number()]).optional().describe('SARIF result index range [start, end] (0-indexed, inclusive).'),
86+
lineRange: z.tuple([z.number(), z.number()]).optional().describe('Line range [start, end] (1-indexed, inclusive). For graphtext/CSV output only.'),
87+
resultIndices: z.tuple([z.number(), z.number()]).optional().describe('SARIF result index range [start, end] (0-indexed, inclusive). For SARIF output only.'),
8888
fileFilter: z.string().optional().describe('For SARIF: only include results whose file path contains this string.'),
89-
grep: z.string().optional().describe('Text search filter: only include lines/results containing this term.'),
9089
maxLines: z.number().optional().describe('Maximum number of lines to return for line-based formats (default: 500).'),
9190
maxResults: z.number().optional().describe('Maximum number of SARIF results to return (default: 100).'),
9291
},
93-
async ({ cacheKey, lineRange, resultIndices, fileFilter, grep, maxLines, maxResults }) => {
92+
async ({ cacheKey, lineRange, resultIndices, fileFilter, maxLines, maxResults }) => {
9493
const store = sessionDataManager.getStore();
9594
const meta = store.getCacheEntryMeta(cacheKey);
9695

9796
if (!meta) {
9897
return { content: [{ type: 'text' as const, text: `No cached result found for key: ${cacheKey}` }] };
9998
}
10099

101-
// For SARIF format with SARIF-specific filters, use SARIF subset retrieval
100+
// SARIF format: always use the SARIF-aware subset retrieval so that
101+
// maxResults is applied and result-level filters (indices, file path) work correctly.
102102
const isSarif = meta.outputFormat.includes('sarif');
103-
if (isSarif && (resultIndices || fileFilter)) {
103+
if (isSarif) {
104104
const subset = store.getCacheSarifSubset(cacheKey, {
105105
resultIndices,
106106
fileFilter,
@@ -134,10 +134,9 @@ function registerQueryResultsCacheRetrieveTool(server: McpServer): void {
134134
};
135135
}
136136

137-
// Line-based subset for graphtext, CSV, or any text format
137+
// Line-based subset for graphtext, CSV, or any other text format.
138138
const subset = store.getCacheContentSubset(cacheKey, {
139139
lineRange,
140-
grep,
141140
maxLines: maxLines ?? 500,
142141
});
143142
if (!subset) {

server/test/src/lib/sqlite-store.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -291,9 +291,9 @@ describe('SqliteStore', () => {
291291
expect(subset!.totalLines).toBe(6); // 5 lines + trailing newline
292292
});
293293

294-
it('should retrieve subset by grep', () => {
294+
it('should retrieve subset by maxLines without lineRange', () => {
295295
store.putCacheEntry({
296-
cacheKey: 'grep',
296+
cacheKey: 'nolimit',
297297
queryName: 'PrintAST',
298298
queryPath: '/p.ql',
299299
databasePath: '/db',
@@ -303,11 +303,11 @@ describe('SqliteStore', () => {
303303
resultContent: 'Function foo\n Param x\nFunction bar\n Param y\n',
304304
});
305305

306-
const subset = store.getCacheContentSubset('grep', { grep: 'Function' });
306+
const subset = store.getCacheContentSubset('nolimit', { maxLines: 2 });
307307
expect(subset).not.toBeNull();
308308
expect(subset!.returnedLines).toBe(2);
309-
expect(subset!.content).toContain('Function foo');
310-
expect(subset!.content).toContain('Function bar');
309+
expect(subset!.truncated).toBe(true);
310+
expect(subset!.content).toBe('Function foo\n Param x');
311311
});
312312

313313
it('should enforce maxLines cap', () => {

0 commit comments

Comments
 (0)