Documentation
¶
Overview ¶
Package mcp: thin-client stdio proxy.
Every Claude Code subagent process spawns its own copy of the project's .mcp.json-configured MCP servers, including "stapler-squad --mcp". Prior to this file, that meant each subprocess called buildMCPDeps() -> BuildCoreDeps() -> NewSessionServiceFromConfig(), which opens its own ent/SQLite client, EventBus, ReviewQueue, and ApprovalStore — a full duplicate of state the already-running stapler-squad HTTP server (localhost:8543) already holds. With N subagents in a session tree, that's N redundant SQLite connections and event buses for read-mostly MCP tool calls.
NewProxyCore/RunProxyServer instead connect to the running server's Streamable HTTP MCP endpoint (mounted at /mcp by NewHTTPHandler) and forward every stdio tool call to it, so the stdio subprocess holds no storage of its own. If the HTTP server isn't reachable (e.g. no daemon running yet), the caller falls back to the original fully-local NewCore() path.
Package mcp implements the MCP (Model Context Protocol) server for Stapler Squad. Activated by the --mcp flag; communicates over stdio transport.
Index ¶
- Constants
- Variables
- func InitMCPLogging()
- func NewCore(store session.InstanceStore, svc *services.SessionService, ...) *mcpserver.MCPServer
- func NewHTTPHandler(store session.InstanceStore, svc *services.SessionService, ...) *mcpserver.StreamableHTTPServer
- func NewProxyCore(ctx context.Context, httpURL string, headers map[string]string) (*mcpserver.MCPServer, *mcpclient.Client, error)
- func ProxyHeaders() map[string]string
- func RunProxyServer(ctx context.Context, httpURL string, headers map[string]string) error
- func RunServer(ctx context.Context, store session.InstanceStore, svc *services.SessionService, ...) error
- func WithSessionUUID(ctx context.Context, id string) context.Context
- type BranchInfo
- type CreateSessionForPRResult
- type CreateSessionResult
- type DiffStats
- type GetSessionDiffResult
- type GetSessionResult
- type GitHubPRSummary
- type ListGitHubPRsResult
- type ListSessionBranchesResult
- type ListSessionsResult
- type MCPError
- type MCPResult
- type ReadSessionOutputResult
- type ReviewCompletionSignaler
- type ReviewTrigger
- type RunCommandResult
- type SearchSessionsResult
- type SendControlResult
- type SessionDetail
- type SessionSummary
- type SetSessionGoalResult
- type SteerSessionResult
- type UpdateSessionTaskResult
- type WaitForOutputResult
- type WriteSessionResult
Constants ¶
const ( ErrPermissionDenied = "PERMISSION_DENIED" ErrItemNotFound = "ITEM_NOT_FOUND" ErrFeatureDisabled = "FEATURE_DISABLED" )
const ( ErrSessionNotFound = "SESSION_NOT_FOUND" ErrInvalidArgument = "INVALID_ARGUMENT" ErrInternalError = "INTERNAL_ERROR" ErrConfirmationRequired = "CONFIRMATION_REQUIRED" ErrInvalidStatusTrans = "INVALID_STATUS_TRANSITION" ErrSessionNotRunning = "SESSION_NOT_RUNNING" ErrRateLimitExceeded = "RATE_LIMIT_EXCEEDED" ErrSessionStartupTimeout = "SESSION_STARTUP_TIMEOUT" ErrInvalidPath = "INVALID_PATH" ErrPTYWriteTimeout = "PTY_WRITE_TIMEOUT" )
Error code constants — machine-readable identifiers for all tool failures.
Variables ¶
ErrProxyUnavailable wraps any failure to connect to the running HTTP MCP server during the initial handshake (transport start, initialize, or tools/list). Callers should treat this as non-fatal and fall back to a fully local MCP core.
Functions ¶
func InitMCPLogging ¶
func InitMCPLogging()
InitMCPLogging redirects all application loggers to stderr so that log lines do not pollute the MCP stdio channel (stdout). Must be called before RunServer.
func NewCore ¶
func NewCore(store session.InstanceStore, svc *services.SessionService, sbMgr *scrollback.ScrollbackManager, storage *session.Storage, eventBus *events.EventBus, prCache *githubpkg.UserPRCache, backlogEnabled func() bool) *mcpserver.MCPServer
NewCore creates an MCPServer with all tools registered. Shared by the stdio path (RunServer) and the HTTP path (NewHTTPHandler). storage is optional — when nil, backlog tools are not registered. eventBus is optional — when nil, triage-complete notifications are disabled. prCache is optional — when nil, GitHub PR tools are not registered. backlogEnabled is optional — when nil, backlog/goal tools are always enabled (matches pre-flag behavior, used by tests). When set, it gates registration at startup (belt-and-suspenders) and is threaded into each backlog/goal handler so a live flag flip takes effect without restarting the MCP server.
func NewHTTPHandler ¶
func NewHTTPHandler(store session.InstanceStore, svc *services.SessionService, sbMgr *scrollback.ScrollbackManager, storage *session.Storage, eventBus *events.EventBus, prCache *githubpkg.UserPRCache, backlogEnabled func() bool) *mcpserver.StreamableHTTPServer
NewHTTPHandler returns an http.Handler that serves the MCP protocol over Streamable HTTP (the MCP 2025-03-26 transport). Mount it at /mcp on the existing HTTP server so Claude sessions can connect without spawning a subprocess. eventBus is optional — pass nil to disable triage-complete notifications. prCache is optional — pass nil to disable GitHub PR tools. backlogEnabled is optional — see NewCore.
func NewProxyCore ¶ added in v1.37.0
func NewProxyCore(ctx context.Context, httpURL string, headers map[string]string) (*mcpserver.MCPServer, *mcpclient.Client, error)
NewProxyCore connects to an already-running stapler-squad HTTP server at httpURL and builds a local *mcpserver.MCPServer whose tools simply forward CallTool requests to it. Returns an error wrapping ErrProxyUnavailable if the remote server cannot be reached or fails the MCP handshake.
The returned *mcpclient.Client must be closed by the caller once the local server is done serving (e.g. via defer).
func ProxyHeaders ¶ added in v1.37.0
ProxyHeaders builds the HTTP headers forwarded on every request to the remote MCP endpoint. Mirrors the X-Stapler-Session-UUID header injected by claudeMCPConfigArgs for the primary (non-proxied) HTTP MCP path, so backlog tools can identify the calling session the same way regardless of transport.
func RunProxyServer ¶ added in v1.37.0
RunProxyServer connects to the running stapler-squad HTTP server and serves stdio MCP as a thin forwarding proxy, blocking until stdin closes or ctx is cancelled. Returns an error wrapping ErrProxyUnavailable (safe to fall back to a local core) if the initial handshake fails; any error returned after a successful handshake reflects a mid-session failure and should not trigger a fallback (stdout may already carry a partial MCP session).
func RunServer ¶
func RunServer(ctx context.Context, store session.InstanceStore, svc *services.SessionService, sbMgr *scrollback.ScrollbackManager, storage *session.Storage, eventBus *events.EventBus, prCache *githubpkg.UserPRCache, backlogEnabled func() bool) error
RunServer initializes and starts the MCP stdio server. It blocks until the context is cancelled or stdin is closed. store is used for read-only discovery tools. svc provides lifecycle operations. sbMgr provides read access to terminal scrollback data persisted on disk. storage is used for backlog tools (optional; pass nil to disable). eventBus is optional — pass nil to disable triage-complete notifications on stdio path. prCache is optional — pass nil to disable GitHub PR tools. backlogEnabled is optional — see NewCore.
Types ¶
type BranchInfo ¶
BranchInfo holds branch metadata for list_session_branches.
type CreateSessionForPRResult ¶ added in v1.35.0
type CreateSessionForPRResult struct {
MCPResult
Session *SessionDetail `json:"session,omitempty"`
}
CreateSessionForPRResult is returned by create_session_for_pr.
type CreateSessionResult ¶
type CreateSessionResult struct {
MCPResult
Session *SessionDetail `json:"session,omitempty"`
MCPInjectionFailed bool `json:"mcp_injection_failed,omitempty"`
}
CreateSessionResult is returned by create_session.
type DiffStats ¶
type DiffStats struct {
FilesChanged int `json:"files_changed"`
Insertions int `json:"insertions"`
Deletions int `json:"deletions"`
}
DiffStats mirrors git.DiffStats for JSON output.
type GetSessionDiffResult ¶
type GetSessionDiffResult struct {
MCPResult
Diff string `json:"diff"`
Stats DiffStats `json:"stats"`
Truncated bool `json:"truncated"`
}
GetSessionDiffResult is the response for get_session_diff.
type GetSessionResult ¶
type GetSessionResult struct {
MCPResult
Session *SessionDetail `json:"session,omitempty"`
}
GetSessionResult is returned by get_session.
type GitHubPRSummary ¶ added in v1.35.0
type GitHubPRSummary struct {
Owner string `json:"owner"`
Repo string `json:"repo"`
Number int `json:"number"`
Title string `json:"title"`
URL string `json:"url"`
Branch string `json:"branch"`
BaseBranch string `json:"base_branch"`
IsDraft bool `json:"is_draft"`
CIStatus string `json:"ci_status"`
ApprovedCount int `json:"approved_count"`
ChangesReqCount int `json:"changes_req_count"`
UpdatedAt time.Time `json:"updated_at"`
ExistingSessionID string `json:"existing_session_id,omitempty"`
WorktreePath string `json:"worktree_path,omitempty"`
}
GitHubPRSummary is the MCP representation of one open pull request.
type ListGitHubPRsResult ¶ added in v1.35.0
type ListGitHubPRsResult struct {
MCPResult
PRs []GitHubPRSummary `json:"prs"`
TotalCount int `json:"total_count"`
Accounts []string `json:"accounts"`
}
ListGitHubPRsResult is returned by list_github_prs.
type ListSessionBranchesResult ¶
type ListSessionBranchesResult struct {
MCPResult
Branches []BranchInfo `json:"branches"`
CurrentBranch string `json:"current_branch"`
}
ListSessionBranchesResult is the response for list_session_branches.
type ListSessionsResult ¶
type ListSessionsResult struct {
MCPResult
Sessions []SessionSummary `json:"sessions"`
TotalCount int `json:"total_count"`
NextCursor *string `json:"next_cursor"`
}
ListSessionsResult is returned by list_sessions.
type MCPError ¶
type MCPError struct {
Code string `json:"code"`
Message string `json:"message"`
Remediation string `json:"remediation,omitempty"`
}
MCPError is the structured error returned in every tool result on failure.
type MCPResult ¶
MCPResult is the top-level wrapper for all tool responses. On success, Success=true and Error is nil. On failure, Success=false and Error is set.
type ReadSessionOutputResult ¶
type ReadSessionOutputResult struct {
MCPResult
Output string `json:"output,omitempty"`
TotalLines int `json:"total_lines"`
Truncated bool `json:"truncated"`
}
ReadSessionOutputResult is the response type for read_session_output.
type ReviewCompletionSignaler ¶ added in v1.35.0
type ReviewCompletionSignaler interface {
StopDriverForSession(sessionTitle string)
}
ReviewCompletionSignaler allows the MCP handler to stop an AutonomousDriver after submit_review_verdict completes. The stop call is belt-and-suspenders; the LLM orchestrator will also detect completion from the terminal tail. Note: Stop() fires fireCompletion(Stuck=true), but the role-aware callback skips all status transitions for SessionRoleReview, so this is safe.
type ReviewTrigger ¶ added in v1.37.0
type ReviewTrigger interface {
TriggerReviewForSession(sessionUUID string)
}
ReviewTrigger allows the MCP handler to spawn a review gate immediately when request_review is called, instead of waiting for the next ReconcileStuck tick (up to 60s later). Implemented by SessionService, which delegates to the BacklogLifecycleListener wired via SetReviewGateTrigger.
type RunCommandResult ¶
type RunCommandResult struct {
MCPResult
Output string `json:"output"`
Truncated bool `json:"truncated"`
TimedOut bool `json:"timed_out"`
LastSequence uint64 `json:"last_sequence"`
}
RunCommandResult is the response for run_command.
type SearchSessionsResult ¶
type SearchSessionsResult struct {
MCPResult
Sessions []SessionSummary `json:"sessions"`
TotalCount int `json:"total_count"`
}
SearchSessionsResult is returned by search_sessions.
type SendControlResult ¶
SendControlResult is the response for send_control.
type SessionDetail ¶
type SessionDetail struct {
SessionSummary
Program string `json:"program"`
SessionType string `json:"session_type"`
WorkingDir string `json:"working_dir,omitempty"`
}
SessionDetail extends SessionSummary with additional fields returned by get_session.
type SessionSummary ¶
type SessionSummary struct {
ID string `json:"id"`
Title string `json:"title"`
Status string `json:"status"`
Tags []string `json:"tags"`
Branch string `json:"branch,omitempty"`
Path string `json:"path"`
CreatedAt time.Time `json:"created_at"`
LastActivityAt time.Time `json:"last_activity_at"`
}
SessionSummary is returned by list_sessions and search_sessions.
type SetSessionGoalResult ¶ added in v1.35.0
type SteerSessionResult ¶ added in v1.35.0
type SteerSessionResult struct {
MCPResult
SessionID string `json:"session_id"`
CharsSent int `json:"chars_sent"`
Result string `json:"result,omitempty"` // set when using --resume subprocess
Method string `json:"method"` // "send_keys" or "resume_subprocess"
}
SteerSessionResult is the response for steer_session.
type UpdateSessionTaskResult ¶ added in v1.35.0
type WaitForOutputResult ¶
type WaitForOutputResult struct {
MCPResult
Matched bool `json:"matched"`
MatchedLine string `json:"matched_line,omitempty"`
Output string `json:"output"`
Truncated bool `json:"truncated"`
}
WaitForOutputResult is the response for wait_for_output.
type WriteSessionResult ¶
WriteSessionResult is the response for write_to_session.