Get started / Docker + MCP
Plug in. Ask more of your vectors.
Run the worker locally, connect your agent, and follow the evidence from your first cluster to its source records. Start with your database or a small synthetic fixture.
Let your coding agent set it up.
Prompt to instruct your coding agent to setup EigenLens MCP Server
Paste into Codex, Claude Code, OpenCode, Pi, or your own coding agent.
Read the full setup prompt
Or follow the manual steps below.
Start the worker on your machine.
Install and start Docker with at least 8 GB of available memory and 2 CPUs for this worker. On Windows, use Docker Desktop with Linux containers. Bash commands also need curl and OpenSSL. The image supports Linux AMD64 and ARM64; no Python installation, registry login or source checkout is needed.
eigenlake/eigenlens:0.1.0Docker Hub ↗mkdir -p ~/eigenlens-deploy
cd ~/eigenlens-deploy
# Generate once. Reuse this file with the same data volume.
if [ ! -f .env ]; then
(umask 077
printf 'EIGENLENS_MCP_TOKEN=%s\nEIGENLENS_CONNECTION_KEY=%s\nEIGENLENS_WORKERS=1\n' \
"$(openssl rand -hex 32)" "$(openssl rand -base64 32 | tr '+/' '-_')" > .env)
fi
# Make the SAME token available to clients launched from this shell.
. ./.env
export EIGENLENS_MCP_TOKEN
docker pull eigenlake/eigenlens:0.1.0
docker run -d --name eigenlens-worker --init --restart unless-stopped \
--publish 127.0.0.1:8020:8000 --memory 8g --cpus 2 \
--env-file .env --env EIGENLENS_CPU_BUDGET=2 \
--volume eigenlens_worker-data:/data \
eigenlake/eigenlens:0.1.0
curl --fail http://127.0.0.1:8020/healthDocker prints a container ID. Give the worker a moment to start; repeat the health request until it returns status: ok. If you already have a container named eigenlens-worker or port 8020 is occupied, see troubleshooting before continuing.
.env private and outside source control. It contains your MCP token and the key used to encrypt saved database connections. Keep the same file with the same data volume across restarts; a replacement key cannot decrypt existing connections. The endpoint is bound to your machine’s loopback interface.Plug the tools into your agent.
The MCP address is http://127.0.0.1:8020/mcp. Your local client must inherit EIGENLENS_MCP_TOKEN with the same value as the worker. Docker’s --env-file sets the container’s environment, not your desktop app’s.
Quit Cursor fully, then launch it from the terminal below so it inherits the token. The cursor command must be installed on your PATH. If you use WSL or a remote development environment, both the client and worker must be reachable from that environment.
cd ~/eigenlens-deploy
. ./.env
export EIGENLENS_MCP_TOKEN
# Quit Cursor fully first, then launch it from this terminal.
cursor .
# Or launch your configured CLI from this same terminal.Worker running and client environment ready?
Opens Cursor’s install confirmation. The link contains an environment-variable reference, never your token. Approve the configuration, then confirm EigenLens is connected in Cursor’s MCP settings.
Copy config / manual setup
Merge this entry into ~/.cursor/mcp.json, or your project’s .cursor/mcp.json. Preserve any existing server entries. Restart Cursor with the token available in its environment.
{
"mcpServers": {
"eigenlens": {
"url": "http://127.0.0.1:8020/mcp",
"headers": {
"Authorization": "Bearer ${env:EIGENLENS_MCP_TOKEN}"
}
}
}
}These steps are for local MCP clients. A hosted agent’s localhost is a different machine. Claude web/remote connectors need a publicly reachable endpoint; this local setup does not provide one.
Bring your data. Or try the fixture.
Download and upload a tiny fixture to exercise the complete flow. It contains three seeded Gaussian groups with ticket-like text, plus two unusual points. Its four-dimensional vectors are synthetic, not language-model embeddings. This checks the workflow; it is not a semantic-quality benchmark.
Download the 62-record JSONL fixture# Run in the terminal where you loaded EIGENLENS_MCP_TOKEN.
curl --fail --location https://www.eigenlake.dev/examples/synthetic-tickets.jsonl -o synthetic-tickets.jsonl
upload_name="synthetic-$(openssl rand -hex 8).jsonl"
curl --fail-with-body \
-H "Authorization: Bearer $EIGENLENS_MCP_TOKEN" \
-H 'Content-Type: application/x-ndjson' \
--data-binary @synthetic-tickets.jsonl \
"http://127.0.0.1:8020/ingress/$upload_name"The upload returns artifact_name. Include that exact returned filename with the prompt below. It identifies a file staged on the worker; a path on your computer is not interchangeable.
Use EigenLens get_capabilities first. I uploaded a 62-record synthetic fixture. Register the artifact_name returned by the upload as a complete_selection. Tell me whether registration succeeded so I can delete the staging upload. Then run DBSCAN search as operation "groups" and BERTopic as operation "themes", using clusters_from "groups" and ngram_max 2. Poll get_job until succeeded, failed or cancelled. On success, read both result summaries, show cluster sizes, unassigned records, topic terms and representative examples. Clearly label everything as synthetic. Report any failure instead of inventing results.Exact registration call
This is an MCP tool-call payload, not a shell command. Replace the filename with the returned artifact_name.
{
"name": "register_records",
"arguments": {
"artifact_name": "<returned artifact_name>",
"selection_scope": "complete_selection"
}
}finally block.# After registration succeeds OR fails; keep the same upload_name.
curl --fail-with-body -X DELETE \
-H "Authorization: Bearer $EIGENLENS_MCP_TOKEN" \
"http://127.0.0.1:8020/ingress/$upload_name"Inspect the evidence behind the answer.
The agent starts an asynchronous job, then reads saved results. Keep the returned handles in the conversation for follow-ups. Clusters and topic terms help you investigate; they do not establish a cause by themselves.
get_job
Poll job_id until succeeded, failed or cancelled. Read info.message for the current stage. Report terminal errors before reading results.
get_summary
Use both results.groups and results.themes after success. Check processed counts, selection scope, effective parameters and unassigned records.
get_examples
Inspect representative source records and text. These are examples, not every member of a cluster.
get_result_page
Follow next_cursor until null for each result. Cluster rows include assignments and pca_3d; topic rows include weighted terms.
Show the exact processed count and selection scope. Read every page of cluster assignments and topic terms until next_cursor is null. Show unassigned records separately. Inspect five representative examples from a cluster before explaining it. If you can render charts, plot the returned pca_3d coordinates and color by cluster_id; otherwise export the rows.MCP returns coordinates and records. Charts require your agent’s own plotting or file-rendering tools. Cluster -1 is unassigned. A valid DBSCAN grouping is not guaranteed for arbitrary data.
Exact analysis and paging calls
MCP tool payloads below use placeholders. Registration or database retrieval supplies the dataset ID; a successful job supplies the two result IDs. Application code should poll with increasing delays for long jobs.
{
"name": "run_analysis",
"arguments": {
"dataset_id": "<returned dataset_id>",
"operations": [
{
"id": "groups",
"type": "cluster",
"algorithm": "dbscan_search"
},
{
"id": "themes",
"type": "topics",
"algorithm": "bertopic",
"clusters_from": "groups",
"parameters": {
"ngram_max": 2,
"top_n": 10
}
}
],
"execution": {
"mode": "async",
"backend": "local"
}
}
}{
"name": "get_job",
"arguments": {
"job_id": "<returned job_id>"
}
}{
"name": "get_summary",
"arguments": {
"result_id": "<results.groups, then results.themes>"
}
}{
"name": "get_result_page",
"arguments": {
"result_id": "<one returned result_id>",
"cursor": null,
"limit": 1000
}
}Keep it running
A few useful checks.
The container name or port is already in use
Check docker ps -a. If it is your existing EigenLens installation, reuse its .env and start it with docker start eigenlens-worker. Do not recreate its key. If another service owns port 8020, choose a free loopback host port and update every MCP/upload/health URL and client config. Do not stop unrelated containers.
The worker is not healthy yet
Wait briefly, repeat the health request, and check docker logs eigenlens-worker. Confirm Docker has sufficient memory and the public image pull completed. On Windows, confirm Linux containers are enabled.
The client reports Unauthorized or no tools
The MCP token is required even for the public Docker image. Reload the same .env token in the client's environment, fully restart the client and reconnect. Never put the token into the website or a shared install link. A healthy /health response alone does not verify MCP authentication.
My database cannot be reached
Check the URL from inside the worker's network, including database firewall rules, authentication, TLS and required ports. Docker localhost is not the host. For Weaviate, both HTTP and gRPC access are needed. Saved connections require the original EIGENLENS_CONNECTION_KEY.
An analysis fails or exceeds a limit
Inspect get_capabilities for active limits and get_job for the error. The published worker configuration allows up to 20,000 records per selection, one concurrent job by default and 30 minutes per job. Row limits do not guarantee a workload will fit in memory. Scope a smaller selection deliberately; do not present it as the whole corpus.
I want to stop or restart
Use cancel_job with the returned job_id to cancel one analysis. Use docker stop eigenlens-worker to stop this installation, then docker start eigenlens-worker to restart it. The named volume retains registered data and completed results. A restart interrupts unfinished jobs; finish or cancel them first. Keep the original .env and never delete the data volume unless you intend to erase it.
Run remotely only with appropriate TLS, authentication and network configuration. This guide keeps the worker local. Automatic artifact retention is not implemented; manage retained data for your deployment.
Build with us
Have a workload in mind?
Talk through your data and where EigenLens could help.