The MCP Gateway and CLI Tool Runner are two complementary subsystems that give Harness AI controlled, auditable access to external and local tools. The MCP Gateway connects the harness to external services through the Model Context Protocol — resolving every tool invocation dynamically against theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/joseluis-dev/harness-ai/llms.txt
Use this file to discover all available pages before exploring further.
tool_registry rather than a hardcoded list — while the CLI Tool Runner executes deterministic local binaries (PDF converters, OCR engines, ETL scripts) under an allowlist, sandboxed, and audited execution environment. Neither subsystem ever decides policy or issues its own tokens; those responsibilities belong exclusively to Harness Core and the Auth Service.
MCP Gateway
Dynamic Tool Resolution
The MCP Gateway carries no embedded list of MCP servers. Every tool invocation is resolved at runtime against thetool_registry table in harness_auth_db. Adding a new MCP server to the harness means inserting a row — no gateway code changes, no redeployment.
The gateway enforces these rules on every invocation:
tool_registry.statemust beactive; disabled or deprecated tools are rejected with404- The
environmentfield must match the running environment required_scopesand per-operationscopevalues are checked before the token is issuedtimeout_msandretry_policyfrom the registry are applied to every outbound call- Payload size and per-user/tool rate limits are enforced independently of the MCP server
Tool Call Flow
Agent Requests Tool
The runtime worker requests a tool by
technical_name (e.g. mcp-readonly-sql) with an operation name and typed arguments.Registry Lookup
tool_gateway queries tool_registry for the tool’s state, environment, required scopes, risk_level, timeout_ms, and retry_policy. Any mismatch returns an error before a token is ever requested.Token Issuance
The runtime obtains an OAuth 2.1 Client Credentials token from the Auth Service (
mcp-auth-service) scoped to the required operation scope. The token is short-lived and carries the risk_level_cap of the requesting client.Tool Invocation
The gateway invokes the MCP server over JSON-RPC 2.0, passing the
Authorization: Bearer <token>, X-Harness-Execution-Id, and X-Harness-Actor-Id headers.Auth-SDK Validation
The MCP server validates the Bearer token using
auth-sdk (local JWKS verification). It checks signature, expiration, scope, and risk_level_cap. No MCP server ever implements its own token validation logic.Risk Level Gate
If
risk_level requires human confirmation (e.g. DESTRUCTIVE, EXTERNAL_SIDE_EFFECT), the gateway responds 202 with an approval_id and suspends the execution pending approval. The Phase 9 approval flow handles the continuation.Transport Types
| Transport | Value | Description |
|---|---|---|
| HTTP MCP | mcp_http | JSON-RPC 2.0 over HTTP. The MCP server exposes a single endpoint. |
| stdio MCP | mcp_stdio | JSON-RPC 2.0 over stdin/stdout for local server processes. |
| CLI | cli | Local binary execution via the CLI Tool Runner (see below). Tool entries with transport=command use this type. |
| HTTP API | http_api | Generic HTTP integration (non-MCP). |
| Inbound webhook | webhook_in | Receive events from external systems. |
| Outbound webhook | webhook_out | Send signed HMAC events to external systems. |
Outbound Headers
All tool calls carry:| Header | Description |
|---|---|
Authorization: Bearer <token> | OAuth 2.1 token from Auth Service. Never in query string. |
X-Harness-Execution-Id | Correlates the tool call with the parent execution and audit trail. |
X-Harness-Actor-Id | Resolved by mcp-identity-connector before the request reaches the gateway. |
Content-Type: application/json | Always JSON. |
Error Handling
| Status | Error | Condition |
|---|---|---|
401 | insufficient_scope | Token valid but scope does not cover the operation. Response includes WWW-Authenticate with resource metadata. |
403 | — | risk_level requires approval or an admin scope is missing. |
404 | — | tool_registry.state is disabled or deprecated, or environment mismatch. |
429 | — | Rate limit exceeded per user or per tool. |
202 | approval_id | Operation requires human confirmation. |
Seeded MCP Servers
The initial set of MCP servers is seeded intotool_registry via infra/postgres/seed/tool_registry_seed.yaml. They are not enumerated in the gateway code.
CLI Tool Runner
The CLI Tool Runner handles tools of typecli (transport=command) — deterministic local binaries that should never be invoked with arbitrary arguments or without authorization. It resolves every command from tool_registry, validates authorization with auth-sdk, and executes the binary under a strict sandbox.
Security Rules
The CLI Tool Runner enforces ten invariants before executing any command:- No free-form commands. Only commands registered in
tool_registrywithtype=cliare executable. - No LLM-generated arguments. All arguments are validated through a declarative schema before construction.
- Commands are resolved from
tool_registry(type=cli,transport=command). A local YAML file is only valid as a seed or bootstrap artifact — runtime truth lives inharness_auth_db. - Parameters are validated by schema.
- Every execution has a hard timeout.
- Commands that touch the filesystem run in an isolated container.
- Network is disabled unless the
tool_registryentry explicitly enables it. stdoutandstderrare recorded in summarized form (not verbatim, to prevent accidental data leakage).- Exit code is recorded on every invocation.
- File size limits are enforced on inputs and outputs.
auth-sdk cannot validate the Bearer, if the scope is insufficient, if state != active, or if the risk_level exceeds what the calling client’s risk_level_cap permits.
Sandbox Controls
Sandbox Restriction Categories
| Category | Controls |
|---|---|
execution_restrictions | CPU quota, memory limit, network disabled by default, container isolation for filesystem-touching commands |
filesystem_restrictions | Read allowlist, write allowlist. All paths are validated against base_dir before argument construction. |
network_restrictions | Egress allowlist. Network is off unless tool_registry.network=true. |
Common Use Cases
- PDF → text extraction (
pdftotext) - OCR on scanned PDFs (
ocrmypdf) - Document metadata extraction
- DOCX → PDF conversion
- Internal validators and schema checkers
- ETL scripts with controlled input/output paths
- Signature verification
- Scheduled report generation
n8n Webhook Adapter
The n8n Webhook Adapter allows n8n to trigger harness automations or receive harness events without gaining direct control over any internal service. Every inbound webhook is validated (HMAC signature + anti-replay timestamp + schema) before being dispatched as a job to the execution queue.client_id and client_secret are provisioned through the Auth Service admin panel — never hardcoded. Outbound events (harness → n8n) use the same HMAC + timestamp scheme so both sides mutually authenticate.
n8n has no permission to invoke tools, agents, or models directly. It can only notify the harness (via inbound webhooks) and receive notifications from the harness (via outbound webhooks). All heavy work runs inside the harness execution pipeline after the event is dispatched to the queue.
Telegram Channel
The Telegram channel is a controlled external input channel, not a shortcut into the harness internals. Every Telegram command follows the mandatory chain:Identity Resolution
A Telegramuser_id (integer) is not an institutional identity. The channel resolves it through mcp-identity-connector:
denied audit event is emitted with reason="unmapped_user".
Allowed Commands
Only these commands are accepted. Any other input is rejected without invoking any tool, agent, or model.| Command | Purpose |
|---|---|
/consultar | RAG query over a document the user has access to |
/resumir <doc_id> | Structured summary of an accessible document |
/aprobar <approval_id> | Approve a pending approval request |
/rechazar <approval_id> <motivo> | Reject a pending approval request with a reason |
/estado <execution_id> | Summarized status of one of the user’s executions |
/ayuda | Lists available commands and their syntax |