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
- Variables
- type Config
- type ConnectionStatus
- type FieldEncryptor
- type IngestOAuthTokenInput
- type IngestTokenResponseInput
- type MultiConfig
- type OAuthConfig
- type OAuthStatus
- type PersistedToken
- type PostgresTokenStore
- type ProbeTool
- type TokenEncryptor
- type TokenStore
- type Toolkit
- func (t *Toolkit) AddConnection(name string, config map[string]any) error
- func (t *Toolkit) Close() error
- func (t *Toolkit) Connection() string
- func (t *Toolkit) ConnectionForTool(toolName string) string
- func (t *Toolkit) HasConnection(name string) bool
- func (t *Toolkit) IngestOAuthToken(ctx context.Context, in IngestOAuthTokenInput) error
- func (*Toolkit) Kind() string
- func (t *Toolkit) ListConnections() []toolkit.ConnectionDetail
- func (t *Toolkit) Name() string
- func (t *Toolkit) ReacquireOAuthToken(ctx context.Context, name string) error
- func (t *Toolkit) RegisterTools(s *mcp.Server)
- func (t *Toolkit) RemoveConnection(name string) error
- func (t *Toolkit) SetEnrichmentEngine(e *enrichment.Engine)
- func (t *Toolkit) SetQueryProvider(provider query.Provider)
- func (t *Toolkit) SetSemanticProvider(provider semantic.Provider)
- func (t *Toolkit) SetTokenStore(s TokenStore)
- func (t *Toolkit) Status(name string) *ConnectionStatus
- func (t *Toolkit) Tools() []string
Constants ¶
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 ¶
var ErrConnectionExists = errors.New("gateway: connection already exists")
ErrConnectionExists is returned when AddConnection is called with a name already live in the toolkit.
var ErrConnectionNotFound = errors.New("gateway: connection not found")
ErrConnectionNotFound is returned when RemoveConnection is called for a name that is not present.
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 ¶
ParseConfig parses a gateway configuration from a map.
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 ¶
MultiConfig holds one or more parsed per-connection gateway configs along with the aggregate toolkit's default connection name.
func ParseMultiConfig ¶
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 ¶
func (s *PostgresTokenStore) Set(ctx context.Context, t PersistedToken) error
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.
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 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 ¶
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 ¶
Close closes every upstream session. Safe to call on a never-registered toolkit.
func (*Toolkit) Connection ¶
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 ¶
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 ¶
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) ListConnections ¶
func (t *Toolkit) ListConnections() []toolkit.ConnectionDetail
ListConnections returns metadata for every live connection, sorted by name.
func (*Toolkit) ReacquireOAuthToken ¶
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 ¶
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 ¶
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 ¶
SetQueryProvider stores the query provider (not consumed directly in v1).
func (*Toolkit) SetSemanticProvider ¶
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.
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). |