gateway

package
v1.57.0 Latest Latest
Warning

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

Go to latest
Published: Apr 26, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package gateway provides an MCP gateway toolkit that proxies tools from an upstream MCP server through the platform's auth, persona, and audit pipeline.

Index

Constants

View Source
const (
	// Kind is the toolkit kind identifier. Each connection of this kind is
	// a remote MCP server that the platform's gateway feature proxies. The
	// kind value is what operators see in the connection picker; the
	// gateway terminology is reserved for the platform-side feature
	// (admin endpoints, internal package, DB tables) that does the proxying.
	Kind = "mcp"

	// AuthModeNone disables outbound authentication.
	AuthModeNone = "none"
	// AuthModeBearer sends "Authorization: Bearer <credential>" on upstream requests.
	AuthModeBearer = "bearer"
	// AuthModeAPIKey sends "X-API-Key: <credential>" on upstream requests.
	AuthModeAPIKey = "api_key"
	// AuthModeOAuth acquires a bearer token via an OAuth 2.1 grant
	// (client_credentials in v1) and refreshes it before expiry.
	AuthModeOAuth = "oauth"

	// OAuthGrantClientCredentials is the machine-to-machine grant type.
	// Requires a token URL, client id, and client secret. No user
	// interaction — the platform exchanges the credentials for a token on
	// behalf of all platform users.
	OAuthGrantClientCredentials = "client_credentials"

	// OAuthGrantAuthorizationCode is the user-driven grant. The operator
	// completes a one-time browser flow at setup; the resulting refresh
	// token is persisted (encrypted) so subsequent platform restarts
	// and background workloads keep working without further interaction.
	OAuthGrantAuthorizationCode = "authorization_code"

	// TrustLevelUntrusted is the default. Upstream responses are treated as
	// untrusted content (reserved for future enforcement).
	TrustLevelUntrusted = "untrusted"
	// TrustLevelTrusted bypasses future content sanitization. Use only for
	// first-party upstreams under the operator's control.
	TrustLevelTrusted = "trusted"

	// DefaultConnectTimeout is the default timeout for initial upstream connection + tool discovery.
	DefaultConnectTimeout = 10 * time.Second
	// DefaultCallTimeout is the default per-tool-call timeout for upstream forwarding.
	DefaultCallTimeout = 60 * time.Second

	// NamespaceSeparator joins the connection name and remote tool name (e.g. "crm__get_contact").
	NamespaceSeparator = "__"
)

Variables

View Source
var ErrConnectionExists = errors.New("gateway: connection already exists")

ErrConnectionExists is returned when AddConnection is called with a name already live in the toolkit.

View Source
var ErrConnectionNotFound = errors.New("gateway: connection not found")

ErrConnectionNotFound is returned when RemoveConnection is called for a name that is not present.

View Source
var ErrTokenNotFound = errors.New("gateway: oauth token not found")

ErrTokenNotFound is returned by TokenStore.Get when no token row exists for a given connection. Callers treat this as "needs reauthentication" and surface a Connect button in the admin UI.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Endpoint is the streamable HTTP URL of the upstream MCP server. Required.
	Endpoint string
	// AuthMode is "none", "bearer", "api_key", or "oauth".
	AuthMode string
	// Credential is the bearer token or API key. Ignored when AuthMode is "none" or "oauth".
	Credential string
	// OAuth carries the OAuth-specific configuration used when AuthMode is "oauth".
	OAuth OAuthConfig
	// ConnectionName is the audit-visible connection identifier and also the
	// tool-name prefix. Defaults to the toolkit instance name when unset.
	ConnectionName string
	// ConnectTimeout caps the initial connection + ListTools call.
	ConnectTimeout time.Duration
	// CallTimeout caps each forwarded tool invocation.
	CallTimeout time.Duration
	// TrustLevel is "untrusted" (default) or "trusted".
	TrustLevel string
}

Config holds gateway toolkit configuration for a single upstream MCP connection.

func ParseConfig

func ParseConfig(cfg map[string]any) (Config, error)

ParseConfig parses a gateway configuration from a map.

func (Config) Validate

func (c Config) Validate() error

Validate returns an error if the configuration is missing required fields or contains invalid values.

type ConnectionStatus

type ConnectionStatus struct {
	Name     string       `json:"name"`
	Healthy  bool         `json:"healthy"`
	AuthMode string       `json:"auth_mode"`
	Tools    []string     `json:"tools,omitempty"`
	OAuth    *OAuthStatus `json:"oauth,omitempty"`
}

ConnectionStatus is a per-connection health snapshot exposed by the admin status endpoint.

type FieldEncryptor

type FieldEncryptor interface {
	Encrypt(plaintext string) (string, error)
	Decrypt(ciphertext string) (string, error)
}

FieldEncryptor abstracts the platform's at-rest field encryption so this package doesn't import pkg/platform (which would create a cycle). The same interface shape is reused by other sub-package stores that need at-rest encryption (e.g. admin's PKCE state).

TokenEncryptor is the legacy alias retained for callers that still reference it; new code should use FieldEncryptor.

type IngestOAuthTokenInput

type IngestOAuthTokenInput struct {
	Name            string
	AccessToken     string
	RefreshToken    string
	ExpiresIn       int
	Scope           string
	AuthenticatedBy string
}

IngestOAuthTokenInput is the parameter set for IngestOAuthToken. Defined as a struct to keep the public method's argument list under the project's revive limit.

type IngestTokenResponseInput

type IngestTokenResponseInput struct {
	AccessToken     string
	RefreshToken    string
	ExpiresIn       int
	Scope           string
	AuthenticatedBy string
}

IngestTokenResponseInput collects the result of an out-of-band OAuth exchange (e.g. the platform's authorization-code callback handler). Used to keep IngestTokenResponse to a single argument.

type MultiConfig

type MultiConfig struct {
	DefaultName string
	Instances   map[string]Config
}

MultiConfig holds one or more parsed per-connection gateway configs along with the aggregate toolkit's default connection name.

func ParseMultiConfig

func ParseMultiConfig(defaultName string, raw map[string]map[string]any) (MultiConfig, error)

ParseMultiConfig validates and returns the parsed config for every instance. Per-instance parse errors are surfaced as fatal (operator must fix the config); dial/connectivity errors are handled at load time in NewMulti, not here.

type OAuthConfig

type OAuthConfig struct {
	// Grant selects the OAuth flow. One of "client_credentials" or
	// "authorization_code".
	Grant string
	// TokenURL is the upstream's OAuth token endpoint.
	TokenURL string
	// AuthorizationURL is the upstream's authorization endpoint. Only
	// used by the authorization_code grant; the platform redirects the
	// admin's browser here to start the flow.
	AuthorizationURL string
	// ClientID is the platform's registered client id with the upstream.
	ClientID string
	// ClientSecret is the platform's registered client secret. Encrypted
	// at rest (same field-level encryption as Credential).
	ClientSecret string
	// Scope is the optional space-delimited scope string.
	Scope string
}

OAuthConfig describes the OAuth 2.1 parameters used when AuthMode is "oauth". The grant determines whether the token is acquired from machine-to-machine credentials or via a one-time browser flow that hands the platform a refresh token for long-running background use.

type OAuthStatus

type OAuthStatus struct {
	Configured      bool      `json:"configured"`
	TokenAcquired   bool      `json:"token_acquired"`
	ExpiresAt       time.Time `json:"expires_at,omitzero"`
	LastRefreshedAt time.Time `json:"last_refreshed_at,omitzero"`
	HasRefreshToken bool      `json:"has_refresh_token"`
	LastError       string    `json:"last_error,omitempty"`
	Grant           string    `json:"grant,omitempty"`
	TokenURL        string    `json:"token_url,omitempty"`
	Scope           string    `json:"scope,omitempty"`
	// AuthenticatedBy is the email/id of the operator who completed the
	// browser flow. Empty for client_credentials and for connections that
	// have not yet been authorized.
	AuthenticatedBy string `json:"authenticated_by,omitempty"`
	// AuthenticatedAt records when the most recent successful exchange
	// (initial OAuth dance or refresh) completed.
	AuthenticatedAt time.Time `json:"authenticated_at,omitzero"`
	// NeedsReauth is true when the platform cannot mint an access token
	// without operator interaction. For authorization_code grants this
	// means: no stored token, or the refresh token has been revoked.
	// The admin UI surfaces a "Connect" button when this is true.
	NeedsReauth bool `json:"needs_reauth,omitempty"`
}

OAuthStatus is a snapshot of token state suitable for the admin status endpoint. All fields are safe to expose to operators (no secret material).

type PersistedToken

type PersistedToken struct {
	ConnectionName  string
	AccessToken     string
	RefreshToken    string
	ExpiresAt       time.Time
	Scope           string
	AuthenticatedBy string
	AuthenticatedAt time.Time
	UpdatedAt       time.Time
}

PersistedToken is the row shape for gateway_oauth_tokens. Tokens are stored encrypted at rest by the platform's FieldEncryptor; this struct carries plaintext values to/from the store API.

type PostgresTokenStore

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

PostgresTokenStore is a sql-backed TokenStore. Pass enc=nil to disable at-rest encryption (refresh tokens stored in plain text — only acceptable for dev environments).

func NewPostgresTokenStore

func NewPostgresTokenStore(db *sql.DB, enc TokenEncryptor) *PostgresTokenStore

NewPostgresTokenStore wires a TokenStore to the given database. enc may be nil; if so a no-op encryptor is used and the WARNING is logged once per process by the platform on startup.

func (*PostgresTokenStore) Delete

func (s *PostgresTokenStore) Delete(ctx context.Context, connection string) error

Delete removes the token row, forcing the next call to surface "needs reauthentication" until the operator clicks Connect again.

func (*PostgresTokenStore) Get

func (s *PostgresTokenStore) Get(ctx context.Context, connection string) (*PersistedToken, error)

Get returns the persisted token for connection or ErrTokenNotFound.

func (*PostgresTokenStore) Set

Set inserts or replaces the token row. Sensitive fields are encrypted before persistence.

type ProbeTool

type ProbeTool struct {
	Name        string `json:"name"`
	LocalName   string `json:"local_name"`
	Description string `json:"description,omitempty"`
}

ProbeTool is a summary of a single discovered upstream tool, used by the admin test endpoint to preview what a connection would expose.

func Probe

func Probe(ctx context.Context, cfg Config) ([]ProbeTool, error)

Probe dials the upstream described by cfg, lists its tools, and closes the session. It does NOT mutate any live toolkit state, so it's safe to call from the admin "test connection" endpoint before persisting a config.

type TokenEncryptor

type TokenEncryptor = FieldEncryptor

TokenEncryptor is an alias for FieldEncryptor kept for backward compatibility with the original gateway-token-store API.

type TokenStore

type TokenStore interface {
	// Get returns the persisted token for a connection or
	// ErrTokenNotFound when none exists.
	Get(ctx context.Context, connection string) (*PersistedToken, error)
	// Set inserts or replaces the token row for a connection.
	Set(ctx context.Context, t PersistedToken) error
	// Delete removes the token row, forcing a re-auth on the next call.
	Delete(ctx context.Context, connection string) error
}

TokenStore persists OAuth tokens for the authorization_code grant so a one-time browser-based authentication grants long-running background access (cron jobs, scheduled workloads). v1 stores a single shared identity per connection.

func NewMemoryTokenStore

func NewMemoryTokenStore() TokenStore

NewMemoryTokenStore returns a TokenStore that lives only in process memory. Useful for tests; production deployments use PostgresTokenStore.

type Toolkit

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

Toolkit is a gateway that proxies tools from one or more upstream MCP servers through the platform's registry, auth, persona, and audit pipeline.

A single Toolkit manages multiple named upstream connections. Each upstream tool is re-exposed under a namespaced local name: "<connection_name>__<remote_tool_name>". Connections can be added or removed at runtime; the MCP server is notified of tool-list changes through AddTool / RemoveTools.

Startup is failure-isolated: an unreachable upstream is logged and skipped — it does not block platform startup. Other connections remain functional.

func New

func New(defaultName string) *Toolkit

New builds a Toolkit with the given default connection name and no initial connections.

func NewMulti

func NewMulti(cfg MultiConfig) *Toolkit

NewMulti builds a Toolkit and pre-loads the given parsed connection configs. Unreachable upstreams are logged and skipped so platform startup is never blocked.

func (*Toolkit) AddConnection

func (t *Toolkit) AddConnection(name string, config map[string]any) error

AddConnection parses the raw config, dials the upstream, discovers its tools, and registers them on the server (if one is already set). The admin layer's hotAddConnection helper logs any returned error as a structured warning.

func (*Toolkit) Close

func (t *Toolkit) Close() error

Close closes every upstream session. Safe to call on a never-registered toolkit.

func (*Toolkit) Connection

func (t *Toolkit) Connection() string

Connection returns the default connection name used in audit logs when a request does not carry one. Empty if no default is configured.

func (*Toolkit) ConnectionForTool

func (t *Toolkit) ConnectionForTool(toolName string) string

ConnectionForTool maps a namespaced local tool name (e.g. "vendor__list_contacts") back to its source connection name. Used by the platform's audit middleware to attribute proxied tool calls to the specific upstream connection they were routed to.

func (*Toolkit) HasConnection

func (t *Toolkit) HasConnection(name string) bool

HasConnection reports whether a connection with the given name is live.

func (*Toolkit) IngestOAuthToken

func (t *Toolkit) IngestOAuthToken(ctx context.Context, in IngestOAuthTokenInput) error

IngestOAuthToken stores tokens obtained from an authorization_code callback into the named connection's token source AND persists them via the toolkit's TokenStore. Triggers re-discovery of the upstream (re-dial + listTools) so the previously "needs reauth" connection becomes live with its discovered tools registered on the MCP server.

func (*Toolkit) Kind

func (*Toolkit) Kind() string

Kind returns the toolkit kind.

func (*Toolkit) ListConnections

func (t *Toolkit) ListConnections() []toolkit.ConnectionDetail

ListConnections returns metadata for every live connection, sorted by name.

func (*Toolkit) Name

func (t *Toolkit) Name() string

Name returns the toolkit instance name.

func (*Toolkit) ReacquireOAuthToken

func (t *Toolkit) ReacquireOAuthToken(ctx context.Context, name string) error

ReacquireOAuthToken forces a fresh client_credentials exchange for the named connection. Returns an error if the connection is missing or not configured for OAuth.

func (*Toolkit) RegisterTools

func (t *Toolkit) RegisterTools(s *mcp.Server)

RegisterTools captures the server reference and registers every tool from every already-loaded connection. Must be called exactly once, after the toolkit is registered in the platform registry.

func (*Toolkit) RemoveConnection

func (t *Toolkit) RemoveConnection(name string) error

RemoveConnection unregisters a connection's tools from the MCP server, closes its upstream session, and removes it from the toolkit.

func (*Toolkit) SetEnrichmentEngine

func (t *Toolkit) SetEnrichmentEngine(e *enrichment.Engine)

SetEnrichmentEngine wires a cross-enrichment engine into this gateway. When set, every successful forwarded tool result is run through the engine before being returned to the client. Safe to call before or after RegisterTools — handlers fetch the current engine on each call.

func (*Toolkit) SetQueryProvider

func (t *Toolkit) SetQueryProvider(provider query.Provider)

SetQueryProvider stores the query provider (not consumed directly in v1).

func (*Toolkit) SetSemanticProvider

func (t *Toolkit) SetSemanticProvider(provider semantic.Provider)

SetSemanticProvider stores the semantic provider (not consumed directly in v1).

func (*Toolkit) SetTokenStore

func (t *Toolkit) SetTokenStore(s TokenStore)

SetTokenStore wires a persistent OAuth token store into the gateway. Required for authorization_code grants to survive process restarts.

When called after AddConnection, any authorization_code placeholder connections (those that were registered as "awaiting reauth" because the store wasn't yet wired) are automatically retried so persisted tokens are picked up without requiring a manual refresh. This makes startup wiring order-independent.

Concurrency: the toolkit lock is HELD ONLY for the snapshot of placeholders to retry and again for the final pointer-swap on each success. The discover() network I/O happens with the lock RELEASED so concurrent Status / ListConnections / Tools / AddConnection callers don't block on potentially-slow upstream dials. The placeholder remains in the connections map throughout, so the admin UI keeps showing "Connect" while a retry is in flight.

func (*Toolkit) Status

func (t *Toolkit) Status(name string) *ConnectionStatus

Status returns a status snapshot for the named connection. Returns nil when the connection is not registered.

func (*Toolkit) Tools

func (t *Toolkit) Tools() []string

Tools returns the aggregate, sorted set of namespaced local tool names across all live connections.

Directories

Path Synopsis
Package enrichment implements the cross-enrichment rule engine for the gateway toolkit.
Package enrichment implements the cross-enrichment rule engine for the gateway toolkit.
Package sources provides concrete enrichment Source adapters for the platform's built-in toolkits (Trino, DataHub).
Package sources provides concrete enrichment Source adapters for the platform's built-in toolkits (Trino, DataHub).

Jump to

Keyboard shortcuts

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