Documentation
¶
Overview ¶
Package xmcp implements the experimental Remote MCP Server runtime endpoint at /x/mcp/{remoteMcpServerId}. It is a temporary path used to prove out the Remote MCP Server proxy plumbing; once the MCP Frontend work lands, Remote MCP Server runtime handling will move under /mcp/... and use slug-based routing.
This package owns the HTTP lifecycle (routing, auth, DB load, header decryption) and delegates the actual forwarding work to github.com/speakeasy-api/gram/server/internal/remotemcp/proxy.
Index ¶
Constants ¶
const RuntimePath = "/x/mcp/{remoteMcpServerId}"
RuntimePath is the experimental runtime path served by this package.
Variables ¶
This section is empty.
Functions ¶
func Attach ¶
func Attach(mux goahttp.Muxer, service *Service, mcpService *mcp.Service, metadataService *mcpmetadata.Service)
Attach registers the experimental Remote MCP Server runtime handler for all supported HTTP methods. DELETE, GET, and POST are required by the MCP Streamable HTTP transport (see spec § Session Management for DELETE and § Listening for Messages from the Server for GET).
Attach also registers /x/mcp aliases for the install page and OAuth .well-known metadata routes, delegating to the existing mcp and mcpmetadata service handlers so the experimental endpoint has parity with /mcp.
Types ¶
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service owns dependencies for the Remote MCP Server runtime endpoint.
func NewService ¶
func NewService( logger *slog.Logger, tracerProvider trace.TracerProvider, meterProvider metric.MeterProvider, db *pgxpool.Pool, sessionManager *sessions.Manager, enc *encryption.Client, authzEngine *authz.Engine, guardianPolicy *guardian.Policy, billingRepo billing.Repository, billingTracker billing.Tracker, ) *Service
NewService constructs a Service with its full dependency graph wired up.
type ToolUsageLimitsInterceptor ¶
type ToolUsageLimitsInterceptor struct {
// contains filtered or unexported fields
}
ToolUsageLimitsInterceptor enforces the free-tier hard cap on tools/call invocations by consulting the billing repository's cached period usage. It is a proxy.ToolsCallRequestInterceptor: it runs after the generic user-request chain and before the request is forwarded upstream. Non-free tiers and orgs with an active subscription skip the check.
The interceptor intentionally fails open when cached usage is unavailable (the billing cache should always be warm, but a transient miss must not take down tool invocation). Failures are logged with the originating org ID so operators can spot them in dashboards.
func NewToolUsageLimitsInterceptor ¶
func NewToolUsageLimitsInterceptor(billingRepo billing.Repository, logger *slog.Logger) *ToolUsageLimitsInterceptor
NewToolUsageLimitsInterceptor constructs an interceptor bound to the given billing repository. The same instance can be reused across requests.
func (*ToolUsageLimitsInterceptor) InterceptToolsCallRequest ¶
func (i *ToolUsageLimitsInterceptor) InterceptToolsCallRequest(ctx context.Context, _ *proxy.ToolsCallRequest) error
InterceptToolsCallRequest implements proxy.ToolsCallRequestInterceptor. It reads the organization and account type from the request's auth context, consults cached billing usage, and returns a forbidden error when the org has exceeded its hard cap.
func (*ToolUsageLimitsInterceptor) Name ¶
func (i *ToolUsageLimitsInterceptor) Name() string
Name implements proxy.ToolsCallRequestInterceptor.
type ToolUsageTrackingInterceptor ¶
type ToolUsageTrackingInterceptor struct {
// contains filtered or unexported fields
}
ToolUsageTrackingInterceptor emits a billing.ToolCallUsageEvent for each tools/call response so Remote MCP Server invocations feed the same Polar meter that gates free-tier usage on the existing /mcp endpoint. It is a proxy.ToolsCallResponseInterceptor: it runs after the generic proxy.RemoteMessageInterceptor chain has accepted the response and before the payload is relayed to the user.
Tracking is fire-and-forget: events are emitted in a goroutine bound to a context derived via context.WithoutCancel so the call completes even if the inbound request context cancels mid-relay. Missing auth context is treated as a no-op and logged so operators can spot misconfiguration without taking down tool invocation.
func NewToolUsageTrackingInterceptor ¶
func NewToolUsageTrackingInterceptor(tracker billing.Tracker, logger *slog.Logger) *ToolUsageTrackingInterceptor
NewToolUsageTrackingInterceptor constructs an interceptor bound to the given billing tracker. The same instance can be reused across requests.
func (*ToolUsageTrackingInterceptor) InterceptToolsCallResponse ¶
func (i *ToolUsageTrackingInterceptor) InterceptToolsCallResponse(ctx context.Context, call *proxy.ToolsCallResponse) error
InterceptToolsCallResponse implements proxy.ToolsCallResponseInterceptor. It emits a billing event for every observed tools/call response — paid tiers included — so Polar metering matches the existing /mcp surface. Always returns nil: tracking is best-effort and must not block the response from reaching the user.
func (*ToolUsageTrackingInterceptor) Name ¶
func (i *ToolUsageTrackingInterceptor) Name() string
Name implements proxy.ToolsCallResponseInterceptor.