mcp

package
v0.38.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

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

func NewServer

func NewServer(opts Options) (*mcp.Server, error)

NewServer builds the MCP server. Tools are registered here rather than discovered so the exposed surface is a deliberate, reviewable list.

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

func ParseScanMode(s string) (ScanMode, error)

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

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

ValidateSagaTool validates a descriptor from a path or inline content.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL