mcp

package
v1.10.2 Latest Latest
Warning

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

Go to latest
Published: May 5, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BestParamSuggestionForTest

func BestParamSuggestionForTest(unknown string, validParams []string, maxDistance int) (string, int)

BestParamSuggestionForTest exposes bestParamSuggestion to the _test package.

func BestValueSuggestionForTest

func BestValueSuggestionForTest(value string, validValues []string, maxDistance int) (string, int)

BestValueSuggestionForTest exposes bestValueSuggestion to the _test package.

func ClassifyOutcomeForTest

func ClassifyOutcomeForTest(result mcpsdk.Result, err error) string

ClassifyOutcomeForTest exposes classifyOutcome to the _test package.

func EditOutcomeEnumForTest

func EditOutcomeEnumForTest() []string

EditOutcomeEnumForTest returns a copy of the closed edit-outcome enum (Phase 53 D-10) for test assertions that the 6-value vocabulary is preserved.

func ExtractBadParamsForTest

func ExtractBadParamsForTest(errMsg string) []string

ExtractBadParamsForTest exposes extractBadParams to the _test package.

func InstallLazyInitMiddleware

func InstallLazyInitMiddleware(server *mcpsdk.Server, activateFn func(ctx context.Context, path string) error, isActiveFn func() bool, defaultRoot string, logger *slog.Logger)

InstallLazyInitMiddleware wires the lazy init middleware onto the MCP SDK server. MUST be called LAST (after InstallSuggestionMiddleware) so it runs FIRST in the LIFO middleware chain -- before TelemetryMiddleware's deadline (Pitfall 3).

func InstallMiddleware

func InstallMiddleware(server *mcpsdk.Server, provider *obs.Provider, resolver ProfileResolver, getSession func(ctx context.Context) *SessionInfo, budgetFn BudgetFunc, registry *ToolRegistry, logger *slog.Logger)

func InstallSuggestionMiddleware

func InstallSuggestionMiddleware(server *mcpsdk.Server, schemaMap *ToolSchemaMap, logger *slog.Logger)

InstallSuggestionMiddleware wires the suggestion middleware onto the MCP SDK server.

func LevenshteinDistanceForTest

func LevenshteinDistanceForTest(a, b string) int

LevenshteinDistanceForTest exposes levenshteinDistance to the _test package.

func OutcomeEnumForTest

func OutcomeEnumForTest() []string

OutcomeEnumForTest returns a copy of the closed outcome enum for test assertions that the 7-value vocabulary is preserved.

func ProfileFilterMiddleware

func ProfileFilterMiddleware(resolver ProfileResolver, getSession func(ctx context.Context) *SessionInfo, briefDescs map[string]string, logger *slog.Logger) mcpsdk.Middleware

ProfileFilterMiddleware creates middleware that filters tool listings based on the active session's AllowedTools and applies description overrides from the profile (PRF-03). For tools/list requests it filters and rewrites descriptions; all other methods pass through unchanged.

func RecordEditOutcome

func RecordEditOutcome(ctx context.Context, toolName, outcome, strategy string)

RecordEditOutcome increments the helix_edit_outcome_total counter. Called from edit (internal/kernel/edit/) and fileops (internal/kernel/fileops/) tool handlers at return.

Closed enums (Phase 53 D-10 + D-11 + Q-4):

outcome  ∈ {success, no_match, ambiguous_match, validation_failed, ls_error, internal}
strategy ∈ {exact, whitespace_normalized, indentation_flexible, none}

Unknown values are dropped silently at the *obs.Metrics layer (EditOutcomeInc), mirroring the closed-enum drop-unknown discipline of RenameStrategyInc. Q-4: "failed" is NEVER a valid strategy value at this layer — fuzzy.StrategyFailed paths emit outcome="no_match", strategy="none".

Test-only sink wiring: the editOutcomeSink package-level pointer is process-global. Tests that mutate it via SetEditOutcomeSinkForTest MUST NOT use t.Parallel() — concurrent goroutines would race over the shared recorder and observe each other's emissions. WR-05: prefer paired t.Cleanup(func() { mcp.SetEditOutcomeSinkForTest(nil) }) in any test that installs a custom sink so the leak does not bleed into adjacent tests. Same caveat applies to setRenameStrategySink (Phase 47 D-07).

func RecordRenameStrategy

func RecordRenameStrategy(ctx context.Context, strategy string)

RecordRenameStrategy increments the helix_rename_strategy_total counter. The strategy string MUST be one of {"lsp-native","rust-client-side"}; any other value is dropped by the underlying obs.Metrics.RenameStrategyInc (closed-enum cardinality discipline, threat T-47-08). ctx is threaded through for future OTel integration; currently the sink adapter discards it.

func SetEditOutcomeSinkForTest

func SetEditOutcomeSinkForTest(fn func(ctx context.Context, toolName, outcome, strategy string))

SetEditOutcomeSinkForTest exposes setEditOutcomeSink to external tests (e.g. internal/kernel/edit/tools_test.go) that need to install a recording recorder without going through InstallMiddleware. Production code MUST continue to wire via InstallMiddleware.

WR-05: this mutates process-global state. Callers MUST NOT use t.Parallel() on tests that touch the sink, and SHOULD pair the call with t.Cleanup(func() { SetEditOutcomeSinkForTest(nil) }) so the recorder does not leak into adjacent tests in the same package.

func SetVersion

func SetVersion(v string)

SetVersion records the binary version reported as MCP `Implementation.Version`. Called once from internal/daemon/daemon.go during bootstrap with the ldflag-injected value (which the daemon receives via an optional version argument; see daemon.New for the wiring).

func StrategyEnumForTest

func StrategyEnumForTest() []string

StrategyEnumForTest returns a copy of the closed strategy enum (Phase 53 D-11 + Q-4) for test assertions that the 4-value vocabulary is preserved. Note: "failed" is intentionally absent — see strategyEnum doc.

func SuggestionMiddleware

func SuggestionMiddleware(schemaMap *ToolSchemaMap, logger *slog.Logger) mcpsdk.Middleware

SuggestionMiddleware creates MCP middleware that enriches error responses with "did you mean" parameter and enum value suggestions. It intercepts both protocol errors (from SDK schema validation) and tool errors (IsError=true), looking up the correct parameter names from the pre-built ToolSchemaMap.

Only tools/call requests are intercepted; all other methods pass through. Per D-09, suggestions only reference parameters from the same tool. Per D-10, no new error kinds are created.

func TelemetryMiddleware

func TelemetryMiddleware(provider *obs.Provider, getSession func(ctx context.Context) *SessionInfo, budgetFn BudgetFunc, logger *slog.Logger) mcpsdk.Middleware

TelemetryMiddleware emits RED metrics for every tools/call and preserves the Phase 8 structured log lines for all methods. The Phase 8 log closure has been absorbed here so we only traverse the middleware chain once per request.

Metric emission is gated on method == "tools/call"; tools/list, initialize, and all other methods are pure log pass-through. This matches the v1.2 scope: RED metrics are per-tool-call only (T-11-09 "accept" disposition).

Types

type ActivateCallback

type ActivateCallback func(ctx context.Context, repoPath string) error

ActivateCallback is called when a project is activated via the activate_project tool. It allows the daemon to wire kernel workspace activation alongside the registry.

type ActivateProjectArgs

type ActivateProjectArgs struct {
	RepoPath string `json:"repo_path" jsonschema:"Path to the repository root"`
}

ActivateProjectArgs is the input schema for the activate_project tool (WRK-01).

type BudgetFunc

type BudgetFunc func(toolName string) time.Duration

InstallMiddleware wires Helix's receiving middleware onto the MCP SDK server (MCP-04 + METRIC-02).

TelemetryMiddleware absorbs the previous Phase 8 logging closure: it preserves the structured log lines for every method AND emits RED metrics for method == "tools/call". It fully replaces the Phase 8 log-only middleware.

NOTE: ProfileFilterMiddleware only touches tools/list; TelemetryMiddleware only emits metrics on tools/call. Ordering between the two is independent, so callers may install them in either order. The D-06 "before ProfileFilter" constraint from CONTEXT.md was written assuming ProfileFilter had a deny path at tool-call time; since it does not in v1.2, that ordering constraint is obsolete here. BudgetFunc returns the timeout budget for a tool name. A nil BudgetFunc disables deadline injection (all calls pass through without a timeout). Wired from degrade.BudgetFor in daemon.go to avoid an import cycle (mcp -> config -> profile -> mcp).

type EchoArgs

type EchoArgs struct {
	Text string `json:"text" jsonschema:"Text to echo back"`
}

EchoArgs is the input schema for the echo diagnostic tool.

type GRPCStream

type GRPCStream interface {
	Recv() (*serenav1.MCPMessage, error)
	Send(*serenav1.MCPMessage) error
}

GRPCStream abstracts the gRPC bidirectional stream for testability.

type GRPCTransport

type GRPCTransport struct {
	// contains filtered or unexported fields
}

GRPCTransport bridges a gRPC bidirectional stream to the MCP SDK's Transport interface. It uses io.Pipe pairs so that gRPC stream messages flow into the MCP SDK's IOTransport.

Data flow:

gRPC stream.Recv() -> pipeWriter (clientToServer) -> IOTransport.Reader -> MCP SDK
MCP SDK -> IOTransport.Writer -> pipeReader (serverToClient) -> gRPC stream.Send()

func NewGRPCTransport

func NewGRPCTransport(stream GRPCStream, sessionID string, firstMsg *serenav1.MCPMessage) *GRPCTransport

NewGRPCTransport creates a new transport backed by a gRPC stream. If firstMsg is non-nil, it is replayed into the client->server pipe before reading from the stream.

func (*GRPCTransport) Connect

func (t *GRPCTransport) Connect(ctx context.Context) (mcpsdk.Connection, error)

Connect returns a Connection that bridges the gRPC stream to the MCP SDK. It spawns goroutines to pump data between gRPC and io.Pipe pairs.

type LazyInitMiddleware

type LazyInitMiddleware struct {
	// contains filtered or unexported fields
}

LazyInitMiddleware transparently activates the workspace on the first tools/call if no workspace is active (LAZY-01). Thread-safe via sync.Once per workspace path (LAZY-02).

func NewLazyInitMiddleware

func NewLazyInitMiddleware(activateFn func(ctx context.Context, path string) error, isActiveFn func() bool, defaultRoot string, logger *slog.Logger) *LazyInitMiddleware

NewLazyInitMiddleware creates a lazy init middleware. activateFn is called to activate a workspace (typically daemon's activate callback). isActiveFn returns true if any workspace is currently active. defaultRoot is the fallback project root (from config or forwarder cwd).

func (*LazyInitMiddleware) Middleware

func (m *LazyInitMiddleware) Middleware() mcpsdk.Middleware

Middleware returns the mcpsdk.Middleware function.

type ModeTransition

type ModeTransition struct {
	From      string
	To        string
	Timestamp time.Time
}

ModeTransition records a single mode switch for audit purposes (D-07).

type PingArgs

type PingArgs struct {
	Message string `json:"message" jsonschema:"Message to echo back"`
}

PingArgs is the input schema for the ping diagnostic tool.

type ProfileResolver

type ProfileResolver interface {
	// ToolDescriptionOverrides returns the description override map for the named profile.
	// Returns nil if the profile has no overrides or is not found.
	ToolDescriptionOverrides(profileName string) map[string]string
}

ProfileResolver provides profile information for middleware filtering. This interface avoids a circular import between mcp and profile packages.

type SerenaMCPServer

type SerenaMCPServer struct {
	// contains filtered or unexported fields
}

SerenaMCPServer wraps the official MCP SDK server with Helix's tool registry, structured errors, and middleware (MCP-01, MCP-02, MCP-03, MCP-05, MCP-06).

func NewSerenaMCPServer

func NewSerenaMCPServer(workspaces *workspace.Registry, logger *slog.Logger, tracer trace.Tracer) *SerenaMCPServer

NewSerenaMCPServer creates a new MCP server with dummy tools registered.

The tracer is used by AddSkillTool to emit kernel.tool.{name} spans on invocation (Phase 55-02 / OBS-04). Per Phase 12 D-01 the tracer is injected (never resolved via otel.GetTracerProvider). When tracer is nil, a process-local noop tracer is substituted so all paths stay safe.

func (*SerenaMCPServer) AddSkillTool

func (s *SerenaMCPServer) AddSkillTool(name, description, briefDescription, helpText string, executor SkillToolExecutor)

AddSkillTool registers a skill-provided tool with a generic ExecuteTool handler. Uses the generic mcpsdk.AddTool so the SDK auto-generates an input schema.

func (*SerenaMCPServer) AddTool

func (s *SerenaMCPServer) AddTool(tool *mcpsdk.Tool, handler mcpsdk.ToolHandler)

AddTool registers a new tool dynamically at runtime (MCP-07).

func (*SerenaMCPServer) AddToolWithMeta

func (s *SerenaMCPServer) AddToolWithMeta(tool *mcpsdk.Tool, handler mcpsdk.ToolHandler, brief, helpText string)

AddToolWithMeta registers a tool with optional BriefDescription and HelpText metadata (DESC-01, DESC-02).

func (*SerenaMCPServer) CollectToolSchemas

func (s *SerenaMCPServer) CollectToolSchemas() []*mcpsdk.Tool

CollectToolSchemas returns all registered tool definitions with their InputSchema for suggestion middleware schema introspection (D-07). Called once at daemon startup after all tools are registered.

func (*SerenaMCPServer) HTTPHandler

func (s *SerenaMCPServer) HTTPHandler() http.Handler

HTTPHandler returns an http.Handler for Streamable HTTP transport (MCP-02).

func (*SerenaMCPServer) Registry

func (s *SerenaMCPServer) Registry() *ToolRegistry

Registry returns the tool registry for dynamic tool management.

func (*SerenaMCPServer) RemoveTool

func (s *SerenaMCPServer) RemoveTool(name string)

RemoveTool removes a tool by name at runtime (MCP-07).

func (*SerenaMCPServer) RunStdio

func (s *SerenaMCPServer) RunStdio(ctx context.Context) error

RunStdio runs the MCP server over stdio transport (MCP-01).

func (*SerenaMCPServer) SDK

func (s *SerenaMCPServer) SDK() *mcpsdk.Server

SDK returns the underlying MCP SDK server for direct use (e.g., transport wiring).

func (*SerenaMCPServer) SetActivateCallback

func (s *SerenaMCPServer) SetActivateCallback(cb ActivateCallback)

SetActivateCallback installs a callback invoked when activate_project succeeds. The daemon uses this to activate the kernel workspace alongside the registry.

type SessionInfo

type SessionInfo struct {
	SessionID    string
	WorkspaceKey string   // hash of workspace.WorkspaceKey
	Mode         string   // current operational mode (D-07) — read/write via accessors after bootstrap
	Profile      string   // active profile name
	Language     string   // active workspace primary language (A2: Phase 11 metric label)
	AllowedTools []string // tools available in current mode/profile (nil = all)

	// ModeHistory records all mode transitions for auditability (D-07).
	ModeHistory []ModeTransition
	// contains filtered or unexported fields
}

SessionInfo tracks Helix-specific session state layered on top of MCP SDK sessions. Per DMN-06: session keyed by MCP session + dirty buffer overlay + mode/capability profile.

Thread-safety: All fields are guarded by mu. Callers MUST use the accessor methods (Snapshot, SetAllowedTools, RecordModeTransition) rather than touching fields directly, because concurrent MCP tool calls and tools/list requests can race on Mode / AllowedTools (threat T-08-08: Tampering / EoP on session state under concurrent switch_mode + tool invocation). Direct field access is retained only for single-writer initialization in the daemon bootstrap before the session is exposed to MCP handlers.

func (*SessionInfo) RecordModeTransition

func (s *SessionInfo) RecordModeTransition(from, to string)

RecordModeTransition appends a transition to the mode history and updates the current mode atomically.

func (*SessionInfo) SetAllowedTools

func (s *SessionInfo) SetAllowedTools(tools []string)

SetAllowedTools replaces the session's tool whitelist under the write lock. The provided slice is copied so callers may safely mutate it afterwards.

func (*SessionInfo) SetLanguage

func (s *SessionInfo) SetLanguage(lang string)

SetLanguage updates the session's active workspace language under the write lock. Symmetric with SetAllowedTools — the Phase 11 TelemetryMiddleware reads this via Snapshot() to populate the "language" metric label (A2).

func (*SessionInfo) Snapshot

func (s *SessionInfo) Snapshot() SessionSnapshot

Snapshot returns a defensively-copied snapshot of the session state. It is the preferred read path for code outside of this package.

type SessionSnapshot

type SessionSnapshot struct {
	SessionID    string
	WorkspaceKey string
	Mode         string
	Profile      string
	Language     string   // A2: v1.2 metric label — empty string is a valid Prometheus label value
	AllowedTools []string // defensive copy; safe to iterate without locking
}

SessionSnapshot is an immutable point-in-time view of a SessionInfo suitable for use by readers (middleware, tool handlers) that need a consistent read of multiple related fields without holding the session lock across further work.

type SkillToolExecutor

type SkillToolExecutor interface {
	ExecuteTool(name string, args map[string]interface{}) (string, error)
}

SkillToolExecutor is implemented by skills that support direct tool execution.

type ToolDef

type ToolDef struct {
	Name             string
	Description      string
	BriefDescription string // short description for tools/list (under 100 tokens, DESC-01)
	HelpText         string // usage examples and patterns for get_tool_help (DESC-02)
	// RegisterFn is called to register this tool with the MCP SDK server.
	// This is a callback because the SDK's AddTool is generic and requires type params.
	RegisterFn func(server interface{}) error
}

ToolDef holds a tool definition before registration with the MCP SDK server.

type ToolParamInfo

type ToolParamInfo struct {
	ValidParams []string            // known parameter names for this tool
	EnumValues  map[string][]string // param_name -> valid enum values (nil if no enums)
}

ToolParamInfo holds known parameter names and enum values for a single tool.

type ToolRegistry

type ToolRegistry struct {
	// contains filtered or unexported fields
}

ToolRegistry manages tools that can be dynamically added/removed (MCP-07).

func NewToolRegistry

func NewToolRegistry(logger *slog.Logger) *ToolRegistry

NewToolRegistry creates a new registry.

func (*ToolRegistry) BriefDescriptions

func (r *ToolRegistry) BriefDescriptions() map[string]string

BriefDescriptions returns a map of tool name to BriefDescription for all tools that have a non-empty BriefDescription (DESC-01).

func (*ToolRegistry) Count

func (r *ToolRegistry) Count() int

Count returns the number of registered tools.

func (*ToolRegistry) Get

func (r *ToolRegistry) Get(name string) *ToolDef

Get returns the ToolDef for a tool by name, or nil if not found.

func (*ToolRegistry) Names

func (r *ToolRegistry) Names() []string

Names returns all registered tool names.

func (*ToolRegistry) Register

func (r *ToolRegistry) Register(def *ToolDef)

Register adds a tool definition to the registry.

func (*ToolRegistry) Unregister

func (r *ToolRegistry) Unregister(name string)

Unregister removes a tool by name.

type ToolSchemaMap

type ToolSchemaMap struct {
	// contains filtered or unexported fields
}

ToolSchemaMap maps tool names to their parameter information, used by SuggestionMiddleware to provide "did you mean" suggestions.

func BuildToolSchemaMap

func BuildToolSchemaMap(tools []*mcpsdk.Tool) *ToolSchemaMap

BuildToolSchemaMap constructs a ToolSchemaMap from registered tool definitions. It extracts parameter names and enum constraints from each tool's InputSchema. Tools whose schema fails to parse are skipped gracefully.

Jump to

Keyboard shortcuts

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