server

package
v0.22.107 Latest Latest
Warning

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

Go to latest
Published: May 1, 2026 License: MIT Imports: 33 Imported by: 0

Documentation

Overview

Package server — HTTP gateway (ADR-014 Phase 2, v0.11).

`clawtool serve --listen :8080 --token-file <path>` mounts a thin HTTP surface that proxies prompts to the supervisor and exposes the agent registry. Every dispatch goes through Supervisor.Send (same call site as the CLI / MCP). Auth is bearer-token at the edge — non-negotiable; the relay opens an exec-arbitrary-code-on-host surface.

TLS is not terminated here. Operators front this with nginx / caddy / Cloudflare Tunnel — we do not invent a cert story (see ADR-014 Rationale).

MCP-over-HTTP Accept-header content negotiation shim.

The mark3labs/mcp-go StreamableHTTPServer (v0.49.0) always replies to a single-response /mcp POST with `Content-Type: application/json` and a bare JSON-RPC body, regardless of the client's Accept header (see streamable_http.go:546 in that release).

rmcp (the Rust MCP SDK that codex's HTTP client is built on) opens initialize with `Accept: text/event-stream` only. When the upstream answers with raw JSON the rmcp parser tries to decode the body as SSE-framed (`data: <json>\n\n`), finds no `event:` lines, and surfaces the misleading

Deserialize error: data did not match any variant of untagged
enum JsonRpcMessage when send initialize request

MCP Streamable-HTTP (2025-06-18) says the server SHOULD honor the client's Accept by responding with `text/event-stream` framed as `data: <json>\n\n`; a single SSE event is a valid response shape.

mcpAcceptShim wraps the streamable handler and post-processes the outgoing response when the client asked for SSE — buffer the `application/json` body the inner handler emits, then write it back as a single `data: ...\n\n` SSE event with the right Content-Type. When the inner handler already chose `text/event-stream` (multi-event drain path, the upgradedHeader branch in mcp-go) we pass through unchanged.

Package server — `/v1/peers` REST surface (ADR-024 Phase 1).

Four endpoints, all bearer-authed by the same authMiddleware every other /v1/* path uses:

GET    /v1/peers                       — list with status / backend / circle / path filters
POST   /v1/peers/register              — body: a2a.RegisterInput; returns the assigned Peer
POST   /v1/peers/{peer_id}/heartbeat   — refresh last_seen + status
DELETE /v1/peers/{peer_id}             — explicit deregister on session end

Wire shape mirrors prassanna-ravishankar/repowire's /peers + /peers/by-pane endpoints so an existing repowire dashboard can be re-pointed at a clawtool daemon with a one-line URL change. Difference: clawtool's auth model is bearer-token (the daemon-wide token in ~/.config/clawtool/listener-token), not repowire's per-peer auth_token; we already have the daemon-shared token so a second layer is unnecessary at this phase.

Registry lifecycle: the handlers fetch a2a.GetGlobal() on every request. buildMCPServer's Phase-1 boot installs a registry into the global slot (with persistence at ~/.config/clawtool/peers.json); daemon shutdown clears it. Handlers return 503 when the global is nil so a misconfigured boot doesn't 500 — operator gets a clear "registry not initialised" hint instead.

Package server starts the clawtool MCP server.

Per ADR-004, clawtool exposes itself as one MCP server over stdio. Per ADR-006, core tools use PascalCase names (Bash, Read, Edit, ...). Per ADR-008, configured sources spawn as child MCP servers and their tools are aggregated under `<instance>__<tool>` wire names.

Boot order on every `clawtool serve`:

  1. Load config + secrets.
  2. Build sources.Manager and start each configured source. Failures on individual sources are non-fatal; their tools just don't show up.
  3. Build a search.Index from descriptors of every tool we plan to register: enabled core tools + ToolSearch + aggregated source tools. This index powers the ToolSearch primitive — see ADR-005 for why search-first is the prerequisite that lets a 50+ tool catalog scale.
  4. Register all tools on the parent MCP server. ToolSearch closes over the index reference; aggregated source-tool handlers route via the manager.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func InitTokenFile added in v0.20.0

func InitTokenFile(path string) (string, error)

InitTokenFile generates a fresh 32-byte (256-bit) hex token and writes it to path with 0600. Used by `clawtool serve init-token` and by tests that need a working credential.

func ServeHTTP added in v0.20.0

func ServeHTTP(ctx context.Context, opts HTTPOptions) error

ServeHTTP runs clawtool as an HTTP gateway. Blocks until the listener returns. Mirrors ServeStdio's lifecycle: build the MCP server (so the same agents/recipes/tools are available), then route HTTP requests through it.

MCP-over-HTTP (`--mcp-http`) mounts the full toolset at /mcp via mark3labs/mcp-go's StreamableHTTPServer (the persistent shared daemon every host fans into; see internal/daemon).

func ServeStdio

func ServeStdio(ctx context.Context) error

ServeStdio runs clawtool as an MCP server speaking over stdio. It blocks until stdin closes (the conventional MCP shutdown signal) or an unrecoverable error occurs.

Types

type HTTPOptions added in v0.20.0

type HTTPOptions struct {
	Listen    string // ":8080" or "0.0.0.0:8080" — passed to http.ListenAndServe.
	TokenFile string // path to a 0600 file containing the bearer token. Refused if missing/empty unless NoAuth is set.
	MCPHTTP   bool   // when true, mount the MCP toolset at /mcp via mcp-go's Streamable HTTP transport.

	// NoAuth runs the listener without bearer-token enforcement. The
	// shared local daemon flips this on by default — the operator's
	// machine is the trust boundary, codex / gemini hit /mcp over
	// loopback without pre-setting CLAWTOOL_TOKEN. Daemon / relay
	// deployments (multi-user, exposed beyond loopback) keep auth on
	// by leaving NoAuth false and supplying TokenFile.
	NoAuth bool
}

HTTPOptions configures the listener.

Jump to

Keyboard shortcuts

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