@samik081/mcp-komodo 0.1.0
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/LICENSE +21 -0
- package/README.md +294 -0
- package/dist/core/client.d.ts +82 -0
- package/dist/core/client.js +41 -0
- package/dist/core/config.d.ts +22 -0
- package/dist/core/config.js +57 -0
- package/dist/core/errors.d.ts +31 -0
- package/dist/core/errors.js +46 -0
- package/dist/core/formatters.d.ts +36 -0
- package/dist/core/formatters.js +511 -0
- package/dist/core/logger.d.ts +15 -0
- package/dist/core/logger.js +26 -0
- package/dist/core/server.d.ts +15 -0
- package/dist/core/server.js +30 -0
- package/dist/core/tools.d.ts +37 -0
- package/dist/core/tools.js +48 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +44 -0
- package/dist/tools/actions.d.ts +12 -0
- package/dist/tools/actions.js +122 -0
- package/dist/tools/alerters.d.ts +13 -0
- package/dist/tools/alerters.js +84 -0
- package/dist/tools/builders.d.ts +13 -0
- package/dist/tools/builders.js +84 -0
- package/dist/tools/builds.d.ts +13 -0
- package/dist/tools/builds.js +160 -0
- package/dist/tools/containers.d.ts +13 -0
- package/dist/tools/containers.js +81 -0
- package/dist/tools/deployments.d.ts +13 -0
- package/dist/tools/deployments.js +282 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.js +32 -0
- package/dist/tools/procedures.d.ts +13 -0
- package/dist/tools/procedures.js +130 -0
- package/dist/tools/repos.d.ts +13 -0
- package/dist/tools/repos.js +132 -0
- package/dist/tools/resource-syncs.d.ts +13 -0
- package/dist/tools/resource-syncs.js +133 -0
- package/dist/tools/servers.d.ts +12 -0
- package/dist/tools/servers.js +270 -0
- package/dist/tools/stacks.d.ts +13 -0
- package/dist/tools/stacks.js +300 -0
- package/dist/tools/write.d.ts +13 -0
- package/dist/tools/write.js +302 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.js +4 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Komodo MCP Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
[](https://www.npmjs.com/package/@samik081/mcp-komodo)
|
|
2
|
+
[](https://opensource.org/licenses/MIT)
|
|
3
|
+
[](https://nodejs.org)
|
|
4
|
+
|
|
5
|
+
# MCP Komodo
|
|
6
|
+
|
|
7
|
+
MCP server for the [Komodo](https://komo.do) DevOps platform. Manage servers, stacks, deployments, builds, and more through natural language in Cursor, Claude Code, and Claude Desktop.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **40 tools** across **12 resource categories** covering the complete Komodo DevOps API
|
|
12
|
+
- **Three access tiers** (`read-only`, `read-execute`, `full`) for granular control
|
|
13
|
+
- **Category filtering** via `KOMODO_CATEGORIES` to expose only the tools you need
|
|
14
|
+
- **Zero HTTP dependencies** -- uses the official `komodo_client` SDK
|
|
15
|
+
- **TypeScript/ESM** with full type safety
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
Run the server directly with npx:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
KOMODO_URL="https://komodo.example.com" \
|
|
23
|
+
KOMODO_API_KEY="your-api-key" \
|
|
24
|
+
KOMODO_API_SECRET="your-api-secret" \
|
|
25
|
+
npx @samik081/mcp-komodo
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The server validates your Komodo connection on startup and fails immediately with a clear error if credentials are missing or invalid.
|
|
29
|
+
|
|
30
|
+
## Configuration
|
|
31
|
+
|
|
32
|
+
**Claude Code CLI (recommended):**
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
claude mcp add --transport stdio komodo \
|
|
36
|
+
--env KOMODO_URL=https://komodo.example.com \
|
|
37
|
+
--env KOMODO_API_KEY=your-api-key \
|
|
38
|
+
--env KOMODO_API_SECRET=your-api-secret \
|
|
39
|
+
-- npx @samik081/mcp-komodo
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**JSON config** (works with Claude Code `.mcp.json`, Claude Desktop `claude_desktop_config.json`, Cursor `.cursor/mcp.json`):
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"mcpServers": {
|
|
47
|
+
"komodo": {
|
|
48
|
+
"command": "npx",
|
|
49
|
+
"args": ["@samik081/mcp-komodo"],
|
|
50
|
+
"env": {
|
|
51
|
+
"KOMODO_URL": "https://komodo.example.com",
|
|
52
|
+
"KOMODO_API_KEY": "your-api-key",
|
|
53
|
+
"KOMODO_API_SECRET": "your-api-secret"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Access Tiers
|
|
61
|
+
|
|
62
|
+
Control which tools are available using the `KOMODO_ACCESS_TIER` environment variable:
|
|
63
|
+
|
|
64
|
+
| Tier | Tools | Description |
|
|
65
|
+
|------|-------|-------------|
|
|
66
|
+
| `full` (default) | 40 | Read, execute, and write -- full control |
|
|
67
|
+
| `read-execute` | 39 | Read and execute -- no resource creation/deletion via write tool |
|
|
68
|
+
| `read-only` | 25 | Read only -- safe for exploration, no state changes |
|
|
69
|
+
|
|
70
|
+
**Tier details:**
|
|
71
|
+
|
|
72
|
+
- **full**: All 40 tools. Includes `komodo_write_resource` for creating, updating, and deleting Komodo resources.
|
|
73
|
+
- **read-execute**: 39 tools. All read tools plus execute tools (deploy, lifecycle, run, etc.). The `komodo_write_resource` tool is hidden.
|
|
74
|
+
- **read-only**: 25 tools. List, get, logs, and stats only. All execute and write tools are hidden.
|
|
75
|
+
|
|
76
|
+
Tools that are not available in your tier are not registered with the MCP server. They will not appear in your AI tool's tool list, keeping the context clean.
|
|
77
|
+
|
|
78
|
+
Set `KOMODO_ACCESS_TIER` to `read-only`, `read-execute`, or `full` (default: `full`).
|
|
79
|
+
|
|
80
|
+
## Environment Variables
|
|
81
|
+
|
|
82
|
+
| Variable | Required | Description |
|
|
83
|
+
|----------|----------|-------------|
|
|
84
|
+
| `KOMODO_URL` | Yes | URL of your Komodo Core instance |
|
|
85
|
+
| `KOMODO_API_KEY` | Yes | API key for authentication |
|
|
86
|
+
| `KOMODO_API_SECRET` | Yes | API secret for authentication |
|
|
87
|
+
| `KOMODO_ACCESS_TIER` | No | Access tier: `read-only`, `read-execute`, or `full` (default: `full`) |
|
|
88
|
+
| `KOMODO_CATEGORIES` | No | Comma-separated category allowlist (e.g., `servers,stacks,builds`) |
|
|
89
|
+
| `DEBUG` | No | Set to any value to enable debug logging to stderr |
|
|
90
|
+
|
|
91
|
+
Generate API keys in the Komodo UI under **Settings > API Keys**.
|
|
92
|
+
|
|
93
|
+
### Available Categories
|
|
94
|
+
|
|
95
|
+
`servers`, `stacks`, `deployments`, `containers`, `builds`, `repos`, `procedures`, `actions`, `builders`, `alerters`, `resource-syncs`, `write`
|
|
96
|
+
|
|
97
|
+
## Tools
|
|
98
|
+
|
|
99
|
+
mcp-komodo provides 40 tools organized by category. Each tool's Access column shows the minimum tier required: `read-only` (available in all tiers), `read-execute` (requires `read-execute` or `full`), or `full` (requires `full` tier only).
|
|
100
|
+
|
|
101
|
+
<details>
|
|
102
|
+
<summary>Servers (6 tools)</summary>
|
|
103
|
+
|
|
104
|
+
| Tool | Description | Access |
|
|
105
|
+
|------|-------------|--------|
|
|
106
|
+
| `komodo_list_servers` | List all servers with status and region | read-only |
|
|
107
|
+
| `komodo_get_server` | Get server configuration, status, and action state | read-only |
|
|
108
|
+
| `komodo_get_server_stats` | Get CPU, memory, disk usage, and load averages | read-only |
|
|
109
|
+
| `komodo_get_server_info` | Get OS details, hardware info, and running processes | read-only |
|
|
110
|
+
| `komodo_prune_docker` | Prune unused Docker resources on a server | read-execute |
|
|
111
|
+
| `komodo_delete_docker_resource` | Delete a specific Docker image, volume, or network | read-execute |
|
|
112
|
+
|
|
113
|
+
</details>
|
|
114
|
+
|
|
115
|
+
<details>
|
|
116
|
+
<summary>Stacks (6 tools)</summary>
|
|
117
|
+
|
|
118
|
+
| Tool | Description | Access |
|
|
119
|
+
|------|-------------|--------|
|
|
120
|
+
| `komodo_list_stacks` | List all stacks with state, server, and service count | read-only |
|
|
121
|
+
| `komodo_get_stack` | Get stack configuration, services, and action state | read-only |
|
|
122
|
+
| `komodo_get_stack_log` | Get logs from stack services, with optional search | read-only |
|
|
123
|
+
| `komodo_deploy_stack` | Deploy or redeploy a stack | read-execute |
|
|
124
|
+
| `komodo_stack_lifecycle` | Start, stop, restart, pause, or unpause a stack | read-execute |
|
|
125
|
+
| `komodo_destroy_stack` | Permanently destroy a stack | read-execute |
|
|
126
|
+
|
|
127
|
+
</details>
|
|
128
|
+
|
|
129
|
+
<details>
|
|
130
|
+
<summary>Deployments (6 tools)</summary>
|
|
131
|
+
|
|
132
|
+
| Tool | Description | Access |
|
|
133
|
+
|------|-------------|--------|
|
|
134
|
+
| `komodo_list_deployments` | List all deployments with state, image, and server | read-only |
|
|
135
|
+
| `komodo_get_deployment` | Get deployment configuration, container status, and action state | read-only |
|
|
136
|
+
| `komodo_get_deployment_log` | Get container logs, with optional search | read-only |
|
|
137
|
+
| `komodo_deploy_deployment` | Deploy with latest image and configuration | read-execute |
|
|
138
|
+
| `komodo_deployment_lifecycle` | Start, stop, restart, pause, or unpause a deployment | read-execute |
|
|
139
|
+
| `komodo_destroy_deployment` | Permanently destroy a deployment | read-execute |
|
|
140
|
+
|
|
141
|
+
</details>
|
|
142
|
+
|
|
143
|
+
<details>
|
|
144
|
+
<summary>Containers (1 tool)</summary>
|
|
145
|
+
|
|
146
|
+
| Tool | Description | Access |
|
|
147
|
+
|------|-------------|--------|
|
|
148
|
+
| `komodo_get_container_log` | Get logs from any Docker container on a server | read-only |
|
|
149
|
+
|
|
150
|
+
</details>
|
|
151
|
+
|
|
152
|
+
<details>
|
|
153
|
+
<summary>Builds (4 tools)</summary>
|
|
154
|
+
|
|
155
|
+
| Tool | Description | Access |
|
|
156
|
+
|------|-------------|--------|
|
|
157
|
+
| `komodo_list_builds` | List all build configurations with version info | read-only |
|
|
158
|
+
| `komodo_get_build` | Get build configuration, builder, and action state | read-only |
|
|
159
|
+
| `komodo_run_build` | Run a build to create a Docker image | read-execute |
|
|
160
|
+
| `komodo_cancel_build` | Cancel a running build | read-execute |
|
|
161
|
+
|
|
162
|
+
</details>
|
|
163
|
+
|
|
164
|
+
<details>
|
|
165
|
+
<summary>Repos (3 tools)</summary>
|
|
166
|
+
|
|
167
|
+
| Tool | Description | Access |
|
|
168
|
+
|------|-------------|--------|
|
|
169
|
+
| `komodo_list_repos` | List all repos with URL, server, and state | read-only |
|
|
170
|
+
| `komodo_get_repo` | Get repo configuration, branch, and action state | read-only |
|
|
171
|
+
| `komodo_repo_clone_pull` | Clone or pull a repo on its target server | read-execute |
|
|
172
|
+
|
|
173
|
+
</details>
|
|
174
|
+
|
|
175
|
+
<details>
|
|
176
|
+
<summary>Procedures (3 tools)</summary>
|
|
177
|
+
|
|
178
|
+
| Tool | Description | Access |
|
|
179
|
+
|------|-------------|--------|
|
|
180
|
+
| `komodo_list_procedures` | List all procedures with state | read-only |
|
|
181
|
+
| `komodo_get_procedure` | Get procedure stages, operations, and action state | read-only |
|
|
182
|
+
| `komodo_run_procedure` | Run a procedure (executes all stages) | read-execute |
|
|
183
|
+
|
|
184
|
+
</details>
|
|
185
|
+
|
|
186
|
+
<details>
|
|
187
|
+
<summary>Actions (3 tools)</summary>
|
|
188
|
+
|
|
189
|
+
| Tool | Description | Access |
|
|
190
|
+
|------|-------------|--------|
|
|
191
|
+
| `komodo_list_actions` | List all actions with state | read-only |
|
|
192
|
+
| `komodo_get_action` | Get action configuration and action state | read-only |
|
|
193
|
+
| `komodo_run_action` | Run a custom TypeScript/Deno action | read-execute |
|
|
194
|
+
|
|
195
|
+
</details>
|
|
196
|
+
|
|
197
|
+
<details>
|
|
198
|
+
<summary>Builders (2 tools)</summary>
|
|
199
|
+
|
|
200
|
+
| Tool | Description | Access |
|
|
201
|
+
|------|-------------|--------|
|
|
202
|
+
| `komodo_list_builders` | List all builders with type | read-only |
|
|
203
|
+
| `komodo_get_builder` | Get builder type, server configuration, and state | read-only |
|
|
204
|
+
|
|
205
|
+
</details>
|
|
206
|
+
|
|
207
|
+
<details>
|
|
208
|
+
<summary>Alerters (2 tools)</summary>
|
|
209
|
+
|
|
210
|
+
| Tool | Description | Access |
|
|
211
|
+
|------|-------------|--------|
|
|
212
|
+
| `komodo_list_alerters` | List all alerters with type | read-only |
|
|
213
|
+
| `komodo_get_alerter` | Get alerter endpoint type, configuration, and status | read-only |
|
|
214
|
+
|
|
215
|
+
</details>
|
|
216
|
+
|
|
217
|
+
<details>
|
|
218
|
+
<summary>Resource Syncs (3 tools)</summary>
|
|
219
|
+
|
|
220
|
+
| Tool | Description | Access |
|
|
221
|
+
|------|-------------|--------|
|
|
222
|
+
| `komodo_list_resource_syncs` | List all resource syncs with state and repo info | read-only |
|
|
223
|
+
| `komodo_get_resource_sync` | Get sync configuration, managed resources, and state | read-only |
|
|
224
|
+
| `komodo_trigger_sync` | Trigger a GitOps sync from the Git repo | read-execute |
|
|
225
|
+
|
|
226
|
+
</details>
|
|
227
|
+
|
|
228
|
+
<details>
|
|
229
|
+
<summary>Write (1 tool)</summary>
|
|
230
|
+
|
|
231
|
+
| Tool | Description | Access |
|
|
232
|
+
|------|-------------|--------|
|
|
233
|
+
| `komodo_write_resource` | Create, update, or delete any Komodo resource | full |
|
|
234
|
+
|
|
235
|
+
</details>
|
|
236
|
+
|
|
237
|
+
## Verify It Works
|
|
238
|
+
|
|
239
|
+
After configuring your MCP client, ask your AI assistant:
|
|
240
|
+
|
|
241
|
+
> "What servers are connected to Komodo?"
|
|
242
|
+
|
|
243
|
+
If the connection is working, the assistant will call `komodo_list_servers` and return your servers with their current state and region.
|
|
244
|
+
|
|
245
|
+
## Usage Examples
|
|
246
|
+
|
|
247
|
+
Once configured, ask your AI tool questions in natural language:
|
|
248
|
+
|
|
249
|
+
- **"List all my servers and their status"** -- calls `komodo_list_servers` to show every server with its current state and region.
|
|
250
|
+
|
|
251
|
+
- **"What's the CPU and memory usage on server prod-01?"** -- calls `komodo_get_server_stats` to show real-time resource utilization.
|
|
252
|
+
|
|
253
|
+
- **"Show me the logs from the production stack"** -- calls `komodo_get_stack_log` to retrieve recent log output from all services in the stack.
|
|
254
|
+
|
|
255
|
+
- **"Deploy the frontend stack"** -- calls `komodo_deploy_stack` to redeploy the stack with its current configuration.
|
|
256
|
+
|
|
257
|
+
- **"Create a new deployment called api-staging with image myapp:latest"** -- calls `komodo_write_resource` to create a new Deployment resource in Komodo.
|
|
258
|
+
|
|
259
|
+
## Troubleshooting
|
|
260
|
+
|
|
261
|
+
**Connection refused**
|
|
262
|
+
Check that `KOMODO_URL` is correct and that Komodo Core is reachable from where the MCP server is running. The server validates the connection on startup, so if it started successfully, the URL was valid at that time.
|
|
263
|
+
|
|
264
|
+
**Invalid credentials / 401 Unauthorized**
|
|
265
|
+
Verify your API key and secret are correct. Check that the key has not been revoked or expired in the Komodo UI under Settings > API Keys.
|
|
266
|
+
|
|
267
|
+
**Tools not showing up in your AI tool**
|
|
268
|
+
Check your access tier setting. In `read-only` mode, only 25 tools are registered. In `read-execute` mode, 39 tools are registered. Use `full` (or omit `KOMODO_ACCESS_TIER`) for all 40 tools. Check `KOMODO_CATEGORIES` -- only tools in listed categories are registered. Also verify the server started without errors by checking stderr output.
|
|
269
|
+
|
|
270
|
+
**Node.js version errors**
|
|
271
|
+
mcp-komodo requires Node.js >= 18.0.0. Check your version with `node --version`.
|
|
272
|
+
|
|
273
|
+
**Parse errors or "invalid JSON" in MCP client**
|
|
274
|
+
This typically means something is writing to stdout besides the MCP server. Ensure no other tools, shell profiles, or startup scripts print to stdout when launching the server. The MCP protocol uses stdout for JSON-RPC communication. All mcp-komodo logging goes to stderr.
|
|
275
|
+
|
|
276
|
+
## Development
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# Install dependencies
|
|
280
|
+
npm install
|
|
281
|
+
|
|
282
|
+
# Build the project
|
|
283
|
+
npm run build
|
|
284
|
+
|
|
285
|
+
# Run in development mode (auto-reload)
|
|
286
|
+
npm run dev
|
|
287
|
+
|
|
288
|
+
# Open the MCP Inspector for interactive testing
|
|
289
|
+
npm run inspect
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## License
|
|
293
|
+
|
|
294
|
+
MIT
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Komodo API client factory with startup validation.
|
|
3
|
+
*
|
|
4
|
+
* CRITICAL: KomodoClient is a FACTORY FUNCTION -- do NOT use `new`.
|
|
5
|
+
* Sensitive patterns are registered BEFORE the client is created
|
|
6
|
+
* so that any error during initialization is also sanitized.
|
|
7
|
+
*/
|
|
8
|
+
import type { AppConfig } from "./config.js";
|
|
9
|
+
/**
|
|
10
|
+
* Create a Komodo API client from config.
|
|
11
|
+
* Registers credentials as sensitive patterns before creating the client.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createClient(config: AppConfig): {
|
|
14
|
+
auth: <T extends import("komodo_client/dist/types.js").AuthRequest["type"], Req extends Extract<import("komodo_client/dist/types.js").AuthRequest, {
|
|
15
|
+
type: T;
|
|
16
|
+
}>>(type: T, params: Req["params"]) => Promise<import("komodo_client/dist/responses.js").AuthResponses[Req["type"]]>;
|
|
17
|
+
user: <T extends import("komodo_client/dist/types.js").UserRequest["type"], Req extends Extract<import("komodo_client/dist/types.js").UserRequest, {
|
|
18
|
+
type: T;
|
|
19
|
+
}>>(type: T, params: Req["params"]) => Promise<import("komodo_client/dist/responses.js").UserResponses[Req["type"]]>;
|
|
20
|
+
read: <T extends import("komodo_client/dist/types.js").ReadRequest["type"], Req extends Extract<import("komodo_client/dist/types.js").ReadRequest, {
|
|
21
|
+
type: T;
|
|
22
|
+
}>>(type: T, params: Req["params"]) => Promise<import("komodo_client/dist/responses.js").ReadResponses[Req["type"]]>;
|
|
23
|
+
write: <T extends import("komodo_client/dist/types.js").WriteRequest["type"], Req extends Extract<import("komodo_client/dist/types.js").WriteRequest, {
|
|
24
|
+
type: T;
|
|
25
|
+
}>>(type: T, params: Req["params"]) => Promise<import("komodo_client/dist/responses.js").WriteResponses[Req["type"]]>;
|
|
26
|
+
execute: <T extends import("komodo_client/dist/types.js").ExecuteRequest["type"], Req extends Extract<import("komodo_client/dist/types.js").ExecuteRequest, {
|
|
27
|
+
type: T;
|
|
28
|
+
}>>(type: T, params: Req["params"]) => Promise<import("komodo_client/dist/responses.js").ExecuteResponses[Req["type"]]>;
|
|
29
|
+
execute_and_poll: <T extends import("komodo_client/dist/types.js").ExecuteRequest["type"], Req extends Extract<import("komodo_client/dist/types.js").ExecuteRequest, {
|
|
30
|
+
type: T;
|
|
31
|
+
}>>(type: T, params: Req["params"]) => Promise<import("komodo_client/dist/types.js").Update | (import("komodo_client/dist/types.js").Update | {
|
|
32
|
+
status: "Err";
|
|
33
|
+
data: import("komodo_client/dist/types.js").BatchExecutionResponseItemErr;
|
|
34
|
+
})[]>;
|
|
35
|
+
poll_update_until_complete: (update_id: string) => Promise<import("komodo_client/dist/types.js").Update>;
|
|
36
|
+
core_version: () => Promise<string>;
|
|
37
|
+
get_update_websocket: ({ on_update, on_login, on_open, on_close, }: {
|
|
38
|
+
on_update: (update: import("komodo_client/dist/types.js").UpdateListItem) => void;
|
|
39
|
+
on_login?: () => void;
|
|
40
|
+
on_open?: () => void;
|
|
41
|
+
on_close?: () => void;
|
|
42
|
+
}) => WebSocket;
|
|
43
|
+
subscribe_to_update_websocket: ({ on_update, on_open, on_login, on_close, retry, retry_timeout_ms, cancel, on_cancel, }: {
|
|
44
|
+
on_update: (update: import("komodo_client/dist/types.js").UpdateListItem) => void;
|
|
45
|
+
on_login?: () => void;
|
|
46
|
+
on_open?: () => void;
|
|
47
|
+
on_close?: () => void;
|
|
48
|
+
retry?: boolean;
|
|
49
|
+
retry_timeout_ms?: number;
|
|
50
|
+
cancel?: import("komodo_client").CancelToken;
|
|
51
|
+
on_cancel?: () => void;
|
|
52
|
+
}) => Promise<void>;
|
|
53
|
+
connect_terminal: ({ query, on_message, on_login, on_open, on_close, }: {
|
|
54
|
+
query: import("komodo_client/dist/types.js").ConnectTerminalQuery;
|
|
55
|
+
} & import("komodo_client").TerminalCallbacks) => WebSocket;
|
|
56
|
+
execute_terminal: (request: import("komodo_client/dist/types.js").ExecuteTerminalBody, callbacks?: import("komodo_client/dist/terminal.js").ExecuteCallbacks) => Promise<void>;
|
|
57
|
+
execute_terminal_stream: (request: import("komodo_client/dist/types.js").ExecuteTerminalBody) => Promise<AsyncIterable<string>>;
|
|
58
|
+
connect_exec: ({ query: { type, query }, on_message, on_login, on_open, on_close, }: {
|
|
59
|
+
query: import("komodo_client").ConnectExecQuery;
|
|
60
|
+
} & import("komodo_client").TerminalCallbacks) => WebSocket;
|
|
61
|
+
connect_container_exec: ({ query, ...callbacks }: {
|
|
62
|
+
query: import("komodo_client/dist/types.js").ConnectContainerExecQuery;
|
|
63
|
+
} & import("komodo_client").TerminalCallbacks) => WebSocket;
|
|
64
|
+
execute_container_exec: (body: import("komodo_client/dist/types.js").ExecuteContainerExecBody, callbacks?: import("komodo_client/dist/terminal.js").ExecuteCallbacks) => Promise<void>;
|
|
65
|
+
execute_container_exec_stream: (body: import("komodo_client/dist/types.js").ExecuteContainerExecBody) => Promise<AsyncIterable<string>>;
|
|
66
|
+
connect_deployment_exec: ({ query, ...callbacks }: {
|
|
67
|
+
query: import("komodo_client/dist/types.js").ConnectDeploymentExecQuery;
|
|
68
|
+
} & import("komodo_client").TerminalCallbacks) => WebSocket;
|
|
69
|
+
execute_deployment_exec: (body: import("komodo_client/dist/types.js").ExecuteDeploymentExecBody, callbacks?: import("komodo_client/dist/terminal.js").ExecuteCallbacks) => Promise<void>;
|
|
70
|
+
execute_deployment_exec_stream: (body: import("komodo_client/dist/types.js").ExecuteDeploymentExecBody) => Promise<AsyncIterable<string>>;
|
|
71
|
+
connect_stack_exec: ({ query, ...callbacks }: {
|
|
72
|
+
query: import("komodo_client/dist/types.js").ConnectStackExecQuery;
|
|
73
|
+
} & import("komodo_client").TerminalCallbacks) => WebSocket;
|
|
74
|
+
execute_stack_exec: (body: import("komodo_client/dist/types.js").ExecuteStackExecBody, callbacks?: import("komodo_client/dist/terminal.js").ExecuteCallbacks) => Promise<void>;
|
|
75
|
+
execute_stack_exec_stream: (body: import("komodo_client/dist/types.js").ExecuteStackExecBody) => Promise<AsyncIterable<string>>;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Validate connectivity to Komodo by calling GetVersion.
|
|
79
|
+
* Must be called during startup before accepting MCP connections.
|
|
80
|
+
* Exits the process with code 1 if validation fails.
|
|
81
|
+
*/
|
|
82
|
+
export declare function validateConnection(client: ReturnType<typeof createClient>, config: AppConfig): Promise<void>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Komodo API client factory with startup validation.
|
|
3
|
+
*
|
|
4
|
+
* CRITICAL: KomodoClient is a FACTORY FUNCTION -- do NOT use `new`.
|
|
5
|
+
* Sensitive patterns are registered BEFORE the client is created
|
|
6
|
+
* so that any error during initialization is also sanitized.
|
|
7
|
+
*/
|
|
8
|
+
import { KomodoClient } from "komodo_client";
|
|
9
|
+
import { logger } from "./logger.js";
|
|
10
|
+
import { registerSensitivePattern, sanitizeMessage } from "./errors.js";
|
|
11
|
+
/**
|
|
12
|
+
* Create a Komodo API client from config.
|
|
13
|
+
* Registers credentials as sensitive patterns before creating the client.
|
|
14
|
+
*/
|
|
15
|
+
export function createClient(config) {
|
|
16
|
+
registerSensitivePattern(config.apiKey);
|
|
17
|
+
registerSensitivePattern(config.apiSecret);
|
|
18
|
+
return KomodoClient(config.url, {
|
|
19
|
+
type: "api-key",
|
|
20
|
+
params: { key: config.apiKey, secret: config.apiSecret },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Validate connectivity to Komodo by calling GetVersion.
|
|
25
|
+
* Must be called during startup before accepting MCP connections.
|
|
26
|
+
* Exits the process with code 1 if validation fails.
|
|
27
|
+
*/
|
|
28
|
+
export async function validateConnection(client, config) {
|
|
29
|
+
try {
|
|
30
|
+
const version = await client.read("GetVersion", {});
|
|
31
|
+
logger.info(`Connected to Komodo at ${config.url} (version: ${version.version})`);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
logger.error(`Failed to connect to Komodo at ${config.url}`);
|
|
35
|
+
logger.error("Check that KOMODO_URL is correct and Komodo Core is running.");
|
|
36
|
+
if (error instanceof Error) {
|
|
37
|
+
logger.error(`Details: ${sanitizeMessage(error.message)}`);
|
|
38
|
+
}
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment variable parsing and validation.
|
|
3
|
+
* Reads required and optional config from process.env.
|
|
4
|
+
*/
|
|
5
|
+
import type { AccessTier } from '../types/index.js';
|
|
6
|
+
export interface AppConfig {
|
|
7
|
+
url: string;
|
|
8
|
+
apiKey: string;
|
|
9
|
+
apiSecret: string;
|
|
10
|
+
accessTier: AccessTier;
|
|
11
|
+
categories: string[] | null;
|
|
12
|
+
debug: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Load and validate application config from environment variables.
|
|
16
|
+
*
|
|
17
|
+
* Required: KOMODO_URL, KOMODO_API_KEY, KOMODO_API_SECRET
|
|
18
|
+
* Optional: KOMODO_ACCESS_TIER (default: 'full'), KOMODO_CATEGORIES, DEBUG
|
|
19
|
+
*
|
|
20
|
+
* Throws clear error (no credentials in message) if required vars are missing.
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadConfig(): AppConfig;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment variable parsing and validation.
|
|
3
|
+
* Reads required and optional config from process.env.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Determine the access tier from KOMODO_ACCESS_TIER.
|
|
7
|
+
*
|
|
8
|
+
* Valid values: "read-only", "read-execute", "full" (default).
|
|
9
|
+
*/
|
|
10
|
+
function parseAccessTier() {
|
|
11
|
+
const tier = process.env.KOMODO_ACCESS_TIER;
|
|
12
|
+
if (tier === "read-only" || tier === "read-execute") {
|
|
13
|
+
return tier;
|
|
14
|
+
}
|
|
15
|
+
return "full";
|
|
16
|
+
}
|
|
17
|
+
function parseCategories(value) {
|
|
18
|
+
if (value === undefined || value === '') {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return value
|
|
22
|
+
.split(',')
|
|
23
|
+
.map((s) => s.trim())
|
|
24
|
+
.filter((s) => s.length > 0);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Load and validate application config from environment variables.
|
|
28
|
+
*
|
|
29
|
+
* Required: KOMODO_URL, KOMODO_API_KEY, KOMODO_API_SECRET
|
|
30
|
+
* Optional: KOMODO_ACCESS_TIER (default: 'full'), KOMODO_CATEGORIES, DEBUG
|
|
31
|
+
*
|
|
32
|
+
* Throws clear error (no credentials in message) if required vars are missing.
|
|
33
|
+
*/
|
|
34
|
+
export function loadConfig() {
|
|
35
|
+
const url = process.env.KOMODO_URL;
|
|
36
|
+
const apiKey = process.env.KOMODO_API_KEY;
|
|
37
|
+
const apiSecret = process.env.KOMODO_API_SECRET;
|
|
38
|
+
const missing = [];
|
|
39
|
+
if (!url)
|
|
40
|
+
missing.push('KOMODO_URL');
|
|
41
|
+
if (!apiKey)
|
|
42
|
+
missing.push('KOMODO_API_KEY');
|
|
43
|
+
if (!apiSecret)
|
|
44
|
+
missing.push('KOMODO_API_SECRET');
|
|
45
|
+
if (missing.length > 0) {
|
|
46
|
+
throw new Error(`Missing required environment variables: ${missing.join(', ')}. ` +
|
|
47
|
+
'Set these variables to connect to your Komodo instance.');
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
url: url.replace(/\/+$/, ''),
|
|
51
|
+
apiKey: apiKey,
|
|
52
|
+
apiSecret: apiSecret,
|
|
53
|
+
accessTier: parseAccessTier(),
|
|
54
|
+
categories: parseCategories(process.env.KOMODO_CATEGORIES),
|
|
55
|
+
debug: Boolean(process.env.DEBUG),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error sanitization layer.
|
|
3
|
+
*
|
|
4
|
+
* Strips sensitive credentials from error messages before they reach
|
|
5
|
+
* the LLM context. All Komodo API errors should go through
|
|
6
|
+
* handleKomodoError() to produce MCP-compliant error responses
|
|
7
|
+
* with isError: true.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Register a string that should be redacted from all error messages.
|
|
11
|
+
* Called at startup with API key and secret before any API calls.
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerSensitivePattern(pattern: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Replace all registered sensitive patterns and common auth header
|
|
16
|
+
* patterns with [REDACTED].
|
|
17
|
+
*/
|
|
18
|
+
export declare function sanitizeMessage(message: string): string;
|
|
19
|
+
/** MCP-compliant error response type with isError flag. */
|
|
20
|
+
export type McpErrorResponse = {
|
|
21
|
+
content: Array<{
|
|
22
|
+
type: "text";
|
|
23
|
+
text: string;
|
|
24
|
+
}>;
|
|
25
|
+
isError: true;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Wrap a Komodo API error into an MCP-compliant error response.
|
|
29
|
+
* Sanitizes the error message to strip any leaked credentials.
|
|
30
|
+
*/
|
|
31
|
+
export declare function handleKomodoError(context: string, error: unknown): McpErrorResponse;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error sanitization layer.
|
|
3
|
+
*
|
|
4
|
+
* Strips sensitive credentials from error messages before they reach
|
|
5
|
+
* the LLM context. All Komodo API errors should go through
|
|
6
|
+
* handleKomodoError() to produce MCP-compliant error responses
|
|
7
|
+
* with isError: true.
|
|
8
|
+
*/
|
|
9
|
+
/** Mutable array of sensitive strings to redact from error messages. */
|
|
10
|
+
const SENSITIVE_PATTERNS = [];
|
|
11
|
+
/**
|
|
12
|
+
* Register a string that should be redacted from all error messages.
|
|
13
|
+
* Called at startup with API key and secret before any API calls.
|
|
14
|
+
*/
|
|
15
|
+
export function registerSensitivePattern(pattern) {
|
|
16
|
+
if (pattern && pattern.length > 0) {
|
|
17
|
+
SENSITIVE_PATTERNS.push(pattern);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Replace all registered sensitive patterns and common auth header
|
|
22
|
+
* patterns with [REDACTED].
|
|
23
|
+
*/
|
|
24
|
+
export function sanitizeMessage(message) {
|
|
25
|
+
let sanitized = message;
|
|
26
|
+
for (const pattern of SENSITIVE_PATTERNS) {
|
|
27
|
+
sanitized = sanitized.replaceAll(pattern, "[REDACTED]");
|
|
28
|
+
}
|
|
29
|
+
// Strip common auth header patterns
|
|
30
|
+
sanitized = sanitized.replace(/x-api-key:\s*\S+/gi, "x-api-key: [REDACTED]");
|
|
31
|
+
sanitized = sanitized.replace(/x-api-secret:\s*\S+/gi, "x-api-secret: [REDACTED]");
|
|
32
|
+
sanitized = sanitized.replace(/authorization:\s*\S+/gi, "authorization: [REDACTED]");
|
|
33
|
+
return sanitized;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Wrap a Komodo API error into an MCP-compliant error response.
|
|
37
|
+
* Sanitizes the error message to strip any leaked credentials.
|
|
38
|
+
*/
|
|
39
|
+
export function handleKomodoError(context, error) {
|
|
40
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
41
|
+
const safeMessage = sanitizeMessage(rawMessage);
|
|
42
|
+
return {
|
|
43
|
+
content: [{ type: "text", text: `Error ${context}: ${safeMessage}` }],
|
|
44
|
+
isError: true,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared response formatting functions for all Komodo resource types.
|
|
3
|
+
*
|
|
4
|
+
* Every formatter converts typed API responses into concise, LLM-friendly
|
|
5
|
+
* plain text. No raw JSON is ever returned. Lists use one line per resource.
|
|
6
|
+
* Details show key fields only, not every config option.
|
|
7
|
+
*/
|
|
8
|
+
import { Types } from "komodo_client";
|
|
9
|
+
export declare function formatServerList(servers: Types.ServerListItem[]): string;
|
|
10
|
+
export declare function formatServerDetail(server: Types.Server, actionState?: Types.ServerActionState): string;
|
|
11
|
+
export declare function formatSystemStats(stats: Types.SystemStats): string;
|
|
12
|
+
export declare function formatSystemInfo(info: Types.SystemInformation): string;
|
|
13
|
+
export declare function formatProcessList(processes: Types.SystemProcess[]): string;
|
|
14
|
+
export declare function formatStackList(stacks: Types.StackListItem[]): string;
|
|
15
|
+
export declare function formatStackDetail(stack: Types.Stack, actionState?: Types.StackActionState): string;
|
|
16
|
+
export declare function formatDeploymentList(deployments: Types.DeploymentListItem[]): string;
|
|
17
|
+
export declare function formatDeploymentDetail(deployment: Types.Deployment, actionState?: Types.DeploymentActionState): string;
|
|
18
|
+
export declare function formatBuildList(builds: Types.BuildListItem[]): string;
|
|
19
|
+
export declare function formatBuildDetail(build: Types.Build, actionState?: Types.BuildActionState): string;
|
|
20
|
+
export declare function formatRepoList(repos: Types.RepoListItem[]): string;
|
|
21
|
+
export declare function formatRepoDetail(repo: Types.Repo, actionState?: Types.RepoActionState): string;
|
|
22
|
+
export declare function formatProcedureList(procedures: Types.ProcedureListItem[]): string;
|
|
23
|
+
export declare function formatProcedureDetail(procedure: Types.Procedure, actionState?: Types.ProcedureActionState): string;
|
|
24
|
+
export declare function formatActionList(actions: Types.ActionListItem[]): string;
|
|
25
|
+
export declare function formatActionDetail(action: Types.Action, actionState?: Types.ActionActionState): string;
|
|
26
|
+
export declare function formatBuilderList(builders: Types.BuilderListItem[]): string;
|
|
27
|
+
export declare function formatBuilderDetail(builder: Types.Builder, actionState?: Record<string, boolean>): string;
|
|
28
|
+
export declare function formatAlerterList(alerters: Types.AlerterListItem[]): string;
|
|
29
|
+
export declare function formatAlerterDetail(alerter: Types.Alerter): string;
|
|
30
|
+
export declare function formatResourceSyncList(syncs: Types.ResourceSyncListItem[]): string;
|
|
31
|
+
export declare function formatResourceSyncDetail(sync: Types.ResourceSync, actionState?: Types.ResourceSyncActionState): string;
|
|
32
|
+
export declare function formatLog(log: Types.Log): string;
|
|
33
|
+
export declare function formatResourceCreated(resourceType: string, resource: any): string;
|
|
34
|
+
export declare function formatResourceUpdated(resourceType: string, resource: any): string;
|
|
35
|
+
export declare function formatResourceDeleted(resourceType: string, resource: any): string;
|
|
36
|
+
export declare function formatUpdateCreated(update: Types.Update, description: string): string;
|