@matthesketh/utopia-cli 0.7.0 → 0.7.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/dist/index.js +164 -0
- package/package.json +8 -8
- package/LICENSE +0 -21
package/dist/index.js
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { existsSync } from "fs";
|
|
5
5
|
import { resolve } from "path";
|
|
6
|
+
import { createInterface } from "readline";
|
|
6
7
|
import { createRequire } from "module";
|
|
8
|
+
import { execSync } from "child_process";
|
|
7
9
|
import {
|
|
8
10
|
createServer,
|
|
9
11
|
build as viteBuild,
|
|
@@ -103,6 +105,160 @@ async function test(args) {
|
|
|
103
105
|
});
|
|
104
106
|
await vitest?.close();
|
|
105
107
|
}
|
|
108
|
+
var CONTENT_CONFIG_FILES = [
|
|
109
|
+
"content.config.ts",
|
|
110
|
+
"content.config.js",
|
|
111
|
+
"content.config.mjs",
|
|
112
|
+
"content.config.mts"
|
|
113
|
+
];
|
|
114
|
+
function findContentConfig() {
|
|
115
|
+
return CONTENT_CONFIG_FILES.find((f) => existsSync(resolve(process.cwd(), f)));
|
|
116
|
+
}
|
|
117
|
+
async function mcpServe() {
|
|
118
|
+
const configFile = findContentConfig();
|
|
119
|
+
if (!configFile) {
|
|
120
|
+
process.stderr.write(
|
|
121
|
+
"No content.config found. utopia mcp serve requires @matthesketh/utopia-content.\n"
|
|
122
|
+
);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
const server = await createServer({
|
|
126
|
+
mode: "production",
|
|
127
|
+
logLevel: "silent",
|
|
128
|
+
server: { middlewareMode: true },
|
|
129
|
+
plugins: [utopia()]
|
|
130
|
+
});
|
|
131
|
+
let handleRequest;
|
|
132
|
+
try {
|
|
133
|
+
await server.ssrLoadModule(resolve(process.cwd(), configFile));
|
|
134
|
+
const content = await server.ssrLoadModule("@matthesketh/utopia-content");
|
|
135
|
+
const names = content.listCollections();
|
|
136
|
+
if (names.length === 0) {
|
|
137
|
+
process.stderr.write(
|
|
138
|
+
"No collections defined. Add defineCollection() calls to your config.\n"
|
|
139
|
+
);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
const contentMcp = await server.ssrLoadModule("@matthesketh/utopia-content/mcp");
|
|
143
|
+
const collectionMap = /* @__PURE__ */ new Map();
|
|
144
|
+
for (const name of names) {
|
|
145
|
+
const col = content.getCollectionAdapter(name);
|
|
146
|
+
if (col) collectionMap.set(name, col);
|
|
147
|
+
}
|
|
148
|
+
const tools = contentMcp.createContentTools(() => collectionMap);
|
|
149
|
+
const toolMap = new Map(tools.map((t) => [t.definition.name, t]));
|
|
150
|
+
const serverInfo = { name: "utopia-content", version: "1.0.0" };
|
|
151
|
+
handleRequest = async (request) => {
|
|
152
|
+
try {
|
|
153
|
+
let result;
|
|
154
|
+
switch (request.method) {
|
|
155
|
+
case "initialize":
|
|
156
|
+
result = {
|
|
157
|
+
protocolVersion: "2024-11-05",
|
|
158
|
+
capabilities: { tools: {} },
|
|
159
|
+
serverInfo
|
|
160
|
+
};
|
|
161
|
+
break;
|
|
162
|
+
case "tools/list":
|
|
163
|
+
result = {
|
|
164
|
+
tools: tools.map((t) => ({
|
|
165
|
+
name: t.definition.name,
|
|
166
|
+
description: t.definition.description,
|
|
167
|
+
inputSchema: t.definition.inputSchema
|
|
168
|
+
}))
|
|
169
|
+
};
|
|
170
|
+
break;
|
|
171
|
+
case "tools/call": {
|
|
172
|
+
const params = request.params;
|
|
173
|
+
const tool = toolMap.get(params.name);
|
|
174
|
+
if (!tool) {
|
|
175
|
+
return {
|
|
176
|
+
jsonrpc: "2.0",
|
|
177
|
+
id: request.id,
|
|
178
|
+
error: { code: -32602, message: `Unknown tool: ${params.name}` }
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
result = await tool.handler(params.arguments ?? {});
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
case "ping":
|
|
185
|
+
result = {};
|
|
186
|
+
break;
|
|
187
|
+
default:
|
|
188
|
+
return {
|
|
189
|
+
jsonrpc: "2.0",
|
|
190
|
+
id: request.id,
|
|
191
|
+
error: { code: -32601, message: `Method not found: ${request.method}` }
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return { jsonrpc: "2.0", id: request.id, result };
|
|
195
|
+
} catch (err) {
|
|
196
|
+
const e = err;
|
|
197
|
+
return {
|
|
198
|
+
jsonrpc: "2.0",
|
|
199
|
+
id: request.id,
|
|
200
|
+
error: { code: e.code ?? -32603, message: e.message ?? "Internal error" }
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
} catch (err) {
|
|
205
|
+
await server.close();
|
|
206
|
+
throw err;
|
|
207
|
+
}
|
|
208
|
+
await server.close();
|
|
209
|
+
const rl = createInterface({ input: process.stdin });
|
|
210
|
+
for await (const line of rl) {
|
|
211
|
+
if (!line.trim()) continue;
|
|
212
|
+
try {
|
|
213
|
+
const request = JSON.parse(line);
|
|
214
|
+
if (request.id == null) continue;
|
|
215
|
+
const response = await handleRequest(request);
|
|
216
|
+
process.stdout.write(JSON.stringify(response) + "\n");
|
|
217
|
+
} catch {
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function mcpInstall() {
|
|
222
|
+
try {
|
|
223
|
+
execSync("claude --version", { stdio: "ignore" });
|
|
224
|
+
} catch {
|
|
225
|
+
console.error(
|
|
226
|
+
"Claude Code CLI not found. Install it first: npm i -g @anthropic-ai/claude-code"
|
|
227
|
+
);
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
execSync("claude mcp add utopia-content -s project -- npx utopia mcp serve", {
|
|
232
|
+
stdio: "inherit",
|
|
233
|
+
cwd: process.cwd()
|
|
234
|
+
});
|
|
235
|
+
console.log("\nUtopiaJS MCP server registered with Claude Code.");
|
|
236
|
+
console.log("Claude Code can now manage your content collections.");
|
|
237
|
+
} catch (err) {
|
|
238
|
+
const e = err;
|
|
239
|
+
console.error("Failed to register MCP server:", e.message);
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function printMcpHelp() {
|
|
244
|
+
console.log(`
|
|
245
|
+
utopia mcp \u2014 MCP server for Claude Code integration
|
|
246
|
+
|
|
247
|
+
Usage:
|
|
248
|
+
utopia mcp <subcommand>
|
|
249
|
+
|
|
250
|
+
Subcommands:
|
|
251
|
+
install Register the UtopiaJS content MCP server with Claude Code
|
|
252
|
+
serve Start the MCP server over stdio (used by Claude Code)
|
|
253
|
+
|
|
254
|
+
The MCP server exposes your content collections as tools:
|
|
255
|
+
list_collections, list_entries, get_entry, create_entry,
|
|
256
|
+
update_entry, delete_entry, search_entries, list_tags, publish_entry
|
|
257
|
+
|
|
258
|
+
Quick start:
|
|
259
|
+
utopia mcp install
|
|
260
|
+
`);
|
|
261
|
+
}
|
|
106
262
|
function printVersion() {
|
|
107
263
|
const require2 = createRequire(import.meta.url);
|
|
108
264
|
const pkg = require2("../package.json");
|
|
@@ -120,6 +276,7 @@ function printHelp() {
|
|
|
120
276
|
build Build for production
|
|
121
277
|
preview Preview production build
|
|
122
278
|
test Run component tests
|
|
279
|
+
mcp Claude Code MCP server integration
|
|
123
280
|
create Create a new project
|
|
124
281
|
|
|
125
282
|
Options:
|
|
@@ -147,6 +304,13 @@ async function main() {
|
|
|
147
304
|
case "test":
|
|
148
305
|
await test(args);
|
|
149
306
|
break;
|
|
307
|
+
case "mcp": {
|
|
308
|
+
const sub = args.rest[0];
|
|
309
|
+
if (sub === "serve") await mcpServe();
|
|
310
|
+
else if (sub === "install") mcpInstall();
|
|
311
|
+
else printMcpHelp();
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
150
314
|
case "create":
|
|
151
315
|
console.log("To create a new UtopiaJS project, run:");
|
|
152
316
|
console.log(" npx create-utopia [project-name]");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matthesketh/utopia-cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "CLI for the UtopiaJS framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,9 +30,13 @@
|
|
|
30
30
|
"files": [
|
|
31
31
|
"dist"
|
|
32
32
|
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsup src/index.ts --format esm",
|
|
35
|
+
"dev": "tsup src/index.ts --format esm --watch"
|
|
36
|
+
},
|
|
33
37
|
"dependencies": {
|
|
34
|
-
"@matthesketh/utopia-
|
|
35
|
-
"@matthesketh/utopia-
|
|
38
|
+
"@matthesketh/utopia-vite-plugin": "^0.7.x",
|
|
39
|
+
"@matthesketh/utopia-test": "^0.7.x"
|
|
36
40
|
},
|
|
37
41
|
"peerDependencies": {
|
|
38
42
|
"vite": "^6.0.0 || ^7.0.0",
|
|
@@ -40,9 +44,5 @@
|
|
|
40
44
|
},
|
|
41
45
|
"devDependencies": {
|
|
42
46
|
"vite": "^7.3.1"
|
|
43
|
-
},
|
|
44
|
-
"scripts": {
|
|
45
|
-
"build": "tsup src/index.ts --format esm",
|
|
46
|
-
"dev": "tsup src/index.ts --format esm --watch"
|
|
47
47
|
}
|
|
48
|
-
}
|
|
48
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Matt Hesketh
|
|
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.
|