@sawala/kodena-mcp 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.
Files changed (3) hide show
  1. package/README.md +268 -0
  2. package/dist/server.js +28152 -0
  3. package/package.json +54 -0
package/README.md ADDED
@@ -0,0 +1,268 @@
1
+ # @sawala/kodena-mcp
2
+
3
+ Drive the Kodena API from any [MCP](https://modelcontextprotocol.io)-capable
4
+ AI agent — Claude Desktop, Claude Code, Cursor, Continue.dev, Zed, and any
5
+ other host that speaks the Model Context Protocol.
6
+
7
+ The server runs as a short-lived Node process on the user's machine,
8
+ spawned by the MCP host. It reuses the credentials written by the
9
+ `@sawala/kodena` CLI, talks JSON-RPC over stdio with the host, and makes
10
+ HTTPS calls to `api.sawala.cloud` on the user's behalf.
11
+
12
+ ```
13
+ ┌─────────────────────┐ stdio JSON-RPC ┌──────────────────┐
14
+ │ Claude Desktop / │ ───────────────────────────────▶ │ kodena-mcp │
15
+ │ Claude Code / │ ◀─────────────────────────────── │ (node process │
16
+ │ Cursor / … │ │ on your laptop) │
17
+ └─────────────────────┘ └─────────┬────────┘
18
+ │ HTTPS
19
+
20
+ ┌──────────────────┐
21
+ │ api.sawala.cloud │
22
+ └──────────────────┘
23
+ ```
24
+
25
+ ## Quick start
26
+
27
+ 1. **Log in once** via the CLI (writes `~/.kodena/credentials`):
28
+
29
+ ```sh
30
+ npm i -g @sawala/kodena
31
+ kodena login
32
+ ```
33
+
34
+ 2. **Wire the MCP server into your host.** Pick the snippet for your tool below.
35
+
36
+ 3. **Ask the agent in plain English.** "List my Kodena scripts."
37
+ "What's my org handle?" "Deploy `./.open-next` to `my-blog`."
38
+
39
+ ## Host configuration
40
+
41
+ ### Claude Desktop
42
+
43
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
44
+ or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "kodena": {
50
+ "command": "npx",
51
+ "args": ["-y", "@sawala/kodena-mcp"]
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ Restart Claude Desktop. The "kodena" server appears in the MCP servers
58
+ list with 18 tools available (or 8, in read-only mode — see below).
59
+
60
+ ### Claude Code
61
+
62
+ ```sh
63
+ claude mcp add kodena -- npx -y @sawala/kodena-mcp
64
+ ```
65
+
66
+ ### Cursor
67
+
68
+ Edit `~/.cursor/mcp.json`:
69
+
70
+ ```json
71
+ {
72
+ "mcpServers": {
73
+ "kodena": {
74
+ "command": "npx",
75
+ "args": ["-y", "@sawala/kodena-mcp"]
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ ### Local-build testing
82
+
83
+ To point a host at a locally built binary (e.g. for development against
84
+ `main`):
85
+
86
+ ```json
87
+ {
88
+ "mcpServers": {
89
+ "kodena": {
90
+ "command": "node",
91
+ "args": ["/absolute/path/to/cli/packages/kodena-mcp/dist/server.js"]
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
97
+ ## Authentication
98
+
99
+ The server reads `~/.kodena/credentials` (written by `kodena login`) on
100
+ every tool call — so `kodena org use <slug>` in a separate terminal
101
+ takes effect on the very next call without restarting the host.
102
+
103
+ For non-interactive environments (CI runners, sandboxed agents), pass
104
+ the token via the MCP server's env:
105
+
106
+ ```json
107
+ {
108
+ "mcpServers": {
109
+ "kodena": {
110
+ "command": "npx",
111
+ "args": ["-y", "@sawala/kodena-mcp"],
112
+ "env": {
113
+ "KODENA_API_TOKEN": "koda_…",
114
+ "KODENA_ORG": "acme"
115
+ }
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ The server NEVER writes to `~/.kodena/credentials` or `~/.kodena/config` —
122
+ token minting and org/project switching remain the CLI's job. To see the
123
+ context the server is using (with the token redacted), an agent can read
124
+ the `kodena://config` resource.
125
+
126
+ ## Tools
127
+
128
+ ### Read (always safe)
129
+
130
+ | Tool | API | Description |
131
+ | --- | --- | --- |
132
+ | `kodena_whoami` | `GET /me` | Identity + active org/project context |
133
+ | `kodena_list_orgs` | `GET /me/orgs` | Memberships, with active + scope flags |
134
+ | `kodena_list_projects` | `GET /projects` | Projects in the active org |
135
+ | `kodena_list_scripts` | `GET /kodena/scripts` | Scripts in the active org, with resolved public URLs |
136
+ | `kodena_get_script` | `GET /kodena/scripts/:slug` | Single script's full row |
137
+ | `kodena_check_slug_available` | `GET /kodena/scripts/slug-available` | Availability check before create |
138
+ | `kodena_get_org_handle` | `GET /kodena/org-handle` | Active org's claimed handle, or null |
139
+ | `kodena_get_custom_domain_status` | `GET /kodena/scripts/:slug/custom-domain-status` | SSL/DNS provisioning state |
140
+
141
+ ### Write (non-destructive)
142
+
143
+ | Tool | API | Description |
144
+ | --- | --- | --- |
145
+ | `kodena_create_script` | `POST /kodena/scripts` | Reserve a new slug (no code uploaded yet) |
146
+ | `kodena_update_script` | `PATCH /kodena/scripts/:slug` | Update metadata (currently: `name`) |
147
+ | `kodena_set_org_handle` | `PUT /kodena/org-handle` | Claim the org's immutable handle |
148
+
149
+ ### Destructive / deploy
150
+
151
+ Every tool here is flagged `destructiveHint: true`; the host surfaces a
152
+ confirmation prompt before invoking. `kodena_delete_script` additionally
153
+ carries `irreversibleHint: true` AND requires an input-level
154
+ `confirm: true` literal — both must agree.
155
+
156
+ | Tool | API | Description |
157
+ | --- | --- | --- |
158
+ | `kodena_deploy_script` | `POST /kodena/scripts/:slug/deploy` | Upload a worker bundle from local paths (10 MiB worker, 100 MiB assets). Supports `dryRun: true` to confirm bundle size first. |
159
+ | `kodena_set_custom_domain` | `POST .../custom-domain` | Attach a hostname (`openWorldHint`: affects DNS) |
160
+ | `kodena_remove_custom_domain` | `DELETE .../custom-domain` | Detach (`openWorldHint`) |
161
+ | `kodena_delete_script` | `DELETE /kodena/scripts/:slug` | `irreversibleHint`; requires `confirm: true` |
162
+ | `kodena_rebuild_assets_manifest` | `POST .../assets/rebuild-manifest` | Resync manifest with stored objects |
163
+ | `kodena_patch_assets` | `POST .../assets/patch` | Add/replace specific asset files (10 MiB per file, 25 MiB aggregate) |
164
+ | `kodena_rehydrate_script` | `POST .../rehydrate` | Re-push stored bundle to Cloudflare |
165
+
166
+ ## Resources
167
+
168
+ | URI | Description |
169
+ | --- | --- |
170
+ | `kodena://config` | Merged view of `~/.kodena/credentials` + `~/.kodena/config` + relevant `KODENA_*` env vars. The bearer token is replaced by `"REDACTED"` (or `"(none)"` when absent). |
171
+ | `kodena://scripts/{slug}/manifest` | Read-only snapshot of a script's row, including its asset manifest. Replace `{slug}` with the script slug. |
172
+
173
+ ## Prompts
174
+
175
+ | Name | Argument | Description |
176
+ | --- | --- | --- |
177
+ | `deploy-current-project` | optional `slug` | Walk the agent through: read config → list scripts → check `./.open-next/worker.js` → dry-run deploy → confirm → deploy. |
178
+
179
+ ## Read-only mode
180
+
181
+ For agents you don't fully trust, set `KODENA_MCP_READ_ONLY=1` in the
182
+ MCP server's env:
183
+
184
+ ```json
185
+ {
186
+ "mcpServers": {
187
+ "kodena": {
188
+ "command": "npx",
189
+ "args": ["-y", "@sawala/kodena-mcp"],
190
+ "env": { "KODENA_MCP_READ_ONLY": "1" }
191
+ }
192
+ }
193
+ }
194
+ ```
195
+
196
+ `tools/list` will then expose only the 8 read tools; the 10 write/destructive
197
+ tools are not registered at all. `tools/call` on any of them returns
198
+ `-32602 InvalidInput "Unknown tool"`.
199
+
200
+ ## Error codes
201
+
202
+ The server uses JSON-RPC's implementation-defined range:
203
+
204
+ | Code | Meaning | Common causes |
205
+ | --- | --- | --- |
206
+ | `-32001` | Unauthenticated | `~/.kodena/credentials` missing; expired/revoked token (re-run `kodena login`) |
207
+ | `-32002` | Not found | Script slug doesn't exist; manifest URI for a deleted script |
208
+ | `-32003` | Forbidden | Token scoped to a different org; insufficient permissions |
209
+ | `-32602` | Invalid params | Schema violation (bad slug, missing field); unknown tool name |
210
+ | `-32000` | Generic | Other backend errors (5xx, unexpected shapes) |
211
+
212
+ ## Troubleshooting
213
+
214
+ **"Not logged in" on every tool call.** Run `kodena login` in a terminal,
215
+ then try again — the server picks up the new credentials on the next call.
216
+
217
+ **Claude Desktop shows "kodena: server disconnected".** Open the host's
218
+ MCP log panel. The most common cause is a stray write to stdout from
219
+ something other than JSON-RPC; this server routes all human-readable
220
+ output to stderr, so the culprit is usually a corrupt npm cache or a
221
+ shell rc-file that prints to stdout. Try `npx --yes --cache /tmp/npx-kodena-mcp @sawala/kodena-mcp --version`
222
+ to confirm the binary itself is clean.
223
+
224
+ **`npx -y` is slow on first start.** Expected — npx downloads the
225
+ package on cold start. Warm cache should be under 2s. To eliminate
226
+ the download entirely, install globally: `npm i -g @sawala/kodena-mcp`
227
+ and use `"command": "kodena-mcp"`.
228
+
229
+ **Deploy fails with "Worker module is N bytes; max 10485760".** Your
230
+ built `worker.js` is over the 10 MiB cap. The CLI's `bundle.ts` enforces
231
+ this server-side; the limit comes from Cloudflare. Lazy-load heavy
232
+ dependencies or split into multiple scripts.
233
+
234
+ ## Development
235
+
236
+ This package lives in the [`sawala-tech/cli`](https://github.com/sawala-tech/cli)
237
+ monorepo:
238
+
239
+ ```sh
240
+ git clone https://github.com/sawala-tech/cli
241
+ cd cli
242
+ npm ci
243
+ npm --workspace packages/kodena-mcp run typecheck
244
+ npm --workspace packages/kodena-mcp run test
245
+ npm --workspace packages/kodena-mcp run build
246
+ ```
247
+
248
+ Inspect the built server with the official MCP Inspector:
249
+
250
+ ```sh
251
+ npx @modelcontextprotocol/inspector ./packages/kodena-mcp/dist/server.js
252
+ ```
253
+
254
+ ## Architecture
255
+
256
+ This server reuses the `@sawala/kodena` CLI's library layer verbatim —
257
+ `api.ts`, `resolve.ts`, `credentials.ts`, `config.ts`, `bundle.ts` —
258
+ via relative imports across the workspace. Auth, scope checks, deploy
259
+ bundling, and var validation are NOT re-implemented. If the CLI's
260
+ library layer is refactored, the MCP server moves with it.
261
+
262
+ The plan that drove this implementation lives at
263
+ [`docs/plan/kodena/PLAN-kodena-mcp-server.md`](https://github.com/sawala-tech/sawala-cloud/blob/main/docs/plan/kodena/PLAN-kodena-mcp-server.md)
264
+ in the `sawala-cloud` repo.
265
+
266
+ ## License
267
+
268
+ MIT. See [`LICENSE`](../../LICENSE).