Go Library API¶
MCP-Scan can be used as a Go library for integration into other tools.
Installation¶
Quick Start¶
package main
import (
"context"
"fmt"
"log"
"github.com/mcphub/mcp-scan/pkg/scanner"
)
func main() {
// Create scanner with configuration
cfg := scanner.Config{
Mode: scanner.ModeFast,
Timeout: 5 * time.Minute,
}
s := scanner.New(cfg)
// Run scan
result, err := s.Scan(context.Background(), "./my-project")
if err != nil {
log.Fatal(err)
}
// Process results
fmt.Printf("Found %d findings\n", result.Summary.Total)
fmt.Printf("MSSS Score: %.1f (Level %d)\n",
result.MSSSScore.Total,
result.MSSSScore.Level)
// Generate report
report, _ := s.GenerateReport(result, "json")
fmt.Println(string(report))
}
Types¶
scanner.Config¶
type Config struct {
// File discovery
Include []string // Glob patterns to include (default: **/*.py, **/*.ts, etc.)
Exclude []string // Glob patterns to exclude (default: node_modules/**, etc.)
// Analysis settings
Mode Mode // ModeFast or ModeDeep
Timeout time.Duration // Maximum scan duration
// Output settings
FailOn types.Severity // Severity threshold for exit code 1
Rules []string // Specific rules to run (empty = all)
RedactSnippets bool // Hide code in output
// Baseline
Baseline string // Path to baseline file
// Parallelism
Workers int // Number of workers (0 = auto)
}
scanner.Mode¶
type Mode string
const (
ModeFast Mode = "fast" // Intra-procedural analysis
ModeDeep Mode = "deep" // Inter-procedural analysis
)
scanner.Result¶
type Result struct {
// Core results
Findings []types.Finding // All detected vulnerabilities
Summary *types.Summary // Aggregated statistics
// Context
Manifest *types.Manifest // Scanned files
MCPSurface *surface.MCPSurface // Detected MCP elements
MSSSScore *msss.Score // Security score
// Metadata
ScanDuration time.Duration
Mode Mode
ExitCode int
BaselinedCount int // Findings excluded by baseline
}
types.Finding¶
type Finding struct {
ID string `json:"id"`
RuleID string `json:"rule_id"`
Severity Severity `json:"severity"`
Confidence Confidence `json:"confidence"`
Language Language `json:"language"`
Location Location `json:"location"`
MCPContext *MCPContext `json:"mcp_context,omitempty"`
Trace *TaintTrace `json:"trace,omitempty"`
Evidence Evidence `json:"evidence"`
Description string `json:"description"`
Remediation string `json:"remediation"`
}
types.Severity¶
type Severity string
const (
SeverityInfo Severity = "info"
SeverityLow Severity = "low"
SeverityMedium Severity = "medium"
SeverityHigh Severity = "high"
SeverityCritical Severity = "critical"
)
// Level returns numeric level for comparison
func (s Severity) Level() int
types.Location¶
type Location struct {
File string `json:"file"`
StartLine int `json:"start_line"`
StartCol int `json:"start_col"`
EndLine int `json:"end_line"`
EndCol int `json:"end_col"`
}
Scanner Methods¶
New¶
Creates a new Scanner instance with the given configuration.
Scan¶
Scans the given path and returns results. The context can be used for cancellation.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
result, err := scanner.Scan(ctx, "./project")
GenerateReport¶
Generates a report in the specified format: "json", "sarif", or "evidence".
ScanFile¶
Scans a single file. Useful for incremental scanning.
Examples¶
Custom Rule Selection¶
cfg := scanner.Config{
Mode: scanner.ModeFast,
Rules: []string{"A", "E", "G"}, // Only RCE, Secrets, Tool Poisoning
}
s := scanner.New(cfg)
result, _ := s.Scan(ctx, "./project")
With Baseline¶
cfg := scanner.Config{
Mode: scanner.ModeFast,
Baseline: ".mcp-scan-baseline.json",
}
s := scanner.New(cfg)
result, _ := s.Scan(ctx, "./project")
fmt.Printf("New findings: %d\n", result.Summary.Total)
fmt.Printf("Baselined: %d\n", result.BaselinedCount)
Deep Mode with Timeout¶
cfg := scanner.Config{
Mode: scanner.ModeDeep,
Timeout: 10 * time.Minute,
FailOn: types.SeverityHigh,
}
s := scanner.New(cfg)
result, err := s.Scan(ctx, "./project")
if result.ExitCode != 0 {
fmt.Println("High severity findings detected!")
}
Processing Findings¶
result, _ := s.Scan(ctx, "./project")
for _, finding := range result.Findings {
fmt.Printf("[%s] %s at %s:%d\n",
finding.Severity,
finding.RuleID,
finding.Location.File,
finding.Location.StartLine)
if finding.MCPContext != nil {
fmt.Printf(" Tool: %s\n", finding.MCPContext.ToolName)
}
if finding.Trace != nil {
fmt.Printf(" Source: %s:%d\n",
finding.Trace.Source.File,
finding.Trace.Source.StartLine)
}
}
SARIF Output for CI¶
result, _ := s.Scan(ctx, "./project")
sarif, _ := s.GenerateReport(result, "sarif")
err := os.WriteFile("results.sarif", sarif, 0644)
Checking MSSS Compliance¶
result, _ := s.Scan(ctx, "./project")
score := result.MSSSScore
fmt.Printf("Score: %.1f\n", score.Total)
fmt.Printf("Level: %d\n", score.Level)
fmt.Printf("Compliant: %v\n", score.Compliant)
if score.Level < 2 {
fmt.Println("Not enterprise-ready!")
}
MCP Surface Analysis¶
result, _ := s.Scan(ctx, "./project")
surface := result.MCPSurface
fmt.Printf("Transport: %s\n", surface.Transport)
fmt.Printf("Tools: %d\n", len(surface.Tools))
for _, tool := range surface.Tools {
fmt.Printf(" - %s: %s\n", tool.Name, tool.Description)
}
Error Handling¶
result, err := s.Scan(ctx, "./project")
if err != nil {
switch {
case errors.Is(err, context.DeadlineExceeded):
log.Fatal("Scan timeout exceeded")
case errors.Is(err, context.Canceled):
log.Fatal("Scan was canceled")
default:
log.Fatalf("Scan error: %v", err)
}
}
Thread Safety¶
The Scanner is safe for concurrent use:
s := scanner.New(cfg)
var wg sync.WaitGroup
for _, project := range projects {
wg.Add(1)
go func(p string) {
defer wg.Done()
result, _ := s.Scan(ctx, p)
// process result
}(project)
}
wg.Wait()
Integration Examples¶
GitHub Action (Go)¶
func main() {
cfg := scanner.Config{
Mode: scanner.ModeFast,
FailOn: types.SeverityHigh,
}
s := scanner.New(cfg)
result, err := s.Scan(context.Background(), ".")
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(3)
}
sarif, _ := s.GenerateReport(result, "sarif")
os.WriteFile(os.Getenv("GITHUB_STEP_SUMMARY"), sarif, 0644)
os.Exit(result.ExitCode)
}
Pre-commit Hook¶
func main() {
// Get staged files
stagedFiles := getStagedFiles()
cfg := scanner.Config{
Mode: scanner.ModeFast,
Include: stagedFiles,
FailOn: types.SeverityHigh,
}
s := scanner.New(cfg)
result, _ := s.Scan(context.Background(), ".")
if result.ExitCode != 0 {
fmt.Println("Security issues found in staged files!")
for _, f := range result.Findings {
fmt.Printf(" %s:%d - %s\n",
f.Location.File,
f.Location.StartLine,
f.Description)
}
os.Exit(1)
}
}
Custom Reporter¶
type SlackReporter struct {
WebhookURL string
}
func (r *SlackReporter) Report(result *scanner.Result) error {
if result.Summary.Total == 0 {
return nil
}
message := fmt.Sprintf(
"🔒 MCP-Scan found %d issues (Score: %.1f)",
result.Summary.Total,
result.MSSSScore.Total)
// Send to Slack
return r.sendWebhook(message)
}