Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ _Changes on `main` since the latest tagged release that have not yet been includ

- **Annotation, audit, cache, and SARIF tools are now always enabled** β€” Removed the `ENABLE_ANNOTATION_TOOLS` opt-in gate; all annotation, audit, query result cache, and SARIF analysis tools are registered by default. The `ENABLE_ANNOTATION_TOOLS` environment variable no longer controls tool availability; when set to `false`, it only disables the related auto-caching behaviour in result processing. ([#223](https://github.com/advanced-security/codeql-development-mcp-server/pull/223))
- **Go-based `ql-mcp-client` rewrite** β€” Replaced the Node.js `ql-mcp-client.js` integration test runner with a Go CLI (`gh-ql-mcp-client`) built with Cobra and `mcp-go`. Adds `list tools/prompts/resources` commands and assertion-based integration test validation. ([#223](https://github.com/advanced-security/codeql-development-mcp-server/pull/223))
- **Code Scanning lifecycle management** β€” Added `code-scanning list-analyses`, `list-alerts`, and `download-analysis` subcommands to `gh-ql-mcp-client` with GitHub REST API integration via `go-gh`. Added `sarif` parent subcommand for SARIF delegation workflows. Enhanced SARIF tools with `sarif_store` (session cache ingest), `sarif_deduplicate_rules` (cross-file rule deduplication), and `fingerprint` overlap mode with automatic fallback. ([#234](https://github.com/advanced-security/codeql-development-mcp-server/pull/234))
- **Persistent MRVA workflow state and caching** β€” Introduced a new `SqliteStore` backend plus annotation, audit, and query result cache tools to support the next phase of MCP-assisted CodeQL development and `seclab-taskflow-agent` integration. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169))
Comment thread
data-douser marked this conversation as resolved.
- **Rust language support** β€” Added first-class Rust support with `PrintAST`, `PrintCFG`, `CallGraphFrom`, `CallGraphTo`, and `CallGraphFromTo` queries, bringing the total supported languages to 10. ([#195](https://github.com/advanced-security/codeql-development-mcp-server/pull/195))
- **Bug fixes and design improvements from recent evaluation sessions** β€” Fixed 5 bugs across `bqrs_interpret`, `bqrs_info`, `annotation_search`, `audit_add_notes`, and `query_results_cache_compare`; added `database_analyze` auto-caching and per-database mutex serialization; auto-enabled annotation tools in VS Code extension. ([#199](https://github.com/advanced-security/codeql-development-mcp-server/pull/199))
Expand All @@ -29,12 +30,13 @@ _Changes on `main` since the latest tagged release that have not yet been includ

#### MCP Server Tools

| Tool | Description |
| ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `annotation_create`, `annotation_get`, `annotation_list`, `annotation_update`, `annotation_delete`, `annotation_search` | General-purpose annotation tools for creating, managing, and searching notes and bookmarks on analysis entities. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
| `audit_store_findings`, `audit_list_findings`, `audit_add_notes`, `audit_clear_repo` | Repo-keyed audit tools for MRVA finding management and triage workflows. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
| `query_results_cache_lookup`, `query_results_cache_retrieve`, `query_results_cache_clear`, `query_results_cache_compare` | Query result cache tools for lookup, subset retrieval, cache clearing, and cross-database comparison. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
| `sarif_list_rules`, `sarif_extract_rule`, `sarif_rule_to_markdown`, `sarif_compare_alerts`, `sarif_diff_runs` | SARIF analysis tools for rule discovery, per-rule extraction, Mermaid dataflow visualization, alert overlap comparison, and cross-run behavioral diffing. ([#204](https://github.com/advanced-security/codeql-development-mcp-server/pull/204)) |
| Tool | Description |
| ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `annotation_create`, `annotation_get`, `annotation_list`, `annotation_update`, `annotation_delete`, `annotation_search` | General-purpose annotation tools for creating, managing, and searching notes and bookmarks on analysis entities. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
| `audit_store_findings`, `audit_list_findings`, `audit_add_notes`, `audit_clear_repo` | Repo-keyed audit tools for MRVA finding management and triage workflows. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
| `query_results_cache_lookup`, `query_results_cache_retrieve`, `query_results_cache_clear`, `query_results_cache_compare` | Query result cache tools for lookup, subset retrieval, cache clearing, and cross-database comparison. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
| `sarif_list_rules`, `sarif_extract_rule`, `sarif_rule_to_markdown`, `sarif_compare_alerts`, `sarif_diff_runs` | SARIF analysis tools for rule discovery, per-rule extraction, Mermaid dataflow visualization, alert overlap comparison, and cross-run behavioral diffing. ([#204](https://github.com/advanced-security/codeql-development-mcp-server/pull/204)) |
| `sarif_store`, `sarif_deduplicate_rules` | SARIF session cache ingest and cross-file rule deduplication tools. `sarif_compare_alerts` enhanced with `fingerprint` overlap mode with automatic fallback to full-path comparison. ([#234](https://github.com/advanced-security/codeql-development-mcp-server/pull/234)) |

#### MCP Server Resources

Expand All @@ -58,6 +60,8 @@ _Changes on `main` since the latest tagged release that have not yet been includ

- Added Rust coverage to CI and release workflows, including query unit tests and VSIX bundling. ([#195](https://github.com/advanced-security/codeql-development-mcp-server/pull/195))
- Added client integration tests for the new Rust queries and for the annotation, audit, and cache tool suites, including an MRVA triage workflow end-to-end test. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169), [#195](https://github.com/advanced-security/codeql-development-mcp-server/pull/195))
- Added `code-scanning` and `sarif` subcommand groups to `gh-ql-mcp-client` with GitHub REST API client integration via `go-gh` for Code Scanning alert lifecycle management. ([#234](https://github.com/advanced-security/codeql-development-mcp-server/pull/234))
- Added `gh` extension packaging support with cross-compilation targets for `darwin/amd64`, `darwin/arm64`, `linux/amd64`, `linux/arm64`, `windows/amd64`. ([#234](https://github.com/advanced-security/codeql-development-mcp-server/pull/234))

### Changed

Expand Down
17 changes: 17 additions & 0 deletions client/cmd/code_scanning.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cmd

import "github.com/spf13/cobra"

var codeScanningCmd = &cobra.Command{
Use: "code-scanning",
Aliases: []string{"cs"},
Short: "Manage Code Scanning analyses and alerts",
Long: "Commands for listing, downloading, dismissing, and reopening Code Scanning analyses and alerts via the GitHub REST API.",
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}

func init() {
rootCmd.AddCommand(codeScanningCmd)
}
81 changes: 81 additions & 0 deletions client/cmd/code_scanning_download_analysis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package cmd

import (
"encoding/json"
"fmt"
"os"
"path/filepath"

gh "github.com/advanced-security/codeql-development-mcp-server/client/internal/github"
"github.com/spf13/cobra"
)

var downloadAnalysisCmd = &cobra.Command{
Use: "download-analysis",
Short: "Download a Code Scanning analysis as SARIF",
RunE: runDownloadAnalysis,
}

var downloadAnalysisFlags struct {
repo string
analysisID int
output string
}

func init() {
codeScanningCmd.AddCommand(downloadAnalysisCmd)

f := downloadAnalysisCmd.Flags()
f.StringVar(&downloadAnalysisFlags.repo, "repo", "", "Repository in owner/repo format (required)")
f.IntVar(&downloadAnalysisFlags.analysisID, "analysis-id", 0, "Analysis ID to download (required)")
f.StringVar(&downloadAnalysisFlags.output, "output", "", "Output file path (default: sarif-downloads/<repo>/<id>.sarif)")

_ = downloadAnalysisCmd.MarkFlagRequired("repo")
_ = downloadAnalysisCmd.MarkFlagRequired("analysis-id")
}

func runDownloadAnalysis(cmd *cobra.Command, _ []string) error {
owner, repo, err := parseRepo(downloadAnalysisFlags.repo)
if err != nil {
return err
}

client, err := gh.NewClient()
if err != nil {
return err
}

sarif, err := client.GetAnalysisSARIF(owner, repo, downloadAnalysisFlags.analysisID)
if err != nil {
return err
}

// Determine output path
outPath := downloadAnalysisFlags.output
if outPath == "" {
outPath = filepath.Join("sarif-downloads", fmt.Sprintf("%s_%s", owner, repo),
fmt.Sprintf("%d.sarif", downloadAnalysisFlags.analysisID))
}

// Ensure directory exists
if err := os.MkdirAll(filepath.Dir(outPath), 0o750); err != nil {
return fmt.Errorf("create output directory: %w", err)
}

// Pretty-print the JSON
var pretty json.RawMessage
if err := json.Unmarshal(sarif, &pretty); err != nil {
// If not valid JSON, write as-is
if writeErr := os.WriteFile(outPath, sarif, 0o600); writeErr != nil {
return fmt.Errorf("write SARIF file: %w", writeErr)
}
} else {
formatted, _ := json.MarshalIndent(pretty, "", " ")
if err := os.WriteFile(outPath, formatted, 0o600); err != nil {
return fmt.Errorf("write SARIF file: %w", err)
}
}

fmt.Fprintf(cmd.OutOrStdout(), "Downloaded SARIF to %s (%d bytes)\n", outPath, len(sarif))
return nil
}
86 changes: 86 additions & 0 deletions client/cmd/code_scanning_list_alerts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package cmd

import (
"encoding/json"
"fmt"
"text/tabwriter"

gh "github.com/advanced-security/codeql-development-mcp-server/client/internal/github"
"github.com/spf13/cobra"
)

var listAlertsCmd = &cobra.Command{
Use: "list-alerts",
Short: "List Code Scanning alerts for a repository",
RunE: runListAlerts,
}

var listAlertsFlags struct {
repo string
ref string
state string
severity string
toolName string
sort string
direction string
perPage int
}

func init() {
codeScanningCmd.AddCommand(listAlertsCmd)

f := listAlertsCmd.Flags()
f.StringVar(&listAlertsFlags.repo, "repo", "", "Repository in owner/repo format (required)")
f.StringVar(&listAlertsFlags.ref, "ref", "", "Git ref to filter by")
f.StringVar(&listAlertsFlags.state, "state", "", "Alert state: open, closed, dismissed, fixed")
f.StringVar(&listAlertsFlags.severity, "severity", "", "Severity: critical, high, medium, low, warning, note, error")
f.StringVar(&listAlertsFlags.toolName, "tool-name", "", "Tool name to filter by")
f.StringVar(&listAlertsFlags.sort, "sort", "", "Sort by (created, updated)")
f.StringVar(&listAlertsFlags.direction, "direction", "", "Sort direction (asc, desc)")
f.IntVar(&listAlertsFlags.perPage, "per-page", 30, "Results per page (max 100)")

_ = listAlertsCmd.MarkFlagRequired("repo")
}

func runListAlerts(cmd *cobra.Command, _ []string) error {
owner, repo, err := parseRepo(listAlertsFlags.repo)
if err != nil {
return err
}

client, err := gh.NewClient()
if err != nil {
return err
}

alerts, err := client.ListAlerts(gh.ListAlertsOptions{
Owner: owner,
Repo: repo,
Ref: listAlertsFlags.ref,
State: listAlertsFlags.state,
Severity: listAlertsFlags.severity,
ToolName: listAlertsFlags.toolName,
Sort: listAlertsFlags.sort,
Direction: listAlertsFlags.direction,
PerPage: listAlertsFlags.perPage,
})
if err != nil {
return err
}

if OutputFormat() == "json" {
enc := json.NewEncoder(cmd.OutOrStdout())
enc.SetIndent("", " ")
return enc.Encode(alerts)
}

w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 4, 2, ' ', 0)
fmt.Fprintln(w, "NUM\tSTATE\tRULE\tSEVERITY\tFILE:LINE\tCREATED")
for _, a := range alerts {
loc := a.MostRecentInstance.Location
locStr := fmt.Sprintf("%s:%d", loc.Path, loc.StartLine)
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%s\n",
a.Number, a.State, a.Rule.ID, a.Rule.Severity, locStr, a.CreatedAt)
}
return w.Flush()
}
81 changes: 81 additions & 0 deletions client/cmd/code_scanning_list_analyses.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package cmd

import (
"encoding/json"
"fmt"
"text/tabwriter"

gh "github.com/advanced-security/codeql-development-mcp-server/client/internal/github"
"github.com/spf13/cobra"
)

var listAnalysesCmd = &cobra.Command{
Use: "list-analyses",
Short: "List Code Scanning analyses for a repository",
RunE: runListAnalyses,
}

var listAnalysesFlags struct {
repo string
ref string
toolName string
sarifID string
sort string
direction string
perPage int
}

func init() {
codeScanningCmd.AddCommand(listAnalysesCmd)

f := listAnalysesCmd.Flags()
f.StringVar(&listAnalysesFlags.repo, "repo", "", "Repository in owner/repo format (required)")
f.StringVar(&listAnalysesFlags.ref, "ref", "", "Git ref to filter by")
f.StringVar(&listAnalysesFlags.toolName, "tool-name", "", "Tool name to filter by (e.g. CodeQL)")
f.StringVar(&listAnalysesFlags.sarifID, "sarif-id", "", "SARIF ID to filter by")
f.StringVar(&listAnalysesFlags.sort, "sort", "", "Sort by (created)")
f.StringVar(&listAnalysesFlags.direction, "direction", "", "Sort direction (asc, desc)")
f.IntVar(&listAnalysesFlags.perPage, "per-page", 30, "Results per page (max 100)")

_ = listAnalysesCmd.MarkFlagRequired("repo")
}

func runListAnalyses(cmd *cobra.Command, _ []string) error {
owner, repo, err := parseRepo(listAnalysesFlags.repo)
if err != nil {
return err
}

client, err := gh.NewClient()
if err != nil {
return err
}

analyses, err := client.ListAnalyses(gh.ListAnalysesOptions{
Owner: owner,
Repo: repo,
Ref: listAnalysesFlags.ref,
ToolName: listAnalysesFlags.toolName,
SarifID: listAnalysesFlags.sarifID,
Sort: listAnalysesFlags.sort,
Direction: listAnalysesFlags.direction,
PerPage: listAnalysesFlags.perPage,
})
if err != nil {
return err
}

if OutputFormat() == "json" {
enc := json.NewEncoder(cmd.OutOrStdout())
enc.SetIndent("", " ")
return enc.Encode(analyses)
}

w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 4, 2, ' ', 0)
fmt.Fprintln(w, "ID\tTOOL\tREF\tCATEGORY\tRESULTS\tRULES\tCREATED")
for _, a := range analyses {
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%d\t%d\t%s\n",
a.ID, a.Tool.Name, a.Ref, a.Category, a.ResultsCount, a.RulesCount, a.CreatedAt)
}
return w.Flush()
}
9 changes: 4 additions & 5 deletions client/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ var (
// rootCmd is the top-level command for the CLI.
var rootCmd = &cobra.Command{
Use: "gh-ql-mcp-client",
Short: "CodeQL Development MCP Client β€” integration test runner and CLI",
Long: `gh-ql-mcp-client is a CLI for running integration tests against a
CodeQL Development MCP Server.
Short: "CodeQL Development MCP Client β€” Code Scanning alert lifecycle management",
Long: `gh-ql-mcp-client is a CLI for managing Code Scanning alert lifecycles.

It connects to a CodeQL Development MCP Server via stdio or HTTP transport
and runs integration test fixtures from client/integration-tests/.
It connects to a CodeQL Development MCP Server to leverage SARIF analysis tools
and uses GitHub's Code Scanning REST API (via gh auth) for alert operations.

Use as a gh extension: gh ql-mcp-client <command> [flags]
Use standalone: gh-ql-mcp-client <command> [flags]`,
Expand Down
16 changes: 16 additions & 0 deletions client/cmd/sarif.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cmd

import "github.com/spf13/cobra"

var sarifCmd = &cobra.Command{
Use: "sarif",
Short: "SARIF analysis and alert comparison tools",
Long: "Commands for comparing, deduplicating, and validating SARIF alerts using MCP server tools and LLM-driven analysis.",
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}

func init() {
rootCmd.AddCommand(sarifCmd)
}
14 changes: 14 additions & 0 deletions client/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,29 @@ module github.com/advanced-security/codeql-development-mcp-server/client
go 1.25.6

require (
github.com/cli/go-gh/v2 v2.13.0
github.com/mark3labs/mcp-go v0.47.0
github.com/spf13/cobra v1.10.2
)

require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/cli/safeexec v1.0.0 // indirect
github.com/cli/shurcooL-graphql v0.0.4 // indirect
github.com/google/jsonschema-go v0.4.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/henvic/httpretty v0.0.6 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/term v0.30.0 // indirect
golang.org/x/text v0.23.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading
Loading