Documentation
¶
Overview ¶
Package mcp is an MCP (Model Context Protocol) client for Stella. It lets agents connect to external MCP servers over HTTP-based transports only (streamable HTTP + SSE); stdio is deliberately unsupported so the multi-user sandbox boundary never spawns local processes.
Registrations are scoped exactly like skills and vault entries (system / system_agent / user / user_agent) and any auth credential is stored age-encrypted in the vault, never in this table.
Index ¶
- Constants
- func IsSystemScope(scope string) bool
- func NamespacedToolName(serverName, toolName string) string
- func ValidAuthType(a string) bool
- func ValidScope(s string) bool
- func ValidTransport(t string) bool
- type Client
- type CreateInput
- type DB
- type Registration
- type Service
- func (s *Service) BearerToken(ctx context.Context, reg Registration) (string, error)
- func (s *Service) Create(ctx context.Context, in CreateInput) (Registration, error)
- func (s *Service) Delete(ctx context.Context, id, scope, userID, agentID string) error
- func (s *Service) ListByScope(ctx context.Context, scope, userID, agentID string) ([]Registration, error)
- func (s *Service) ResolveForContext(ctx context.Context, userID, agentID string) ([]Registration, error)
- func (s *Service) Update(ctx context.Context, in UpdateInput) (Registration, error)
- type ToolProvider
- type UpdateInput
- type Vault
Constants ¶
const ( ScopeUser = "user" ScopeUserAgent = "user_agent" ScopeSystem = "system" ScopeSystemAgent = "system_agent" )
Scope values mirror the skill/vault 4-value model.
const ( // TransportStreamableHTTP is the streamable HTTP transport (2025 spec). TransportStreamableHTTP = "streamable_http" // TransportSSE is the HTTP + Server-Sent Events transport (2024-11-05 spec). TransportSSE = "sse" )
Transport values. HTTP-based only; stdio is intentionally absent.
const ( AuthTypeNone = "none" AuthTypeBearer = "bearer" )
Auth types. OAuth is deferred: store an encrypted bearer token per connection.
const ToolNamespaceSep = "__"
ToolNamespaceSep separates the MCP prefix, server name, and tool name in the namespaced tool id exposed to the model (e.g. mcp__github__create_issue).
Variables ¶
This section is empty.
Functions ¶
func IsSystemScope ¶
IsSystemScope reports whether a scope is admin-managed (no owning user).
func NamespacedToolName ¶
NamespacedToolName returns the agent-facing tool name for a remote MCP tool, namespaced by server so tools from different servers do not collide with core, plugin, or skill tools. Both server and remote tool segments are normalized to [A-Za-z0-9_]; callers still detect collisions between normalized names.
func ValidAuthType ¶
ValidAuthType reports whether a is a supported auth type.
func ValidScope ¶
ValidScope reports whether s is one of the 4 scope values.
func ValidTransport ¶
ValidTransport reports whether t is an accepted HTTP-based transport. It rejects stdio and anything else so a sandbox can never launch a process.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a live connection to one external MCP server. It is safe to Close more than once.
func Connect ¶
Connect opens an MCP session to the server described by reg, injecting the bearer token (may be empty) on every HTTP request. Only HTTP-based transports are built; an unsupported transport is rejected here rather than dialed.
func (*Client) CallTool ¶
CallTool proxies a tools/call for the remote tool name with the given args and flattens the result content to a single string for the model.
type CreateInput ¶
type CreateInput struct {
Scope string
UserID string
AgentID string
Name string
URL string
Transport string
AuthType string
Token string
}
CreateInput describes a new registration. Token is the raw bearer token, stored encrypted in the vault and never persisted in mcp_server.
type DB ¶
type DB interface {
CreateMCPServer(ctx context.Context, arg sqlc.CreateMCPServerParams) (sqlc.McpServer, error)
GetMCPServerByID(ctx context.Context, id string) (sqlc.McpServer, error)
ListMCPServersByScope(ctx context.Context, arg sqlc.ListMCPServersByScopeParams) ([]sqlc.McpServer, error)
ListMCPServersForAgentContext(ctx context.Context, arg sqlc.ListMCPServersForAgentContextParams) ([]sqlc.McpServer, error)
UpdateMCPServerByScope(ctx context.Context, arg sqlc.UpdateMCPServerByScopeParams) (sqlc.McpServer, error)
DeleteMCPServerByScope(ctx context.Context, arg sqlc.DeleteMCPServerByScopeParams) error
}
DB is the persistence surface the Service needs. *sqlc.Queries satisfies it.
type Registration ¶
type Registration struct {
ID string
Scope string
UserID string
AgentID string
Name string
URL string
Transport string
AuthType string
CredentialRef string // vault entry name holding the bearer token; "" when none
Enabled bool
CreatedAt time.Time
UpdatedAt time.Time
}
Registration is one MCP server registration (metadata only, no secret).
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service manages MCP server registrations and their encrypted credentials. The registration table holds no secret material — the bearer token lives in the vault and is referenced by CredentialRef.
func NewService ¶
NewService builds a Service. vault may be nil, in which case bearer auth is rejected (there is nowhere to store the secret).
func NewServiceForPool ¶
NewServiceForPool builds a Service backed by the given connection pool, owning construction of its sqlc query set. vault may be nil, in which case bearer auth is rejected (there is nowhere to store the secret).
func (*Service) BearerToken ¶
BearerToken returns the decrypted bearer token for a registration, or an empty string when the server needs no auth.
func (*Service) Create ¶
func (s *Service) Create(ctx context.Context, in CreateInput) (Registration, error)
Create validates the input, stores any bearer token in the vault, and inserts the registration. Enum validation (scope, transport, auth) happens here so the stdio transport and other invalid values are rejected before touching the DB.
func (*Service) ListByScope ¶
func (s *Service) ListByScope(ctx context.Context, scope, userID, agentID string) ([]Registration, error)
ListByScope returns every registration in exactly one scope/owner bucket.
func (*Service) ResolveForContext ¶
func (s *Service) ResolveForContext(ctx context.Context, userID, agentID string) ([]Registration, error)
ResolveForContext returns the enabled registrations visible to a (user, agent), deduplicated by name with precedence user_agent > user > system_agent > system (the SQL already orders most-specific-first).
func (*Service) Update ¶
func (s *Service) Update(ctx context.Context, in UpdateInput) (Registration, error)
Update modifies a registration in the given current scope/owner bucket and returns the updated row. Omitted fields keep their current values. If bearer auth stays enabled and Token is omitted, the existing encrypted token is kept; moving scopes copies that token to the new vault bucket.
type ToolProvider ¶
type ToolProvider struct {
// contains filtered or unexported fields
}
ToolProvider surfaces the tools of every MCP server visible to a (user, agent) context into the agent tool registry, proxying tools/call back to the server. A down or misbehaving server is logged and skipped so it can never break an agent session.
func NewToolProvider ¶
func NewToolProvider(svc *Service) *ToolProvider
NewToolProvider builds a provider over the registration service.
func (*ToolProvider) ToolsForContext ¶
ToolsForContext connects to each visible, enabled MCP server, lists its tools, and returns them namespaced and ready to register. The caller owns the tools' lifetime: closing the tool registry closes any client session lazily opened by a tool call.
type UpdateInput ¶
type UpdateInput struct {
ID string
Scope string
UserID string
AgentID string
NewScope *string
NewUserID string
NewAgentID string
Name *string
URL *string
Transport *string
AuthType *string
Enabled *bool
Token *string
}
UpdateInput describes a partial registration update. Nil fields keep the current value; Token nil keeps the current bearer token, while Token != nil replaces it.
type Vault ¶
type Vault interface {
SetScoped(ctx context.Context, scope, userID, agentID, name, plaintext string) error
SetSystemScoped(ctx context.Context, scope, agentID, name, plaintext string) error
GetScoped(ctx context.Context, scope, userID, agentID, name string) (string, error)
DeleteScoped(ctx context.Context, scope, userID, agentID, name string) error
DeleteSystemScoped(ctx context.Context, scope, agentID, name string) error
}
Vault stores and retrieves the per-connection bearer token, age-encrypted at rest under the same 4-value scope as the registration. *vault.Service satisfies it.