> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/harness-ai/untitled-1/use-harness-ai/ide-and-integrations/mcp-server/self-hosted-deployment.md).

# Self-hosted deployment

When more than one user or automation needs access, you can run Harness MCP Server as shared infrastructure. Docker and Kubernetes deployments both use **http** transport, which gives you session-based access, health checks, and per-session credentials.

***

### Run with Docker <a href="#run-with-docker" id="run-with-docker"></a>

To run Harness MCP server with Docker, execute the following command in your terminal:

```bash
docker run --rm -p 3000:3000 \
  -e HARNESS_API_KEY=pat.xxx.xxx.xxx \
  harness-mcp-server
```

By default, the container runs in HTTP mode on port 3000 and includes a built-in health check.

***

### Deploy to Kubernetes <a href="#deploy-to-kubernetes" id="deploy-to-kubernetes"></a>

To run Harness MCP server with Kubernetes, execute the following commands in your terminal:

```bash
# 1. Edit the Secret with your credentials <a href="#1-edit-the-secret-with-your-credentials" id="1-edit-the-secret-with-your-credentials"></a>
# k8s/secret.yaml: replace HARNESS_API_KEY and HARNESS_ACCOUNT_ID <a href="#k8ssecretyaml-replace-harnessapikey-and-harnessaccountid" id="k8ssecretyaml-replace-harnessapikey-and-harnessaccountid"></a>

# 2. Apply all manifests <a href="#2-apply-all-manifests" id="2-apply-all-manifests"></a>
kubectl apply -f k8s/

# 3. Verify the deployment <a href="#3-verify-the-deployment" id="3-verify-the-deployment"></a>
kubectl -n harness-mcp get pods

# 4. Port-forward for local testing <a href="#4-port-forward-for-local-testing" id="4-port-forward-for-local-testing"></a>
kubectl -n harness-mcp port-forward svc/harness-mcp-server 3000:80
curl http://localhost:3000/health
```

You will receive two replicas, each with readiness and liveness probes, resource limits, and a non-root security context.

***

### Use MCP gateways <a href="#use-mcp-gateways" id="use-mcp-gateways"></a>

MCP gateways are reverse proxies that handle authentication, governance, tool routing, and observability in one place, and the server works with them. The server implements the standard MCP protocol over both stdio and HTTP transports, so it resides behind any MCP-compliant gateway.

Tested gateways include [Docker MCP Gateway](https://docs.docker.com/), [Portkey](https://portkey.ai/features/mcp), [LiteLLM](https://docs.litellm.ai/docs/mcp), [Envoy AI Gateway](https://aigateway.envoyproxy.io/), [Kong](https://developer.konghq.com/mcp/), and others. With a **stdio-based** gateway, you can stay on the default transport. With an **HTTP-based** gateway, you can start the server with `http` transport and point the gateway at the `/mcp` endpoint.

***

### HTTP transport <a href="#http-transport" id="http-transport"></a>

In HTTP mode, the server exposes the following endpoints:

| Endpoint  | Method    | Description                                                         |
| --------- | --------- | ------------------------------------------------------------------- |
| `/mcp`    | `POST`    | MCP JSON-RPC endpoint (initialize and session requests)             |
| `/mcp`    | `GET`     | SSE stream for server-initiated messages (progress, elicitation)    |
| `/mcp`    | `DELETE`  | Terminate an active MCP session                                     |
| `/mcp`    | `OPTIONS` | CORS preflight                                                      |
| `/health` | `GET`     | Health check that returns `{ "status": "ok", "sessions": <count> }` |

The HTTP transport runs in session-based mode. An `initialize` request creates a new MCP session, the server hands back an `mcp-session-id` header, and every request after that must carry the same header. Sessions that sit idle for 30 minutes are cleared out.

***

### Serve multiple users <a href="#serve-multiple-users" id="serve-multiple-users"></a>

On a shared HTTP deployment where each client authenticates as a different Harness user, set `HARNESS_MCP_MODE=multi-user`:

* Leave `HARNESS_API_KEY` out of the server config. In this mode, the server holds no Harness credentials of its own.
* Every session sends `x-harness-api-key` on the `initialize` request. Add `x-harness-account-id` when the API key does not embed an account segment.
* A session can also send `x-harness-org` and `x-harness-project` to set its default scope, and `x-harness-auto-approve-risk` to tighten the deployment-level auto-approve threshold.
* The Harness API key travels with every Harness API call in that session, so the audit trail in Harness points back to the real user.
* `HARNESS_MCP_AUTH_TOKEN` stands apart from session credentials and still gates the transport layer.
* Set `HARNESS_SEARCH_PROVIDER` to `remote` in this mode, since multi-user deployments do not support the `local` provider.

***

### Next steps <a href="#next-steps" id="next-steps"></a>

* [Environment variables](/harness-ai/use-harness-ai/harness-ai/connect-with-ai/harness-mcp-server/environment-variables.md): Configure host validation, bearer tokens, rate limits, and audit logging.
* [Approvals and safety](/harness-ai/use-harness-ai/harness-ai/connect-with-ai/harness-mcp-server/approvals-and-safety.md): Set read-only mode or a risk threshold for shared environments.
* [Harness Hosted MCP](/harness-ai/use-harness-ai/harness-ai/connect-with-ai/harness-mcp-server/hosted-mcp.md): Use the Harness-managed endpoint instead of self-hosting.
