mcp

package
v0.60.0 Latest Latest
Warning

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

Go to latest
Published: Jul 19, 2026 License: AGPL-3.0 Imports: 18 Imported by: 0

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

View Source
const (
	ScopeUser        = "user"
	ScopeUserAgent   = "user_agent"
	ScopeSystem      = "system"
	ScopeSystemAgent = "system_agent"
)

Scope values mirror the skill/vault 4-value model.

View Source
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.

View Source
const (
	AuthTypeNone   = "none"
	AuthTypeBearer = "bearer"
)

Auth types. OAuth is deferred: store an encrypted bearer token per connection.

View Source
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

func IsSystemScope(scope string) bool

IsSystemScope reports whether a scope is admin-managed (no owning user).

func NamespacedToolName

func NamespacedToolName(serverName, toolName string) string

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

func ValidAuthType(a string) bool

ValidAuthType reports whether a is a supported auth type.

func ValidScope

func ValidScope(s string) bool

ValidScope reports whether s is one of the 4 scope values.

func ValidTransport

func ValidTransport(t string) bool

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

func Connect(ctx context.Context, reg Registration, bearer string) (*Client, error)

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

func (c *Client) CallTool(ctx context.Context, name string, args map[string]any) (string, error)

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.

func (*Client) Close

func (c *Client) Close() error

Close ends the session. Idempotent so multiple tool wrappers can share one client and each safely Close it on registry teardown.

func (*Client) ListTools

func (c *Client) ListTools(ctx context.Context) ([]*mcpsdk.Tool, error)

ListTools returns the tools the server currently advertises.

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

func NewService(db DB, vault Vault) *Service

NewService builds a Service. vault may be nil, in which case bearer auth is rejected (there is nowhere to store the secret).

func NewServiceForPool

func NewServiceForPool(pool *pgxpool.Pool, vault Vault) *Service

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

func (s *Service) BearerToken(ctx context.Context, reg Registration) (string, error)

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) Delete

func (s *Service) Delete(ctx context.Context, id, scope, userID, agentID string) error

Delete removes a registration in the given scope and its vault credential.

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

func (p *ToolProvider) ToolsForContext(ctx context.Context, userID, agentID string) []pkgtools.Tool

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.

Jump to

Keyboard shortcuts

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