This document provides detailed guidance on using CodeQL Development MCP Server tools to create workshop materials.
find_codeql_query_files- Locate query files and related resourcesexplain_codeql_query- Understand query purpose and implementationcodeql_resolve_metadata- Extract query metadata
codeql_test_extract- Create test databasescodeql_test_run- Execute query testscodeql_test_accept- Update expected results
codeql_query_run- Run queries against databasescodeql_query_compile- Validate query syntaxcodeql_bqrs_interpret- Generate output from query results
codeql_database_create- Create CodeQL databasescodeql_resolve_database- Validate database structure
Use find_codeql_query_files to locate all files related to a source query:
{
"queryPath": "/path/to/production/Query.ql"
}Returns:
{
"queryFile": "/path/to/production/Query.ql",
"testDirectory": "/path/to/production/test/QueryTest/",
"testFiles": ["test.cpp", "QueryTest.expected", "QueryTest.qlref"],
"metadata": {
"name": "Find unsafe pointers",
"kind": "problem",
"id": "cpp/unsafe-pointer"
}
}Use explain_codeql_query to understand query logic:
{
"queryPath": "/path/to/production/Query.ql"
}Returns natural language explanation of:
- Query purpose
- Key predicates and their roles
- Data flow configurations
- Sources and sinks
- Filter conditions
Use this to plan workshop stages and decomposition.
Use codeql_resolve_metadata to get structured metadata:
{
"queryPath": "/path/to/production/Query.ql"
}Returns:
{
"name": "Find unsafe pointers",
"description": "Identifies potentially unsafe pointer usage",
"kind": "problem",
"problem.severity": "warning",
"id": "cpp/unsafe-pointer",
"precision": "high"
}Use codeql_test_extract to create databases for test directories:
{
"testPath": "<workshop_dir>/exercises-tests/Exercise1",
"searchPath": ["<workshop_dir>/exercises"]
}This creates Exercise1.testproj/ in the test directory.
For solutions tests:
{
"testPath": "<workshop_dir>/solutions-tests/Exercise1",
"searchPath": ["<workshop_dir>/solutions"]
}Use codeql_resolve_database to check database structure:
{
"database": "<workshop_dir>/exercises-tests/Exercise1/Exercise1.testproj"
}Returns database metadata including language and source root.
Use codeql_test_run to execute query tests:
{
"testPath": "<workshop_dir>/solutions-tests/Exercise1",
"searchPath": ["<workshop_dir>/solutions"]
}Returns:
{
"passed": true,
"failures": [],
"testCases": 1,
"duration": "1.2s"
}For failed tests:
{
"passed": false,
"failures": [
{
"test": "Exercise1",
"expected": 5,
"actual": 3,
"diff": "Expected result at line 10 missing"
}
]
}Test entire directories:
{
"testPath": "<workshop_dir>/solutions-tests",
"searchPath": ["<workshop_dir>/solutions"]
}Use codeql_test_accept when actual results are correct:
{
"testPath": "<workshop_dir>/solutions-tests/Exercise1",
"searchPath": ["<workshop_dir>/solutions"]
}This updates Exercise1.expected with actual results.
Use with caution: Only accept results after validating they are correct.
Use codeql_query_compile to check queries compile:
{
"query": "<workshop_dir>/solutions/Exercise1.ql",
"searchPath": ["<workshop_dir>/solutions"]
}Returns compilation errors if any:
{
"success": false,
"errors": [
{
"message": "Cannot resolve type 'Foo'",
"location": {
"file": "Exercise1.ql",
"line": 10,
"column": 5
}
}
]
}Use codeql_query_run to execute queries:
{
"query": "<workshop_dir>/solutions/Exercise1.ql",
"database": "<workshop_dir>/solutions-tests/Exercise1/Exercise1.testproj",
"searchPath": ["<workshop_dir>/solutions"],
"outputFormat": "sarif-latest"
}Returns path to BQRS results file.
Use predefined tool queries for AST generation:
{
"queryName": "PrintAST",
"queryLanguage": "cpp",
"database": "<workshop_dir>/tests-common/test.testproj",
"searchPath": [],
"outputFormat": "bqrs"
}Generate control flow graphs:
{
"queryName": "PrintCFG",
"queryLanguage": "cpp",
"database": "<workshop_dir>/tests-common/test.testproj",
"searchPath": [],
"outputFormat": "bqrs"
}Use codeql_bqrs_interpret to convert BQRS to graphtext:
{
"file": "/path/to/results.bqrs",
"format": "graphtext",
"output": "<workshop_dir>/graphs/Exercise1-ast.txt"
}For specific result sets:
{
"file": "/path/to/results.bqrs",
"format": "graphtext",
"output": "<workshop_dir>/graphs/Exercise1-ast.txt",
"t": ["kind=graph", "id=ast"]
}{
"file": "/path/to/results.bqrs",
"format": "csv",
"output": "<workshop_dir>/results/Exercise1-results.csv"
}{
"file": "/path/to/results.bqrs",
"format": "sarif-latest",
"output": "<workshop_dir>/results/Exercise1-results.sarif"
}// Pseudocode showing workflow steps - actual tool invocation varies by implementation
// 1. Find all query files
const queryFiles = await find_codeql_query_files({
queryPath: sourceQueryPath
});
// 2. Explain query logic
const explanation = await explain_codeql_query({
queryPath: sourceQueryPath
});
// 3. Extract metadata
const metadata = await codeql_resolve_metadata({
queryPath: sourceQueryPath
});
// Use this information to plan stages// Create directories (use file system operations)
// Create codeql-pack.yml files
// Create codeql-workspace.ymlFor each stage (working backwards from complete query):
// 1. Create solution query file (filesystem)
// 2. Compile to validate syntax
await codeql_query_compile({
query: `<workshop_dir>/solutions/Exercise${n}.ql`,
searchPath: ['<workshop_dir>/solutions']
});
// 3. Create test files (filesystem)
// 4. Extract test database
await codeql_test_extract({
testPath: `<workshop_dir>/solutions-tests/Exercise${n}`,
searchPath: ['<workshop_dir>/solutions']
});
// 5. Run query to get actual results
await codeql_query_run({
query: `<workshop_dir>/solutions/Exercise${n}.ql`,
database: `<workshop_dir>/solutions-tests/Exercise${n}/Exercise${n}.testproj`,
searchPath: ['<workshop_dir>/solutions']
});
// 6. Run tests
const testResults = await codeql_test_run({
testPath: `<workshop_dir>/solutions-tests/Exercise${n}`,
searchPath: ['<workshop_dir>/solutions']
});
// 7. If needed, accept results
if (!testResults.passed) {
// Review actual results, validate correctness
await codeql_test_accept({
testPath: `<workshop_dir>/solutions-tests/Exercise${n}`,
searchPath: ['<workshop_dir>/solutions']
});
}For each stage:
// 1. Copy solution to exercise (filesystem)
// 2. Remove implementation details (filesystem)
// 3. Add TODO comments and hints (filesystem)
// 4. Create or copy test files
// 5. Extract test database
await codeql_test_extract({
testPath: `<workshop_dir>/exercises-tests/Exercise${n}`,
searchPath: ['<workshop_dir>/exercises']
});
// 6. Optionally compile to check syntax
await codeql_query_compile({
query: `<workshop_dir>/exercises/Exercise${n}.ql`,
searchPath: ['<workshop_dir>/exercises']
});For stages where AST/CFG helpful:
// 1. Run PrintAST
const astResults = await codeql_query_run({
queryName: 'PrintAST',
queryLanguage: language,
database: `<workshop_dir>/tests-common/test.testproj`,
outputFormat: 'bqrs'
});
// 2. Interpret to graphtext
await codeql_bqrs_interpret({
file: astResults.bqrsPath,
format: 'graphtext',
output: `<workshop_dir>/graphs/Exercise${n}-ast.txt`
});
// 3. Run PrintCFG
const cfgResults = await codeql_query_run({
queryName: 'PrintCFG',
queryLanguage: language,
database: `<workshop_dir>/tests-common/test.testproj`,
outputFormat: 'bqrs'
});
// 4. Interpret to graphtext
await codeql_bqrs_interpret({
file: cfgResults.bqrsPath,
format: 'graphtext',
output: `<workshop_dir>/graphs/Exercise${n}-cfg.txt`
});// Test all solutions
const solutionsResults = await codeql_test_run({
testPath: '<workshop_dir>/solutions-tests',
searchPath: ['<workshop_dir>/solutions']
});
if (!solutionsResults.passed) {
// Handle failures - investigate and fix
}
// Verify exercises compile
for (let n = 1; n <= stageCount; n++) {
await codeql_query_compile({
query: `<workshop_dir>/exercises/Exercise${n}.ql`,
searchPath: ['<workshop_dir>/exercises']
});
}const compileResult = await codeql_query_compile({
query: queryPath,
searchPath: [searchPath]
});
if (!compileResult.success) {
for (const error of compileResult.errors) {
console.error(`${error.location.file}:${error.location.line}: ${error.message}`);
}
// Fix errors and retry
}const testResult = await codeql_test_run({
testPath: testPath,
searchPath: [searchPath]
});
if (!testResult.passed) {
for (const failure of testResult.failures) {
console.error(`Test ${failure.test} failed:`);
console.error(` Expected ${failure.expected} results, got ${failure.actual}`);
console.error(` Diff: ${failure.diff}`);
}
// Review actual results
// If correct, accept them:
await codeql_test_accept({
testPath: testPath,
searchPath: [searchPath]
});
}try {
const dbInfo = await codeql_resolve_database({
database: databasePath
});
} catch (error) {
console.error(`Database validation failed: ${error.message}`);
// Re-extract database
await codeql_test_extract({
testPath: testPath,
searchPath: [searchPath]
});
}For creating a single workshop stage:
find_codeql_query_files(analyze source)explain_codeql_query(understand logic)- Create solution query file
codeql_query_compile(validate syntax)- Create test files
codeql_test_extract(create database)codeql_query_run(execute query)codeql_test_run(validate results)codeql_test_accept(if needed)- Create exercise query file
codeql_query_compile(validate exercise)- Generate graphs if needed
Some operations can be parallelized:
Safe to parallelize:
- Compiling multiple queries
- Running tests for different stages
- Generating graphs for different stages
Must be sequential:
- Extract database before running tests
- Compile before running query
- Run query before interpreting results
- Reuse test databases when test code is identical
- Create shared databases in tests-common/
- Only extract when test code changes
Run tests for entire directories:
// Instead of running each test individually
await codeql_test_run({
testPath: '<workshop_dir>/solutions-tests',
searchPath: ['<workshop_dir>/solutions']
});Store BQRS files for reuse:
const bqrsPath = await codeql_query_run({...});
// Interpret same BQRS to multiple formats
await codeql_bqrs_interpret({ file: bqrsPath, format: "csv", ... });
await codeql_bqrs_interpret({ file: bqrsPath, format: "sarif-latest", ... });
await codeql_bqrs_interpret({ file: bqrsPath, format: "graphtext", ... });Issue: .qlref file has wrong path
Solution: Ensure path is relative to exercises/ or solutions/ directory:
Exercise1.ql # Not ../Exercise1.ql or /abs/path/Exercise1.ql
Issue: Database not extracted
Solution: Run codeql_test_extract before codeql_test_run
Issue: Syntax errors or missing dependencies
Solution:
- Check
codeql-pack.ymlhas correct dependencies - Run
codeql pack install - Review compilation error messages
Issue: Query behavior changed or expected results outdated
Solution:
- Review actual results from test run
- Validate correctness
- Use
codeql_test_acceptto update if correct
Compile queries before considering them complete:
await codeql_query_compile({
query: queryPath,
searchPath: [searchPath]
});Test each stage as you create it:
await codeql_test_run({
testPath: stageTestPath,
searchPath: [searchPath]
});Use searchPath to resolve dependencies:
{
query: queryPath,
searchPath: [
workshopDir + "/solutions",
workshopDir + "/common"
]
}When accepting test results, document why:
// Accepting results after validating:
// - All 5 expected array accesses are found
// - No false positives in output
// - Edge cases handled correctly
await codeql_test_accept({...});- CodeQL CLI Documentation
- SKILL.md - Main workshop creation skill
- Workshop Structure Reference
- Example Workshops