commserver

package
v1.7.0 Latest Latest
Warning

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

Go to latest
Published: Aug 10, 2026 License: AGPL-3.0 Imports: 21 Imported by: 0

Documentation

Overview

Package commserver exposes the inter-session communication subsystem (internal/comm) as an MCP endpoint, separate from the knowledge base's.

Why a separate endpoint and not more tools on /mcp

A client registers Ken twice. That separation is a security property, not packaging taste: a knowledge-base token cannot send messages and a comm token cannot write knowledge, each surface gets independent rate accounting so a poll loop cannot starve `kb_*` calls, revocation is per-surface, and an operator can firewall or disable one without the other. It also lets this endpoint refuse the permissive CORS the knowledge-base endpoint needs for a browser-based connector, since nothing here has a browser client.

What this package does not do

It does not decide whether a receiving session should act on a message. The instructions tell a model to treat message content as data and to confirm with its human before acting on instructions found inside one — and that is advice, not a control: Ken cannot verify a client surfaced it, cannot scope it per tool, and gets no signal that a human confirmed anything. The enforced boundary is upstream, in who may open a channel at all: a human mints the pairing code. docs/COMM.md §8 states this rather than implying a guarantee this code cannot make.

Index

Constants

View Source
const (
	ScopeComm     = "comm"
	ScopeCommFile = "comm-file"
)

ScopeComm is the capability required by every tool on this endpoint.

ScopeCommFile is RESERVED and required by nothing yet: file exchange is deferred to a later MINOR (docs/COMM.md §11). It is declared now because splitting a shipped `comm` scope into two later would be a MAJOR under COMPATIBILITY.md, while merging two into one is free.

Variables

This section is empty.

Functions

This section is empty.

Types

type Deps

type Deps struct {
	// Comm is the message store. Required.
	Comm *comm.Store
	// Store is the knowledge base, used ONLY to authenticate bearer tokens.
	// Nothing in this package reads or writes knowledge.
	Store *store.Store
	// TokenLimiter is comm's own rate bucket, separate from the knowledge base's.
	// Optional; nil disables per-token limiting on this endpoint.
	TokenLimiter ratelimit.Limiter
	// Metrics is optional.
	Metrics *metrics.Registry
	// MaxPollWaitSeconds bounds a long poll. Clamped server-side regardless of
	// what an operator configures, because a wait that ties or exceeds the client's
	// tool timeout turns a successful empty poll into a tool ERROR, which models
	// handle badly — and reverse proxies commonly read-timeout at 60s.
	MaxPollWaitSeconds int
}

Deps are the collaborators for the comm MCP endpoint.

type FileHandler

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

The byte-relay HTTP surface: PUT and GET /comm/files/{grant}.

This exists because payload bytes must never travel as tool-call tokens (C8): tool arguments are generated token by token by a model, so the model mints a one-time grant over MCP and then drives the actual bytes with a shell tool — curl does resumable HTTP correctly, and the tokens spent are one command line.

Two credentials are required on every request, deliberately: the bearer token (which must carry `comm-file` and must OWN the endpoint the grant was minted for) and the grant itself (single-use, minutes-lived, bound to one attachment and one direction). A leaked URL is useless without the token; a leaked token cannot touch bytes it was never granted. This is what "no HTTP path serves an attachment without authentication" means in practice.

func NewFileHandler

func NewFileHandler(d Deps, h *Handler) *FileHandler

NewFileHandler builds the relay surface. h supplies the long-poll wakeup.

func (*FileHandler) ServeHTTP

func (f *FileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

type Handler

type Handler struct {
	http.Handler
	// contains filtered or unexported fields
}

Handler is the comm MCP endpoint.

func NewHTTPHandler

func NewHTTPHandler(d Deps) *Handler

NewHTTPHandler builds the comm endpoint: a streamable-HTTP MCP server wrapped in comm-only bearer auth.

func (*Handler) Drain

func (h *Handler) Drain()

Drain wakes every parked long poll and refuses new ones. Call before HTTP shutdown so a restart is invisible to connected agents rather than producing a burst of severed connections.

func (*Handler) ParkedWaiters

func (h *Handler) ParkedWaiters() int

ParkedWaiters reports how many long polls are currently parked (metrics/tests).

func (*Handler) SetMaxPollWait

func (h *Handler) SetMaxPollWait(seconds int)

SetMaxPollWait updates the long-poll ceiling live. The value is clamped to hardMaxPollWait no matter what an operator configures: a wait that ties or exceeds the client's own tool timeout converts a successful empty poll into a tool ERROR, and reverse proxies commonly read-timeout at 60s.

Jump to

Keyboard shortcuts

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