Documentation
¶
Index ¶
- Constants
- func New(version string) *cobra.Command
- func NewServer(version string, deps Deps) *mcp.Server
- func RenderDocs() string
- type BugCreateParams
- type BugCreateResult
- type BugListParams
- type BugListResult
- type CreateParams
- type CreateResult
- type Deps
- type DepsParams
- type DepsResult
- type FilesParams
- type FilesResult
- type GrepParams
- type GrepResult
- type ImplementParams
- type ImplementResult
- type ListParams
- type ListResult
- type NextParams
- type NextResult
- type PrioritizeParams
- type PrioritizeResult
- type ScanParams
- type ScanResult
- type Scopes
- type SearchParams
- type SearchResult
- type ShowParams
- type ShowResult
- type StatusParams
- type StatusResult
- type StatusStats
- type ToolSpec
- type ViewParams
Constants ¶
const ( // EnvToken grants read and mutate. EnvToken = "CANARY_MCP_TOKEN" //nolint:gosec // env var NAME, not a credential value // EnvReadToken grants read only. EnvReadToken = "CANARY_MCP_READ_TOKEN" //nolint:gosec // env var NAME, not a credential value )
Environment variables that configure MCP authentication. Their VALUES are never logged, echoed in an error, or written to a response body: an error message that names the expected token is the same leak as printing it.
const DefaultDBPath = ".canary/canary.db"
DefaultDBPath is the index every Canary command defaults to, relative to the server root.
Variables ¶
This section is empty.
Functions ¶
func New ¶
New returns the MCP subcommand for Canary.
version is the binary's version (ldflags), reported to clients as the server implementation version. It used to be the string "1.0.0", which meant every build in the field identified itself identically.
func NewServer ¶ added in v0.3.3
NewServer builds the MCP server with every registered tool bound to deps.
func RenderDocs ¶ added in v0.3.3
func RenderDocs() string
RenderDocs returns docs/MCP_TOOLS.md, generated from Registry.
The file on disk is asserted to equal this string, so the documentation cannot describe a tool set the server does not have.
Types ¶
type BugCreateParams ¶
type BugCreateParams struct {
Title string `json:"title" jsonschema:"description:Bug title,required"`
Aspect string `` /* 144-byte string literal not displayed */
Severity string `json:"severity,omitempty" jsonschema:"description:Severity level (S1 S2 S3 S4)"`
Priority string `json:"priority,omitempty" jsonschema:"description:Priority level (P0 P1 P2 P3)"`
File string `json:"file,omitempty" jsonschema:"description:File the bug lives in relative to the server root, optionally with :line"`
Owner string `json:"owner,omitempty" jsonschema:"description:Bug owner/assignee"`
Description string `json:"description,omitempty" jsonschema:"description:Detailed description, recorded on the token"`
}
BugCreateParams defines parameters for the bug create tool
type BugCreateResult ¶
type BugCreateResult struct {
// Token is the CANARY comment to paste into the source file. The row is
// rebuilt from source on the next `canary index`, so the comment is what
// makes the bug survive a re-index.
Token string `json:"token"`
BugID string `json:"bugId"`
Title string `json:"title"`
Aspect string `json:"aspect"`
Severity string `json:"severity"`
Priority string `json:"priority"`
FilePath string `json:"filePath"`
Line int `json:"line"`
}
BugCreateResult defines the output for the bug create tool
type BugListParams ¶
type BugListParams struct {
Status string `json:"status,omitempty" jsonschema:"description:Filter by status (OPEN INVESTIGATING FIXED WONTFIX)"`
Severity string `json:"severity,omitempty" jsonschema:"description:Filter by severity (CRITICAL HIGH MEDIUM LOW)"`
Limit int `json:"limit,omitempty" jsonschema:"description:Maximum results (default 20, max 100)"`
}
BugListParams defines parameters for the bug list tool
type BugListResult ¶
type BugListResult struct {
Bugs []*storage.Token `json:"bugs"`
Count int `json:"count"`
Total int `json:"total"`
}
BugListResult defines the output for the bug list tool
type CreateParams ¶
type CreateParams struct {
ReqID string `json:"reqId" jsonschema:"description:Requirement ID (e.g. CBIN-CLI-105),required"`
Feature string `json:"feature" jsonschema:"description:Feature name,required"`
Aspect string `json:"aspect,omitempty" jsonschema:"description:Aspect (API CLI Engine etc.)"`
Status string `json:"status,omitempty" jsonschema:"description:Status (STUB IMPL TESTED BENCHED)"`
Owner string `json:"owner,omitempty" jsonschema:"description:Owner/assignee"`
}
CreateParams defines parameters for the create tool
type CreateResult ¶
type CreateResult struct {
Token string `json:"token"`
ReqID string `json:"reqId"`
Feature string `json:"feature"`
Aspect string `json:"aspect"`
Status string `json:"status"`
}
CreateResult defines the output for the create tool
type Deps ¶ added in v0.3.3
type Deps struct {
// Root is the tree this server answers for. It is resolved to an
// absolute path at startup; an empty value means the working directory.
Root string
// DBPath is the token index. Empty means DefaultDBPath under Root.
DBPath string
}
Deps are the resolved inputs every tool handler runs against: the tree the server was started on and the index inside it.
They exist so a tool answers questions about the server's root rather than about whatever directory the process happens to be in. A path a caller supplies is resolved against Root and confined to it (see confine), which is what keeps `scan` from being pointed at an unrelated tree.
type DepsParams ¶
type DepsParams struct {
ReqID string `json:"reqId" jsonschema:"description:requirement ID,required"`
Direction string `json:"direction,omitempty" jsonschema:"description:forward (what it depends on, default) or reverse (what depends on it)"`
}
DepsParams selects a requirement and traversal direction.
type DepsResult ¶
type DepsResult struct {
ReqID string `json:"reqId"`
Direction string `json:"direction"`
Dependencies []string `json:"dependencies"`
Count int `json:"count"`
}
DepsResult carries dependency IDs only -- deliberately no token payloads.
type FilesParams ¶
type FilesParams struct {
ReqID string `json:"reqId" jsonschema:"description:Requirement ID to find files for,required"`
}
FilesParams defines parameters for the files tool
type FilesResult ¶
type FilesResult struct {
ReqID string `json:"reqId"`
Files []string `json:"files"`
FileCount int `json:"fileCount"`
}
FilesResult defines the output for the files tool
type GrepParams ¶
type GrepParams struct {
Pattern string `json:"pattern" jsonschema:"description:Pattern to search for in token fields,required"`
Field string `json:"field,omitempty" jsonschema:"description:Field to search (req feature aspect owner or all)"`
Limit int `json:"limit,omitempty" jsonschema:"description:Maximum results (default 20, max 100)"`
}
GrepParams defines parameters for the grep tool
type GrepResult ¶
type GrepResult struct {
Pattern string `json:"pattern"`
Field string `json:"field"`
Tokens []*storage.Token `json:"tokens"`
Count int `json:"count"`
Total int `json:"total"`
// TotalIsLowerBound is true when the underlying overfetch hit its ceiling
// (maxToolLimit+1 rows came back for an "all"-field search), meaning
// Total is a floor, not an exact count.
TotalIsLowerBound bool `json:"total_is_lower_bound,omitempty"`
}
GrepResult defines the output for the grep tool
type ImplementParams ¶
type ImplementParams struct {
ReqID string `json:"reqId" jsonschema:"description:Requirement ID to implement,required"`
}
ImplementParams defines parameters for the implement tool
type ImplementResult ¶
type ImplementResult struct {
Message string `json:"message"`
ReqID string `json:"reqId"`
Guidance string `json:"guidance,omitempty"`
SpecPath string `json:"specPath,omitempty"`
PlanPath string `json:"planPath,omitempty"`
HasSpec bool `json:"hasSpec"`
HasPlan bool `json:"hasPlan"`
TokenCount int `json:"tokenCount"`
CurrentPhase string `json:"currentPhase,omitempty"`
}
ImplementResult defines the output for the implement tool
type ListParams ¶
type ListParams struct {
Status string `json:"status,omitempty" jsonschema:"description:Filter by status (STUB IMPL TESTED BENCHED)"`
Aspect string `json:"aspect,omitempty" jsonschema:"description:Filter by aspect (API CLI Engine etc.)"`
Owner string `json:"owner,omitempty" jsonschema:"description:Filter by owner"`
Limit int `json:"limit,omitempty" jsonschema:"description:Maximum number of results"`
}
ListParams defines parameters for the list tool
type ListResult ¶
type ListResult struct {
Tokens []*storage.Token `json:"tokens"`
Count int `json:"count"`
Total int `json:"total"`
// TotalIsLowerBound is true when the underlying overfetch hit its ceiling
// (maxToolLimit+1 rows came back), meaning Total is a floor, not an exact
// count -- there may be more matches than reported.
TotalIsLowerBound bool `json:"total_is_lower_bound,omitempty"`
}
ListResult defines the output for the list tool
type NextParams ¶
type NextParams struct {
Status string `json:"status,omitempty" jsonschema:"description:Filter by status (STUB or IMPL)"`
Aspect string `json:"aspect,omitempty" jsonschema:"description:Filter by aspect"`
}
NextParams defines parameters for the next tool
type NextResult ¶
type NextResult struct {
Token *storage.Token `json:"token,omitempty"`
ReqID string `json:"reqId,omitempty"`
Feature string `json:"feature,omitempty"`
Aspect string `json:"aspect,omitempty"`
Status string `json:"status,omitempty"`
Priority int `json:"priority,omitempty"`
Message string `json:"message,omitempty"`
// Source names where the answer came from: "database" (a fresh token
// index) or "filesystem" (the index was missing or stale, so the tree was
// scanned). An agent that gets no work back can tell an empty tree from
// an unbuilt index.
Source string `json:"source,omitempty"`
// Blocked counts candidates passed over because a dependency was not
// complete -- what separates "nothing left to do" from "everything left
// is waiting on something".
Blocked int `json:"blocked,omitempty"`
}
NextResult defines the output for the next tool
type PrioritizeParams ¶
type PrioritizeParams struct {
ReqID string `json:"reqId" jsonschema:"description:Requirement ID to prioritize,required"`
Priority int `json:"priority" jsonschema:"description:Priority level 1-10 (1=highest, 10=lowest),required"`
}
PrioritizeParams defines parameters for the prioritize tool
type PrioritizeResult ¶
type PrioritizeResult struct {
Message string `json:"message"`
ReqID string `json:"reqId"`
Priority int `json:"priority"`
Updated int `json:"updated"`
}
PrioritizeResult defines the output for the prioritize tool
type ScanParams ¶
type ScanParams struct {
Root string `json:"root,omitempty" jsonschema:"description:Root directory to scan"`
ProjectOnly bool `json:"projectOnly,omitempty" jsonschema:"description:Filter by project requirement ID pattern"`
}
ScanParams defines parameters for the scan tool
type ScanResult ¶
type ScanResult struct {
Message string `json:"message"`
Root string `json:"root"`
Tokens int `json:"total_tokens"`
// Requirements is the unique requirement count, which the message has
// always reported but the structured result did not.
Requirements int `json:"unique_requirements"`
}
ScanResult defines the output for the scan tool
type SearchParams ¶
type SearchParams struct {
Keywords string `json:"keywords" jsonschema:"description:Search keywords,required"`
Limit int `json:"limit,omitempty" jsonschema:"description:Maximum results (default 20, max 100)"`
}
SearchParams defines parameters for the search tool
type SearchResult ¶
type SearchResult struct {
Keywords string `json:"keywords"`
Tokens []*storage.Token `json:"tokens"`
Count int `json:"count"`
Total int `json:"total"`
// TotalIsLowerBound is true when the underlying overfetch hit its ceiling
// (maxToolLimit+1 rows came back), meaning Total is a floor, not an exact
// count -- there may be more matches than reported.
TotalIsLowerBound bool `json:"total_is_lower_bound,omitempty"`
}
SearchResult defines the output for the search tool
type ShowParams ¶
type ShowParams struct {
ReqID string `json:"reqId" jsonschema:"description:Requirement ID (e.g. CBIN-123),required"`
Limit int `json:"limit,omitempty" jsonschema:"description:Maximum results (default 20, max 100)"`
}
ShowParams defines parameters for the show tool
type ShowResult ¶
type ShowResult struct {
ReqID string `json:"reqId"`
Tokens []*storage.Token `json:"tokens"`
Count int `json:"count"`
Total int `json:"total"`
}
ShowResult defines the output for the show tool
type StatusParams ¶
type StatusParams struct {
ReqID string `json:"reqId" jsonschema:"description:Requirement ID (e.g. CBIN-123),required"`
}
StatusParams defines parameters for the status tool
type StatusResult ¶
type StatusResult struct {
ReqID string `json:"reqId"`
Stats StatusStats `json:"stats"`
// DeclaredCompletionPct is the percentage of tokens declaring
// STATUS=TESTED or STATUS=BENCHED -- declared status, not verified
// evidence. Renamed from "CompletionPct" (R-15) so the field name itself
// cannot be misread as a verified completion percentage.
DeclaredCompletionPct int `json:"declared_completion_pct"`
Tokens []*storage.Token `json:"tokens"`
Total int `json:"total"`
}
StatusResult defines the output for the status tool
type StatusStats ¶
type StatusStats struct {
Total int `json:"total"`
Stub int `json:"stub"`
Impl int `json:"impl"`
Tested int `json:"tested"`
Benched int `json:"benched"`
// DeclaredComplete counts tokens declaring STATUS=TESTED or
// STATUS=BENCHED -- a claim, not proof. Renamed from "Completed" (R-15):
// the old name and the summary text below implied verified completion.
DeclaredComplete int `json:"declared_complete"`
}
StatusStats holds progress statistics.
These counts reflect DECLARED token STATUS only, not verified evidence: a token counted in DeclaredComplete may have no passing test or bench record at all. Do not read Completed/DeclaredComplete as "done" -- use evidence.Complete for that question.
type ToolSpec ¶ added in v0.3.3
type ToolSpec struct {
Name string
Description string
// Mutates reports whether the tool writes. A read-scoped bearer token is
// refused on these; everything else is readable with either token.
Mutates bool
Register func(s *mcp.Server, deps Deps)
}
ToolSpec is one MCP tool: its identity, whether calling it changes stored state, and how it is registered.
Registry is the only place tools are declared. The server, the authorization scope check and docs/MCP_TOOLS.md are all derived from it, so a tool cannot be exposed without also being documented and scoped -- the failure mode of the previous design, where nineteen imperative AddTool calls sat beside a hand-maintained forty-line banner that had drifted from them.
func Registry ¶ added in v0.3.3
func Registry() []ToolSpec
Registry returns every tool this server exposes, in presentation order.
Every entry here has a postcondition a caller can check. The five placeholder tools that used to be registered -- specify, plan, index, bug-create and gap-mark -- returned a success message and changed nothing; an agent could not tell them from tools that worked. They are unregistered, and bug-create is back as a real tool that persists a row.
type ViewParams ¶
type ViewParams struct {
ReqID string `json:"reqId" jsonschema:"description:requirement ID e.g. CBIN-105 or PLAT-4521,required"`
Limit int `json:"limit,omitempty" jsonschema:"description:max entries per list section (default 10)"`
}
ViewParams identifies the requirement to aggregate.