Control Token + MCP Tool Surface

JobCache's Core API separates public legacy reads, general control operations, and participant lifecycle authority. The new App MCP has no bearer at all: it calls only the App API, and scoped operations require the caller to present the opaque session link capability explicitly.

The credentials

JOBCACHE_CONTROL_TOKEN gates JobCache's general control routes:

Endpoint Caller
POST /api/corpus/search careervector-api server-side corpus gateway
GET /api/ads/lookup careervector-api worker during workspace hydration
POST /api/ads/resolve careervector-api worker (when a workspace imports a new job URL)
POST /api/commands/drain Operator / scheduled drainer
POST /api/catalog/sync Operator
POST /api/corpus/erasures/drain Operator / explicit control-plane call

Two narrower credentials are intentionally not aliases for the control token:

  • JOBCACHE_CORPUS_LIFECYCLE_TOKEN authorizes direct inbound POST /api/corpus/participants/erase calls.
  • JOBCACHE_CORPUS_WORKER_TOKEN is outbound only. The manual erasure drain sends it to CareerVector's /internal/corpus/erasures/claim and /ack routes, where that worker is granted only the erase capability.

Browsers never receive any of these values.

Every configured bearer must contain at least 24 characters after trimming, and the control, lifecycle, and worker values must be pairwise different. Core enforces this itself and returns 503 before authorization or database access when the credential set is weak or aliases two capabilities.

The erasure worker sends its bearer only to an HTTPS CareerVector base URL. Plain HTTP is accepted solely for loopback development addresses; URL-embedded credentials, query strings, and fragments are rejected.

POST /api/corpus/search is read-only but intentionally belongs to the authenticated internal boundary: it is the stable role/snapshot contract between products, not the public ad-browsing API. CareerVector sends the bearer from its server-side JOBCACHE_CONTROL_TOKEN binding. Browsers never receive it.

Legacy read endpoints stay open

GET /api/search, GET /api/postings, GET /healthz, and GET /metrics remain public on the Core origin. The authenticated Core route does not replace or silently tighten those legacy surfaces. Product MCP tools live only in jobcache/mcp/ and reach the App API rather than this compatibility process.

MCP tool surface

jobcache/mcp/ is the standalone Worker for mcp.jobcache.corbet.ch. It mirrors public App search/evidence plus link-scoped session, saved-view, snapshot and reduction operations. It may create or delete App-local state, but it never exposes Core delivery, erasure-drain or other internal administration. Destructive tools are annotated accordingly.

The App owns its protected Core connection. MCP neither stores nor forwards a Core/App control token, and caller Authorization headers are discarded. The old MCP mounted inside the provider-suspended Render interface has been deleted. The App and standalone MCP Workers are the live boundary.

See also

Source: jobcache/wiki/content/api/control-token.md