---
title: Architecture
slug: litmus-mcp-server/architecture
docTags: 
createdAt: 2026-05-11T21:37:01.393Z
---

The Litmus MCP Server is two cooperating processes packaged in one container.

## Processes

| Process    | File                | Port | Role                                                                                                                |
| ---------- | ------------------- | ---- | ------------------------------------------------------------------------------------------------------------------- |
| MCP server | `src/server.py`     | 8000 | Implements the MCP protocol over SSE. Exposes 57 tools and a set of `litmus://docs/*` resources.                    |
| Web client | `src/web_client.py` | 9000 | FastAPI app: chat UI, config pages, LLM streaming, multi-instance management. Launches `server.py` as a subprocess. |

Both ports come from a single Docker image. The Web UI is optional; clients can hit the SSE endpoint directly without ever touching port 9000.

## Request flow (Web UI)

```javascript
Browser
  |
  | POST /chat
  v
web_client.py  --->  client_utils.process_streaming_query
                          |
                          |  anthropic.messages.stream() / OpenAI / Gemini
                          v
                     LLM provider
                          |
                          |  tool_use events
                          v
                     session.call_tool(name, args)
                          |
                          v
                     MCP server (port 8000)
                          |
                          v
                     server.py handle_call_tool
                          |
                          v
                     tools/<category>_tools.py
                          |
                          v
                     Litmus Edge REST / NATS / InfluxDB
```

## Request flow (external MCP client)

```javascript
Claude Desktop / Cursor / VS Code / Windsurf / Claude Code
  |
  |  SSE (with headers)
  v
MCP server (port 8000)
  |
  v
tools/<category>_tools.py
  |
  v
Litmus Edge REST / NATS / InfluxDB
```

## Authentication

The server is stateless. Every tool call receives a `request` object and pulls credentials from headers (SSE mode) or environment variables (STDIO mode) at call time, via helpers in `src/utils/auth.py`:

- `get_litmus_connection(request)` - Litmus Edge REST/SDK
- `get_nats_connection_params(request)` - NATS broker
- `get_influx_connection_params(request)` - InfluxDB

This means a single MCP server can be shared across many users, each presenting their own headers. There is no server-side session, no shared credentials.

## Multi-instance edge support

The Web UI lets you register multiple Litmus Edge devices and switch between them. Internally, instances live in `.env` as:

```javascript
EDGE_INSTANCE_1_URL=...
EDGE_INSTANCE_1_CLIENT_ID=...
EDGE_INSTANCE_1_CLIENT_SECRET=...
EDGE_INSTANCE_1_NAME=...
EDGE_INSTANCE_2_URL=...
ACTIVE_EDGE_INSTANCE=1
```

The active instance's credentials are mirrored into the canonical `EDGE_URL`, `EDGE_API_CLIENT_ID`, `EDGE_API_CLIENT_SECRET` keys so the rest of the system needs no awareness of multi-tenancy.

See [Multi-Instance Edge](#).

## Transport modes

| Mode          | When to use                                          | Auth source                 |
| ------------- | ---------------------------------------------------- | --------------------------- |
| SSE (default) | Remote or shared MCP server, any HTTP-capable client | HTTP headers per connection |
| STDIO         | Single-user local install with Claude Desktop        | Environment variables       |

STDIO is opt-in via `ENABLE_STDIO=true` in `src/config.py` or environment.

## Source layout

```javascript
src/
├── server.py              MCP server entrypoint, SSE setup
├── web_client.py          FastAPI app, all web routes
├── client_utils.py        LLM streaming, tool-call loop
├── env_config.py          .env read/write, path constants
├── config.py              Ports, SSL, NATS/InfluxDB defaults
├── conversation.py        In-memory chat history
├── utils/
│   ├── auth.py            Header -> connection params
│   └── formatting.py      Tool response shape helpers
└── tools/
    ├── devicehub_tools.py
    ├── dm_tools.py
    ├── marketplace_tools.py
    ├── data_tools.py
    ├── digitaltwins_tools.py
    ├── system_tools.py
    ├── lem_tools.py
    └── resource_tools.py  MCP Resources (live docs.litmus.io)
```

Each `*_tools.py` exports a `TOOLS = [...]` list of dicts. `server.py` concatenates them and dispatches by name.
