MCP integration
Lens exposes its platform capabilities as a Model Context Protocol (MCP) server, so an MCP-capable client can inspect and operate Lens the same way the built-in Lens Assistant does. The MCP layer is a thin adapter: every tool calls Lens' own REST API over loopback — no cluster, auth or domain logic is re-implemented in the MCP server.
Endpoint and transport
| Property | Value |
|---|---|
| Method / path | POST /api/mcp (on the Lens BFF/Node server) |
| Default port | SERVER_PORT / PORT (3000; scripts/lens-local.sh picks the next free port above it if 3000 is already in use) |
| Transport | MCP Streamable HTTP, JSON-RPC 2.0 |
| Session | Stateless — one ephemeral MCP server per request, no Mcp-Session-Id |
| Other methods | GET / DELETE /api/mcp return 405 (no server→client stream in stateless mode) |
The endpoint is stateless on purpose: it scales horizontally and every tool re-reads live data from the REST API, so responses always reflect the current state.
Authentication
POST /api/mcp requires a signed-in session that holds one of these permissions:
mcp:tool:invoke, orplayground:chat:use
Send the session either as the browser cookie prism_session or as a bearer token:
Authorization: Bearer <session-token>
<session-token> is the value of the prism_session cookie issued at login (read it from
your browser's devtools while signed in). Requests are introspected against
GET /api/v1/auth/session; unauthenticated calls get 401 unauthenticated, and a session
without the permission above gets 403.
A dedicated credential for third-party MCP clients (API key / OAuth scope) is a
planned, separate design — today external clients reuse a signed-in session. See
docs/design/mcp-playground-design.md (Phase 4) for the open questions.
Tools
The catalog is generated from Lens' REST surface and grouped by domain. Each tool carries a risk tier:
| Tier | Meaning | Examples |
|---|---|---|
read | Read-only inspection | list_clusters, list_deployments, get_deployment_pod_logs, get_flow_map_metrics, list_storage_volumes, search_huggingface_models |
write | Changes state (create / start / stop / install) | create_simulation_task, start_cluster_bootstrap, create_standard_vllm_deployment_run, install_gpu_driver, create_ai_provider |
approve | Destructive; needs explicit confirmation | delete_cluster, delete_configuration_artifact, delete_deployment_execution, delete_evaluation_workflow, delete_ai_provider |
Discover the exact, current list at runtime with tools/list (names change as modules
evolve). All tools return JSON; a failing call comes back as an MCP error result
(isError: true) whose message is the underlying REST error.
Connect a client
MCP Inspector
- Start the Lens dev stack (
scripts/lens-local.sh start). - In MCP Inspector choose Streamable HTTP, URL
http://<lens-host>:3000/api/mcp. - Add header
Authorization: Bearer <session-token>, then Connect and list tools.
Generic MCP client config
{
"mcpServers": {
"lens": {
"type": "http",
"url": "http://<lens-host>:3000/api/mcp",
"headers": {
"Authorization": "Bearer <session-token>"
}
}
}
}
Raw JSON-RPC
BASE=http://<lens-host>:3000/api/mcp
H="Authorization: Bearer <session-token>"
# 1) handshake
curl -s $BASE -H "$H" -H 'content-type: application/json' -d '{
"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'
# 2) list tools
curl -s $BASE -H "$H" -H 'content-type: application/json' -d '{
"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# 3) call a read tool
curl -s $BASE -H "$H" -H 'content-type: application/json' -d '{
"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"list_clusters","arguments":{}}}'
Notes
- Tools are read/write/approve; the
approvetier should only be invoked behind a human confirmation step (as the Lens Assistant UI does) — an agent must not auto-approve. - The MCP server never talks to clusters directly: it calls Lens REST, which applies the same authentication, RBAC and scoping rules as the UI.
- Because the transport is stateless, a new
initializeis not required per call, but every request must still carry the credentials above.