---
title: MCP Server | Developer Documentation
description: Run the LlamaParse MCP server on a self-hosted LlamaCloud deployment: enabling it in Helm values, giving it its own ingress hostname and certificate, and how API key authentication changes file uploads.
---

## Self-Hosting Documentation Access

This section requires a password to access. Interested in self-hosting? [Contact sales](https://www.llamaindex.ai/contact) to learn more.

Password:

Access Documentation

Self-Hosting Documentation Access Granted Logout

The [LlamaParse MCP server](/llamaparse/for-agents/mcp/index.md) exposes your deployment’s document-processing capabilities as tools any MCP-compatible agent can call. Self-hosted deployments run their own copy, so documents and API keys stay inside your network — agents talk to your MCP server, and it talks to your LlamaCloud backend over the cluster’s internal network.

## Enable the server

values.yaml

```
config:
  mcp:
    enabled: true
```

The MCP server is released from its own repository, so its version does not track the chart’s. The chart pins a published tag for you, and there is normally nothing to set. Override it — under the top-level `mcp` key, not `config.mcp` — if you mirror images into your own registry, or to move to a newer MCP release than the one your chart version pins:

```
mcp:
  image: your-registry.example/llamacloud-mcp:<tag>
```

A pod reporting `ImagePullBackOff` is almost always this: a cluster that cannot reach the default registry, and no mirrored tag set here.

By default the server calls the LlamaCloud backend at its in-cluster address, so there is nothing to configure for it to reach the API. Set `config.mcp.llamaCloudBaseUrl` only if you need it to call a different endpoint; a public host there must use `https`.

## Give it a hostname

MCP needs a hostname of its own — it answers on paths the web UI already uses, so it cannot share the main one. Point a second DNS name at the same ingress and set it as the public URL:

```
ingress:
  enabled: true
  host: cloud.your-company.example
  tlsSecretName: llamacloud-tls
  ingressClassName: nginx


config:
  mcp:
    enabled: true
    publicUrl: https://mcp.your-company.example
```

The chart adds an ingress rule sending that host to the MCP service. Two things it cannot do for you:

- `mcp.your-company.example` has to resolve to the same ingress as `cloud.your-company.example`.
- `llamacloud-tls` has to cover **both** names. One certificate serves both, so it needs a subject alternative name for each, or a wildcard.

The MCP rule shares the Ingress object with the web UI, so everything in `ingress.annotations` applies to it as well. Re-read any rewrite, auth or timeout annotation you set for the UI before assuming it suits MCP — an ingress controller’s default read timeout in particular governs how long a single MCP request may take.

Set `publicUrl` to a full URL including the scheme, and without a path — clients append their own (`/mcp`, `/parse/mcp`, and the rest). Wherever the chart derives a route from it, a value with no scheme is refused at render time rather than quietly producing no route. Once it is set, the web UI starts offering ready-made MCP client configuration, because it finally knows a URL your users’ agents can reach.

The rule is derived from `publicUrl`, so the chart routes **any** `publicUrl` host that differs from `ingress.host`. Two shapes leave it out of the way: a `publicUrl` on `ingress.host`, which it never routes because MCP answers on paths the web UI already owns, and `ingress.enabled: false`, where it renders no Ingress at all. In either case send what you route to the `llamacloud-mcp` service on port 80.

What you cannot do today is keep the chart’s Ingress enabled, advertise MCP on a hostname of its own, and route that hostname yourself — the chart adds its own rule for it, and two Ingresses claiming one host resolve in an order you do not control.

## Authentication

Self-hosted MCP servers authenticate with a LlamaCloud API key, which users pass as a bearer token:

```
{
  "mcpServers": {
    "llamaparse": {
      "url": "https://mcp.your-company.example/mcp",
      "headers": { "Authorization": "Bearer ${LLAMA_CLOUD_API_KEY}" }
    }
  }
}
```

One tool behaves differently as a result. `getUploadUrl` hands back a pre-signed URL for uploading a local file, and it is **not available to API key callers** — it would leave a standing credential for anyone who reached that URL. Agents should call `uploadFileByUrl` instead, with a URL the server can reach. Everything else works the same.

### Documents hosted inside your network

`uploadFileByUrl` refuses private and link-local addresses by default, which stops a caller using the server to reach things it should not. If the documents your users upload genuinely live on an internal host, allow it explicitly:

```
config:
  mcp:
    allowPrivateUploadHosts: true
```

Only turn this on if you are comfortable with callers naming internal addresses, since it is what the default protects against.

## Check it is working

Terminal window

```
kubectl -n <your-namespace> get ingress
kubectl -n <your-namespace> get pods -l app.kubernetes.io/name=llamacloud-mcp
```

Then confirm the server is reachable at the hostname you configured:

Terminal window

```
curl -sS https://mcp.your-company.example/api/healthz
```

A pod that starts and an endpoint that answers do not prove a client can use it — connect an agent and call a tool. The [MCP documentation](/llamaparse/for-agents/mcp/index.md) covers client configuration and the full tool list, and applies to your deployment with your own hostname in place of `mcp.llamaindex.ai`.
