Admin MCP Server
Local stdio MCP control surface for agent-driven Sterling operator workflows.
The Admin MCP server in apps/admin-mcp is a local stdio Model Context Protocol server for Codex, Claude-style desktop clients, and other MCP-capable agents. It gives an operator agent the same kind of runtime, discovery, review, press, artifact, and VPS publish controls that the Electron desktop app exposes, but without requiring a visual desktop shell.
The server is intentionally an adapter, not a second scraping implementation. The scraping and orchestration brain remains in services/platform-api/src/rosterscraper/*, with the FastAPI app mounted from rosterscraper.api.app:app. MCP calls either supervise the local API/worker runtime through @sterling/admin-runtime or call the control-plane HTTP routes exposed by that local API.
Architecture
MCP client
|- Codex
|- Claude Desktop
`- other local MCP hosts
|
| stdio
v
apps/admin-mcp
|- src/index.ts
|- src/server.ts
|- src/tools.ts
`- src/resources.ts
|
v
@sterling/admin-runtime
|- env parsing and redaction
|- secure env cache
|- local API and worker process supervision
|- readiness, watchdog, logs, and artifact paths
|- control-plane HTTP client
`- snapshot package builder
|
v
http://127.0.0.1:13000
services/platform-api/src/rosterscraper/api/app.py
|- runtime, discovery, sessions, review, press, jobs
|- Celery worker queues
|- Postgres and Redis
|- object storage and artifacts
`- VPS sync APIThe active Electron app remains available as a visual adapter. MCP is a second operator adapter over the same runtime boundary. New scrape logic should not be copied into apps/admin-mcp; add backend capabilities to services/platform-api first, then expose them through MCP as needed.
Package Layout
| Path | Responsibility |
|---|---|
apps/admin-mcp/src/index.ts | Boots the MCP server over StdioServerTransport. |
apps/admin-mcp/src/server.ts | Creates the server, context, tools, and resources. |
apps/admin-mcp/src/tools.ts | Registers the Sterling MCP tool surface and zod input schemas. |
apps/admin-mcp/src/resources.ts | Registers long-lived MCP resources and resource templates. |
apps/admin-mcp/src/context.ts | Creates the runtime manager and control-plane client context. |
apps/admin-mcp/src/format.ts | Formats successful and failed tool responses for MCP clients. |
packages/admin-runtime/src/runtime-manager.ts | Supervises the managed API and scrape-local worker processes. |
packages/admin-runtime/src/secure-env-store.ts | Stores imported env bundles with Keychain-backed encryption on macOS. |
packages/admin-runtime/src/env.ts | Parses env bundles, applies runtime defaults, and redacts secrets. |
packages/admin-runtime/src/control-plane-client.ts | Wraps control-plane HTTP and SSE-style calls used by MCP tools. |
packages/admin-runtime/src/snapshot-package.ts | Builds versioned snapshot_package payloads for VPS publish intent calls. |
Startup Model
MCP connection is inert. Connecting Codex or another MCP host to apps/admin-mcp lists tools and resources only; it does not start scraping, open browsers, create jobs, or publish anything.
The managed runtime starts only when one of these happens:
sterling_runtime_startis called.sterling_runtime_repairis called.- A workflow tool is called with
ensure_runtime: true.
The default local API origin is http://127.0.0.1:13000. The runtime manager starts:
- the FastAPI app with
uvicorn rosterscraper.api.app:app, - a Celery worker that advertises
scrape-local,validation-publish, - runtime heartbeat and readiness checks,
- log capture under the MCP data directory.
The watchdog does not restart the API while startup is still in progress. It waits for the API and worker to finish their initial readiness path, then monitors health from there.
Env and Secret Handling
The operator imports runtime configuration through sterling_runtime_import_env_bundle. That env bundle becomes the local runtime source of truth for the MCP-managed API and worker.
Production/default storage:
- Data directory:
~/Library/Application Support/Sterling Admin MCP/ - Env cache: encrypted AES-256-GCM payload
- Encryption key: macOS Keychain-backed secret
Plaintext env cache is allowed only for local tests and development when:
STERLING_MCP_ALLOW_PLAINTEXT_ENV_CACHE=trueDo not enable plaintext cache for real operator use.
The runtime redacts secrets when returning status or import previews. This includes obvious secret variables and URL credentials such as database passwords in DATABASE_URL, REDIS_URL, and related connection strings.
Environment Variables
| Variable | Purpose |
|---|---|
STERLING_REPO_ROOT | Repo root used to resolve services/platform-api and workspace paths. Defaults upward from the MCP app when possible. |
STERLING_MCP_DATA_DIR | Overrides the default data/log/env-cache directory. |
STERLING_MCP_BACKEND_DIR | Overrides the backend working directory. Defaults to services/platform-api. |
STERLING_MCP_PYTHON | Python executable used to launch uvicorn and Celery. |
STERLING_MCP_ALLOW_PLAINTEXT_ENV_CACHE | Allows plaintext env cache for tests/dev only. |
STERLING_MCP_API_HOST | Managed API host. Default: 127.0.0.1. |
STERLING_MCP_API_PORT | Managed API port. Default: 13000. |
The imported env bundle supplies backend values such as DATABASE_URL, REDIS_URL, OBJECT_STORAGE_*, ATTORNEY_MEDIA_*, LLM provider settings, browser/runtime settings, and VPS sync configuration. For production-direct operation from a Mac, Tailscale must be online when database or Redis hosts are reachable only on the tailnet.
Tool Surface
Runtime
| Tool | Purpose |
|---|---|
sterling_runtime_status | Returns env-cache state, managed process status, API health, worker heartbeat, readiness, log paths, and VPS status. |
sterling_runtime_import_env_bundle | Imports an env file or env text into the secure local cache and returns a redacted preview. |
sterling_runtime_start | Starts the managed API and worker. |
sterling_runtime_stop | Stops the managed API and worker and frees the local API port. |
sterling_runtime_repair | Reconciles runtime state by stopping stale managed processes and starting a clean runtime. |
sterling_runtime_tail_logs | Reads recent lines from the managed API, worker, or runtime logs. |
sterling_vps_status | Checks the configured VPS sync/health lane. |
Roster Discovery
| Tool | Purpose |
|---|---|
sterling_list_firms | Lists configured firms from the control plane. |
sterling_upsert_firm | Creates or updates a firm configuration. |
sterling_roster_chat | Sends a discovery chat message and returns conversation/run state. |
sterling_get_conversation | Reads a discovery conversation by id. |
sterling_save_preview | Saves a discovered or edited preview explicitly. |
sterling_export_attorneys_csv | Exports attorneys from a session/import path to CSV. |
Discovery defaults are agent-flexible:
execution_targetdefaults toauto.browser_providerdefaults tonull.- The backend can choose local/cloud/browser behavior according to runtime settings and readiness.
Discovery does not publish by itself. Save and publish remain separate MCP calls.
Review and Publish
| Tool | Purpose |
|---|---|
sterling_list_review_batches | Lists staged review batches. |
sterling_get_staged_import | Reads a staged import and its rows. |
sterling_update_staged_rows | Updates staged review rows before publishing. |
sterling_publish_session | Publishes an approved session/import into the product-facing state. |
sterling_publish_snapshot_to_vps | Builds and sends a versioned snapshot package to /desktop/sync/publish-intent. |
Publishing is explicit. Agents should not call publish tools unless the operator asked to publish or apply a snapshot.
Press Monitoring
| Tool | Purpose |
|---|---|
sterling_press_discover_source | Plans or discovers a press/news source for a firm or URL. |
sterling_press_create_monitor | Creates a monitor from a reviewed source plan. |
sterling_press_run_now | Runs a press monitor immediately. |
sterling_press_review_articles | Lists discovered press articles needing review. |
sterling_press_decide_article | Approves, rejects, or otherwise decides a reviewed press article. |
Jobs and Artifacts
| Tool | Purpose |
|---|---|
sterling_list_sessions | Lists recent extraction/discovery sessions. |
sterling_get_extraction | Reads extraction details by id. |
sterling_get_source_report | Reads source-report artifacts for a session. |
sterling_list_scheduled_jobs | Lists recurring jobs. |
sterling_create_scheduled_job | Creates a recurring roster scrape job for an approved EIP/skill. |
sterling_update_scheduled_job | Updates a recurring roster scrape job schedule, status, execution target, or review policy. |
sterling_run_scheduled_job_now | Runs a scheduled job immediately. |
sterling_delete_scheduled_job | Deletes or archives a recurring roster scrape job. |
Resources
Resources expose long-lived context to MCP clients without forcing every interaction through a tool call.
| Resource | Type | Purpose |
|---|---|---|
sterling://runtime/status | Static resource | Current runtime status as JSON. |
sterling://review/batches | Static resource | Current staged review batch list. |
sterling://logs/{service} | Template | API, worker, or runtime logs. |
sterling://conversation/{id} | Template | Discovery conversation context. |
sterling://session/{id} | Template | Session/extraction context. |
sterling://session/{id}/source-report | Template | Source report for a session. |
sterling://extraction/{id} | Template | Extraction detail context. |
Using With Codex
Build the MCP server first:
pnpm --dir apps/admin-mcp buildThen configure Codex to start the compiled stdio server. A local Codex config entry should look like:
[mcp_servers.sterling_admin]
command = "node"
args = ["/Users/ciphore/viewport/apps/admin-mcp/dist/index.js"]
cwd = "/Users/ciphore/viewport"
[mcp_servers.sterling_admin.env]
STERLING_REPO_ROOT = "/Users/ciphore/viewport"For development against TypeScript source, use the app script instead:
[mcp_servers.sterling_admin]
command = "pnpm"
args = ["--dir", "apps/admin-mcp", "start"]
cwd = "/Users/ciphore/viewport"
[mcp_servers.sterling_admin.env]
STERLING_REPO_ROOT = "/Users/ciphore/viewport"A normal first-run operator sequence is:
- Call
sterling_runtime_status. - Call
sterling_runtime_import_env_bundlewith a trusted env file path. - Start Tailscale if the env points at tailnet-only Postgres or Redis hosts.
- Call
sterling_runtime_start. - Confirm status shows
lifecycle: "ready",apiHealthy: true,workerHeartbeatHealthy: true, and VPS status online when expected. - Use read-only tools such as
sterling_list_sessionsandsterling_list_firms. - Run discovery/review/publish tools only when the operator asks for that workflow.
Safety Rules
- MCP connection alone must stay inert.
- Discovery may create conversations or runs, but it must not publish.
- Save, review, publish, and VPS apply are explicit tool calls.
- VPS snapshot publish calls must be signed with
DESKTOP_SYNC_SECRET_KEYorCONTROL_PLANE_SECRET_KEY. - Default discovery execution target is
auto. - Default browser provider is unresolved/null so the backend and agent can choose the right route.
- The MCP server should call existing control-plane APIs instead of duplicating backend logic.
- The secure env cache should stay encrypted for real operator use.
- Full scrape, row mutation, publish, and VPS snapshot calls are not part of a default smoke test.
Verification Runbook
Use these checks after changing apps/admin-mcp or packages/admin-runtime:
pnpm --dir packages/admin-runtime build
pnpm --dir packages/admin-runtime test
pnpm --dir apps/admin-mcp build
pnpm --dir apps/admin-mcp testRun the existing desktop regression suite when shared runtime behavior could affect Electron:
pnpm --dir apps/admin-desktop testFor SDK-level smoke testing, start the MCP server through stdio and verify:
- the server boots without starting the runtime,
tools/listreturns the Sterling tools,resources/listreturns static resources,- resource templates include logs, conversations, sessions, reports, and extractions.
For production-direct live smoke testing, verify Tailscale and public API reachability first:
/usr/bin/nc -vz -G 5 100.79.46.125 15432
/usr/bin/nc -vz -G 5 100.79.46.125 16379
/usr/bin/curl -sS -m 5 https://api.sterlingindex.com/healthzThen import a trusted env bundle, start the runtime, and confirm:
lifecycleisready,apiHealthyistrue,workerHeartbeatHealthyistrue,- VPS status is
onlinewhen the sync API is configured, sterling_list_sessionsreturns recent session data,sterling_list_firmsreturns configured firms,sterling_runtime_stopshuts down the managed API and worker,- nothing remains listening on
127.0.0.1:13000.
Failure Modes
| Symptom | Likely cause | Operator action |
|---|---|---|
| API stays in startup or readiness never resolves | Tailnet database or Redis is unreachable | Start Tailscale, then check the DB and Redis host/ports. |
| Runtime reports missing env cache | No env bundle has been imported | Call sterling_runtime_import_env_bundle with a trusted env file. |
Port 13000 is occupied | Another API process is already listening | Use sterling_runtime_status and logs to confirm ownership, then stop the conflicting process if appropriate. |
| Runtime identity mismatch | A process on 13000 was not started by this MCP runtime | Stop the foreign process or use its own owner to manage it. |
| Worker heartbeat unhealthy | Celery failed to connect to Redis or crashed during startup | Tail worker logs and verify REDIS_URL. |
| VPS status offline | Sync API health lane is unreachable or env is missing | Check public API health, Tailscale route, and VPS sync env. |
| MCP tool call times out during startup | Backend dependency is blocking app startup | Tail API logs and verify database, Redis, object storage, and required secrets. |
Current Boundaries
The first MCP version is local-first and operator-powerful, but it deliberately stays within existing Sterling runtime boundaries:
- It does not replace
services/platform-api. - It does not duplicate roster scraping, press discovery, validation, or publish logic.
- It does not change dashboard product APIs.
- It does not make Electron obsolete immediately; Electron remains the visual adapter.
- It provides the shared
@sterling/admin-runtimepackage that Electron can adopt later for runtime supervision parity.