lattice-mcp 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +49 -24
- package/README.md +171 -72
- package/index.js +39 -12
- package/package.json +3 -2
package/AGENTS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> `lattice-mcp` is the **Model Context Protocol server for Lattice**, the container
|
|
4
4
|
> orchestration platform that runs every `appleby.cloud` service. It exposes the
|
|
5
|
-
> `lattice-api` admin surface to Claude Code as **
|
|
5
|
+
> `lattice-api` admin surface to Claude Code as **126 typed tools** — workers, stacks,
|
|
6
6
|
> containers, deployments, databases, registries, networks, volumes and instance config.
|
|
7
7
|
> This file orients any agent/worker before touching code in this repo.
|
|
8
8
|
>
|
|
@@ -32,8 +32,9 @@ Those live in [`lattice-api`](https://github.com/aidenappl/lattice-api) and
|
|
|
32
32
|
- **Runtime:** Node ≥18 (needs global `fetch` and `AbortSignal.timeout`). `"type": "module"` —
|
|
33
33
|
ESM only, top-level `await` is used at the bottom of `index.js`.
|
|
34
34
|
- **`@modelcontextprotocol/sdk` ^1.29.0** — `McpServer` + `StdioServerTransport`.
|
|
35
|
-
- **`zod
|
|
36
|
-
|
|
35
|
+
- **`zod` ^4.4.3** — argument schemas. Declared explicitly as of **1.1.1** (it was previously
|
|
36
|
+
only resolved transitively through the MCP SDK, a latent fragility); the range matches the
|
|
37
|
+
version the SDK resolves.
|
|
37
38
|
- No build step, no bundler, no tests, no lint config. `node --check index.js` is the only
|
|
38
39
|
static gate.
|
|
39
40
|
|
|
@@ -41,7 +42,7 @@ Those live in [`lattice-api`](https://github.com/aidenappl/lattice-api) and
|
|
|
41
42
|
|
|
42
43
|
| Path | Role |
|
|
43
44
|
|------|------|
|
|
44
|
-
| `index.js` | Everything: `--setup` flow, config read, `api()` HTTP helper, `text()`/`body()` helpers, all
|
|
45
|
+
| `index.js` | Everything: `--setup` flow, config read, `api()` HTTP helper, `text()`/`body()` helpers, all 126 `server.tool(...)` registrations, transport connect. |
|
|
45
46
|
| `package.json` | npm metadata. `bin.lattice-mcp` → `index.js`, so `npx lattice-mcp` works. |
|
|
46
47
|
| `README.md` | User-facing setup + full tool table. |
|
|
47
48
|
| `AGENTS.md` | This file. |
|
|
@@ -90,9 +91,12 @@ and supply the real token.
|
|
|
90
91
|
the noun (`lattice_list_database_instances`). The prefix is what disambiguates these from
|
|
91
92
|
`monitor_*` and `forta_*` tools in a shared client.
|
|
92
93
|
- **`api(method, path, params, body)`** — `params` become query string entries (undefined/null
|
|
93
|
-
are dropped), `body` is JSON-encoded.
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
are dropped), `body` is JSON-encoded. Failures are returned as tool output, never thrown, so
|
|
95
|
+
they surface to the agent rather than crashing the transport. A network-level failure returns
|
|
96
|
+
`{success:false, error_message: "API request failed: …"}`; a response that arrives but is not
|
|
97
|
+
JSON (e.g. a 502/504 HTML page from the TLS proxy) returns
|
|
98
|
+
`{success:false, error_code: <http status>, error_message: "API returned a non-JSON response …"}`
|
|
99
|
+
with a truncated body — bodies are never logged, only returned, since they can carry secrets.
|
|
96
100
|
- **`body(obj)`** strips `undefined` keys. **Always use it on PUT/PATCH tools.** The API treats
|
|
97
101
|
a present-but-null field as an explicit clear, so forwarding raw `{...fields}` on an update
|
|
98
102
|
would wipe every field the caller didn't pass.
|
|
@@ -122,28 +126,48 @@ exits immediately if either is missing. In practice these come from the `env` bl
|
|
|
122
126
|
|
|
123
127
|
**Tool groups**, in file order:
|
|
124
128
|
|
|
129
|
+
The counts below sum to **126**, matching the header and `grep -c 'server.tool(' index.js`. The
|
|
130
|
+
first rows are the original, pre-`1.1.0` tools (registered top-of-file with no banner comment);
|
|
131
|
+
every bolded row corresponds to a `// ───` banner group and matches its exact in-file name.
|
|
132
|
+
|
|
125
133
|
| Group | Tools | Notes |
|
|
126
134
|
|-------|-------|-------|
|
|
127
|
-
| Overview & health |
|
|
135
|
+
| Overview & health | 3 | `lattice_overview`, `lattice_health`, `lattice_get_version` |
|
|
128
136
|
| Workers | 3 + 4 actions | list/get/metrics; reboot, upgrade, stop-all, start-all |
|
|
129
|
-
| Stacks | 2 +
|
|
130
|
-
| Containers |
|
|
131
|
-
| Deployments | 4 | list/get/logs, rollback,
|
|
132
|
-
|
|
|
133
|
-
|
|
|
134
|
-
| **
|
|
135
|
-
| **
|
|
136
|
-
| **
|
|
137
|
-
| **
|
|
138
|
-
| **
|
|
139
|
-
| **
|
|
140
|
-
| **
|
|
141
|
-
| **
|
|
137
|
+
| Stacks | 2 + 5 actions | list/get; deploy, restart, stop, start, update |
|
|
138
|
+
| Containers | 4 + 8 actions | list/get/logs/lifecycle; start, stop, restart, kill, pause, unpause, remove, recreate. (`lattice_get_container_metrics` is *not* here — it lives under **Discovery & diagnostics**.) |
|
|
139
|
+
| Deployments | 4 | list/get/logs, rollback. (`lattice_approve_deployment` is *not* here — it lives under **Stacks — lifecycle, compose & deploy tokens**.) |
|
|
140
|
+
| Instance self-update | 2 | `lattice_update_api`, `lattice_update_web` — tell the API/web container to pull its latest image and redeploy itself |
|
|
141
|
+
| Audit & API tokens | 4 | `lattice_get_audit_log`; API token list/create/delete |
|
|
142
|
+
| **Database instances** | **11** | CRUD, `lattice_database_action` (start/stop/restart/remove enum), `lattice_get_database_credentials`, snapshot list/create/restore/delete |
|
|
143
|
+
| **Backup destinations** | **6** | list/get/create/update/delete + `lattice_test_backup_destination` |
|
|
144
|
+
| **Registries** | **8** | list/create/update/delete, `lattice_test_registry`, `lattice_test_registry_inline`, `lattice_list_registry_repositories`, `lattice_list_registry_tags` |
|
|
145
|
+
| **Discovery & diagnostics** | **7** | `lattice_search`, `lattice_get_anomalies`, `lattice_get_fleet_metrics`, `lattice_get_versions`, `lattice_refresh_versions`, `lattice_get_container_metrics`, `lattice_get_self` |
|
|
146
|
+
| **Stacks — lifecycle, compose & deploy tokens** | **13** | create/delete, `lattice_get_stack_containers`, compose update/sync/import, export/import, `lattice_save_stack_as_template`, deploy-token list/create/delete, `lattice_approve_deployment` |
|
|
147
|
+
| **Containers — definition CRUD** | **3** | `lattice_create_container`, `lattice_update_container`, `lattice_delete_container` |
|
|
148
|
+
| **Workers — registration, tokens, volumes, networks** | **16** | worker create/update/delete, `lattice_get_worker_container_stats`, worker-token ×3, volume ×3, worker-network ×3, `lattice_list_all_networks`, `lattice_delete_network`, `lattice_force_remove_container` |
|
|
149
|
+
| **Global env vars, templates, webhooks** | **12** | env-var CRUD (4), template list/create/delete (3), webhook list/create/update/delete/test (5) |
|
|
150
|
+
| **Users & instance configuration** | **11** | user CRUD (4); SSO get/update (2); SMTP get/update/test (3); notification-prefs get/update (2) |
|
|
142
151
|
|
|
143
152
|
Bolded groups were added in **1.1.0**, closing a gap where the MCP had drifted roughly two
|
|
144
153
|
months behind `lattice-api` — database instances shipped in the API in May 2026 and were
|
|
145
154
|
entirely unreachable from the MCP until then.
|
|
146
155
|
|
|
156
|
+
**1.1.1** is a bug-fix release (no tool count change). It corrects three request-shape/route bugs
|
|
157
|
+
verified against `lattice-api` handlers: `lattice_get_self` now calls `GET /auth/self` (the old
|
|
158
|
+
`GET /admin/self` route never existed and always 404'd — the endpoint is `HandleAuthSelf` on the
|
|
159
|
+
bearer-authed `/auth` subrouter); `lattice_force_remove_container` now sends `{container_name}` in
|
|
160
|
+
the JSON body (`HandleForceRemoveContainer` reads it there, not from query params, so the old call
|
|
161
|
+
always 400'd); and `lattice_test_backup_destination` now marks `worker_id` as **required** (a query
|
|
162
|
+
param the handler 400s without — the test dispatches over the worker's WebSocket). It also hardens
|
|
163
|
+
`api()` against non-JSON responses (see *How code is written here*) and declares `zod` explicitly.
|
|
164
|
+
|
|
165
|
+
**1.1.2** adds `lattice_get_version` (`GET /version`, so agents can read the deployed API version
|
|
166
|
+
for deploy-drift checks without shelling out to `curl`), and widens two read tools to pass filter
|
|
167
|
+
params the handlers already accept but the tools were dropping: `lattice_get_audit_log` gains
|
|
168
|
+
`user_id` / `action` / `resource_type` / `offset` (answer "who deleted stack X" server-side instead
|
|
169
|
+
of scanning 50 rows), and `lattice_get_container_logs` gains `offset` / `worker_id`. Tool count 125 → 126.
|
|
170
|
+
|
|
147
171
|
**Consolidations.** Where `lattice-api` exposes several paths served by one handler, this repo
|
|
148
172
|
exposes one tool with an enum rather than N tools. `lattice_database_action` covers
|
|
149
173
|
`/start`, `/stop`, `/restart` and `/remove`. Worker actions are the historical exception — they
|
|
@@ -187,9 +211,10 @@ predate this convention and remain separate tools.
|
|
|
187
211
|
- **Do not break tool names.** They are a public contract: renaming one silently breaks any
|
|
188
212
|
saved workflow or prompt that referenced it. Add a new tool and deprecate in the description
|
|
189
213
|
instead.
|
|
190
|
-
- **`zod` is
|
|
191
|
-
|
|
192
|
-
|
|
214
|
+
- **`zod` is declared explicitly** in `package.json` (`^4.4.3`) as of **1.1.1**. It used to
|
|
215
|
+
resolve only transitively through the MCP SDK, which meant a SDK change that dropped or hoisted
|
|
216
|
+
it differently would break every tool schema at startup. Keep the declared range aligned with
|
|
217
|
+
the version the SDK actually resolves (check `package-lock.json`).
|
|
193
218
|
- **Keep destructive descriptions honest.** If a tool destroys data, the description must say so
|
|
194
219
|
and name the safer alternative.
|
|
195
220
|
- Publishing is outward-facing and effectively irreversible (npm unpublish is restricted after
|
package/README.md
CHANGED
|
@@ -1,18 +1,55 @@
|
|
|
1
1
|
# lattice-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Model Context Protocol server for [Lattice](https://github.com/aidenappl/lattice-api), the container orchestration platform that runs every `appleby.cloud` service. Gives Claude Code direct, typed access to workers, stacks, containers, deployments, databases, registries, networks, volumes and instance configuration.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> **appleby.cloud platform** · MCP server · published to npm as `lattice-mcp` · consumed via `npx -y lattice-mcp`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
`lattice-mcp` is a single-file Node ESM program (`index.js`) that speaks MCP over stdio and translates tool calls into HTTP requests against the `lattice-api` admin surface. It exposes **126 typed tools** and holds no business logic, caching or state of its own — every behaviour (pagination, validation, side effects) comes from `lattice-api`.
|
|
12
|
+
|
|
13
|
+
Once configured, ask Claude Code things like:
|
|
14
|
+
|
|
15
|
+
- "What's the status of all stacks?"
|
|
16
|
+
- "Show me logs for the forta-api container"
|
|
17
|
+
- "Which containers are unhealthy?" (`lattice_get_anomalies` is the best first call)
|
|
18
|
+
- "Deploy stack 5" / "Rollback the last deployment on stack 12"
|
|
19
|
+
- "What image tags can I deploy from the registry?"
|
|
20
|
+
|
|
21
|
+
## Role in the appleby.cloud ecosystem
|
|
22
|
+
|
|
23
|
+
| Repo | Relationship |
|
|
24
|
+
|------|--------------|
|
|
25
|
+
| [`lattice-api`](https://github.com/aidenappl/lattice-api) | The API this wraps — its route table is the source of truth for tool coverage. |
|
|
26
|
+
| [`lattice-web`](https://github.com/aidenappl/lattice-web) | Next.js dashboard over the same API. |
|
|
27
|
+
| [`lattice-runner`](https://github.com/aidenappl/lattice-runner) | Agent on each worker VM; WebSocket back to `lattice-api`. |
|
|
28
|
+
| `monitor-mcp` / `forta-mcp` / `keyring-mcp` / `openbucket-mcp` | Sibling MCP servers, same single-file structure. |
|
|
29
|
+
|
|
30
|
+
## Tech stack
|
|
31
|
+
|
|
32
|
+
- **Node ≥18** (needs global `fetch` and `AbortSignal.timeout`), ESM (`"type": "module"`).
|
|
33
|
+
- **`@modelcontextprotocol/sdk` ^1.29.0** — `McpServer` + `StdioServerTransport`.
|
|
34
|
+
- **`zod` ^4.4.3** for argument schemas (a declared dependency as of 1.1.1).
|
|
35
|
+
- No build step, no bundler. `node --check index.js` is the only static gate.
|
|
36
|
+
|
|
37
|
+
## Getting started
|
|
38
|
+
|
|
39
|
+
### Prerequisites
|
|
40
|
+
|
|
41
|
+
- Node ≥18.
|
|
42
|
+
- A Lattice API URL and API token. Generate a token from the Lattice web dashboard under **Settings > API Tokens**.
|
|
43
|
+
|
|
44
|
+
### Setup
|
|
45
|
+
|
|
46
|
+
Quickest — interactive setup writes the `lattice` block into `~/.mcp.json`:
|
|
6
47
|
|
|
7
48
|
```bash
|
|
8
49
|
npx lattice-mcp --setup
|
|
9
50
|
```
|
|
10
51
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
## Manual Setup
|
|
14
|
-
|
|
15
|
-
Add to `~/.mcp.json`:
|
|
52
|
+
Or configure it manually in `~/.mcp.json`:
|
|
16
53
|
|
|
17
54
|
```json
|
|
18
55
|
{
|
|
@@ -29,21 +66,42 @@ Add to `~/.mcp.json`:
|
|
|
29
66
|
}
|
|
30
67
|
```
|
|
31
68
|
|
|
32
|
-
|
|
69
|
+
Restart Claude Code after setup so the new server and tools are picked up.
|
|
70
|
+
|
|
71
|
+
### Environment variables
|
|
72
|
+
|
|
73
|
+
| Variable | Required | Description |
|
|
74
|
+
|----------|----------|-------------|
|
|
75
|
+
| `LATTICE_API_URL` | Yes | Lattice API base URL |
|
|
76
|
+
| `LATTICE_API_TOKEN` | Yes | Bearer token for authentication (sent on every request) |
|
|
77
|
+
|
|
78
|
+
## Development
|
|
79
|
+
|
|
80
|
+
| Command | What it does |
|
|
81
|
+
|---------|--------------|
|
|
82
|
+
| `node index.js --setup` | Interactive setup — writes the `lattice` block into `~/.mcp.json` |
|
|
83
|
+
| `npm install` | Install dependencies (not vendored) |
|
|
84
|
+
| `node --check index.js` | Syntax gate — the only static check that exists |
|
|
85
|
+
| `LATTICE_API_URL=… LATTICE_API_TOKEN=… node index.js` | Run the server on stdio |
|
|
86
|
+
| `grep -c 'server.tool(' index.js` | Confirm the tool count (should be 126) |
|
|
87
|
+
| `npm publish` | Publish to npm — **this is deployment** (requires 2FA passkey from an interactive terminal) |
|
|
33
88
|
|
|
34
89
|
## Tools
|
|
35
90
|
|
|
36
|
-
|
|
91
|
+
All 126 tools, grouped as they appear in `index.js`. ⚠️ marks destructive tools; their descriptions state the blast radius.
|
|
92
|
+
|
|
93
|
+
### Overview & health
|
|
37
94
|
| Tool | Description |
|
|
38
95
|
|------|-------------|
|
|
39
|
-
| `lattice_overview` | Fleet overview — worker
|
|
96
|
+
| `lattice_overview` | Fleet overview — worker/stack/container counts, failed stacks, CPU/memory |
|
|
40
97
|
| `lattice_health` | API health and database connectivity |
|
|
98
|
+
| `lattice_get_version` | Deployed lattice-api version string — check deploy drift against GitHub tags |
|
|
41
99
|
|
|
42
100
|
### Workers
|
|
43
101
|
| Tool | Description |
|
|
44
102
|
|------|-------------|
|
|
45
|
-
| `lattice_list_workers` | List workers with status, IP, versions |
|
|
46
|
-
| `lattice_get_worker` | Detailed worker info |
|
|
103
|
+
| `lattice_list_workers` | List workers with status, IP, versions, heartbeat |
|
|
104
|
+
| `lattice_get_worker` | Detailed worker info including metrics |
|
|
47
105
|
| `lattice_get_worker_metrics` | CPU, memory, disk, network metrics |
|
|
48
106
|
| `lattice_reboot_worker` | Reboot a worker machine |
|
|
49
107
|
| `lattice_upgrade_worker` | Upgrade worker runner to latest |
|
|
@@ -55,18 +113,18 @@ Generate an API token from the Lattice web dashboard under **Settings > API Toke
|
|
|
55
113
|
|------|-------------|
|
|
56
114
|
| `lattice_list_stacks` | List stacks with status and worker assignment |
|
|
57
115
|
| `lattice_get_stack` | Full stack details including compose YAML |
|
|
58
|
-
| `lattice_update_stack` | Update stack configuration |
|
|
59
116
|
| `lattice_deploy_stack` | Deploy a stack (all or specific containers) |
|
|
60
117
|
| `lattice_restart_stack` | Restart all containers in a stack |
|
|
61
118
|
| `lattice_stop_stack` | Stop all containers in a stack |
|
|
62
119
|
| `lattice_start_stack` | Start all containers in a stack |
|
|
120
|
+
| `lattice_update_stack` | Update stack configuration |
|
|
63
121
|
|
|
64
122
|
### Containers
|
|
65
123
|
| Tool | Description |
|
|
66
124
|
|------|-------------|
|
|
67
125
|
| `lattice_list_containers` | List containers with status, image, ports, health |
|
|
68
126
|
| `lattice_get_container` | Full container details |
|
|
69
|
-
| `lattice_get_container_logs` | Recent container logs (stdout/stderr) |
|
|
127
|
+
| `lattice_get_container_logs` | Recent container logs (stdout/stderr); `offset` paginates into older logs, filter by `stream`/`worker_id` |
|
|
70
128
|
| `lattice_get_container_lifecycle` | Lifecycle events (start, stop, health changes) |
|
|
71
129
|
| `lattice_start_container` | Start a stopped container |
|
|
72
130
|
| `lattice_stop_container` | Stop a running container |
|
|
@@ -74,8 +132,8 @@ Generate an API token from the Lattice web dashboard under **Settings > API Toke
|
|
|
74
132
|
| `lattice_kill_container` | Force kill a container |
|
|
75
133
|
| `lattice_pause_container` | Pause a running container |
|
|
76
134
|
| `lattice_unpause_container` | Unpause a paused container |
|
|
77
|
-
| `lattice_remove_container` | Remove a container |
|
|
78
|
-
| `lattice_recreate_container` | Remove and recreate a container |
|
|
135
|
+
| `lattice_remove_container` | Remove a container ⚠️ |
|
|
136
|
+
| `lattice_recreate_container` | Remove and recreate a container ⚠️ |
|
|
79
137
|
|
|
80
138
|
### Deployments
|
|
81
139
|
| Tool | Description |
|
|
@@ -83,36 +141,21 @@ Generate an API token from the Lattice web dashboard under **Settings > API Toke
|
|
|
83
141
|
| `lattice_list_deployments` | List deployments with status and timing |
|
|
84
142
|
| `lattice_get_deployment` | Deployment details with container-level status |
|
|
85
143
|
| `lattice_get_deployment_logs` | Pull, create, start, swap events with timing |
|
|
86
|
-
| `lattice_rollback_deployment` | Rollback to previous state |
|
|
144
|
+
| `lattice_rollback_deployment` | Rollback to previous state ⚠️ |
|
|
145
|
+
|
|
146
|
+
### Instance self-update
|
|
147
|
+
| Tool | Description |
|
|
148
|
+
|------|-------------|
|
|
149
|
+
| `lattice_update_api` | Trigger the Lattice API container to self-update |
|
|
150
|
+
| `lattice_update_web` | Trigger the Lattice web container to update |
|
|
87
151
|
|
|
88
|
-
###
|
|
152
|
+
### Audit & API tokens
|
|
89
153
|
| Tool | Description |
|
|
90
154
|
|------|-------------|
|
|
91
|
-
| `lattice_get_audit_log` |
|
|
92
|
-
| `lattice_update_api` | Trigger API self-update |
|
|
93
|
-
| `lattice_update_web` | Trigger web container update |
|
|
155
|
+
| `lattice_get_audit_log` | Audit log entries (who did what, when); filter by `user_id`/`action`/`resource_type`, `offset` paginates |
|
|
94
156
|
| `lattice_list_api_tokens` | List API tokens |
|
|
95
157
|
| `lattice_create_api_token` | Create a new API token |
|
|
96
|
-
| `lattice_delete_api_token` | Delete an API token |
|
|
97
|
-
|
|
98
|
-
## Example Prompts
|
|
99
|
-
|
|
100
|
-
- "What's the status of all stacks?"
|
|
101
|
-
- "Show me logs for the forta-api container"
|
|
102
|
-
- "Deploy stack 5"
|
|
103
|
-
- "Which containers are unhealthy?"
|
|
104
|
-
- "Rollback the last deployment on stack 12"
|
|
105
|
-
|
|
106
|
-
## Environment Variables
|
|
107
|
-
|
|
108
|
-
| Variable | Required | Description |
|
|
109
|
-
|----------|----------|-------------|
|
|
110
|
-
| `LATTICE_API_URL` | Yes | Lattice API base URL |
|
|
111
|
-
| `LATTICE_API_TOKEN` | Yes | API token for authentication |
|
|
112
|
-
|
|
113
|
-
## License
|
|
114
|
-
|
|
115
|
-
MIT
|
|
158
|
+
| `lattice_delete_api_token` | Delete an API token ⚠️ |
|
|
116
159
|
|
|
117
160
|
### Database instances
|
|
118
161
|
| Tool | Description |
|
|
@@ -132,18 +175,22 @@ MIT
|
|
|
132
175
|
### Backup destinations
|
|
133
176
|
| Tool | Description |
|
|
134
177
|
|------|-------------|
|
|
135
|
-
| `lattice_list_backup_destinations`
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
178
|
+
| `lattice_list_backup_destinations` | List backup destinations |
|
|
179
|
+
| `lattice_get_backup_destination` | One destination's configuration |
|
|
180
|
+
| `lattice_create_backup_destination` | Create a destination |
|
|
181
|
+
| `lattice_update_backup_destination` | Update a destination |
|
|
182
|
+
| `lattice_delete_backup_destination` | Delete a destination ⚠️ |
|
|
183
|
+
| `lattice_test_backup_destination` | Test connectivity without writing a backup (requires a connected `worker_id`) |
|
|
139
184
|
|
|
140
185
|
### Registries
|
|
141
186
|
| Tool | Description |
|
|
142
187
|
|------|-------------|
|
|
143
|
-
| `lattice_list_registries` | Configured registries |
|
|
144
|
-
| `lattice_create_registry`
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
188
|
+
| `lattice_list_registries` | Configured container registries |
|
|
189
|
+
| `lattice_create_registry` | Add a registry |
|
|
190
|
+
| `lattice_update_registry` | Update a registry |
|
|
191
|
+
| `lattice_delete_registry` | Delete a registry ⚠️ |
|
|
192
|
+
| `lattice_test_registry` | Test a saved registry's stored credentials |
|
|
193
|
+
| `lattice_test_registry_inline` | Test registry credentials before saving |
|
|
147
194
|
| `lattice_list_registry_repositories` | What images exist |
|
|
148
195
|
| `lattice_list_registry_tags` | **What versions are deployable** |
|
|
149
196
|
|
|
@@ -153,53 +200,105 @@ MIT
|
|
|
153
200
|
| `lattice_search` | Search workers, stacks and containers in one call |
|
|
154
201
|
| `lattice_get_anomalies` | **Restart loops, unhealthy containers, offline workers — best first call** |
|
|
155
202
|
| `lattice_get_fleet_metrics` | Aggregated fleet CPU/memory/disk/network |
|
|
156
|
-
| `lattice_get_versions`
|
|
203
|
+
| `lattice_get_versions` | Runner versions and what's outdated |
|
|
204
|
+
| `lattice_refresh_versions` | Re-poll every worker for its current runner version |
|
|
157
205
|
| `lattice_get_container_metrics` | Per-container metrics over time |
|
|
158
206
|
| `lattice_get_self` | Which user the token authenticates as |
|
|
159
207
|
|
|
160
|
-
### Stacks —
|
|
208
|
+
### Stacks — lifecycle, compose & deploy tokens
|
|
161
209
|
| Tool | Description |
|
|
162
210
|
|------|-------------|
|
|
163
|
-
| `lattice_create_stack`
|
|
211
|
+
| `lattice_create_stack` | Create an empty stack |
|
|
212
|
+
| `lattice_delete_stack` | Delete a stack and all its containers ⚠️ |
|
|
164
213
|
| `lattice_get_stack_containers` | Containers in a stack |
|
|
165
|
-
| `lattice_update_stack_compose`
|
|
214
|
+
| `lattice_update_stack_compose` | Replace a stack's compose YAML |
|
|
215
|
+
| `lattice_sync_stack_compose` | Reconcile container records against stored compose YAML |
|
|
166
216
|
| `lattice_import_compose` | Create a stack from compose YAML |
|
|
167
|
-
| `lattice_export_stack`
|
|
217
|
+
| `lattice_export_stack` | Export a stack's full definition as portable JSON |
|
|
218
|
+
| `lattice_import_stack_export` | Recreate a stack from an export document |
|
|
168
219
|
| `lattice_save_stack_as_template` | Save a stack as a reusable template |
|
|
169
220
|
| `lattice_list_deploy_tokens` | CI deploy tokens — `last_used_at` shows whether CI reaches Lattice |
|
|
170
|
-
| `lattice_create_deploy_token`
|
|
221
|
+
| `lattice_create_deploy_token` | Create a CI deploy token |
|
|
222
|
+
| `lattice_delete_deploy_token` | Delete a CI deploy token ⚠️ |
|
|
171
223
|
| `lattice_approve_deployment` | Approve a deployment awaiting approval |
|
|
172
224
|
|
|
173
225
|
### Container definitions
|
|
174
226
|
| Tool | Description |
|
|
175
227
|
|------|-------------|
|
|
176
|
-
| `lattice_create_container`
|
|
177
|
-
| `
|
|
228
|
+
| `lattice_create_container` | Add a container definition to a stack |
|
|
229
|
+
| `lattice_update_container` | Update a container definition |
|
|
230
|
+
| `lattice_delete_container` | Delete definition and its running container ⚠️ |
|
|
178
231
|
|
|
179
|
-
### Workers —
|
|
232
|
+
### Workers — registration, tokens, volumes, networks
|
|
180
233
|
| Tool | Description |
|
|
181
234
|
|------|-------------|
|
|
182
|
-
| `lattice_create_worker`
|
|
183
|
-
| `
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
235
|
+
| `lattice_create_worker` | Register a worker |
|
|
236
|
+
| `lattice_update_worker` | Update a worker's name, hostname, IP, status, labels |
|
|
237
|
+
| `lattice_delete_worker` | Delete a worker ⚠️ |
|
|
238
|
+
| `lattice_get_worker_container_stats` | Live per-container stats from one worker |
|
|
239
|
+
| `lattice_list_worker_tokens` | Worker registration tokens |
|
|
240
|
+
| `lattice_create_worker_token` | Create a registration token for a worker |
|
|
241
|
+
| `lattice_delete_worker_token` | Delete a worker token ⚠️ |
|
|
242
|
+
| `lattice_list_worker_volumes` | Docker volumes on a worker |
|
|
243
|
+
| `lattice_create_worker_volume` | Create a Docker volume on a worker |
|
|
244
|
+
| `lattice_delete_worker_volume` | Delete a Docker volume ⚠️ |
|
|
245
|
+
| `lattice_list_worker_networks` | Docker networks on a worker |
|
|
246
|
+
| `lattice_create_worker_network` | Create a Docker network on a worker |
|
|
247
|
+
| `lattice_delete_worker_network` | Delete a Docker network ⚠️ |
|
|
248
|
+
| `lattice_list_all_networks` | Every tracked network across the fleet |
|
|
249
|
+
| `lattice_delete_network` | Delete a tracked network by Lattice ID ⚠️ |
|
|
188
250
|
| `lattice_force_remove_container` | Force-remove a wedged container ⚠️ |
|
|
189
251
|
|
|
190
252
|
### Env vars, templates & webhooks
|
|
191
253
|
| Tool | Description |
|
|
192
254
|
|------|-------------|
|
|
193
|
-
| `lattice_list_env_vars`
|
|
194
|
-
| `
|
|
195
|
-
| `
|
|
255
|
+
| `lattice_list_env_vars` | Global `${VAR}` interpolation values (secrets masked) |
|
|
256
|
+
| `lattice_create_env_var` | Create a global environment variable |
|
|
257
|
+
| `lattice_update_env_var` | Update a global environment variable |
|
|
258
|
+
| `lattice_delete_env_var` | Delete a global environment variable ⚠️ |
|
|
259
|
+
| `lattice_list_templates` | Saved stack templates |
|
|
260
|
+
| `lattice_create_template` | Create a stack template |
|
|
261
|
+
| `lattice_delete_template` | Delete a stack template ⚠️ |
|
|
262
|
+
| `lattice_list_webhooks` | Outbound event webhooks |
|
|
263
|
+
| `lattice_create_webhook` | Create an outbound webhook |
|
|
264
|
+
| `lattice_update_webhook` | Update a webhook |
|
|
265
|
+
| `lattice_delete_webhook` | Delete a webhook ⚠️ |
|
|
266
|
+
| `lattice_test_webhook` | Send a test payload to a webhook |
|
|
196
267
|
|
|
197
268
|
### Users & instance configuration
|
|
198
269
|
| Tool | Description |
|
|
199
270
|
|------|-------------|
|
|
200
|
-
| `lattice_list_users`
|
|
201
|
-
| `
|
|
202
|
-
| `
|
|
203
|
-
| `
|
|
271
|
+
| `lattice_list_users` | List Lattice users with roles and status |
|
|
272
|
+
| `lattice_create_user` | Create a local Lattice user |
|
|
273
|
+
| `lattice_update_user` | Update a user's name, role or active flag ⚠️ |
|
|
274
|
+
| `lattice_delete_user` | Delete a Lattice user ⚠️ |
|
|
275
|
+
| `lattice_get_sso_config` | Get the Forta SSO configuration |
|
|
276
|
+
| `lattice_update_sso_config` | Update SSO config ⚠️ (can lock out SSO users) |
|
|
277
|
+
| `lattice_get_smtp_config` | Get the SMTP configuration |
|
|
278
|
+
| `lattice_update_smtp_config` | Update the SMTP configuration |
|
|
279
|
+
| `lattice_test_smtp` | Send a test email with the saved SMTP config |
|
|
280
|
+
| `lattice_get_notification_prefs` | Per-event notification preferences |
|
|
281
|
+
| `lattice_update_notification_prefs` | Update notification preferences |
|
|
282
|
+
|
|
283
|
+
## Project structure
|
|
284
|
+
|
|
285
|
+
Everything lives in one file:
|
|
286
|
+
|
|
287
|
+
| Path | Role |
|
|
288
|
+
|------|------|
|
|
289
|
+
| `index.js` | The whole server: `--setup` flow, config read, `api()` HTTP helper, `text()`/`body()` helpers, all 126 `server.tool(...)` registrations, transport connect. |
|
|
290
|
+
| `package.json` | npm metadata; `bin.lattice-mcp` → `index.js`. |
|
|
291
|
+
| `AGENTS.md` | Contributor/agent guide — conventions, handler contracts, verification. |
|
|
292
|
+
| `README.md` | This file. |
|
|
293
|
+
|
|
294
|
+
## Deployment
|
|
204
295
|
|
|
205
|
-
|
|
296
|
+
Published to npm as `lattice-mcp` (public). Consumers run `npx -y lattice-mcp`, which resolves the latest published version — so **publishing is deployment**, and a running MCP server must be restarted to pick up a new version. `npm publish` requires 2FA via passkey from an interactive terminal.
|
|
297
|
+
|
|
298
|
+
## Contributing & further reading
|
|
299
|
+
|
|
300
|
+
Read [`AGENTS.md`](./AGENTS.md) before changing code — it documents the one-shape tool pattern, the `body()`/`api()` helpers, the "read the handler before adding a tool" rule, and the verification steps. Related repos: [`lattice-api`](https://github.com/aidenappl/lattice-api), [`lattice-web`](https://github.com/aidenappl/lattice-web), [`lattice-runner`](https://github.com/aidenappl/lattice-runner).
|
|
301
|
+
|
|
302
|
+
## License
|
|
303
|
+
|
|
304
|
+
MIT
|
package/index.js
CHANGED
|
@@ -77,12 +77,27 @@ async function api(method, path, params, body) {
|
|
|
77
77
|
opts.headers["Content-Type"] = "application/json";
|
|
78
78
|
opts.body = JSON.stringify(body);
|
|
79
79
|
}
|
|
80
|
+
let res;
|
|
80
81
|
try {
|
|
81
|
-
|
|
82
|
-
return await res.json();
|
|
82
|
+
res = await fetch(url.toString(), opts);
|
|
83
83
|
} catch (err) {
|
|
84
|
+
// Network-level failure (DNS, connection refused, timeout) — no response at all.
|
|
84
85
|
return { success: false, error: err.message, error_message: `API request failed: ${err.message}` };
|
|
85
86
|
}
|
|
87
|
+
// Response arrived. Read the body once as text, then try to parse it as JSON.
|
|
88
|
+
// On parse failure surface the HTTP status and a truncated text body rather than
|
|
89
|
+
// an opaque parse error — a 502/504 HTML page from the TLS proxy lands here.
|
|
90
|
+
// Never log bodies anywhere; responses can carry secrets.
|
|
91
|
+
const raw = await res.text();
|
|
92
|
+
try {
|
|
93
|
+
return JSON.parse(raw);
|
|
94
|
+
} catch {
|
|
95
|
+
return {
|
|
96
|
+
success: false,
|
|
97
|
+
error_code: res.status,
|
|
98
|
+
error_message: `API returned a non-JSON response (HTTP ${res.status})${raw ? `: ${raw.slice(0, 500)}` : ""}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
86
101
|
}
|
|
87
102
|
|
|
88
103
|
function text(data) {
|
|
@@ -99,7 +114,7 @@ function body(obj) {
|
|
|
99
114
|
|
|
100
115
|
const server = new McpServer({
|
|
101
116
|
name: "lattice",
|
|
102
|
-
version: "1.
|
|
117
|
+
version: "1.1.2",
|
|
103
118
|
});
|
|
104
119
|
|
|
105
120
|
// Overview
|
|
@@ -114,6 +129,12 @@ server.tool("lattice_health", "Check API health and database connectivity", {},
|
|
|
114
129
|
return { content: text(res) };
|
|
115
130
|
});
|
|
116
131
|
|
|
132
|
+
// Version
|
|
133
|
+
server.tool("lattice_get_version", "Get the deployed lattice-api version string. Use to check deploy drift against GitHub tags/commits (e.g. for /howfarbehind).", {}, async () => {
|
|
134
|
+
const res = await api("GET", "/version");
|
|
135
|
+
return { content: text(res) };
|
|
136
|
+
});
|
|
137
|
+
|
|
117
138
|
// Workers
|
|
118
139
|
server.tool("lattice_list_workers", "List all workers with status, IP, Docker version, runner version, last heartbeat", {
|
|
119
140
|
status: z.enum(["online", "offline", "disconnected"]).optional().describe("Filter by worker status"),
|
|
@@ -174,9 +195,11 @@ server.tool("lattice_get_container", "Get full container details including confi
|
|
|
174
195
|
server.tool("lattice_get_container_logs", "Get recent container logs (stdout/stderr)", {
|
|
175
196
|
id: z.number().describe("Container ID"),
|
|
176
197
|
limit: z.number().optional().describe("Number of log lines (default 50)"),
|
|
198
|
+
offset: z.number().optional().describe("Skip this many lines — paginate past the tail into older logs"),
|
|
177
199
|
stream: z.enum(["stdout", "stderr"]).optional().describe("Filter by stream"),
|
|
178
|
-
|
|
179
|
-
|
|
200
|
+
worker_id: z.number().optional().describe("Filter by worker ID"),
|
|
201
|
+
}, async ({ id, limit, offset, stream, worker_id }) => {
|
|
202
|
+
const res = await api("GET", `/admin/containers/${id}/logs`, { limit, offset, stream, worker_id });
|
|
180
203
|
return { content: text(res) };
|
|
181
204
|
});
|
|
182
205
|
|
|
@@ -213,10 +236,14 @@ server.tool("lattice_get_deployment_logs", "Get deployment logs: pull, create, s
|
|
|
213
236
|
});
|
|
214
237
|
|
|
215
238
|
// Audit log
|
|
216
|
-
server.tool("lattice_get_audit_log", "Get recent audit log entries (who did what, when)", {
|
|
239
|
+
server.tool("lattice_get_audit_log", "Get recent audit log entries (who did what, when). Filter by user, action, or resource type to answer 'who deleted X' without scanning.", {
|
|
217
240
|
limit: z.number().optional().describe("Number of entries (default 50)"),
|
|
218
|
-
|
|
219
|
-
|
|
241
|
+
offset: z.number().optional().describe("Skip this many entries for pagination"),
|
|
242
|
+
user_id: z.number().optional().describe("Filter by the user who performed the action"),
|
|
243
|
+
action: z.string().optional().describe("Filter by action (e.g. create, update, delete, deploy)"),
|
|
244
|
+
resource_type: z.string().optional().describe("Filter by resource type (e.g. stack, container, worker, registry)"),
|
|
245
|
+
}, async ({ limit, offset, user_id, action, resource_type }) => {
|
|
246
|
+
const res = await api("GET", "/admin/audit-log", { limit, offset, user_id, action, resource_type });
|
|
220
247
|
return { content: text(res) };
|
|
221
248
|
});
|
|
222
249
|
|
|
@@ -559,9 +586,9 @@ server.tool("lattice_delete_backup_destination", "Delete a backup destination. I
|
|
|
559
586
|
return { content: text(res) };
|
|
560
587
|
});
|
|
561
588
|
|
|
562
|
-
server.tool("lattice_test_backup_destination", "Test connectivity and credentials for a backup destination without writing a real backup", {
|
|
589
|
+
server.tool("lattice_test_backup_destination", "Test connectivity and credentials for a backup destination without writing a real backup. The test is dispatched over the worker's WebSocket, so worker_id is required and that worker must be connected", {
|
|
563
590
|
id: z.number().describe("Backup destination ID"),
|
|
564
|
-
worker_id: z.number().
|
|
591
|
+
worker_id: z.number().describe("Worker to run the test from — required; the test runs on this worker over its WebSocket, so it must be connected"),
|
|
565
592
|
}, async ({ id, worker_id }) => {
|
|
566
593
|
const res = await api("POST", `/admin/backup-destinations/${id}/test`, { worker_id });
|
|
567
594
|
return { content: text(res) };
|
|
@@ -682,7 +709,7 @@ server.tool("lattice_get_container_metrics", "Get a single container's CPU, memo
|
|
|
682
709
|
});
|
|
683
710
|
|
|
684
711
|
server.tool("lattice_get_self", "Get the user this API token authenticates as, including role", {}, async () => {
|
|
685
|
-
const res = await api("GET", "/
|
|
712
|
+
const res = await api("GET", "/auth/self");
|
|
686
713
|
return { content: text(res) };
|
|
687
714
|
});
|
|
688
715
|
|
|
@@ -974,7 +1001,7 @@ server.tool("lattice_force_remove_container", "Force-remove a container on a wor
|
|
|
974
1001
|
id: z.number().describe("Worker ID"),
|
|
975
1002
|
name: z.string().describe("Container name to force-remove"),
|
|
976
1003
|
}, async ({ id, name }) => {
|
|
977
|
-
const res = await api("POST", `/admin/workers/${id}/force-remove`, { name });
|
|
1004
|
+
const res = await api("POST", `/admin/workers/${id}/force-remove`, null, { container_name: name });
|
|
978
1005
|
return { content: text(res) };
|
|
979
1006
|
});
|
|
980
1007
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lattice-mcp",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "MCP server for Lattice container orchestration platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"url": "git+https://github.com/aidenappl/lattice-mcp.git"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
28
|
+
"zod": "^4.4.3"
|
|
28
29
|
}
|
|
29
30
|
}
|