Documentation
¶
Overview ¶
Package mcp exposes Draugr to AI coding agents over the Model Context Protocol.
The reason this exists is narrower than "agents are popular". An agent asked "is this safe to ship?" will answer the question one way or another: if Draugr isn't callable it will improvise — shell out to whatever scanner it can find, invent a scope, and read raw tool output in its own context window. That improvised answer has no recorded scope, no organizational risk context, and no relationship to what CI will decide. Being callable is what makes the agent's answer and the pipeline's answer the same answer.
Two design rules follow from that:
- **Read-only by default.** Scanning clones repositories, executes external tools and reaches the network. An agent triggering that unprompted is a bad surprise, so `scan` is registered only when the operator opts in. Everything else is safe to call freely.
- **Return decisions, not data.** A tool that hands back raw scanner output has moved the problem into the agent's context window rather than solving it. These tools return prioritized, deduplicated, normalized results — the same thing a person sees.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Control ¶
type Control struct {
Name string `json:"name" jsonschema:"the control's name, as used under config.controllers in a Saga"`
Scope string `json:"scope" jsonschema:"whether the control runs per component or once for the project"`
Purpose string `json:"purpose" jsonschema:"what the control checks for"`
DefaultScanners []string `json:"defaultScanners" jsonschema:"scanners that run when the control is enabled"`
OptInScanners []string `` /* 134-byte string literal not displayed */
}
Control is one control an agent could enable.
type ControlsOutput ¶
type ControlsOutput struct {
Controls []Control `json:"controls"`
// Hint is where the agent should put what it learned. Returning capability without saying
// how to use it just moves the guesswork somewhere else.
Hint string `json:"hint"`
}
ControlsOutput is the list_controls result.
func ListControls ¶
func ListControls(reg *engine.Registry) ControlsOutput
ListControls reports the controls this build registers.
type Counts ¶
type Counts struct {
Critical int `json:"critical"`
High int `json:"high"`
Medium int `json:"medium"`
Low int `json:"low"`
}
Counts tallies the whole report, not just what was returned — a narrowed list shouldn't make the rest of the backlog look like it vanished.
type EmptyInput ¶
type EmptyInput struct{}
EmptyInput is the argument type for tools that take none. The SDK derives a schema from the input type, and an empty struct is how you say "no arguments" rather than "any arguments".
type Finding ¶
type Finding struct {
Priority string `json:"priority,omitempty" jsonschema:"P1 (act now) through P4 (lowest)"`
Severity string `json:"severity" jsonschema:"critical, high, medium or low"`
Score float64 `json:"score,omitempty" jsonschema:"CVSS-style numeric severity, when the scanner gave one"`
RuleID string `json:"ruleId"`
Scanner string `json:"scanner,omitempty"`
Location string `json:"location,omitempty" jsonschema:"file:line, image reference, or endpoint"`
Message string `json:"message"`
HelpURI string `json:"helpUri,omitempty" jsonschema:"where the rule is documented; fetch this rather than guessing what the rule means"`
}
Finding is one prioritized result, flattened to what a reader needs to act.
type Options ¶
type Options struct {
// Scan says whether a client may start scans. The zero value is ScanOff.
Scan ScanMode
// Registry supplies the controllers and scanners. Required.
Registry *engine.Registry
// Root is the directory searched for Saga descriptors to expose as resources. Empty means
// the working directory.
Root string
}
Options configures the server's exposed surface.
type ScanInput ¶
type ScanInput struct {
Path string `json:"path" jsonschema:"path to the Saga descriptor to scan"`
MinPriority string `json:"minPriority,omitempty" jsonschema:"only return findings at this priority or above: p1, p2, p3 or p4"`
Limit int `json:"limit,omitempty" jsonschema:"maximum findings to return; defaults to 20"`
}
ScanInput selects what to scan.
type ScanMode ¶
type ScanMode string
ScanMode says whether, and on what terms, a client may start a scan.
const ( // ScanOff doesn't register the tool at all. The default: an assistant can't set off work // like that because it was curious, and the read-only tools are where the value starts. ScanOff ScanMode = "off" // ScanAsk registers it and asks the user to approve each call, through the client. This is // the mode to want — permission granted for the scan in front of you rather than for every // scan this session — but it needs a client that implements elicitation, and many don't. ScanAsk ScanMode = "ask" // ScanAlways registers it and runs without asking. Right for a sandbox or CI, where there's // nobody to ask. ScanAlways ScanMode = "always" )
The scan modes. A scan clones repositories, executes external tools and reaches the network, so the question isn't only "may it" but "who agrees to it, and when".
func ParseScanMode ¶
ParseScanMode validates a mode name.
type ScanOutput ¶
type ScanOutput struct {
Verdict string `json:"verdict" jsonschema:"pass or fail, by the same policy the CI gate applies"`
SummarizeOutput
}
ScanOutput is the verdict plus the ranked findings behind it.
type SchemaOutput ¶
type SchemaOutput struct {
Schema map[string]any `json:"schema" jsonschema:"the JSON Schema for a Saga descriptor"`
Version string `json:"draugrVersion" jsonschema:"the Draugr build this schema came from"`
Hint string `json:"hint"`
}
SchemaOutput carries the descriptor's JSON Schema.
Schema is a decoded object rather than raw bytes so a client receives the schema itself: MCP validates a tool's output against the schema derived from this type, and a []byte field derives as an array, which the schema document then fails to be.
func GetSchema ¶
func GetSchema() (SchemaOutput, error)
GetSchema returns the schema embedded in this binary — the one that will actually be enforced, as opposed to whatever is published on the web for some other version.
type SummarizeInput ¶
type SummarizeInput struct {
Path string `json:"path" jsonschema:"path to a results.sarif or report.json produced by draugr scan"`
// MinPriority narrows the list the way --min-priority does on the CLI.
MinPriority string `json:"minPriority,omitempty" jsonschema:"only return findings at this priority or above: p1, p2, p3 or p4"`
// Limit caps how many findings come back. Context is the scarce resource here.
Limit int `json:"limit,omitempty" jsonschema:"maximum findings to return; defaults to 20"`
}
SummarizeInput points at a report already on disk.
type SummarizeOutput ¶
type SummarizeOutput struct {
Total int `json:"total" jsonschema:"findings in the report before any filtering"`
Returned int `json:"returned"`
Counts Counts `json:"counts"`
Findings []Finding `json:"findings"`
Note string `json:"note,omitempty"`
}
SummarizeOutput is the ranked answer to "what should I fix?".
func SummarizeReportTool ¶
func SummarizeReportTool(_ context.Context, _ *mcp.CallToolRequest, in SummarizeInput) (*mcp.CallToolResult, SummarizeOutput, error)
SummarizeReportTool reads a report from disk and returns it ranked.
type ValidateInput ¶
type ValidateInput struct {
Path string `json:"path,omitempty" jsonschema:"path to a Saga descriptor on disk"`
Content string `json:"content,omitempty" jsonschema:"the descriptor's YAML content, for validating an edit before writing it"`
}
ValidateInput accepts a descriptor either by path or inline.
type ValidateOutput ¶
type ValidateOutput struct {
Valid bool `json:"valid"`
// Error is why it isn't, in the same words the CLI would use.
Error string `json:"error,omitempty"`
// Components and Controls describe what the descriptor actually asks for, which is how an
// agent checks that a descriptor says what it intended rather than merely parsing.
Components []string `json:"components,omitempty"`
Controls []string `json:"controls,omitempty"`
}
ValidateOutput reports whether the descriptor is usable.
func ValidateSagaTool ¶
func ValidateSagaTool(_ context.Context, _ *mcp.CallToolRequest, in ValidateInput) (*mcp.CallToolResult, ValidateOutput, error)
ValidateSagaTool validates a descriptor from a path or inline content.