> For the complete documentation index, see [llms.txt](https://docs.lumidb.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.lumidb.com/integrations/connecting-ai-assistants-mcp.md).

# Connecting AI assistants (MCP)

Connect Claude, ChatGPT (Codex), Copilot, Cursor or your own agent to LumiDB with the Model Context Protocol (MCP).

LumiDB has a built-in [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server. Once it's connected, an AI assistant or agent can find your datasets, read their metadata, render point clouds into images and compute volumes. Your data stays in LumiDB, and nothing is downloaded.

Setup takes about five minutes: create an API key in LumiDB, then add the server to your AI client.

{% hint style="warning" %}
**Experimental:** The MCP server is read-only and still evolving. Tool names and parameters may change. Send feedback to <help@lumidb.com>.
{% endhint %}

## Before you start

You need:

* A LumiDB account with access to at least one project. See [Account management](/get-started/account-management.md).
* An API key. [Step 1](#step-1-create-an-api-key) shows how to create one.
* An MCP client that supports **Streamable HTTP** and lets you set a request header. Claude, Claude Code, Codex, Copilot Studio, VS Code, Cursor and the Python SDKs all qualify.

### Server details

| Setting        | Value                                                      |
| -------------- | ---------------------------------------------------------- |
| Server URL     | `https://api.lumidb.com/api/mcp`                           |
| Transport      | Streamable HTTP                                            |
| Authentication | LumiDB API key in a request header                         |
| Access         | Read-only, limited to the projects the key's owner can see |

The server accepts the API key in any of these headers. Use the one your client supports:

| Header                                             | Value                           |
| -------------------------------------------------- | ------------------------------- |
| `x-api-key` (also `apikey`, `api-key`, `x-apikey`) | `lumi_...` (the key on its own) |
| `Authorization`                                    | `apikey lumi_...`               |

{% hint style="info" %}
With `Authorization`, the value must start with `apikey` and a space. A request without a valid key returns `401 Unauthorized`.
{% endhint %}

### Available tools

| Tool                  | What it does                                                                                                                                                                                                                               |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `search_datasets`     | Lists your point clouds and rasters, with an optional bounding box (`[west, south, east, north]` in WGS84). Returns at most 100 results.                                                                                                   |
| `describe_dataset`    | Returns a dataset's metadata: point count, classifications, density, extents, CRS, capture dates and user metadata.                                                                                                                        |
| `compute_volume`      | Computes cut, fill and net volume between a point cloud surface and a base surface inside a box or polygon. Takes point cloud IDs, the boundary and its projected CRS, base heights for each vertex and an optional classification filter. |
| `render_point_clouds` | Renders one or more point clouds to a PNG from a camera you choose: perspective or orthographic, with optional cropping and classification filters.                                                                                        |

This is the first set of tools, and we're adding more. Missing a tool you need? Send your request to <help@lumidb.com>.

## Step 1: Create an API key

1. Sign in at [app.lumidb.com](https://app.lumidb.com) and select the organization that has your data.
2. In the left sidebar under **Admin**, click **API keys**, then click **Create API key**.

<figure><img src="https://150512722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMI9s5xLuAdXOTKpfljc3%2Fuploads%2FPFP34nmkgkTGhLNOJjEc%2Flumidb-mcp-01-api-keys-page.png?alt=media&amp;token=f59cdd8b-93ab-42d3-ba2d-ca9e4d07aa2a" alt="LumiDB API keys page with the API keys menu item and the Create API key button highlighted"><figcaption><p>The API keys page</p></figcaption></figure>

3. Give the key a descriptive **Name**, such as the tool you'll use it in (for example `Claude MCP`). Choose when it **Expires**: Never, 1 day, 7 days, 30 days, or a custom date. Then click **Create API key**.

<div align="left"><figure><img src="https://150512722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMI9s5xLuAdXOTKpfljc3%2Fuploads%2FQLg3GCZUBU8CRNH3hmlK%2Flumidb-mcp-02-new-api-key.png?alt=media&amp;token=d6fc5f1d-adf6-4888-9018-ecd0cadd5a1d" alt="New API key dialog with name Claude MCP and expiry 30 days" width="480"><figcaption><p>Name the key and set an expiry</p></figcaption></figure></div>

4. Click **Copy** and store the key somewhere safe, such as a password manager. It starts with `lumi_`, and LumiDB shows it **only once**.

<div align="left"><figure><img src="https://150512722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMI9s5xLuAdXOTKpfljc3%2Fuploads%2FMUU1JHYO9NVHivmMPn4Y%2Flumidb-mcp-03-key-created.png?alt=media&amp;token=77a30951-dde3-4c1a-b3ad-19b6be9f958a" alt="Dialog confirming the new API key, with the key value hidden and the Copy button highlighted" width="480"><figcaption><p>Copy the key now. You won't see it again.</p></figcaption></figure></div>

{% hint style="danger" %}
**Keep your key private.** The key has the same project access as you do in this organization. The MCP server only reads data, but the same key also works with the LumiDB REST API. Never paste the key into a chat message, and never commit it to a Git repository. Create a separate key for each tool so you can revoke one without affecting the others.
{% endhint %}

{% hint style="info" %}
Don't see **API keys** in the sidebar? Ask your organization admin to create a key for you, or contact <help@lumidb.com>.
{% endhint %}

## Step 2: Connect your AI client

Pick your client below. Each example uses `lumi_your_key_here` as a placeholder. Replace it with your own key.

* [Claude (web and desktop)](#claude-web-and-desktop)
* [Claude Code](#claude-code)
* [ChatGPT and OpenAI](#chatgpt-and-openai)
* [Microsoft Copilot Studio](#microsoft-copilot-studio)
* [GitHub Copilot in VS Code](#github-copilot-in-vs-code)
* [Cursor](#cursor)
* [Python: your own agent](#python-your-own-agent)

### Claude (web and desktop)

Custom connectors are available on all Claude plans. The Free plan allows one custom connector. On Team and Enterprise plans, an Owner adds the connector under **Organization settings → Connectors**, and members then connect to it.

1. In Claude, open **Settings**. Under **Customize**, select **Connectors**. Click **+ Add** in the top-right corner and choose to add a custom connector.

<figure><img src="https://150512722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMI9s5xLuAdXOTKpfljc3%2Fuploads%2FXIgssCmzRky8CSp8B5eU%2Flumidb-mcp-04-claude-connectors.png?alt=media&amp;token=9b927c1f-d928-4282-800f-7261ffff9f4c" alt="Claude Settings with Connectors selected and the Add button highlighted" width="720"><figcaption><p>Settings → Connectors → + Add</p></figcaption></figure>

2. Enter a **Name** (for example `LumiDB MCP`) and the server URL `https://api.lumidb.com/api/mcp`. Click **Continue**.

<div align="left"><figure><img src="https://150512722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMI9s5xLuAdXOTKpfljc3%2Fuploads%2FpeADFOsqoERn8X1AJdfM%2Flumidb-mcp-05-claude-add-connector.png?alt=media&amp;token=8cc4c5a1-0707-4610-996d-b382205fa319" alt="Add custom connector dialog with name LumiDB MCP and URL https://api.lumidb.com/api/mcp" width="520"><figcaption><p>Name and server URL</p></figcaption></figure></div>

3. Under **Authentication**, select **No sign-in**. Under **Request headers**, choose **`apikey`** as the header name and paste your key as the value. Enter the key on its own, with no prefix. Leave **Required** checked, then click **Add**.

<div align="left"><figure><img src="https://150512722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMI9s5xLuAdXOTKpfljc3%2Fuploads%2FRe1vEJrGBRchRSNbZy7a%2Flumidb-mcp-06-claude-request-header.png?alt=media&amp;token=6efb306e-f149-4da5-a410-72844be346c1" alt="Authentication set to No sign-in, with an apikey request header holding the masked API key" width="520"><figcaption><p>Select No sign-in and add the apikey header</p></figcaption></figure></div>

4. To use it in a chat, click **+** in the message box, open **Connectors** and make sure **LumiDB MCP** is turned on.

{% hint style="info" %}

* Claude can't change a connector's header after you save it. To switch to a new key, remove the connector and add it again.
* On Team and Enterprise plans, the key the Owner enters is shared by everyone who uses the connector. Create it from an account that has access to the right projects.
* **Request headers** is a beta feature in Claude. If the section isn't in your dialog, use [Claude Code](#claude-code), or connect Claude Desktop with the local bridge below.
  {% endhint %}

<details>

<summary>Claude Desktop without Request headers (local bridge)</summary>

This option runs [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) on your computer to forward requests with your key. It requires [Node.js](https://nodejs.org) 18 or later.

1. In Claude Desktop, open **Settings → Developer → Edit Config**.
2. Add `lumidb` under `mcpServers` in `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "lumidb": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://api.lumidb.com/api/mcp",
        "--header",
        "x-api-key:${LUMIDB_API_KEY}"
      ],
      "env": {
        "LUMIDB_API_KEY": "lumi_your_key_here"
      }
    }
  }
}
```

3. Restart Claude Desktop.

Keep `x-api-key:${LUMIDB_API_KEY}` exactly as written, with no space after the colon. The key goes in `env`.

</details>

### Claude Code

Run this in your terminal:

```bash
claude mcp add --transport http lumidb https://api.lumidb.com/api/mcp \
  --header "x-api-key: lumi_your_key_here"
```

Add `--scope user` to make LumiDB available in all your projects. Without it, the server is only added to the current project.

Check the connection with `claude mcp list`. LumiDB should show **✔ Connected**. Inside a session, use `/mcp`.

To share the setup with your team without sharing a key, add a `.mcp.json` file to the repository. Each person then sets `LUMIDB_API_KEY` in their own environment:

```json
{
  "mcpServers": {
    "lumidb": {
      "type": "http",
      "url": "https://api.lumidb.com/api/mcp",
      "headers": {
        "x-api-key": "${LUMIDB_API_KEY}"
      }
    }
  }
}
```

The first time you run `claude` in the repository, Claude Code asks you to approve the server.

### ChatGPT and OpenAI

{% hint style="warning" %}
**ChatGPT (web and app) can't connect yet.** As of October 2026, ChatGPT's custom MCP servers only support OAuth or no authentication, and there's no field for an API key header. Use Codex or the OpenAI Agents SDK instead.
{% endhint %}

**Codex CLI.** Add this to `~/.codex/config.toml`:

```toml
[mcp_servers.lumidb]
url = "https://api.lumidb.com/api/mcp"
env_http_headers = { "x-api-key" = "LUMIDB_API_KEY" }
```

Set the key in your shell (`export LUMIDB_API_KEY=lumi_your_key_here`), then start `codex` and type `/mcp` to confirm LumiDB is listed. Codex reads the header value from the `LUMIDB_API_KEY` environment variable.

**OpenAI Agents SDK (Python).** Install it with `pip install openai-agents`, then run:

```python
import asyncio
import os

from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp


async def main():
    async with MCPServerStreamableHttp(
        name="LumiDB",
        params={
            "url": "https://api.lumidb.com/api/mcp",
            "headers": {"x-api-key": os.environ["LUMIDB_API_KEY"]},
            "timeout": 60,
        },
        client_session_timeout_seconds=60,  # renders can take a while
    ) as lumidb:
        agent = Agent(
            name="Spatial data assistant",
            instructions="Use the LumiDB tools to answer questions about 3D datasets.",
            mcp_servers=[lumidb],
        )
        result = await Runner.run(agent, "Which point clouds do I have in central Helsinki?")
        print(result.final_output)


asyncio.run(main())
```

### Microsoft Copilot Studio

You can add LumiDB as a tool for a Copilot Studio agent, and then publish the agent to Microsoft 365 Copilot or Teams.

1. Open your agent and go to **Tools**. Select **Add a tool → New tool → Model Context Protocol**.
2. Fill in the fields:
   * **Server name:** `LumiDB`
   * **Server description:** `Search, describe and render 3D point clouds and rasters stored in LumiDB.` The agent uses this description to decide when to call the server.
   * **Server URL:** `https://api.lumidb.com/api/mcp`
3. Under authentication, select **API key**. Set **Type** to **Header** and the header name to `x-api-key`. Select **Create**.
4. In **Add tool**, select **Create a new connection**, enter your LumiDB API key, then select **Add to agent**.

### GitHub Copilot in VS Code

Create `.vscode/mcp.json` in your workspace. To use it in every workspace, run **MCP: Open User Configuration** instead.

```json
{
  "inputs": [
    {
      "type": "promptString",
      "id": "lumidb-api-key",
      "description": "LumiDB API key",
      "password": true
    }
  ],
  "servers": {
    "lumidb": {
      "type": "http",
      "url": "https://api.lumidb.com/api/mcp",
      "headers": {
        "x-api-key": "${input:lumidb-api-key}"
      }
    }
  }
}
```

The first time the server starts, VS Code asks for your key and stores it securely. To start or check the server, run **MCP: List Servers**. Then use Copilot Chat in **Agent** mode.

### Cursor

Add the server to `~/.cursor/mcp.json` to use it in all projects, or to `.cursor/mcp.json` in a single project:

```json
{
  "mcpServers": {
    "lumidb": {
      "url": "https://api.lumidb.com/api/mcp",
      "headers": {
        "x-api-key": "lumi_your_key_here"
      }
    }
  }
}
```

Don't commit a project `mcp.json` that contains your key. Cursor can also read the key from an environment variable. See the variable interpolation section of [Cursor's MCP docs](https://cursor.com/docs/mcp).

Open **Customize** in Cursor's sidebar and check that the LumiDB toggle is on. If it doesn't connect, open the **Output** panel and select **MCP Logs**.

### Python: your own agent

Building your own agent? Use the official [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk). This example needs `mcp` version 2 or later (`pip install "mcp>=2"`):

```python
import asyncio
import os

from mcp import ClientSession
from mcp.client.streamable_http import create_mcp_http_client, streamable_http_client

LUMIDB_MCP_URL = "https://api.lumidb.com/api/mcp"


async def main():
    http_client = create_mcp_http_client(headers={"x-api-key": os.environ["LUMIDB_API_KEY"]})
    async with http_client:
        async with streamable_http_client(LUMIDB_MCP_URL, http_client=http_client) as (read, write):
            async with ClientSession(read, write) as session:
                await session.initialize()

                tools = await session.list_tools()
                print("Tools:", [t.name for t in tools.tools])

                # Datasets in central Helsinki: [west, south, east, north] in WGS84
                result = await session.call_tool(
                    "search_datasets", {"bbox": [24.90, 60.15, 24.97, 60.20]}
                )
                print(result.structured_content or result.content)


asyncio.run(main())
```

With `mcp` 1.x, use `streamablehttp_client(LUMIDB_MCP_URL, headers={...})` instead. It yields `(read, write, get_session_id)`.

## Step 3: Try it

Ask your assistant in plain language. For example:

* *"Which point clouds and rasters do I have in central Helsinki?"*
* *"Describe the Jätkäsaari mobile mapping scan: point count, density, capture dates and classifications."*
* *"Render an oblique view of the Jätkäsaari scan from the south."*
* *"Render a top-down view of this dataset with only ground points (class 2)."*

The assistant decides which tools to call. When it renders, it gets back an image of your data. Clients that support interactive tool views, such as Claude, show the image in the chat:

<figure><img src="https://150512722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMI9s5xLuAdXOTKpfljc3%2Fuploads%2Fs7l89syLKsctxaIv9BQF%2Flumidb-mcp-08-example-render.jpg?alt=media&amp;token=e998be79-3b91-43e2-b443-85fad5dc3099" alt="Oblique point cloud render of the Jätkäsaari district in Helsinki, returned by render_point_clouds"><figcaption><p>Example output from <code>render_point_clouds</code>: Jätkäsaari mobile mapping scan, Helsinki (data: Cyclomedia / Mobility Lab Helsinki)</p></figcaption></figure>

## Revoke a key

To revoke a key, open **API keys**, click the trash icon on the key's row and confirm. The status changes to **Revoked**. It can take up to a minute before the key stops working.

<figure><img src="https://150512722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMI9s5xLuAdXOTKpfljc3%2Fuploads%2FNZvV2rjNzk5RsseNEwF6%2Flumidb-mcp-07-api-key-revoked.png?alt=media&amp;token=f977a82b-378d-4567-9c1f-00d73c51e23d" alt="API keys list showing a revoked key and an API key revoked confirmation"><figcaption><p>A revoked key</p></figcaption></figure>

Revoke a key immediately if it may have leaked. To rotate a key, create a new one, update your client, then revoke the old key.

## Current limitations

* **Read-only.** The MCP server can't import, export, edit or delete data.
* **Point clouds only for rendering.** Renders use stored RGB colours, or grey when a dataset has no RGB. Colouring by intensity or classification isn't available yet, and rasters can be listed and described but not rendered.
* **Search returns at most 100 datasets.** Use a bounding box to narrow it down.
* **Large renders take longer.** Start with small images. If your client times out, raise its timeout.

## Troubleshooting

| Problem                                                                              | What to check                                                                                                                                             |
| ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `401 Unauthorized`: "No authentication method provided"                              | The key isn't being sent. Check the header name, and that your client actually passes the header.                                                         |
| `401 Unauthorized` while sending a key                                               | The key is mistyped, expired or revoked. With `Authorization`, make sure the value is `apikey lumi_...`.                                                  |
| Claude Code shows **Needs authentication** or "Dynamic Client Registration rejected" | Claude Code didn't get a valid key and fell back to OAuth. Remove the server (`claude mcp remove lumidb`) and add it again with the correct `--header`.   |
| Connected, but no datasets are found                                                 | API keys belong to one organization. Make sure you created the key in the organization that holds the data, and that your user can access those projects. |
| No **Request headers** section in Claude                                             | The feature isn't enabled for your Claude organization yet. Use Claude Code or the Claude Desktop local bridge.                                           |

Still stuck? Contact <help@lumidb.com> and tell us which client you're using and the exact error message. Never include your API key.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.lumidb.com/integrations/connecting-ai-assistants-mcp.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
