Documentation
¶
Index ¶
- Constants
- Variables
- func Attach(mux goahttp.Muxer, service *Service)
- func BuildHeaders(systemEnv *toolconfig.CaseInsensitiveEnv, ...) map[string]string
- type AuthRejectedError
- type CachedListServers
- type CachedServerDetailsResponse
- type CallToolResult
- type CatalogService
- func (s *CatalogService) Details(ctx context.Context, registryID uuid.UUID, serverName string, ...) (*ServerDetails, error)
- func (s *CatalogService) List(ctx context.Context, search *string, registryID *uuid.UUID) ([]*types.ExternalMCPServerEntry, error)
- func (s *CatalogService) ReaderFor(source CatalogSource) (RegistryReader, error)
- func (s *CatalogService) Source(ctx context.Context, registryID uuid.UUID) (CatalogSource, error)
- func (s *CatalogService) Sources(ctx context.Context) ([]CatalogSource, error)
- type CatalogSource
- type Client
- type ClientOptions
- type ExternalMCPOAuthConfig
- type HeaderDefinition
- type ListServersParams
- type ListServersResult
- type Metrics
- func (m *Metrics) RecordHeaderMismatch(ctx context.Context)
- func (m *Metrics) RecordRecoveryAttempt(ctx context.Context)
- func (m *Metrics) RecordRecoveryExhaustion(ctx context.Context)
- func (m *Metrics) RecordRecoveryFailure(ctx context.Context)
- func (m *Metrics) RecordRecoverySuccess(ctx context.Context)
- type OAuthDiscoveryResult
- type OfficialRegistryAdapter
- type PlanResolver
- type ProxyToolEntry
- type ProxyToolExecutor
- type PulseBackend
- type Registry
- type RegistryBackend
- type RegistryClient
- func (c *RegistryClient) ClearCache(ctx context.Context, registryURL string) error
- func (c *RegistryClient) GetServerDetails(ctx context.Context, registry Registry, serverName string, ...) (*ServerDetails, error)
- func (c *RegistryClient) ListServers(ctx context.Context, registry Registry, params ListServersParams) (ListServersResult, error)
- func (c *RegistryClient) WithAllowedCIDRBlocks(cidrs ...string) *RegistryClient
- type RegistryReader
- type RemoteHeader
- type RemoteVariable
- type ServerDetails
- type Service
- func (s *Service) APIKeyAuth(ctx context.Context, key string, schema *security.APIKeyScheme) (context.Context, error)
- func (s *Service) ClearCache(ctx context.Context, payload *gen.ClearCachePayload) error
- func (s *Service) GetServerDetails(ctx context.Context, payload *gen.GetServerDetailsPayload) (*types.ExternalMCPServer, error)
- func (s *Service) GetSetupDocs(ctx context.Context, payload *gen.GetSetupDocsPayload) (*gen.GetSetupDocsResult, error)
- func (s *Service) ListCatalog(ctx context.Context, payload *gen.ListCatalogPayload) (*gen.ListCatalogResult, error)
- func (s *Service) ListRegistries(ctx context.Context, payload *gen.ListRegistriesPayload) (*gen.ListRegistriesResult, error)
- type SystemEnvLoader
- type Tool
- type ToolAnnotations
- type ToolCallEnv
- type ToolCallPlan
- type ToolExtractor
- type ToolExtractorTask
- type ToolExtractorTaskMCPServer
Constants ¶
const ( OAuthVersionNone = "none" // No OAuth required OAuthVersion21 = "2.1" // MCP OAuth with RFC 8414 discovery + dynamic registration OAuthVersion20 = "2.0" // Legacy OAuth 2.0 (no AS discovery, requires static client config) )
OAuthVersion represents the detected OAuth version/capability level.
const ProxyToolNameDelimiter = "--"
ProxyToolNameDelimiter separates the slug from the tool name in proxy tool names.
Variables ¶
var ( ErrCatalogSourceNotFound = errors.New("catalog source not found") ErrCatalogSourceDisabled = errors.New("catalog source is not enabled and certified") ErrUnknownRegistrySource = errors.New("unknown registry source profile") )
var ErrResponseTooLarge = errors.New("external mcp response body exceeds the configured read limit")
Functions ¶
func BuildHeaders ¶
func BuildHeaders( systemEnv *toolconfig.CaseInsensitiveEnv, userConfig *toolconfig.CaseInsensitiveEnv, headerDefs []HeaderDefinition, oauthToken string, ) map[string]string
BuildHeaders constructs HTTP headers from system environment variables and user configuration.
Logic:
- ALL system env values become headers using the appropriate header names.
- For keys with header definitions, use the definition's HeaderName.
- For keys without definitions, derive the header name using ToHTTPHeader.
- User config can override values (only for keys with header definitions).
- Empty values are skipped.
- If oauthToken is provided and no Authorization header was already set from config, sets Authorization: Bearer <token>.
Types ¶
type AuthRejectedError ¶
AuthRejectedError is returned when an MCP server rejects authentication (401 or 403). WWWAuthenticate is populated when the server provides a WWW-Authenticate header.
func (*AuthRejectedError) Error ¶
func (e *AuthRejectedError) Error() string
type CachedListServers ¶
type CachedListServers struct {
Key string
Servers []*types.ExternalMCPServerEntry
}
CachedListServers wraps the full, deduplicated list of external MCP server summaries for a registry. The catalog is small and stable, so the whole list is cached under a single key per registry.
func (CachedListServers) CacheKey ¶
func (c CachedListServers) CacheKey() string
func (CachedListServers) TTL ¶
func (c CachedListServers) TTL() time.Duration
type CachedServerDetailsResponse ¶
type CachedServerDetailsResponse struct {
Key string
Details *ServerDetails
}
CachedServerDetailsResponse wraps server details for caching.
func (CachedServerDetailsResponse) CacheKey ¶
func (c CachedServerDetailsResponse) CacheKey() string
func (CachedServerDetailsResponse) TTL ¶
func (c CachedServerDetailsResponse) TTL() time.Duration
type CallToolResult ¶
type CallToolResult struct {
Content []json.RawMessage
IsError bool
}
CallToolResult represents the result of a tool call.
type CatalogService ¶
type CatalogService struct {
// contains filtered or unexported fields
}
CatalogService is the single source selection and aggregation boundary for dashboard and Platform MCP catalogue reads. It exposes only enabled and certified sources with a known, code-reviewed adapter/profile combination.
func NewCatalogService ¶
func NewCatalogService(db *pgxpool.Pool, pulse RegistryReader, official RegistryReader) *CatalogService
func (*CatalogService) Details ¶
func (s *CatalogService) Details(ctx context.Context, registryID uuid.UUID, serverName string, allowedRemoteURLs []string) (*ServerDetails, error)
Details always re-fetches the selected server through its source-specific adapter. Catalogue discovery is not readiness evidence and cached list data is never used to materialize a registration.
func (*CatalogService) List ¶
func (s *CatalogService) List(ctx context.Context, search *string, registryID *uuid.UUID) ([]*types.ExternalMCPServerEntry, error)
List returns a deterministic merged catalogue. A same-specifier entry from two sources remains distinct because source identity is part of its provenance; only duplicates within a source are collapsed by its adapter.
func (*CatalogService) ReaderFor ¶
func (s *CatalogService) ReaderFor(source CatalogSource) (RegistryReader, error)
ReaderFor resolves the reviewed adapter/profile for a source returned by Sources. It deliberately accepts no caller-supplied URL or profile.
func (*CatalogService) Source ¶
func (s *CatalogService) Source(ctx context.Context, registryID uuid.UUID) (CatalogSource, error)
Source resolves one enabled and certified source by its opaque database ID. It is used by detail paths that must preserve their surface-specific response projection while sharing source admission with the aggregate catalogue.
func (*CatalogService) Sources ¶
func (s *CatalogService) Sources(ctx context.Context) ([]CatalogSource, error)
Sources returns only registry rows allowed to participate in the shared catalogue. Consumers that need their own projection can retain the source provenance while delegating fetches back through ReaderFor.
type CatalogSource ¶
type CatalogSource struct {
Registry Registry
SourceType string
AuthProfile string
CertificationVersion string
Priority int32
SourceKey string
Legacy bool
}
CatalogSource is an operator-owned, reviewed registry configuration. It is loaded from mcp_registries; request callers never provide a source URL, adapter, or auth profile.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client represents an active connection to an external MCP server.
func NewClient ¶
func NewClient(ctx context.Context, logger *slog.Logger, guardianPolicy *guardian.Policy, remoteURL string, transportType types.TransportType, opts *ClientOptions) (*Client, error)
NewClient creates a new client connection to an external MCP server. This performs the MCP protocol initialization internally.
func (*Client) CallTool ¶
func (c *Client) CallTool(ctx context.Context, toolName string, arguments json.RawMessage, schema json.RawMessage) (*CallToolResult, error)
CallTool calls a tool on the external MCP server. A nil schema deliberately sends an ordinary call first, without discovery. Only conformant pre-execution HeaderMismatch responses permit one discovery and replay. Proxy schemas are not persisted, so later isolated calls may need the same recovery again.
type ClientOptions ¶
type ClientOptions struct {
// Metrics optionally injects recovery instruments; nil uses the process OTel provider.
Metrics *Metrics
// Authorization is the value for the Authorization header (e.g., "Bearer token").
// If empty, no Authorization header is sent.
Authorization string
// Headers contains additional HTTP headers to send with each request.
// Keys are header names, values are header values.
Headers map[string]string
// DisableRetries skips both the HTTP-transport retry layer and the MCP
// transport's own connection retries. The two compound (up to 4 HTTP
// attempts per MCP-level retry, each with its own backoff), which is
// fine for the resilient gateway proxy path but defeats a caller-imposed
// context deadline meant to bound a one-shot interactive probe — without
// this, an unreachable server can take minutes to report as such instead
// of the ~10s the probe intends.
DisableRetries bool
// MaxResponseBytes caps each HTTP response when greater than zero. It is
// intended for short-lived, untrusted probes; the long-lived gateway path
// leaves this at zero.
MaxResponseBytes int64
}
ClientOptions contains options for creating an MCP client.
type ExternalMCPOAuthConfig ¶
type ExternalMCPOAuthConfig struct {
// RemoteURL is the parsed URL of the external MCP server
RemoteURL *url.URL
// RegistryID is the ID of the MCP registry the server belongs to
RegistryID string
// Slug is the tool prefix slug (e.g., "github")
Slug string
// Name is the reverse-DNS server name (e.g., "ai.exa/exa")
Name string
// OAuth metadata from the external server
OAuthVersion string // "2.1", "2.0", or "none"
AuthorizationEndpoint string // OAuth authorization endpoint URL
TokenEndpoint string // OAuth token endpoint URL
RegistrationEndpoint string // OAuth dynamic client registration endpoint URL
ScopesSupported []string // OAuth scopes supported by the server
}
ExternalMCPOAuthConfig contains OAuth configuration extracted from an external MCP tool that requires OAuth authentication.
func ResolveOAuthConfig ¶
func ResolveOAuthConfig(toolset *types.Toolset) *ExternalMCPOAuthConfig
ResolveOAuthConfig returns the OAuth configuration from the first external MCP tool in the toolset that requires OAuth, or nil if none found.
type HeaderDefinition ¶
type HeaderDefinition struct {
Name string // Prefixed environment variable name (e.g., "SLACK_X_API_KEY")
HeaderName string // HTTP header to send (e.g., "X-Api-Key")
}
HeaderDefinition maps an environment variable name to an HTTP header name.
type ListServersParams ¶
type ListServersParams struct {
Search *string
}
ListServersParams contains optional parameters for listing servers.
type ListServersResult ¶
type ListServersResult struct {
Servers []*types.ExternalMCPServerEntry
}
ListServersResult is the result of a ListServers call.
type Metrics ¶
type Metrics struct {
// contains filtered or unexported fields
}
Metrics records parameter-header recovery without request-derived dimensions. Share one instance across clients. These diagnostic counters do not meter logical tool calls or billable usage. The zero value and nil receiver are safe.
func NewMetrics ¶
func NewMetrics(provider metric.MeterProvider, logger *slog.Logger) *Metrics
func (*Metrics) RecordHeaderMismatch ¶
RecordHeaderMismatch counts each mismatch response, including on replay.
func (*Metrics) RecordRecoveryAttempt ¶
RecordRecoveryAttempt counts the start of the single permitted recovery.
func (*Metrics) RecordRecoveryExhaustion ¶
RecordRecoveryExhaustion counts a repeated mismatch after the one replay. Exhaustion is a subset of failures, not an additional recovery attempt.
func (*Metrics) RecordRecoveryFailure ¶
RecordRecoveryFailure counts an unsuccessful refresh or replay, including exhaustion. Every completed attempt records exactly one success or failure.
func (*Metrics) RecordRecoverySuccess ¶
RecordRecoverySuccess counts a replay with neither a protocol nor tool error.
type OAuthDiscoveryResult ¶
type OAuthDiscoveryResult struct {
Version string // "2.1", "2.0", or "none"
Issuer string // Authorization server issuer from RFC 8414 metadata.
AuthorizationEndpoint string
TokenEndpoint string
RegistrationEndpoint string
ScopesSupported []string
// ClientIDMetadataDocumentSupported reports whether the authorization
// server advertises client_id_metadata_document_supported (OAuth CIMD
// draft). When true, a client may send a metadata-document URL as
// client_id instead of dynamically registering.
ClientIDMetadataDocumentSupported bool
// TokenEndpointAuthMethodsSupported is the authorization server's
// advertised token_endpoint_auth_methods_supported. Empty means the
// document omitted the field; CIMD public clients require "none" only
// when the server enumerated methods.
TokenEndpointAuthMethodsSupported []string
// ProbeIncomplete reports that at least one discovery request failed
// without the server cleanly saying the document is not there (only a
// 404 or 410 says that): unreachable host, TLS failure, auth or
// rate-limit refusal, 5xx, or invalid published metadata. A Version of
// "none" with ProbeIncomplete set means discovery could not run to
// completion — callers that treat "none" as "publishes no OAuth
// metadata" must keep that case distinct.
ProbeIncomplete bool
}
OAuthDiscoveryResult contains the OAuth metadata discovered for an external MCP server.
func DiscoverOAuthMetadata ¶
func DiscoverOAuthMetadata(ctx context.Context, logger *slog.Logger, guardianPolicy *guardian.Policy, wwwAuthenticate string, remoteURL string) (*OAuthDiscoveryResult, error)
DiscoverOAuthMetadata discovers OAuth configuration for an external MCP server. It parses the WWW-Authenticate header and fetches metadata from discovered URLs. If no metadata URLs are in the header, it probes standard well-known locations.
type OfficialRegistryAdapter ¶
type OfficialRegistryAdapter struct {
// contains filtered or unexported fields
}
OfficialRegistryAdapter implements the public read-only v0.1 Official MCP Registry contract. It is deliberately not composed into production until its source profile is certified and enabled by a later rollout.
func NewOfficialRegistryAdapter ¶
func NewOfficialRegistryAdapter(logger *slog.Logger, policy *guardian.Policy) *OfficialRegistryAdapter
func (*OfficialRegistryAdapter) GetServerDetails ¶
func (a *OfficialRegistryAdapter) GetServerDetails(ctx context.Context, registry Registry, serverName string, allowedRemoteURLs []string) (*ServerDetails, error)
func (*OfficialRegistryAdapter) ListServers ¶
func (a *OfficialRegistryAdapter) ListServers(ctx context.Context, registry Registry, params ListServersParams) (ListServersResult, error)
type PlanResolver ¶
type PlanResolver func(ctx context.Context, toolURN urn.Tool, projectID uuid.UUID) (*ToolCallPlan, error)
PlanResolver resolves a tool URN to a ToolCallPlan.
type ProxyToolEntry ¶
type ProxyToolEntry struct {
SourceSlug string // e.g., "slack" - used for matching
URN urn.Tool // URN of the proxy tool (e.g., tools:ext-mcp:slack:proxy)
}
ProxyToolEntry contains metadata needed for matching incoming tool calls to proxy tools.
type ProxyToolExecutor ¶
type ProxyToolExecutor struct {
// contains filtered or unexported fields
}
ProxyToolExecutor provides matching for external MCP tool names. The executor matches tool names against MCP server slugs and returns the external tool name. Actual execution happens elsewhere using the returned URN to get a plan and create a client.
func BuildProxyToolExecutor ¶
func BuildProxyToolExecutor(logger *slog.Logger, guardianPolicy *guardian.Policy, tools []*types.Tool) *ProxyToolExecutor
BuildProxyToolExecutor creates a ProxyToolExecutor from a list of tools. Filters internally to only include external MCP tools with Type "proxy".
func (*ProxyToolExecutor) DoList ¶
func (e *ProxyToolExecutor) DoList( ctx context.Context, projectID uuid.UUID, userConfig *toolconfig.CaseInsensitiveEnv, oauthToken string, loadSystemEnv SystemEnvLoader, resolve PlanResolver, ) ([]Tool, error)
DoList lists tools from all proxy tools in this executor. For each entry, loads system env, resolves the plan, connects to the MCP server, lists tools, and prefixes tool names with the source slug.
func (*ProxyToolExecutor) HasEntries ¶
func (e *ProxyToolExecutor) HasEntries() bool
HasEntries returns true if this executor has any proxy tool entries.
func (*ProxyToolExecutor) MatchPlanInputs ¶
func (e *ProxyToolExecutor) MatchPlanInputs(ctx context.Context, toolName string, projectID uuid.UUID, resolve PlanResolver) (*ToolCallPlan, error)
MatchPlanInputs checks if the given tool name belongs to any proxy tool in this executor. If matched, resolves the ToolCallPlan inputs and sets ToolName to the external tool name. Returns nil if no match (not an error). Returns error if resolver fails. Expected format: <slug>--<toolName>
type PulseBackend ¶
type PulseBackend struct {
// contains filtered or unexported fields
}
func NewPulseBackend ¶
type RegistryBackend ¶
type RegistryClient ¶
type RegistryClient struct {
// contains filtered or unexported fields
}
RegistryClient handles communication with external MCP registries.
func NewRegistryClient ¶
func NewRegistryClient(logger *slog.Logger, tracerProvider trace.TracerProvider, guardianPolicy *guardian.Policy, backend RegistryBackend, cacheImpl cache.Cache) *RegistryClient
NewRegistryClient creates a new registry client.
func (*RegistryClient) ClearCache ¶
func (c *RegistryClient) ClearCache(ctx context.Context, registryURL string) error
ClearCache removes all cached entries for the given registry URL.
func (*RegistryClient) GetServerDetails ¶
func (c *RegistryClient) GetServerDetails(ctx context.Context, registry Registry, serverName string, allowedRemoteURLs []string) (*ServerDetails, error)
GetServerDetails fetches server details including the remote URL from the registry. If allowedRemoteURLs is provided and non-empty, only remotes with matching URLs are considered.
func (*RegistryClient) ListServers ¶
func (c *RegistryClient) ListServers(ctx context.Context, registry Registry, params ListServersParams) (ListServersResult, error)
ListServers fetches every server from the given registry and applies an optional in-memory search filter. The catalog is small and stable, so the full list is fetched, deduplicated, and cached under a single key per registry; callers receive the whole result set and paginate client-side.
func (*RegistryClient) WithAllowedCIDRBlocks ¶
func (c *RegistryClient) WithAllowedCIDRBlocks(cidrs ...string) *RegistryClient
WithAllowedCIDRBlocks returns a client whose registry requests may reach the supplied trusted CIDR blocks. Callers must use this only for code-defined, non-user-controlled registries such as the local fixture.
type RegistryReader ¶
type RegistryReader interface {
ListServers(ctx context.Context, registry Registry, params ListServersParams) (ListServersResult, error)
GetServerDetails(ctx context.Context, registry Registry, serverName string, allowedRemoteURLs []string) (*ServerDetails, error)
}
RegistryReader is the narrow, normalized registry contract consumed by both dashboard and Platform MCP catalogue projections. RegistryClient remains the Pulse-compatible transport implementation; CatalogService selects an adapter before delegating to it.
type RemoteHeader ¶
type RemoteHeader struct {
Name string `json:"name"`
IsSecret bool `json:"isSecret"`
IsRequired bool `json:"isRequired"`
Description *string `json:"description,omitempty"`
Placeholder *string `json:"placeholder,omitempty"`
}
RemoteHeader represents a header requirement from the registry.
type RemoteVariable ¶
type RemoteVariable struct {
Description *string `json:"description,omitempty"`
IsSecret bool `json:"isSecret"`
IsRequired bool `json:"isRequired"`
Default *string `json:"default,omitempty"`
Choices []string `json:"choices,omitempty"`
}
RemoteVariable represents a URL template variable from the registry.
type ServerDetails ¶
type ServerDetails struct {
Name string
Description string
Version string
RemoteURL string
TransportType externalmcptypes.TransportType
Tools []serverTool
Headers []RemoteHeader
Variables map[string]RemoteVariable
}
ServerDetails contains detailed information about an MCP server including connection info. Headers and variables are copied from the selected server-owned remote. Callers must still validate configuration values against these declarations; they must never treat the registry response as permission to accept arbitrary endpoints.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func NewService ¶
func NewService(logger *slog.Logger, tracerProvider trace.TracerProvider, db *pgxpool.Pool, sessions *sessions.Manager, registryClient *RegistryClient, catalog *CatalogService, authzEngine *authz.Engine, serverURL *url.URL) *Service
func (*Service) APIKeyAuth ¶
func (*Service) ClearCache ¶
func (*Service) GetServerDetails ¶
func (s *Service) GetServerDetails(ctx context.Context, payload *gen.GetServerDetailsPayload) (*types.ExternalMCPServer, error)
func (*Service) GetSetupDocs ¶
func (s *Service) GetSetupDocs(ctx context.Context, payload *gen.GetSetupDocsPayload) (*gen.GetSetupDocsResult, error)
func (*Service) ListCatalog ¶
func (s *Service) ListCatalog(ctx context.Context, payload *gen.ListCatalogPayload) (*gen.ListCatalogResult, error)
func (*Service) ListRegistries ¶
func (s *Service) ListRegistries(ctx context.Context, payload *gen.ListRegistriesPayload) (*gen.ListRegistriesResult, error)
type SystemEnvLoader ¶
type SystemEnvLoader func(ctx context.Context, toolURN urn.Tool) (*toolconfig.CaseInsensitiveEnv, error)
SystemEnvLoader loads system environment variables for a given tool URN.
type Tool ¶
type Tool struct {
Name string
Description string
Schema json.RawMessage
Annotations *ToolAnnotations
}
Tool represents a tool discovered from an external MCP server.
type ToolAnnotations ¶
type ToolAnnotations struct {
Title string `json:"title,omitempty"`
ReadOnlyHint *bool `json:"readOnlyHint,omitempty"`
DestructiveHint *bool `json:"destructiveHint,omitempty"`
IdempotentHint *bool `json:"idempotentHint,omitempty"`
OpenWorldHint *bool `json:"openWorldHint,omitempty"`
}
ToolAnnotations contains MCP tool behavior hints.
type ToolCallEnv ¶
type ToolCallEnv = toolconfig.ToolCallEnv
ToolCallEnv is an alias for toolconfig.ToolCallEnv.
type ToolCallPlan ¶
type ToolCallPlan struct {
RemoteURL string
ToolName string // The tool name to call on the MCP server
InputSchema json.RawMessage // Original upstream schema; nil for a proxy placeholder
Slug string
RequiresOAuth bool
TransportType externalmcptypes.TransportType
HeaderDefinitions []HeaderDefinition
}
ToolCallPlan contains the execution plan for calling a tool on an external MCP server.
type ToolExtractor ¶
type ToolExtractor struct {
// contains filtered or unexported fields
}
func NewToolExtractor ¶
func NewToolExtractor( logger *slog.Logger, guardianPolicy *guardian.Policy, db *pgxpool.Pool, registryClient *RegistryClient, ) *ToolExtractor
func (*ToolExtractor) Do ¶
func (te *ToolExtractor) Do(ctx context.Context, task ToolExtractorTask) error