Skip to content

Commit 42e9a3d

Browse files
committed
fix: promote key prompt parameters from optional to required
Make databasePath, language, queryPath, and sarifPath required where the prompt depends on them. VS Code now correctly marks these fields as required in the slash-command input dialog.
1 parent d0427c6 commit 42e9a3d

5 files changed

Lines changed: 247 additions & 311 deletions

File tree

extensions/vscode/test/suite/mcp-prompt-e2e.integration.test.ts

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ suite('MCP Prompt Error Handling Integration Tests', () => {
126126
const result = await client.getPrompt({
127127
name: 'explain_codeql_query',
128128
arguments: {
129+
databasePath: 'nonexistent/database',
129130
queryPath: 'nonexistent/path/to/query.ql',
130131
language: 'javascript',
131132
},
@@ -153,6 +154,7 @@ suite('MCP Prompt Error Handling Integration Tests', () => {
153154
const result = await client.getPrompt({
154155
name: 'explain_codeql_query',
155156
arguments: {
157+
databasePath: existingFile,
156158
queryPath: existingFile,
157159
language: 'javascript',
158160
},
@@ -183,6 +185,7 @@ suite('MCP Prompt Error Handling Integration Tests', () => {
183185
const result = await client.getPrompt({
184186
name: 'explain_codeql_query',
185187
arguments: {
188+
databasePath: '/some/db',
186189
queryPath: '/some/query.ql',
187190
language: 'rust',
188191
},
@@ -322,22 +325,25 @@ suite('MCP Prompt Error Handling Integration Tests', () => {
322325
console.log('[mcp-prompt-e2e] sarif_rank_false_positives correctly warned for nonexistent path');
323326
});
324327

325-
test('sarif_rank_false_positives with no arguments should return content without warning', async function () {
328+
test('sarif_rank_false_positives with no arguments should reject missing sarifPath', async function () {
326329
this.timeout(15_000);
327330

328-
const result = await client.getPrompt({
329-
name: 'sarif_rank_false_positives',
330-
arguments: {},
331-
});
332-
333-
const text = getFirstMessageText(result);
334-
// With no file paths provided, there should be no file-not-found warning.
335-
assert.ok(
336-
!text.includes('does not exist'),
337-
`Response should not contain path warnings when no paths given. Got:\n${text.slice(0, 500)}`,
338-
);
331+
// sarifPath is required; SDK should reject with a clear error.
332+
try {
333+
await client.getPrompt({
334+
name: 'sarif_rank_false_positives',
335+
arguments: {},
336+
});
337+
assert.fail('Should have thrown for missing required sarifPath');
338+
} catch (error: unknown) {
339+
const msg = error instanceof Error ? error.message : String(error);
340+
assert.ok(
341+
msg.includes('sarifPath') || msg.includes('Required'),
342+
`Error should mention the missing field. Got: ${msg.slice(0, 500)}`,
343+
);
344+
}
339345

340-
console.log('[mcp-prompt-e2e] sarif_rank_false_positives returned clean response with no args');
346+
console.log('[mcp-prompt-e2e] sarif_rank_false_positives correctly rejected missing sarifPath');
341347
});
342348

343349
// ─────────────────────────────────────────────────────────────────────
@@ -389,25 +395,28 @@ suite('MCP Prompt Error Handling Integration Tests', () => {
389395
});
390396

391397
// ─────────────────────────────────────────────────────────────────────
392-
// All prompts with all-optional params should handle empty args gracefully
398+
// Prompts with required fields should return validation error on empty args
393399
// ─────────────────────────────────────────────────────────────────────
394400

395-
test('ql_tdd_basic with empty arguments should return content without errors', async function () {
401+
test('ql_tdd_basic with empty arguments should reject missing language', async function () {
396402
this.timeout(15_000);
397403

398-
const result = await client.getPrompt({
399-
name: 'ql_tdd_basic',
400-
arguments: {},
401-
});
402-
403-
const text = getFirstMessageText(result);
404-
assert.ok(text.length > 0, 'Should return non-empty content');
405-
assert.ok(
406-
!text.includes('does not exist'),
407-
'Should not contain path warnings with no args',
408-
);
404+
// language is required; SDK should reject with a clear error.
405+
try {
406+
await client.getPrompt({
407+
name: 'ql_tdd_basic',
408+
arguments: {},
409+
});
410+
assert.fail('Should have thrown for missing required language');
411+
} catch (error: unknown) {
412+
const msg = error instanceof Error ? error.message : String(error);
413+
assert.ok(
414+
msg.includes('language') || msg.includes('Required'),
415+
`Error should mention the missing field. Got: ${msg.slice(0, 500)}`,
416+
);
417+
}
409418

410-
console.log('[mcp-prompt-e2e] ql_tdd_basic returned clean response with empty args');
419+
console.log('[mcp-prompt-e2e] ql_tdd_basic correctly rejected missing language');
411420
});
412421

413422
test('run_query_and_summarize_false_positives with nonexistent queryPath should return warning', async function () {

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

Lines changed: 38 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -64516,23 +64516,23 @@ var workshopCreationWorkflowSchema = external_exports.object({
6451664516
numStages: external_exports.coerce.number().optional().describe("Number of incremental stages (default: 4-8)")
6451764517
});
6451864518
var qlTddBasicSchema = external_exports.object({
64519-
language: external_exports.enum(SUPPORTED_LANGUAGES).optional().describe("Programming language for the query (optional)"),
64519+
language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Programming language for the query"),
6452064520
queryName: external_exports.string().optional().describe("Name of the query to develop")
6452164521
});
6452264522
var qlTddAdvancedSchema = external_exports.object({
6452364523
database: external_exports.string().optional().describe("Path to the CodeQL database for analysis"),
64524-
language: external_exports.enum(SUPPORTED_LANGUAGES).optional().describe("Programming language for the query (optional)"),
64524+
language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Programming language for the query"),
6452564525
queryName: external_exports.string().optional().describe("Name of the query to develop")
6452664526
});
6452764527
var sarifRankSchema = external_exports.object({
6452864528
queryId: external_exports.string().optional().describe("CodeQL query/rule identifier"),
64529-
sarifPath: external_exports.string().optional().describe("Path to the SARIF file to analyze")
64529+
sarifPath: external_exports.string().describe("Path to the SARIF file to analyze")
6453064530
});
6453164531
var describeFalsePositivesSchema = external_exports.object({
64532-
queryPath: external_exports.string().optional().describe("Path to the CodeQL query file")
64532+
queryPath: external_exports.string().describe("Path to the CodeQL query file")
6453364533
});
6453464534
var explainCodeqlQuerySchema = external_exports.object({
64535-
databasePath: external_exports.string().optional().describe("Optional path to a real CodeQL database for profiling"),
64535+
databasePath: external_exports.string().describe("Path to a CodeQL database for profiling"),
6453664536
language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Programming language of the query"),
6453764537
queryPath: external_exports.string().describe("Path to the CodeQL query file (.ql or .qlref)")
6453864538
});
@@ -64552,8 +64552,8 @@ var findOverlappingQueriesSchema = external_exports.object({
6455264552
packRoot: external_exports.string().optional().describe("Directory containing codeql-pack.yml for the pack that will own the new query")
6455364553
});
6455464554
var qlLspIterativeDevelopmentSchema = external_exports.object({
64555-
language: external_exports.enum(SUPPORTED_LANGUAGES).optional().describe("Programming language for the query"),
64556-
queryPath: external_exports.string().optional().describe("Path to the query file being developed"),
64555+
language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Programming language for the query"),
64556+
queryPath: external_exports.string().describe("Path to the query file being developed"),
6455764557
workspaceUri: external_exports.string().optional().describe("Workspace URI for LSP dependency resolution")
6455864558
});
6455964559
function toPermissiveShape(shape) {
@@ -64769,17 +64769,13 @@ ${content}`
6476964769
async ({ language, queryName }) => {
6477064770
const template = loadPromptTemplate("ql-tdd-basic.prompt.md");
6477164771
let contextSection = "## Your Development Context\n\n";
64772-
if (language) {
64773-
contextSection += `- **Language**: ${language}
64772+
contextSection += `- **Language**: ${language}
6477464773
`;
64775-
}
6477664774
if (queryName) {
6477764775
contextSection += `- **Query Name**: ${queryName}
6477864776
`;
6477964777
}
64780-
if (language || queryName) {
64781-
contextSection += "\n";
64782-
}
64778+
contextSection += "\n";
6478364779
return {
6478464780
messages: [
6478564781
{
@@ -64811,10 +64807,8 @@ ${content}`
6481164807
if (dbResult.warning) warnings.push(dbResult.warning);
6481264808
}
6481364809
let contextSection = "## Your Development Context\n\n";
64814-
if (language) {
64815-
contextSection += `- **Language**: ${language}
64810+
contextSection += `- **Language**: ${language}
6481664811
`;
64817-
}
6481864812
if (queryName) {
6481964813
contextSection += `- **Query Name**: ${queryName}
6482064814
`;
@@ -64823,9 +64817,7 @@ ${content}`
6482364817
contextSection += `- **Database**: ${resolvedDatabase}
6482464818
`;
6482564819
}
64826-
if (language || queryName || resolvedDatabase) {
64827-
contextSection += "\n";
64828-
}
64820+
contextSection += "\n";
6482964821
const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
6483064822
return {
6483164823
messages: [
@@ -64851,24 +64843,17 @@ ${content}`
6485164843
async ({ queryId, sarifPath }) => {
6485264844
const template = loadPromptTemplate("sarif-rank-false-positives.prompt.md");
6485364845
const warnings = [];
64854-
let resolvedSarifPath = sarifPath;
64855-
if (sarifPath) {
64856-
const spResult = resolvePromptFilePath(sarifPath);
64857-
resolvedSarifPath = spResult.resolvedPath;
64858-
if (spResult.warning) warnings.push(spResult.warning);
64859-
}
64846+
const spResult = resolvePromptFilePath(sarifPath);
64847+
const resolvedSarifPath = spResult.resolvedPath;
64848+
if (spResult.warning) warnings.push(spResult.warning);
6486064849
let contextSection = "## Analysis Context\n\n";
6486164850
if (queryId) {
6486264851
contextSection += `- **Query ID**: ${queryId}
6486364852
`;
6486464853
}
64865-
if (resolvedSarifPath) {
64866-
contextSection += `- **SARIF File**: ${resolvedSarifPath}
64854+
contextSection += `- **SARIF File**: ${resolvedSarifPath}
6486764855
`;
64868-
}
64869-
if (queryId || resolvedSarifPath) {
64870-
contextSection += "\n";
64871-
}
64856+
contextSection += "\n";
6487264857
const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
6487364858
return {
6487464859
messages: [
@@ -64894,24 +64879,17 @@ ${content}`
6489464879
async ({ queryId, sarifPath }) => {
6489564880
const template = loadPromptTemplate("sarif-rank-true-positives.prompt.md");
6489664881
const warnings = [];
64897-
let resolvedSarifPath = sarifPath;
64898-
if (sarifPath) {
64899-
const spResult = resolvePromptFilePath(sarifPath);
64900-
resolvedSarifPath = spResult.resolvedPath;
64901-
if (spResult.warning) warnings.push(spResult.warning);
64902-
}
64882+
const spResult = resolvePromptFilePath(sarifPath);
64883+
const resolvedSarifPath = spResult.resolvedPath;
64884+
if (spResult.warning) warnings.push(spResult.warning);
6490364885
let contextSection = "## Analysis Context\n\n";
6490464886
if (queryId) {
6490564887
contextSection += `- **Query ID**: ${queryId}
6490664888
`;
6490764889
}
64908-
if (resolvedSarifPath) {
64909-
contextSection += `- **SARIF File**: ${resolvedSarifPath}
64890+
contextSection += `- **SARIF File**: ${resolvedSarifPath}
6491064891
`;
64911-
}
64912-
if (queryId || resolvedSarifPath) {
64913-
contextSection += "\n";
64914-
}
64892+
contextSection += "\n";
6491564893
const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
6491664894
return {
6491764895
messages: [
@@ -64937,18 +64915,14 @@ ${content}`
6493764915
async ({ queryPath }) => {
6493864916
const template = loadPromptTemplate("run-query-and-summarize-false-positives.prompt.md");
6493964917
const warnings = [];
64940-
let resolvedQueryPath = queryPath;
64941-
if (queryPath) {
64942-
const qpResult = resolvePromptFilePath(queryPath);
64943-
resolvedQueryPath = qpResult.resolvedPath;
64944-
if (qpResult.warning) warnings.push(qpResult.warning);
64945-
}
64946-
let contextSection = "## Analysis Context\n\n";
64947-
if (resolvedQueryPath) {
64948-
contextSection += `- **Query Path**: ${resolvedQueryPath}
64918+
const qpResult = resolvePromptFilePath(queryPath);
64919+
const resolvedQueryPath = qpResult.resolvedPath;
64920+
if (qpResult.warning) warnings.push(qpResult.warning);
64921+
const contextSection = `## Analysis Context
64922+
64923+
- **Query Path**: ${resolvedQueryPath}
64924+
6494964925
`;
64950-
}
64951-
contextSection += "\n";
6495264926
const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
6495364927
return {
6495464928
messages: [
@@ -64977,21 +64951,16 @@ ${content}`
6497764951
const qpResult = resolvePromptFilePath(queryPath);
6497864952
const resolvedQueryPath = qpResult.resolvedPath;
6497964953
if (qpResult.warning) warnings.push(qpResult.warning);
64980-
let resolvedDatabasePath = databasePath;
64981-
if (databasePath) {
64982-
const dbResult = resolvePromptFilePath(databasePath);
64983-
resolvedDatabasePath = dbResult.resolvedPath;
64984-
if (dbResult.warning) warnings.push(dbResult.warning);
64985-
}
64954+
const dbResult = resolvePromptFilePath(databasePath);
64955+
const resolvedDatabasePath = dbResult.resolvedPath;
64956+
if (dbResult.warning) warnings.push(dbResult.warning);
6498664957
let contextSection = "## Query to Explain\n\n";
6498764958
contextSection += `- **Query Path**: ${resolvedQueryPath}
6498864959
`;
6498964960
contextSection += `- **Language**: ${language}
6499064961
`;
64991-
if (resolvedDatabasePath) {
64992-
contextSection += `- **Database Path**: ${resolvedDatabasePath}
64962+
contextSection += `- **Database Path**: ${resolvedDatabasePath}
6499364963
`;
64994-
}
6499564964
contextSection += "\n";
6499664965
const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
6499764966
return {
@@ -65102,34 +65071,25 @@ ${workspaceUri ? `- **Workspace URI**: ${workspaceUri}
6510265071
async ({ language, queryPath, workspaceUri }) => {
6510365072
const template = loadPromptTemplate("ql-lsp-iterative-development.prompt.md");
6510465073
const warnings = [];
65105-
let resolvedQueryPath = queryPath;
65106-
if (queryPath) {
65107-
const qpResult = resolvePromptFilePath(queryPath);
65108-
resolvedQueryPath = qpResult.resolvedPath;
65109-
if (qpResult.warning) warnings.push(qpResult.warning);
65110-
}
65074+
const qpResult = resolvePromptFilePath(queryPath);
65075+
const resolvedQueryPath = qpResult.resolvedPath;
65076+
if (qpResult.warning) warnings.push(qpResult.warning);
6511165077
let resolvedWorkspaceUri = workspaceUri;
6511265078
if (workspaceUri) {
6511365079
const wsResult = resolvePromptFilePath(workspaceUri);
6511465080
resolvedWorkspaceUri = wsResult.resolvedPath;
6511565081
if (wsResult.warning) warnings.push(wsResult.warning);
6511665082
}
6511765083
let contextSection = "## Your Development Context\n\n";
65118-
if (language) {
65119-
contextSection += `- **Language**: ${language}
65084+
contextSection += `- **Language**: ${language}
6512065085
`;
65121-
}
65122-
if (resolvedQueryPath) {
65123-
contextSection += `- **Query Path**: ${resolvedQueryPath}
65086+
contextSection += `- **Query Path**: ${resolvedQueryPath}
6512465087
`;
65125-
}
6512665088
if (resolvedWorkspaceUri) {
6512765089
contextSection += `- **Workspace URI**: ${resolvedWorkspaceUri}
6512865090
`;
6512965091
}
65130-
if (language || resolvedQueryPath || resolvedWorkspaceUri) {
65131-
contextSection += "\n";
65132-
}
65092+
contextSection += "\n";
6513365093
const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
6513465094
return {
6513565095
messages: [

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.

0 commit comments

Comments
 (0)