Documentation
¶
Overview ¶
Package representative exposes a deliberately small MCP interface to an external agent. It never exposes the seat/controller API or tool registry.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrUnauthenticated = errors.New("unauthenticated") )
var ErrInvalidConfig = errors.New("invalid representative authentication configuration")
Functions ¶
func New ¶
func New(st ConversationStore, auth Authenticator) http.Handler
New returns a standalone handler. Mount it only on the dedicated external listener: there is intentionally no fallback to the privileged platform API.
Types ¶
type Authenticator ¶
type Authenticator interface {
Authenticate(*http.Request) (Principal, error)
Discovery(http.ResponseWriter, *http.Request)
Challenge() string
}
Authenticator verifies every HTTP request independently, including requests made by a previously initialized MCP client.
type Config ¶
type Config struct {
ResourceURL string `json:"resourceURL"`
OAuth *OAuthConfig `json:"oauth,omitempty"`
Principals []PrincipalConfig `json:"principals"`
}
Config must be mounted from an operator-managed Secret, not embedded in public chart values. The whole file is validated anew on every request.
func LoadConfig ¶
LoadConfig opens the file each time, including following Kubernetes Secret volume symlink updates. Invalid, missing, or oversized files fail closed; the last successfully read configuration is deliberately never cached.
type ConversationStore ¶
type ConversationStore interface {
SendExternalMessage(context.Context, store.ExternalPrincipal, store.ExternalMessage) (*store.ExternalRequest, error)
ExternalRequestStatus(context.Context, store.ExternalPrincipal, string) (*store.ExternalRequest, error)
ReadExternalConversation(context.Context, store.ExternalPrincipal, string, int, int) (*store.ExternalConversation, error)
}
ConversationStore keeps acceptance, replies and idempotency durable.
type FileAuthenticator ¶
type FileAuthenticator struct {
// contains filtered or unexported fields
}
FileAuthenticator reopens its Secret-backed configuration and validates every credential on every HTTP request. It does not cache either manual mappings or OAuth introspection results. Keep the mounted Secret file available and use a projected volume (not subPath) for Kubernetes rotation to take effect.
func NewFileAuthenticator ¶
func NewFileAuthenticator(path string) (*FileAuthenticator, error)
NewFileAuthenticator checks configuration immediately so a misconfigured externally reachable listener never starts. Later read failures fail closed.
func (*FileAuthenticator) Authenticate ¶
func (a *FileAuthenticator) Authenticate(r *http.Request) (Principal, error)
Authenticate accepts only one strict Authorization: Bearer header. Request bodies, cookies, tool arguments, and URL query parameters never provide an identity. The caller must separately verify that the mapped representative is active before reading or writing organization data.
func (*FileAuthenticator) Challenge ¶
func (a *FileAuthenticator) Challenge() string
Challenge advertises only the validated, operator-configured public URL; untrusted Host or forwarded headers never determine the discovery address. On config failure it reveals no stale discovery information.
func (*FileAuthenticator) Discovery ¶
func (a *FileAuthenticator) Discovery(w http.ResponseWriter, r *http.Request)
Discovery serves RFC 9728 protected-resource metadata with the SDK's CORS and method handling. Mount it at both the root and path-suffixed well-known routes. It exposes no client secret, principal mapping, or bearer digest.
type OAuthConfig ¶
type OAuthConfig struct {
Issuer string `json:"issuer"`
IntrospectionURL string `json:"introspectionURL"`
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RequiredScope string `json:"requiredScope"`
}
OAuthConfig describes an existing authorization server, not an authorization server implemented by this gateway. It must support RFC 7662 introspection with client_secret_basic and return active, iss, aud, exp, sub, client_id, and scope. The sole accepted audience is Config.ResourceURL.
type Principal ¶
type Principal struct {
ID string `json:"id"`
OrganizationID string `json:"organizationID"`
RepresentativeSeatKey string `json:"representativeSeatKey"`
CallerID string `json:"callerID"`
}
Principal is a trusted mapping from an external credential to one representative. None of these fields may come from MCP tool arguments.
type PrincipalConfig ¶
type PrincipalConfig struct {
Principal
BearerSHA256 []string `json:"bearerSHA256,omitempty"`
OAuthSubject string `json:"oauthSubject,omitempty"`
OAuthClientID string `json:"oauthClientID,omitempty"`
}
PrincipalConfig allows overlapping manual keys during rotation, or an exact OAuth subject/client pair, or both. BearerSHA256 holds lowercase hex SHA-256 digests, never plaintext keys. Generate keys from at least 32 random bytes: a digest alone cannot prove that its original key had sufficient entropy.