Documentation
¶
Index ¶
- Constants
- Variables
- func IsPolicyBlockedCode(code int64) bool
- func IsRPCError(err error) bool
- type Composer
- type ConsentRequiredError
- type CredentialResolver
- type Dialer
- type DialerFunc
- type DiscoveryCache
- type Introspector
- type PluginRunner
- func (r *PluginRunner) PreRequest(ctx context.Context, rc *appconsumer.RoutableConsumer, name string, ...) (*StageResult, error)
- func (r *PluginRunner) PreResponse(ctx context.Context, rc *appconsumer.RoutableConsumer, name string, ...) (*StageResult, error)
- func (r *PluginRunner) PreResponseDiscovery(ctx context.Context, rc *appconsumer.RoutableConsumer, result json.RawMessage) error
- type Prompt
- type RPCError
- type Resource
- type ResourceTemplate
- type RoleScoper
- type StageResult
- type Target
- type Tool
- type ToolNotPermittedError
- type Upstream
Constants ¶
const CodeRateLimited int64 = -32004
CodeRateLimited is returned whenever a denial is a matter of timing rather than of permission: the gateway plan throttle (rpc_dispatcher), TrustGuard's evaluate 429, and any policy plugin answering 429. Clients act on the two codes very differently — -32001 is never worth retrying and this one is worth retrying after Retry-After — so the distinction has to follow the status the plugin chose, not the plugin's identity.
CodeUnavailable is returned when gateway plan entitlements cannot be resolved (unknown tier) or TrustGuard evaluate returns 503. Aligns with HTTP 503 on the proxy path.
Variables ¶
var ( ErrToolNotFound = fmt.Errorf("mcp: tool not found: %w", commonerrors.ErrNotFound) ErrPromptNotFound = fmt.Errorf("mcp: prompt not found: %w", commonerrors.ErrNotFound) ErrResourceNotFound = fmt.Errorf("mcp: resource not found: %w", commonerrors.ErrNotFound) ErrNoMCPRegistries = fmt.Errorf("mcp: no MCP registries attached to consumer: %w", commonerrors.ErrValidation) )
var ErrAudienceMismatch = errors.New("mcp: inbound token audience does not match the upstream's expected audience")
var ErrNoPrincipal = errors.New("mcp: downstream auth mode requires an authenticated user identity")
var ErrNoRoleAccess = errors.New("mcp: no role grants MCP access for this identity")
var ErrNotSupported = errors.New("mcp upstream does not support this method")
var ErrUnreachable = errors.New("mcp upstream unreachable")
Functions ¶
func IsPolicyBlockedCode ¶ added in v0.20.0
IsPolicyBlockedCode reports whether a JSON-RPC error is a policy denial.
func IsRPCError ¶
Types ¶
type Composer ¶
type Composer interface {
ListTools(ctx context.Context, rc *appconsumer.RoutableConsumer) ([]Tool, error)
CallTool(ctx context.Context, rc *appconsumer.RoutableConsumer, name string, arguments json.RawMessage) (json.RawMessage, error)
ListResources(ctx context.Context, rc *appconsumer.RoutableConsumer) ([]Resource, error)
ListResourceTemplates(ctx context.Context, rc *appconsumer.RoutableConsumer) ([]ResourceTemplate, error)
ReadResource(ctx context.Context, rc *appconsumer.RoutableConsumer, uri string) (json.RawMessage, error)
ListPrompts(ctx context.Context, rc *appconsumer.RoutableConsumer) ([]Prompt, error)
GetPrompt(ctx context.Context, rc *appconsumer.RoutableConsumer, name string, arguments map[string]string) (json.RawMessage, error)
}
func NewComposer ¶
func NewComposer(dialer Dialer, creds CredentialResolver, discovery DiscoveryCache, logger *slog.Logger) Composer
type ConsentRequiredError ¶
func (*ConsentRequiredError) Error ¶
func (e *ConsentRequiredError) Error() string
type CredentialResolver ¶
type CredentialResolver interface {
Apply(ctx context.Context, rc *appconsumer.RoutableConsumer, reg *registrydomain.Registry, target *Target) error
}
func NewCredentialResolver ¶
func NewCredentialResolver( exchanger sts.Exchanger, vault vaultdomain.Repository, connect appoauth.ConnectService, provider appoauth.ProviderClient, logger *slog.Logger, ) CredentialResolver
type DialerFunc ¶
type DiscoveryCache ¶
type Introspector ¶
type Introspector interface {
ListRegistryTools(ctx context.Context, gatewayID ids.GatewayID, registryID ids.RegistryID) ([]Tool, error)
}
func NewIntrospector ¶
func NewIntrospector(registries appregistry.Finder, dialer Dialer) Introspector
type PluginRunner ¶ added in v0.3.4
type PluginRunner struct {
// contains filtered or unexported fields
}
PluginRunner runs the resolved plugin chain on the native MCP tools/call path, mirroring pkg/app/proxy for the LLM path. It is a thin adapter over the shared plugins.Executor: it builds stage contexts from JSON-RPC values and maps a plugin block to a JSON-RPC error.
func NewPluginRunner ¶ added in v0.3.4
func NewPluginRunner(executor appplugins.Executor, logger *slog.Logger) *PluginRunner
NewPluginRunner accepts the shared executor port; a nil executor makes every method a no-op (plugin-free parity with today's MCP path).
func (*PluginRunner) PreRequest ¶ added in v0.3.4
func (r *PluginRunner) PreRequest( ctx context.Context, rc *appconsumer.RoutableConsumer, name string, arguments json.RawMessage, ) (*StageResult, error)
PreRequest runs StagePreRequest over the tools/call params. The returned StageResult carries the effective tool input — a plugin may have rewritten it — or a payload a plugin produced in place of calling the upstream at all. A non-nil error is an *RPCError: a policy denied the call and the caller skips the upstream dial. Per RUN-832 the call fails open on any non-block error (guard unavailable, decode failure): it is logged and the call proceeds.
func (*PluginRunner) PreResponse ¶ added in v0.3.4
func (r *PluginRunner) PreResponse( ctx context.Context, rc *appconsumer.RoutableConsumer, name string, arguments json.RawMessage, result json.RawMessage, ) (*StageResult, error)
PreResponse runs StagePreResponse over the tool result. A StageResult with a Result replaces the tool's output (TrustGuard data-masking); nil keeps the original. A non-nil error is an *RPCError: the response was blocked and the caller discards the result. Per RUN-832 the call fails open on any non-block error in this direction too: it is logged and the original result is kept.
func (*PluginRunner) PreResponseDiscovery ¶ added in v0.30.3
func (r *PluginRunner) PreResponseDiscovery( ctx context.Context, rc *appconsumer.RoutableConsumer, result json.RawMessage, ) error
PreResponseDiscovery runs StagePreResponse over a discovery result (a tool listing) but applies only the outcomes that make sense for static server metadata. A tool listing is not user data: a threat detector — indirect prompt injection or code injection reading a malicious tool description — should be able to block it, but a data-masking transform (DLP) must not touch it. Redacting example emails baked into a description is pointless and would mangle or, when the mask cannot be applied, destroy discovery.
So a genuine denial (a PluginError or a non-2xx short-circuit) stops the listing, while a 2xx transform (the masking path) is dropped and the original listing is kept. Fails open on any non-block error, like the other stages.
type Prompt ¶
type Prompt struct {
Name string
// contains filtered or unexported fields
}
func (Prompt) MarshalJSON ¶
func (*Prompt) UnmarshalJSON ¶
type RPCError ¶
type RPCError struct {
Code int64
Message string
Data json.RawMessage
HTTPStatus int // wire + metrics HTTP status for gateway denials; upstream RPC errors stay on 200
HTTPHeaders map[string][]string
}
func (*RPCError) ResolvedHTTPStatus ¶ added in v0.23.0
ResolvedHTTPStatus returns the HTTP status for gateway denials (wire + telemetry).
type ResourceTemplate ¶
type ResourceTemplate struct {
Name string
URITemplate string
// contains filtered or unexported fields
}
func (ResourceTemplate) MarshalJSON ¶
func (rt ResourceTemplate) MarshalJSON() ([]byte, error)
func (*ResourceTemplate) UnmarshalJSON ¶
func (rt *ResourceTemplate) UnmarshalJSON(data []byte) error
type RoleScoper ¶
type RoleScoper interface {
Scope(ctx context.Context, rc *appconsumer.RoutableConsumer, data *appconsumer.Data) (*appconsumer.RoutableConsumer, error)
}
func NewRoleScoper ¶
func NewRoleScoper(oidcResolver approle.OIDCResolver) RoleScoper
type StageResult ¶ added in v0.29.0
type StageResult struct {
// Arguments is the effective tool input after the request stage. Empty when
// no plugin rewrote it.
Arguments json.RawMessage
// Result is a payload that stands in for the tool's output: the masked
// result from the response stage, or a reply a plugin produced itself in the
// request stage instead of letting the call reach the upstream.
Result json.RawMessage
}
StageResult is what a plugin stage decided for a tools/call. A plugin may rewrite the payload rather than block it — TrustGuard's data-masking does exactly that — so the caller has to carry the rewritten value forward instead of reusing the one it sent in.
type Target ¶
func StaticTarget ¶
func StaticTarget(reg *registrydomain.Registry) Target
type Tool ¶
type Tool struct {
Name string
// contains filtered or unexported fields
}
func (Tool) MarshalJSON ¶
func (*Tool) UnmarshalJSON ¶
type ToolNotPermittedError ¶ added in v0.25.3
type ToolNotPermittedError struct {
Tool string
}
ToolNotPermittedError reports a tool the upstream offers but the consumer's toolkit excludes. It is a denial, not a missing tool and not an upstream failure, so it carries its own type: the handler answers it as a policy block the agent can read, while telemetry records it as forbidden.
func (*ToolNotPermittedError) Error ¶ added in v0.25.3
func (e *ToolNotPermittedError) Error() string
type Upstream ¶
type Upstream interface {
ListTools(ctx context.Context) ([]Tool, error)
CallTool(ctx context.Context, name string, arguments json.RawMessage) (json.RawMessage, error)
ListResources(ctx context.Context) ([]Resource, error)
ListResourceTemplates(ctx context.Context) ([]ResourceTemplate, error)
ReadResource(ctx context.Context, uri string) (json.RawMessage, error)
ListPrompts(ctx context.Context) ([]Prompt, error)
GetPrompt(ctx context.Context, name string, arguments map[string]string) (json.RawMessage, error)
SupportsResources() bool
SupportsPrompts() bool
Close(ctx context.Context)
}