mcp

package
v1.3.1 Latest Latest
Warning

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

Go to latest
Published: Apr 21, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package mcp implements the embedded MCP server that exposes the Escape CLI commands as MCP tools over HTTP.

Index

Constants

View Source
const GetToolSpecToolName = "escape_get_tool_spec"

GetToolSpecToolName is the built-in tool that returns the full input schema of a compressed/stubbed tool on demand. Intent-aware tools/list serves minimal stubs for non-selected tools; the LLM uses this tool to zoom in when it decides to call one of them.

Variables

View Source
var ErrDocsIndexUnavailable = errors.New("docs index unavailable")

ErrDocsIndexUnavailable is returned when the docs index can't be fetched.

Functions

func BuildDocsQuery added in v1.3.1

func BuildDocsQuery(query string) string

BuildDocsQuery drops noise words from a user query so the docs search index can match meaningful terms.

func BuildStubTool added in v1.3.1

func BuildStubTool(spec ToolSpec) (mcpgo.Tool, error)

BuildStubTool rebuilds a ToolSpec's mcp Tool with the heavy `body` property replaced by a small placeholder. Positional args and flag bindings are preserved verbatim because they are already compact and useful hints. The executor still uses the original spec (positional args, flags, body) at call time — this only affects what is advertised on tools/list.

`required` is reconstructed from the original RawInputSchema so any tool whose full schema marks `body` (or another non-positional flag) as required stays required in the stub. Otherwise compact_only mode would let the model emit calls that the executor immediately rejects.

func InjectAuthContext

func InjectAuthContext(ctx context.Context, req *http.Request) context.Context

InjectAuthContext derives a context that carries the credentials extracted from the incoming HTTP request so downstream tool handlers can access them.

func NewIntentMiddleware added in v1.3.1

func NewIntentMiddleware(next http.Handler, opts IntentOptions) http.Handler

NewIntentMiddleware wraps next so that tools/list responses are rewritten according to Mode. All other requests pass through unchanged.

func RegisterBuiltinTools

func RegisterBuiltinTools(server *mcpserver.MCPServer, specs []ToolSpec)

RegisterBuiltinTools registers the MCP-native helper tools (e.g. the tool discovery endpoint) that ship with the embedded server.

func RegisterCommandTools

func RegisterCommandTools(
	server *mcpserver.MCPServer,
	specs []ToolSpec,
	options CommandExecutionOptions,
)

RegisterCommandTools walks the supplied specs and registers one MCP handler per tool on the server. Each handler spawns a bounded CLI subprocess.

func RegisterKnowledgeTools added in v1.3.1

func RegisterKnowledgeTools(server *mcpserver.MCPServer, opts KnowledgeOptions) error

RegisterKnowledgeTools registers the knowledge_answer_question tool on the given server. Port of createKnowledgeTools from the TS mcp-server.

func StemToken added in v1.3.1

func StemToken(value string) string

StemToken is a port of services/mcp-server/src/lanes/knowledge/stemming.ts. Kept intentionally lightweight — NOT a full Porter stemmer — because this matches what the docs search index expects.

Types

type Auth

type Auth struct {
	APIKey        string
	Authorization string
}

Auth carries the credentials extracted from an incoming MCP request, forwarded to the CLI subprocess through sanitized environment variables.

func AuthFromContext

func AuthFromContext(ctx context.Context) (Auth, error)

AuthFromContext recovers the Auth value previously stored by InjectAuthContext and reports an error if the request lacks credentials.

type ChatContext added in v1.3.1

type ChatContext struct {
	Current string             `json:"current"`
	History []ChatContextEntry `json:"history,omitempty"`
}

ChatContext is the payload carried in the X-Escape-Chat-Context header. It holds the user's current message and a few recent turns, so the classifier can resolve ambiguous pronouns and domain paraphrases (e.g. "findings" vs "issues").

type ChatContextEntry added in v1.3.1

type ChatContextEntry struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

ChatContextEntry is one prior chat turn.

type Classifier added in v1.3.1

type Classifier interface {
	Rank(ctx context.Context, chatCtx ChatContext, digest []ToolDigest) ([]string, error)
	TopK() int
}

Classifier ranks tools by their relevance to a chat context. Nil Classifier means "not configured"; callers should treat that as "no ranking available" and fall back to a compact catalog.

func NewClassifierFromEnv added in v1.3.1

func NewClassifierFromEnv() (Classifier, error)

NewClassifierFromEnv builds a Classifier from the MCP_CLASSIFIER_* env vars. If the endpoint or api key are missing, returns (nil, nil) so callers can opt-in without hard-failing at boot.

type CommandExecutionOptions

type CommandExecutionOptions struct {
	PublicAPIURL string
}

CommandExecutionOptions carries the shared runtime inputs the tool handlers need that are not part of a specific tool spec.

type DocsSearchIndex added in v1.3.1

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

DocsSearchIndex is the Go port of services/mcp-server/src/lanes/knowledge/search-index.ts.

func NewDocsSearchIndex added in v1.3.1

func NewDocsSearchIndex(options DocsSearchIndexOptions) *DocsSearchIndex

NewDocsSearchIndex builds a docs search index with sensible defaults. Any option can be overridden by passing DocsSearchIndexOptions.

func (*DocsSearchIndex) Search added in v1.3.1

func (d *DocsSearchIndex) Search(ctx context.Context, queryInput string, limit int) ([]KnowledgeSearchResult, error)

Search returns the top N documentation matches for the given query.

type DocsSearchIndexOptions added in v1.3.1

type DocsSearchIndexOptions struct {
	DocsSiteURL    string
	SearchIndexURL string
	TTL            time.Duration
	HTTPClient     *http.Client
}

DocsSearchIndexOptions configures the docs search index.

type ExecutionOptions

type ExecutionOptions struct {
	Command        []string
	DisplayCommand []string
	Body           any
	Auth           Auth
	PublicAPIURL   string
}

ExecutionOptions carries the request-scoped inputs ExecuteCLICommand needs to spawn one CLI subprocess.

type ExecutionResult

type ExecutionResult struct {
	Stdout          string
	Stderr          string
	StdoutTruncated bool
	StderrTruncated bool
	ExitCode        int
	Payload         any
}

ExecutionResult is the captured stdout/stderr/exit-code plus the parsed JSON payload (when the CLI produced valid JSON on stdout).

func ExecuteCLICommand

func ExecuteCLICommand(ctx context.Context, options ExecutionOptions) (*ExecutionResult, error)

ExecuteCLICommand spawns the current escape-cli binary with the supplied command + arguments, forwards authentication through a sanitized environment, pipes the optional request body to stdin, and returns the structured result. The caller is responsible for binding a timeout on ctx.

type FlagBinding

type FlagBinding struct {
	Property string
	FlagName string
	Kind     string
}

FlagBinding maps an MCP tool property to a CLI flag on the underlying Cobra command, including the type the value must be rendered as.

type IntentMode added in v1.3.1

type IntentMode string

IntentMode controls how the tools/list response is shaped. See the MCP_INTENT_FILTER env var for the runtime switch.

const (
	// IntentModeOn runs the classifier when a chat-context header is present.
	// Selected tools ship with full schemas; the rest ship as compact stubs.
	IntentModeOn IntentMode = "on"
	// IntentModeCompactOnly always ships compact stubs for every command-backed
	// tool. The classifier is never consulted. Useful when the classifier is
	// misconfigured but we still need to fit under size limits.
	IntentModeCompactOnly IntentMode = "compact_only"
	// IntentModeOff disables the middleware and returns the raw library
	// response (every tool with its full schema). Emergency rollback only.
	IntentModeOff IntentMode = "off"
)

func ModeFromEnv added in v1.3.1

func ModeFromEnv(fallback IntentMode) IntentMode

ModeFromEnv resolves MCP_INTENT_FILTER, defaulting to fallback when unset or invalid.

type IntentOptions added in v1.3.1

type IntentOptions struct {
	Mode       IntentMode
	Classifier Classifier
	Specs      []ToolSpec
}

IntentOptions configures the HTTP interceptor.

type KnowledgeOptions added in v1.3.1

type KnowledgeOptions struct {
	DocsSiteURL     string
	DocsIndexURL    string
	PlatformBaseURL string
	DocsTTL         int64
}

KnowledgeOptions configures the answer_question tool. Zero-value fields fall back to the production defaults (docs.escape.tech, app.escape.tech).

type KnowledgeSearchResult added in v1.3.1

type KnowledgeSearchResult struct {
	Title   string `json:"title"`
	URL     string `json:"url"`
	Snippet string `json:"snippet"`
}

KnowledgeSearchResult is what the tool returns per match.

type LinkIntent added in v1.3.1

type LinkIntent struct {
	ExplicitLinkRequest bool
	Target              LinkTarget
}

LinkIntent is the detector's verdict.

func DetectLinkIntent added in v1.3.1

func DetectLinkIntent(query string) LinkIntent

DetectLinkIntent classifies a user question by the surface they want a link to (docs / platform / both / none) and whether they asked explicitly.

type LinkTarget added in v1.3.1

type LinkTarget string

LinkTarget describes which surfaces the link-intent detector thinks the question is about. Ported from services/mcp-server/src/lanes/knowledge/link-intent.ts.

const (
	LinkTargetDocs     LinkTarget = "docs"
	LinkTargetPlatform LinkTarget = "platform"
	LinkTargetBoth     LinkTarget = "both"
	LinkTargetNone     LinkTarget = "none"
)

LinkTarget* enumerate the surfaces the link-intent detector can route the caller to. Mirrors the TS LinkTarget enum so behavior matches across both MCP servers.

type PlatformLink struct {
	Label string `json:"label"`
	URL   string `json:"url"`
}

PlatformLink is what the selector returns.

type PlatformLinkSelector added in v1.3.1

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

PlatformLinkSelector picks relevant platform deep links for a query.

func NewPlatformLinkSelector added in v1.3.1

func NewPlatformLinkSelector(baseURL string) (*PlatformLinkSelector, error)

NewPlatformLinkSelector builds a selector using the embedded catalog and the given base URL (e.g. https://app.escape.tech).

func NewPlatformLinkSelectorWithCatalog added in v1.3.1

func NewPlatformLinkSelectorWithCatalog(baseURL string, catalog []PlatformRoute) (*PlatformLinkSelector, error)

NewPlatformLinkSelectorWithCatalog lets callers override the catalog (mainly for tests). A nil/empty catalog falls back to the embedded one.

func (*PlatformLinkSelector) Select added in v1.3.1

func (s *PlatformLinkSelector) Select(queryContext string, limit int) []PlatformLink

Select returns up to `limit` platform links that match the query context. Ported from platform-links.ts (scoreRoute + createPlatformLinkSelector).

type PlatformRoute added in v1.3.1

type PlatformRoute struct {
	Path   string   `json:"path"`
	Tokens []string `json:"tokens"`
}

PlatformRoute is a single entry of the curated platform-URL catalog. Ported from services/mcp-server/src/generated/platform-routes.generated.ts.

type Server

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

Server is the embedded MCP server that exposes CLI commands over HTTP.

func NewServer

func NewServer(options ServerOptions) *Server

NewServer builds a non-started embedded MCP server from the supplied options.

func (*Server) Serve

func (s *Server) Serve(ctx context.Context) error

Serve starts the embedded MCP server and blocks until the supplied context is cancelled. The shutdown path uses a detached context to give in-flight handlers a bounded drain window.

type ServerOptions

type ServerOptions struct {
	Version      string
	Port         int
	PublicAPIURL string
	Tools        []ToolSpec
	// IntentMode controls the tools/list interceptor. When empty the server
	// defaults to IntentModeCompactOnly, which serves compact stubs but never
	// calls a classifier. Set to IntentModeOn to enable classifier-driven
	// expansion (requires MCP_CLASSIFIER_* env vars). IntentModeOff disables
	// the middleware entirely.
	IntentMode IntentMode
	// Classifier is an optional ranker used when IntentMode == IntentModeOn.
	// If nil while IntentModeOn, the server behaves as IntentModeCompactOnly.
	Classifier Classifier
}

ServerOptions configures the embedded HTTP-based MCP server.

type ToolDigest added in v1.3.1

type ToolDigest struct {
	Name        string `json:"name"`
	Description string `json:"description"`
}

ToolDigest is the compact tool metadata the classifier sees.

type ToolSpec

type ToolSpec struct {
	Name           string
	Path           string
	Description    string
	Tool           mcpgo.Tool
	Command        []string
	PositionalArgs []string
	FlagBindings   []FlagBinding
	BodyProperty   string
	// AllowExtraArgs opts the tool into reading a free-form `args` string array
	// from the request payload and forwarding it verbatim to the subprocess.
	// Off by default so the Cobra-to-MCP mapping remains an explicit allowlist.
	AllowExtraArgs bool
}

ToolSpec fully describes one CLI-backed MCP tool: its MCP-level metadata plus the subprocess invocation plan (command path, positional + flag bindings, and optional stdin body property).

Jump to

Keyboard shortcuts

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