# Company OS MCP Server

Dedicated stdio MCP server for the Company OS HTTP API.

## One-command companion connection

After the package is published, connect the current project to a model-free
Company OS companion stack with one command:

```bash
npx --yes @hsm/company-os-mcp-server connect codex
# or
npx --yes @hsm/company-os-mcp-server connect claude
```

`companyos connect` runs the installer and Compose definition embedded in that
exact npm release, pulls the matching versioned Company OS image, starts
Postgres and `hsm_console` in `companion` mode, verifies ledger health, and
generates the project-scoped host configuration from
`companyos.integration.json`. It does not fetch mutable files from the source
repository. Use `--no-start` when the stack already exists and only host
configuration should be regenerated. The harness-first command stays in the
terminal by default; pass `--open` to open the optional Console.
`COMPANY_OS_IMAGE` remains an explicit
operator override for prerelease or private-registry testing.

No provider key or model setting is requested. The host supplies its own model.
On first use, the MCP tools conduct the durable Passport flow:

1. `company_passport_start`
2. `company_passport_answer`
3. `company_passport_prepare` for human review
4. `company_passport_answer` to record the explicit authority/change-set confirmation
5. `company_passport_commission`

Commissioning creates a distinct `claude-code` or `codex` company agent, grants
eight bounded 30-day scopes, and writes owner/host credentials to private 0600
binding files under `HSMII_HOME` (default `~/.hsm-ii`). Credentials are never
written to `.mcp.json`, `.codex/config.toml`, command arguments, or MCP results.

It exposes Company OS tasks, memory, tool catalog workflows, run events,
tenant-scoped trace queries, approval/HITL endpoints, and the Gestion Velora
customer-intake/email handoff as MCP tools. Mutating or approval-sensitive tools
require `confirm=true` by default.

`company_os_trace_query` is the read-only fleet-debugging seam. Ask for bounded
rows from `otel-v1-apm-span-*`, then pass a returned run id to `company_os_why`
or `company_os_timeline` for the authoritative ledger explanation. The MCP
server calls the Company OS API rather than OpenSearch, so company scoping stays
server-owned.

The MCP initialization response also publishes the mandatory operator contract:
identify → understand → govern → simulate → authorize → execute → verify →
record. Read-only work stops after grounded understanding; mutations must close
the complete loop and leave independently verified task-trail evidence.

## Console-session CLI login

```bash
companyos login
companyos status
companyos logout
```

`companyos login` opens Company OS Console with an OAuth-style Authorization
Code + PKCE request. The existing HttpOnly operator and company-principal
sessions stay in the browser. After the operator chooses a company and approves
the requested scopes, Company OS creates a separate scoped CLI worker and
returns a one-hour access credential plus a rotating refresh credential. Only
the refresh envelope is persisted. On macOS it is stored in a mode-0600 file
under `~/Library/Application Support/Company OS/` so CLI use does not trigger
Keychain approval dialogs; Linux and Windows use their operating-system
credential stores. No user access key is written to `~/.hsm-ii` or a project
file. Each authenticated CLI invocation rotates the refresh credential.
`companyos logout` revokes every credential for that isolated CLI worker before
deleting its locally stored refresh envelope.
This CLI session flow does not create `~/.hsm-ii`; the Passport/MCP host
commissioning flow described above is a separate installation path.

## Terminal chat

Use the Company OS AgentChat harness directly from a terminal, including a
Tern shell tab:

```bash
company-os chat
```

This is a terminal client for the authenticated Company OS host. On the same
machine as Zeron, it reads the active company identity and transport credential
from the private local auth home, confirms the selected company with the host,
then sends each turn directly to the host API on port 3847. A valid company
principal or scoped CLI session is required; an old tenant binding can expire.
The terminal prints the confirmed company before accepting a turn. Company OS owns the
chat thread, selects the adopted model, runs its agent harness, and records the
run and receipts in the company ledger. The terminal can close without discarding the host
thread; the printed thread ID can be resumed later:

```bash
company-os chat --thread-id <thread-uuid>
```

If the selected local company's principal expired, a signed-in owner or admin
on an approved device can authorize a fresh local CLI session with
`company-os login --company <company-id>`. Chat uses that session directly
through the local host after authorization.

On another machine, the CLI uses a scoped remote login. That login requires
`company_os:tools` and a non-loopback HTTPS Company OS endpoint:

```bash
./company-os login --console-url https://<company-os-host> --device
./company-os chat
```

Company OS performs model selection and provider execution on the host; no
provider key is needed in the terminal process.

For a headless terminal, use `companyos login --device`, open the displayed
Console URL on a signed-in device, and enter the one-time code.

## Run

```bash
cd services/company-os-mcp-server
npm install
npm run build
HSM_COMPANY_API_BASE=http://127.0.0.1:3847 HSM_COMPANY_ID=<company-uuid> npm run mcp
```

The same transport and handler contract is available as a thin operator CLI.
It prints canonical API JSON without building a second run-story projection:

```bash
npm run build
HSM_COMPANY_API_BASE=http://127.0.0.1:3847 HSM_COMPANY_ID=<company-uuid> \
  npx company-os what <run-uuid>
```

## MCP operator commands

`companyos mcp` checks the selected CLI company's host, connector projection,
and read-only stdio MCP handshake. `companyos mcp --help` lists the command tree;
each command has its own `--help` without contacting the host.

```bash
companyos mcp status
companyos mcp doctor --client omp
companyos mcp tools --search task
companyos mcp connect omp
companyos mcp connectors list
companyos mcp connectors show github
companyos mcp connectors resources github
companyos mcp connectors prompts github
```

Connector reads use the host's company-scoped MCP connector routes. The list
prints connector keys, provider, status, and redacted OAuth state; `--json`
returns the canonical response. `--quiet` on the list prints connector keys.
Resource and prompt responses identify live transport when one is attached;
stored projections are shown otherwise.

An authorized operator can request `companyos mcp connectors enable ID --confirm`
or `disable ID --confirm`. The host rechecks company authority and returns a
governance receipt. `--idempotency-key KEY` makes retries explicit. A CLI
confirmation never grants authority. OAuth and reconnect are omitted from this
CLI until their live provider transport paths are proved end to end.

`companyos mcp serve --stdio` exposes the current CLI session's read-only tools
to an MCP client. Its standard output carries MCP protocol data only. The
generated OMP profile invokes this public command, so it does not depend on a
package-internal JavaScript path. Rerun `companyos mcp connect omp` to refresh an
older profile. `companyos mcp doctor --client omp` checks the local OMP version,
plugin health, and profile even if the Company OS host is unavailable; its host
and live MCP checks still require a valid CLI session.

For an OMP upgrade, run the offline compatibility smoke with the installed
binary before trying a live Company OS session:

```bash
npm --prefix services/company-os-mcp-server run build
node services/company-os-mcp-server/scripts/omp-compatibility-smoke.mjs
COMPANY_OS_OMP_BIN=/path/to/omp2 node services/company-os-mcp-server/scripts/omp-compatibility-smoke.mjs
```

The smoke uses a temporary profile and dummy model credential. It checks OMP
RPC startup, pinned adapter loading, and stdio MCP initialize/tools/list without
a model prompt or company credentials. It does not verify the live host or
governed broker. After login and host startup, `companyos mcp doctor --client omp`
checks the real read-only handshake. Governed OMP runs retain their separate
host-issued broker grant and receipt path.

The CLI exposes `vocabulary`, task lifecycle commands, paginated task/run
events, `ps`, `inspect`, `what`, `why`, `timeline`, `diff`, `preview`,
`prepare-fork`, and `select-winner`. The first daily-operator slice is:

```bash
company-os task list --state open
company-os task create --title "Investigate deployment" --confirm
company-os task run <task-id> --prompt "Collect evidence" --idempotency-key "task:<task-id>:run:1" --confirm
company-os events <run-id> --follow
company-os task cancel <task-id> --reason "Superseded" --confirm
```

Company branding and invoice rules are also available through the CLI. Every
named company resolves to the Gestion Velora document baseline adapted to its
identity; an operator can later store an approved, versioned profile override:

```bash
company-os company profile show
company-os company profile set --file PROFILE.json --dry-run
company-os company invoice-format show
company-os company invoice-format set --file INVOICE_FORMAT.json --confirm
```

The active profile is injected into task `llm-context` and is available to MCP
clients through `company_os_get_document_profile`. See
`docs/company-os/document-branding-and-invoicing.md` for the schema and
override rules.

`events --follow` emits canonical execution-event objects as JSONL, advances
with the server's `last_seq`, and drains once more after the canonical run story
reports a terminal state. Task creation, execution, cancellation, fork
preparation, and Gate selection require `--confirm`; API authentication,
principal scoping, idempotency, spend, settlement, and receipts remain
server-owned.

The approval inbox and receipt evidence commands are server-backed:

```bash
company-os approvals --status pending
company-os approval decide <approval-id> --decision approved --confirm
company-os receipt list
company-os receipt show terminal:<receipt-uuid>
company-os receipt verify terminal:<receipt-uuid>
company-os verify task <task-id>
company-os verify run <run-id>
```

`approvals` returns the authenticated company's canonical approval rows and
explicitly classifies pre-envelope rows as `legacy_unverifiable`. The decision
command requires confirmation, refreshes that authoritative inbox, and binds
the submitted choice to the server-stored presentation, subject, and request
digests. It never accepts a caller-invented approval projection.

Receipt IDs are family-qualified (`terminal:`, `run_event:`, `governance:`, or
`spend:`), so `show` can resolve the exact tenant-scoped source row. Terminal
receipts are verified by recomputing the database-owned canonical hash and
checking both chain linkage and the stored company head. Timeline families
without a digest contract return `verification_supported=false` and never
claim to be verified.

`verify task` and `verify run` use the same authenticated company principal to
replay immutable lifecycle histories and compare them with their live
projections. The responses include `verified`, `has_drift`, `drift_kind`,
aggregate versions, and redacted evidence for each checked projection; missing
history or a replay failure is never reported as verified.

## Grok Remote MCP bridge

The package also includes a stateful Streamable HTTP MCP server for an xAI/Grok
Remote MCP connector. It reuses the same Company OS handlers and operator
contract as stdio; it is not a second agent runtime or policy engine.

Start it after the Company OS API is available:

```bash
cd services/company-os-mcp-server
npm run build
HSM_COMPANY_API_BASE=https://company-os.internal \
HSM_COMPANY_ID=<company-uuid> \
HSM_COMPANY_PRINCIPAL_TOKEN=<server-held-principal-token> \
HSM_COMPANY_PRINCIPAL_COMPANY_ID=<company-uuid> \
HSM_COMPANY_OS_REMOTE_MCP_TOKEN=<strong-random-grok-token> \
npm run start:http
```

The endpoint is `http://127.0.0.1:3850/mcp` by default and exposes an
unauthenticated `GET /healthz`. Put it behind an HTTPS reverse proxy before
giving the URL to Grok. The inbound Grok token is accepted only as a bearer
header and is never forwarded to Company OS; the server adds only its own API
and company principal credentials. Every session is bound to the configured
company, and a request containing another `company_id` is refused.

The default remote allowlist is read-only:

```text
company_os_health, company_os_list_companies, company_os_get_company,
company_os_get_document_profile, company_os_dashboard, company_os_list_tasks,
company_os_get_task, company_os_list_agent_runs, company_os_run_story,
company_os_list_run_surfaces, company_os_trace_query, company_os_search_memory,
company_os_list_approvals,
company_os_show_approval, company_os_verify_task, company_os_verify_run
```

Override it explicitly with `HSM_COMPANY_OS_REMOTE_MCP_TOOLS`. Any tool outside
the read-only admission set additionally requires
`HSM_COMPANY_OS_REMOTE_MCP_ALLOW_MUTATIONS=1`; the existing Company OS
confirmation, governance, approval, execution, verification, and receipt
checks still apply. The remote boundary always runs in `bound` approval mode,
whatever the local stdio setting is: a mutating call must cite a workflow
approval that a different principal already approved (not expired and not yet
used), and the remote session cannot decide approvals itself. A model-supplied
`confirm=true` is not human approval.

Conceptual xAI Remote MCP configuration:

```json
{
  "type": "mcp",
  "server_url": "https://company-os.example.com/mcp",
  "server_label": "company_os",
  "server_description": "Governed Company OS tasks, memory, runs, and verification",
  "allowed_tools": [
    "company_os_dashboard",
    "company_os_list_tasks",
    "company_os_get_task",
    "company_os_list_agent_runs",
    "company_os_run_story",
    "company_os_search_memory",
    "company_os_verify_task"
  ],
  "authorization": "<same-grok-token-as-HSM_COMPANY_OS_REMOTE_MCP_TOKEN>"
}
```

Use `HSM_COMPANY_OS_REMOTE_MCP_HOST`, `..._PORT`, and `..._PATH` to change the
listener. Non-loopback binds must also set
`HSM_COMPANY_OS_REMOTE_MCP_ALLOWED_HOSTS`; comma-separated origin allowlisting
is available through `HSM_COMPANY_OS_REMOTE_MCP_ALLOWED_ORIGINS`. The bridge
also enforces bounded JSON bodies and a per-source fixed-window request limit.

### Result presentation contract

Every MCP tool call returns both forms of the same disposable projection:

- `structuredContent` uses the checked-in `hsm.company_os.result.v1` envelope
  (`schemas/company_os_result.v1.json`). Its `data` field contains the redacted
  canonical Company OS payload; `outcome`, `governance`, `authority`, `bounds`,
  and `links` make state and next action explicit for an agent or rich client.
- `content` is a Markdown fallback designed for chat hosts that ignore
  structured results. It leads with status, summary, verification, explicit
  evidence references, next action, and a Console link when
  `HSM_COMPANY_OS_CONSOLE_ORIGIN` is configured.

The envelope is not a second ledger or a second run story. A successful tool
call is never treated as verification: the result says `not_available` unless
the canonical payload explicitly reports verification. Waiting, approval
required, governed refusal, infrastructure failure, and oversized payloads are
distinct states. Oversized structured payloads become an explicit `partial`
result with `bounds.truncated=true`; JSON is never cut mid-object. Console links
are navigation only and grant no authority.

## Environment

- `HSM_COMPANY_API_BASE` or `HSM_COMPANY_API_URL`: Company OS API base. Defaults to `http://127.0.0.1:3847`.
- `HSM_COMPANY_API_BEARER` or `HSM_COMPANY_API_TOKEN`: optional bearer token.
- `HSM_COMPANY_ID`: default company UUID for tools that accept `company_id`.
- `HSM_COMPANY_PRINCIPAL_TOKEN` (or `HSM_PRINCIPAL_TOKEN`): optional verified principal credential.
- `HSM_COMPANY_PRINCIPAL_COMPANY_ID`: optional explicit company binding for the principal credential; defaults to `HSM_COMPANY_ID`.
- `OUROBOROS_ACTOR_ID` or `HSM_COMPANY_TASK_ACTOR`: actor recorded for approval and HITL calls.
- `HSM_COMPANY_MCP_APPROVAL_MODE`: `strict` by default. Set `permissive` only for trusted local automation. `bound` requires every mutating call to cite a workflow approval already approved by a different principal, and refuses to decide approvals from the MCP session; the remote bridge always uses it.
- `HSM_AI_CORPUS_INDEX`: optional owner-only private Codex/Claude corpus index with local conversation vectors (mode 0600 preferred; 0400/0500/0700 are accepted when a mounted volume forces owner bits). Group/other access is always rejected. When absent, `company_os_private_corpus_search` reports `available=false`; private recall defaults to semantic-only retrieval and fails rather than silently claiming a lexical fallback is semantic.
- `HSM_AI_CORPUS_SHA256`: mandatory exact SHA-256 when an index is configured. Search fails closed if the current index digest differs.
- `HSM_AI_CORPUS_BINDING_FILE`: optional absolute path to a mode-0600 binding file containing only `HSM_AI_CORPUS_INDEX=<absolute path>` and `HSM_AI_CORPUS_SHA256=<64 hex characters>`. The repository launcher reads `$HSM_COMPANY_OS_AUTH_HOME/private-corpus/active.env` by default when neither corpus variable is already set; it parses only those two named values and never sources the file.
- `HSM_AI_CORPUS_SEARCH_SCRIPT`: optional absolute path to the fixed local search adapter for packaged layouts.
- `HSM_AI_CORPUS_PYTHON`: optional Python executable used with the fixed argument-only search adapter; defaults to `python3`.

Remote Grok MCP bridge settings:

- `HSM_COMPANY_OS_REMOTE_MCP_TOKEN`: required inbound bearer token issued to the Grok connector.
- `HSM_COMPANY_OS_REMOTE_MCP_TOOLS`: optional comma-separated remote allowlist; absent means the read-only default above.
- `HSM_COMPANY_OS_REMOTE_MCP_ALLOW_MUTATIONS`: set to `1` only when intentionally adding non-read-only tools.
- `HSM_COMPANY_OS_REMOTE_MCP_HOST`: listener host; defaults to `127.0.0.1`.
- `HSM_COMPANY_OS_REMOTE_MCP_PORT`: listener port; defaults to `3850`.
- `HSM_COMPANY_OS_REMOTE_MCP_PATH`: MCP path; defaults to `/mcp`.
- `HSM_COMPANY_OS_REMOTE_MCP_MAX_BODY_BYTES`: maximum JSON request body; defaults to `1048576`.
- `HSM_COMPANY_OS_REMOTE_MCP_MAX_REQUESTS_PER_MINUTE`: fixed-window request limit per source; defaults to `120`.
- `HSM_COMPANY_OS_REMOTE_MCP_ALLOWED_HOSTS`: optional exact Host header allowlist for DNS-rebinding protection.
- `HSM_COMPANY_OS_REMOTE_MCP_ALLOWED_ORIGINS`: optional exact Origin header allowlist.
- `HSM_COMPANY_OS_CONSOLE_ORIGIN`: optional absolute HTTPS Console origin used for result deep links; links are omitted when unset.

The HTTP bridge requires `HSM_COMPANY_ID`, `HSM_COMPANY_PRINCIPAL_TOKEN`, and
the matching principal company binding even for its read-only default. It can
load those server-held credentials from the normal private Company OS binding
files described above.

## Lifecycle convergence proof

The lifecycle tools expose company-scoped task events, agent-run lease and
recovery fields, approved recovery executions, Beads outbox settlement, durable
projection health, and a snapshot-bound projection-proof scan. Follow each
projection proof `next_cursor` unchanged until `complete=true`; every page is
bound to the first page's `snapshot_as_of`, and `zero_drift=true` requires
complete current evidence with matching source revisions and counts.

`npm run proof:five-loop` is a destructive local acceptance harness: it creates
uniquely labelled governed proof Beads, kills both the verified `hsm_console`
process and its verified Beads outbox sidecar once, and waits for supervised
PID/instance rotation, automatic completion, recovery execution,
projection convergence, and an unattended supervision soak. Run it only
against a loopback, shell-supervised runtime backed by an isolated proof
database/company, and set all three explicit gates:

```bash
HSM_FIVE_LOOP_ISOLATED_RUNTIME=1 \
HSM_FIVE_LOOP_ALLOW_MUTATION=1 \
HSM_FIVE_LOOP_ALLOW_PROCESS_KILL=1 \
HSM_FIVE_LOOP_SCOPE_LABEL=mcp-five-loop-proof-scope-<unique> \
HSM_HARNESS_CHECKPOINT_DIR=/private/tmp/<unique>/checkpoints \
HSM_HARNESS_TOOL_CHECKPOINT_DIR=/private/tmp/<unique>/tool-checkpoints \
HSM_COMPANY_OS_AUTH_HOME=/private/tmp/<unique>/auth \
HSM_BR_BV_BINDING_FILE=/private/tmp/<unique>/binding.env \
npm run proof:five-loop
```

`HSM_HARNESS_TOOL_CHECKPOINT_DIR` is a **different directory** from
`HSM_HARNESS_CHECKPOINT_DIR`, and both must exist. Without the tool one, every
mutating worker tool — `bash`, `company_tool_call`, `company_create_task` — is
refused with `required mutation evidence store HSM_HARNESS_TOOL_CHECKPOINT_DIR
is unset or blank`, while read-only tools keep succeeding. The worker then looks
alive (heartbeats, tool cycles, `finalize_response`) while accomplishing nothing,
and the proof fails as an unexplained `timed out waiting for automatic task
completion`. Preflight checks both.

Isolation requires overriding **all five** `HSM_COMPANY_OS_*DATABASE_URL`
variables, not just `HSM_COMPANY_OS_DATABASE_URL`. The repo `.env` defines every
lane against the shared database, so overriding one leaves the migration lane
pointed at production — which is how an unpublished migration reached a shared
database on 2026-08-30. The lane principals must also be the `NOINHERIT`
`company_*_login` roles: startup refuses a superuser LOGIN.

The launcher writes `hsm-console.pid`, `beads-projection-sync.pid`, and
`beads-outbox-worker.pid` beneath the private auth home (or to their explicit
`HSM_*_PID_FILE` overrides). The proof refuses to kill a PID unless its live
command matches the expected owned process. Use an empty, unique company tenant;
the harness refuses a tenant that already contains tasks, correlations, or runs.

The harness writes its durable readback artifact under
`artifacts/company-os-five-loop/`; it never treats process logs as acceptance
evidence. Each artifact also carries an independent `acceptance` envelope. It
reports `ok=true` only when every durable phase is present, crash recovery
rotated the lease generation while preserving run/session identity, the
supervision soak stayed healthy, and the complete projection scan proved
snapshot-bound zero drift. Partial-run failure metadata is sanitized before it
is persisted.

The principal header is stripped from caller-provided headers and added back
only for the exact `HSM_COMPANY_API_BASE` origin when the request company scope
matches the configured principal company. Unscoped health/company-list calls,
cross-company calls, and redirects never receive the principal token.

The MCP façade includes the short run-story/frame aliases `ps`, `inspect`,
`what`, `why`, `timeline`, `diff`, `preview`, `rewind`, and `replay`. The
`steer` alias is the governed live-run control: it requires strict confirmation
and a principal token, and a refused delivery is never reported as successful.
`pause`, `signal`, and `attach` remain explicit unsupported vocabulary entries.

## Beads projection proof scan

Use `company_os_list_beads_projection_proofs` to independently verify the
Company OS projection of the Beads ledger. Each row identifies one immutable
Bead-to-task link and its latest evidence at the scan boundary, including the
exact `canonical_status`, evidence digest, source revision, canonical snapshot
and epoch digests, and whether the evidence was `current`, `expired`, or
`missing` at `snapshot_as_of`. Every page repeats snapshot-wide integrity
counters for missing/expired evidence, unknown status, malformed or mismatched
digests/revisions, mixed source epochs, and expected-vs-observed link totals.
`zero_drift=true` is computed by Company OS only when all of those checks pass.

The endpoint uses opaque keyset cursors rather than offsets. Start without a
cursor, retain `snapshot_as_of` and `total_links` as scan evidence, then pass
each `next_cursor` unchanged until `complete=true`. Every continuation remains
bound to the first page's timestamp, so links or evidence appended during the
scan cannot shift or duplicate pages.

Company OS terminal intent flows back to Beads through the supervised
`scripts/company-os-beads-outbox-worker.mjs` sidecar. It requires the
server-only executor bearer plus an active principal token bound to the same
configured company, executes only `scripts/br-governed.mjs`, and settles only
after two matching canonical Beads readbacks. A recovered `executing` attempt
is read back and moved to reconciliation; it is never blindly re-executed.

## Approval Model

The server does not invent a new approval ledger. It wraps existing Company OS endpoints:

`company_os_operator_vocabulary` is the read-only Phase 7 discovery call. It returns the
server-authored `hsm.company_os.operator_vocabulary.v1` contract, including whether each verb is
read-only, governed, preview-only, or currently unsupported. MCP does not reinterpret those
dispositions or turn an unsupported verb into a provider-specific command.

- `company_os_record_task_decision`
- `company_os_dispatch_command` (typed registry operations through the host command plane; keyed operations need `idempotency_key`, approval-gated ones need `approval_id`)
- `company_os_set_task_requires_human`
- `company_os_resume_tool_execution`
- `company_os_hitl_should_pause`
- `company_os_hitl_record_override`
- `company_os_hitl_preferences`

In strict mode, mutating tools return an `approval_required` error unless the caller passes `confirm=true` after explicit operator approval.

## Voice Commander / Gestion Velora handoff

The phone-call bridge uses the existing Company OS customer and task ledger:

1. `company_os_upsert_customer` creates or updates a customer/prospect by a
   stable `external_ref`.
2. `company_os_create_customer_request` forces `source=phone` and uses
   `source_ref` to make retries idempotent.
3. `company_os_promote_customer_request_to_task` promotes that request into the
   canonical Company OS task and flat Bead routing contract.
4. `company_os_ingest_email_operator_item` places an approved call summary in
   the email queue as `pending_draft`.
5. `company_os_propose_email_reply` adds a suggested reply; Company OS leaves it
   `pending_approval` for a separate human verifier and does not send it.

All five tools require confirmation in strict mode. Their schemas accept
approved summaries, structured metadata, and evidence references. They do not
accept raw transcript or recording parameters, and nested transcript, audio,
credential, and secret fields are rejected before an HTTP request is made.

## Tool Catalog Flow

Company OS enforces discover -> describe -> call for catalog tools:

1. `company_os_discover_tools`
2. `company_os_describe_tool`
3. `company_os_call_tool`

`company_os_call_tool` defaults to `dry_run=true`; non-dry-run calls require `confirm=true` in strict mode.

## Remote HTTP MCP bounds and refusal receipts

Remote sessions are bounded by `HSM_COMPANY_OS_REMOTE_MCP_MAX_SESSIONS` and
closed after `HSM_COMPANY_OS_REMOTE_MCP_SESSION_IDLE_TTL_MS`; request-rate
windows are evicted after one minute and capped by
`HSM_COMPANY_OS_REMOTE_MCP_MAX_RATE_LIMIT_KEYS`.

Refusal responses are authoritative and remain fail-open when the asynchronous
governance receipt sink is unavailable. The server increments its refusal-
receipt failure counter, invokes the failure observer when configured, and
emits a structured error rather than silently discarding the failure.
