mcp

package
v0.2.49 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2026 License: GPL-2.0, GPL-3.0 Imports: 22 Imported by: 0

Documentation

Overview

Package mcp persists and serves the user's configured MCP (Model Context Protocol) servers.

Storage model

A single file at <configDir>/mcp.json, mode 0600, written atomically (temp + rename) via fileutil.SaveBytes. The file holds an ordered array of Server records. Order is the display order; no separate index.

Scope

One scope only: user-global. Vibekit runs one container per user; per- chat or per-workspace MCP sets would add schema churn with no clear benefit. This matches how kiro-cli's mcpServers parameter is scoped to a session (not a chat), and we intentionally use the same set for every bridge spawned within the same container.

Secrets

Env values and header values often contain API keys. Store returns them masked ("***") from public reads; Update preserves the stored value when the client sends "***" so the UI can round-trip without re-submitting secrets. On disk the file is plaintext with 0600 perms — the threat model is the same as the chat files that already live in the same directory (user's own container).

Index

Constants

View Source
const SecretMask = api.SecretMask

SecretMask references the shared api.SecretMask constant.

Variables

View Source
var (
	ErrNotFound     = errors.New("server not found")
	ErrNameConflict = errors.New("server name already exists")
	ErrPersist      = errors.New("persist failed")

	// ErrPersistMarshal and ErrPersistWrite are typed sub-sentinels for
	// ErrPersist. Callers can still match the parent via
	// errors.Is(err, ErrPersist); the sub-sentinels let the HTTP layer
	// log at different levels (marshal = programmer bug, write = transient infra).
	ErrPersistMarshal = fmt.Errorf("%w: marshal", ErrPersist)
	ErrPersistWrite   = fmt.Errorf("%w: write", ErrPersist)
)

Package-level errors. All HTTP handlers map these to 4xx responses; anything else is a 500. ErrPersist wraps the underlying filesystem error from SaveJSON's temp+rename so writeErr can route mutator failures to 500 with a generic body (no filesystem path leaked to the browser) while the full error still shows up in slog.

Functions

func NewPrewarmRunner

func NewPrewarmRunner(ctx context.Context, store *Store) *prewarm.Runner

NewPrewarmRunner creates a prewarm runner using the store directly as the server lister (Store satisfies prewarm.ServerLister via its EnabledServers method).

func Validate

func Validate(s *Server) error

Validate checks a fully-populated Server record. Called on every create/update before persist. Callers do not run their own checks; this is the single source of truth.

Types

type KeyPair

type KeyPair struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

KeyPair is an ordered env-var or header entry. Ordered (vs map) so the UI can edit entries without dropping duplicates; the on-wire ACP format is a JSON object so we flatten on export.

type RegistryEntry

type RegistryEntry struct {
	Name        string            `json:"name"`
	Title       string            `json:"title,omitempty"`
	Description string            `json:"description,omitempty"`
	Version     string            `json:"version,omitempty"`
	Repository  string            `json:"repository,omitempty"`
	Packages    []RegistryPackage `json:"packages,omitempty"`
	Remotes     []RegistryRemote  `json:"remotes,omitempty"`
}

RegistryEntry is the browser-facing shape of one search result.

type RegistryEnvVar

type RegistryEnvVar struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	Format      string `json:"format,omitempty"`
	Required    bool   `json:"required,omitempty"`
	Secret      bool   `json:"secret,omitempty"`
}

RegistryEnvVar / RegistryHeader describe a configurable field the user must fill in before the server will run.

type RegistryHeader

type RegistryHeader struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	Value       string `json:"value,omitempty"`
	Required    bool   `json:"required,omitempty"`
	Secret      bool   `json:"secret,omitempty"`
}

RegistryHeader describes an HTTP header the user must configure before the remote server will run.

type RegistryPackage

type RegistryPackage struct {
	RegistryType string           `json:"registry_type"`
	Identifier   string           `json:"identifier"`
	Version      string           `json:"version,omitempty"`
	EnvVars      []RegistryEnvVar `json:"env_vars,omitempty"`
}

RegistryPackage is one install option from a stdio-speaking server. Only npm and oci are surfaced; everything else is hidden so the UI doesn't offer install paths we can't fulfil on the container.

type RegistryProxy

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

RegistryProxy fetches + caches + shapes upstream registry responses.

func NewRegistryProxy

func NewRegistryProxy() *RegistryProxy

NewRegistryProxy returns a ready-to-use proxy with sensible timeouts and a redirect allowlist. The default http.Client follows up to 10 redirects, which would let a compromised or moved upstream bounce the proxy to 169.254.169.254, 127.0.0.1, or a LAN service. We restrict redirects to the registry host itself and cap at 3 hops.

func (*RegistryProxy) RegisterRoutes

func (p *RegistryProxy) RegisterRoutes(mux *http.ServeMux)

RegisterRoutes wires /api/mcp/registry/search.

GET /api/mcp/registry/search?q=<query>&limit=<n>

type RegistryRemote

type RegistryRemote struct {
	Type    string           `json:"type"`
	URL     string           `json:"url"`
	Headers []RegistryHeader `json:"headers,omitempty"`
}

RegistryRemote is one remote transport (http/sse) option.

type Server

type Server struct {
	URL               string    `json:"url,omitempty"`
	Name              string    `json:"name"`
	Command           string    `json:"command,omitempty"`
	OAuthClientID     string    `json:"oauth_client_id,omitempty"`
	OAuthClientSecret string    `json:"oauth_client_secret,omitempty"`
	ID                ServerID  `json:"id"`
	Transport         Transport `json:"transport"`
	Args              []string  `json:"args,omitempty"`
	Env               []KeyPair `json:"env,omitempty"`
	Headers           []KeyPair `json:"headers,omitempty"`
	DisabledTools     []string  `json:"disabled_tools,omitempty"`
	AutoApprove       []string  `json:"auto_approve,omitempty"`
	KnownTools        []string  `json:"known_tools,omitempty"`
	CreatedAt         int64     `json:"created_at"`
	UpdatedAt         int64     `json:"updated_at"`
	Prewarm           bool      `json:"prewarm,omitempty"`
	Enabled           bool      `json:"enabled"`
}

Server is one user-configured MCP server. ID is a short stable identifier used in URLs and events (generated at create time); Name is the user-visible label that also becomes the kiro-cli mcpServer name (must be unique across the configured set).

func NewServer

func NewServer(transport Transport, name string, opts ...ServerOption) (*Server, error)

NewServer constructs a Server with validated transport-specific fields. Fields inappropriate for the given transport are rejected at creation time rather than deferred to Validate(). Returns an error if the transport is unknown or if transport-incompatible fields are populated.

func (*Server) UnmarshalJSON

func (s *Server) UnmarshalJSON(data []byte) error

UnmarshalJSON validates the transport field at the JSON parse boundary, rejecting unknown transport values early rather than letting them flow through to runtime dispatch. All three transports (stdio, http, sse) are accepted as first-class values and preserved verbatim — "sse" is no longer folded into "http", since KAS accepts a distinct SSE entry over the v3 wire (see the Transport doc in store.go).

type ServerID

type ServerID string

ServerID is a validated identifier for an MCP server record. Values are generated at Create time via newID() and are base32-encoded random values. The type prevents accidental Name-as-ID confusion at compile time, mirroring api.ChatID and api.SessionID.

func ParseServerID

func ParseServerID(raw string) (ServerID, error)

ParseServerID validates a raw string as a server ID. Returns an error if the value is empty or exceeds 32 characters.

func (ServerID) String

func (id ServerID) String() string

String implements fmt.Stringer.

type ServerOption

type ServerOption func(*Server)

ServerOption configures a Server during construction via NewServer.

func WithCommand

func WithCommand(cmd string, args ...string) ServerOption

WithCommand sets the command for stdio transport servers.

func WithEnv

func WithEnv(env []KeyPair) ServerOption

WithEnv sets environment variables for stdio transport servers.

func WithHeaders

func WithHeaders(headers []KeyPair) ServerOption

WithHeaders sets HTTP headers for HTTP transport servers.

func WithOAuthClientID

func WithOAuthClientID(id string) ServerOption

WithOAuthClientID sets the OAuth client ID for HTTP transport servers.

func WithURL

func WithURL(url string) ServerOption

WithURL sets the URL for HTTP transport servers.

type Store

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

Store holds the persisted list in memory plus the coordination needed to serialise writes and notify watchers on changes.

func New

func New(ctx context.Context, configDir string, onChange func(context.Context)) (*Store, error)

New loads the file (or initialises empty) and returns a ready store. onChange is invoked on a fresh goroutine (without the store mutex held) whenever the persisted set is mutated; nil is valid if no one cares. The callback is free to call back into the store — it won't deadlock on the caller's write lock. The ctx is stored for use in fire-and-forget persist paths (e.g. SetKnownTools) so writes are cancellable on shutdown.

func (*Store) ACPServers

func (s *Store) ACPServers(ctx context.Context) []map[string]any

ACPServers satisfies api.MCPConfig by returning every enabled server shaped for kiro-cli's session/new / session/load mcpServers parameter. Secrets are included; the slice must not be logged.

func (*Store) Create

func (s *Store) Create(ctx context.Context, in *Server) (*Server, error)

Create inserts a new server, assigning a fresh ID and timestamps. Validates shape before persisting. Returns a masked copy of the stored record.

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, id ServerID) error

Delete removes a server by id. No-op if not found.

func (*Store) EnabledNames

func (s *Store) EnabledNames(_ context.Context) map[string]struct{}

EnabledNames satisfies api.MCPConfig, returning the set of enabled server names for the hub's defensive filtering of init notifications.

func (*Store) EnabledRaw

func (s *Store) EnabledRaw(ctx context.Context) []*Server

EnabledRaw returns a deep copy of every enabled server with secrets intact. Used when constructing the mcpServers parameter for kiro-cli. Not exposed over HTTP.

func (*Store) EnabledServers

func (s *Store) EnabledServers(ctx context.Context) []prewarm.ServerInfo

EnabledServers returns the prewarm-relevant view of enabled servers. Satisfies prewarm.ServerLister so the Store can be passed directly to prewarm.NewRunner without an adapter.

func (*Store) Get

func (s *Store) Get(_ context.Context, id ServerID) *Server

Get returns a masked copy of one server, or nil.

func (*Store) List

func (s *Store) List(ctx context.Context) []*Server

List returns a deep copy of every server with secrets masked. Safe to serve directly over the wire.

func (*Store) RegisterRoutes

func (s *Store) RegisterRoutes(mux *http.ServeMux)

RegisterRoutes wires the MCP config endpoints.

GET    /api/mcp          → list (secrets masked)
POST   /api/mcp          → create
GET    /api/mcp/{id}     → one (secrets masked)
PUT    /api/mcp/{id}     → replace (preserves "***" values)
PATCH  /api/mcp/{id}     → toggle enabled: body {"enabled": bool}
DELETE /api/mcp/{id}     → remove

func (*Store) SetEnabled

func (s *Store) SetEnabled(ctx context.Context, id ServerID, enabled bool) (*Server, error)

SetEnabled flips the enabled flag for one server. Returns the updated masked copy.

func (*Store) SetKnownTools

func (s *Store) SetKnownTools(ctx context.Context, name string, tools []string)

SetKnownTools updates the cached tool list for the named server. Called when kiro-cli reports commands/available with per-server tool names. Persists to mcp.json so the UI can show suggestions even when the server is disconnected. No-op if the server name isn't found, or if the incoming set is identical to what's already stored.

func (*Store) SetOnChange

func (s *Store) SetOnChange(fn func(context.Context))

SetOnChange replaces the change callback.

func (*Store) Update

func (s *Store) Update(ctx context.Context, id ServerID, in *Server) (*Server, error)

Update replaces one server by id. Fields whose secret value equals SecretMask are preserved from the existing record, so a client can edit non-secret fields without re-submitting the secret. Returns a masked copy of the stored record.

type Transport

type Transport string

Transport names the MCP transports vibekit accepts in mcp.json. "stdio" is universal; "http" is the Streamable HTTP transport (2025-03-26 MCP spec); "sse" is the legacy HTTP+SSE remote transport.

SSE is a first-class, stored transport (not normalized to "http"): kiro-cli v3 (KAS) re-advertises mcpCapabilities.sse:true and accepts a distinct {type:"sse", url, headers} entry on session/new (verified against the KAS 2.12 acp-server bundle + a live session/new probe; a bogus transport is rejected, so "sse" is genuinely accepted, not merely tolerated). "sse" and "http" share the same remote wire shape (url + headers) and differ only in the ACP `type` discriminator, so both are validated as remote transports and both round-trip through the store verbatim.

const (
	TransportStdio Transport = "stdio"
	TransportHTTP  Transport = "http"
	TransportSSE   Transport = "sse"
)

TransportStdio, TransportHTTP, and TransportSSE define the valid Transport values for MCP server connections.

func ParseTransport

func ParseTransport(s string) (Transport, error)

ParseTransport validates a raw string as a known transport. All three transports (stdio, http, sse) are first-class: "sse" is preserved as TransportSSE, not folded into "http" — KAS accepts a distinct SSE mcpServers entry over the v3 wire (see the Transport doc).

func (Transport) Valid

func (t Transport) Valid() bool

Valid reports whether t is one of the known transport values.

Directories

Path Synopsis
Package prewarm handles npx package pre-warming for MCP servers.
Package prewarm handles npx package pre-warming for MCP servers.

Jump to

Keyboard shortcuts

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