doc2mcp 0.1.15 → 0.1.17
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/README.md +34 -8
- package/dist/index.js +185 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="
|
|
3
|
+
<img src="https://doc2mcp.site/doc2mcp-cli-banner.png" alt="doc2mcp — turn any docs site into a hosted MCP server from your terminal" width="100%" />
|
|
4
4
|
|
|
5
5
|
# doc2mcp
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ Point it at a docs URL, and doc2mcp crawls, analyzes, and serves it as a token-s
|
|
|
13
13
|
[](https://nodejs.org)
|
|
14
14
|
[](https://github.com/gautammanak1/doc2mcp/blob/main/LICENSE)
|
|
15
15
|
|
|
16
|
-
[Website](https://doc2mcp.site) · [
|
|
16
|
+
[Website](https://doc2mcp.site) · [CLI](https://doc2mcp.site/cli) · [Docs](https://doc2mcp.site/docs) · [CLI guide](https://doc2mcp.site/docs/cli)
|
|
17
17
|
|
|
18
18
|
</div>
|
|
19
19
|
|
|
@@ -51,11 +51,13 @@ doc2mcp https://docs.stripe.com
|
|
|
51
51
|
|
|
52
52
|
# 3. When it's ready, pick your editor — the MCP is installed for you
|
|
53
53
|
# ✔ Cursor ✔ VS Code ✔ Claude Desktop ✔ Windsurf
|
|
54
|
+
|
|
55
|
+
# 4. Chat with your docs without leaving the terminal
|
|
56
|
+
doc2mcp chat
|
|
54
57
|
```
|
|
55
58
|
|
|
56
|
-
That's it. The same hosted pipeline powers the [website](https://doc2mcp.site)
|
|
57
|
-
|
|
58
|
-
dashboard and marketplace too.
|
|
59
|
+
That's it. The same hosted pipeline powers the [website](https://doc2mcp.site), so a project you
|
|
60
|
+
create in the CLI shows up in your dashboard and marketplace too.
|
|
59
61
|
|
|
60
62
|
## Commands
|
|
61
63
|
|
|
@@ -67,6 +69,7 @@ dashboard and marketplace too.
|
|
|
67
69
|
| [`doc2mcp whoami`](#doc2mcp-whoami) | Show the account you're signed in as |
|
|
68
70
|
| [`doc2mcp list`](#doc2mcp-list) | List the MCP projects on your account |
|
|
69
71
|
| [`doc2mcp install <projectId>`](#doc2mcp-install-projectid) | Install an existing MCP into your editors |
|
|
72
|
+
| [`doc2mcp chat [projectId]`](#doc2mcp-chat-projectid) | Chat with your docs in the terminal (AI answers from your MCP) |
|
|
70
73
|
| `doc2mcp --version` | Print the installed CLI version |
|
|
71
74
|
| `doc2mcp --help` | Show usage and all commands |
|
|
72
75
|
|
|
@@ -92,7 +95,7 @@ Tips:
|
|
|
92
95
|
- Point at the **docs** URL (`https://docs.stripe.com`), not the marketing homepage.
|
|
93
96
|
- The URL must start with `http://` or `https://`.
|
|
94
97
|
- Conversions count against your plan's monthly limit (free includes 5/month), shared with the
|
|
95
|
-
website
|
|
98
|
+
website and chat.
|
|
96
99
|
|
|
97
100
|
---
|
|
98
101
|
|
|
@@ -161,6 +164,29 @@ You'll be prompted to choose which detected clients to write to:
|
|
|
161
164
|
|
|
162
165
|
Existing config is merged, not overwritten.
|
|
163
166
|
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### `doc2mcp chat [projectId]`
|
|
170
|
+
|
|
171
|
+
Chat with your docs **right from the terminal**. doc2mcp answers natural-language questions from
|
|
172
|
+
the crawled documentation — with cited sources — using the project's hosted MCP (the same
|
|
173
|
+
`ask_documentation` tool your editor calls). This is the Playground experience, in your shell.
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Interactive: choose a project, then ask anything
|
|
177
|
+
doc2mcp chat
|
|
178
|
+
|
|
179
|
+
# Skip the picker by passing a project ID
|
|
180
|
+
doc2mcp chat prj_123abc
|
|
181
|
+
|
|
182
|
+
# One-shot answer (handy in scripts / CI)
|
|
183
|
+
doc2mcp chat prj_123abc -m "How do I authenticate requests?"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
- With no arguments, you pick from your `ready` projects.
|
|
187
|
+
- Type `/exit` (or press Esc) to leave an interactive session.
|
|
188
|
+
- Each answer lists the source pages it used so you can verify it.
|
|
189
|
+
|
|
164
190
|
## Configuration
|
|
165
191
|
|
|
166
192
|
| Setting | Default | Notes |
|
|
@@ -175,7 +201,7 @@ Existing config is merged, not overwritten.
|
|
|
175
201
|
| `command not found: doc2mcp` | You installed locally or your shell cached PATH. Reinstall with `npm i -g doc2mcp`, then run `hash -r` or open a new terminal. You can also use `npx doc2mcp <url>`. |
|
|
176
202
|
| Browser doesn't open on `login` | Copy the printed URL into your browser manually, then approve. |
|
|
177
203
|
| `login` can't reach the server | Confirm you're online; for self-hosting set `DOC2MCP_API_URL` to your instance. |
|
|
178
|
-
| "Limit reached" | You've hit your plan's monthly conversion limit (shared across CLI
|
|
204
|
+
| "Limit reached" | You've hit your plan's monthly conversion limit (shared across CLI and web). |
|
|
179
205
|
| Editor doesn't pick up the MCP | Fully restart the editor after install so it reloads MCP config. |
|
|
180
206
|
|
|
181
207
|
## How it works
|
|
@@ -209,7 +235,7 @@ already exists).
|
|
|
209
235
|
|
|
210
236
|
- 📦 npm: https://www.npmjs.com/package/doc2mcp
|
|
211
237
|
- 🌐 Website: https://doc2mcp.site
|
|
212
|
-
-
|
|
238
|
+
- 🖥️ CLI page: https://doc2mcp.site/cli
|
|
213
239
|
- 📚 Docs: https://doc2mcp.site/docs
|
|
214
240
|
- 🧭 CLI guide: https://doc2mcp.site/docs/cli
|
|
215
241
|
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import
|
|
5
|
+
import pc7 from "picocolors";
|
|
6
6
|
|
|
7
7
|
// src/commands/account.ts
|
|
8
8
|
import pc from "picocolors";
|
|
@@ -73,8 +73,10 @@ async function runWhoami() {
|
|
|
73
73
|
`);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// src/commands/
|
|
77
|
-
import
|
|
76
|
+
// src/commands/chat.ts
|
|
77
|
+
import { cancel, intro, isCancel, outro, select, text } from "@clack/prompts";
|
|
78
|
+
import ora2 from "ora";
|
|
79
|
+
import pc4 from "picocolors";
|
|
78
80
|
|
|
79
81
|
// src/api.ts
|
|
80
82
|
import pc2 from "picocolors";
|
|
@@ -88,14 +90,14 @@ var ApiError = class extends Error {
|
|
|
88
90
|
}
|
|
89
91
|
};
|
|
90
92
|
async function parseJson(response) {
|
|
91
|
-
const
|
|
92
|
-
if (!
|
|
93
|
+
const text2 = await response.text();
|
|
94
|
+
if (!text2) {
|
|
93
95
|
return null;
|
|
94
96
|
}
|
|
95
97
|
try {
|
|
96
|
-
return JSON.parse(
|
|
98
|
+
return JSON.parse(text2);
|
|
97
99
|
} catch {
|
|
98
|
-
return { raw:
|
|
100
|
+
return { raw: text2 };
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
async function apiFetch(path, options = {}) {
|
|
@@ -230,9 +232,151 @@ async function ensureLoggedIn() {
|
|
|
230
232
|
}
|
|
231
233
|
}
|
|
232
234
|
|
|
235
|
+
// src/commands/chat.ts
|
|
236
|
+
async function pickProject(explicitId) {
|
|
237
|
+
if (explicitId) {
|
|
238
|
+
return await apiFetch(`/api/cli/projects/${explicitId}`);
|
|
239
|
+
}
|
|
240
|
+
const data = await apiFetch(
|
|
241
|
+
"/api/cli/projects"
|
|
242
|
+
);
|
|
243
|
+
const ready = data.projects.filter((p) => p.status === "ready");
|
|
244
|
+
if (ready.length === 0) {
|
|
245
|
+
process.stdout.write(
|
|
246
|
+
`${pc4.yellow("No ready MCP projects yet.")} Create one: ${pc4.bold("doc2mcp <docs-url>")}
|
|
247
|
+
`
|
|
248
|
+
);
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
const choice = await select({
|
|
252
|
+
message: "Which docs do you want to chat with?",
|
|
253
|
+
options: ready.map((p) => ({
|
|
254
|
+
value: p.id,
|
|
255
|
+
label: p.name,
|
|
256
|
+
hint: p.sourceUrl ?? void 0
|
|
257
|
+
}))
|
|
258
|
+
});
|
|
259
|
+
if (isCancel(choice)) {
|
|
260
|
+
cancel("Cancelled.");
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
return await apiFetch(`/api/cli/projects/${choice}`);
|
|
264
|
+
}
|
|
265
|
+
async function askDocs(mcp, question) {
|
|
266
|
+
const response = await fetch(mcp.url, {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: {
|
|
269
|
+
"Content-Type": "application/json",
|
|
270
|
+
Authorization: `Bearer ${mcp.token}`
|
|
271
|
+
},
|
|
272
|
+
body: JSON.stringify({
|
|
273
|
+
jsonrpc: "2.0",
|
|
274
|
+
id: 1,
|
|
275
|
+
method: "tools/call",
|
|
276
|
+
params: { name: "ask_documentation", arguments: { question } }
|
|
277
|
+
})
|
|
278
|
+
});
|
|
279
|
+
const payload = await response.json();
|
|
280
|
+
if (!response.ok || payload.error) {
|
|
281
|
+
throw new ApiError(
|
|
282
|
+
payload.error?.message ?? `MCP request failed (${response.status})`,
|
|
283
|
+
response.status,
|
|
284
|
+
payload
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
const raw = payload.result?.content?.[0]?.text ?? "";
|
|
288
|
+
try {
|
|
289
|
+
return JSON.parse(raw);
|
|
290
|
+
} catch {
|
|
291
|
+
return { question, answer: raw };
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function renderAnswer(answer) {
|
|
295
|
+
process.stdout.write(`
|
|
296
|
+
${pc4.cyan("\u25C6")} ${answer.answer.trim()}
|
|
297
|
+
`);
|
|
298
|
+
if (answer.sources && answer.sources.length > 0) {
|
|
299
|
+
process.stdout.write(`
|
|
300
|
+
${pc4.dim("Sources:")}
|
|
301
|
+
`);
|
|
302
|
+
for (const source of answer.sources.slice(0, 6)) {
|
|
303
|
+
process.stdout.write(` ${pc4.dim("\u2022")} ${source.title} ${pc4.dim(source.url)}
|
|
304
|
+
`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
process.stdout.write("\n");
|
|
308
|
+
}
|
|
309
|
+
async function answerOnce(mcp, question) {
|
|
310
|
+
const spinner = ora2("Thinking\u2026").start();
|
|
311
|
+
try {
|
|
312
|
+
const answer = await askDocs(mcp, question);
|
|
313
|
+
spinner.stop();
|
|
314
|
+
renderAnswer(answer);
|
|
315
|
+
} catch (error) {
|
|
316
|
+
spinner.fail("Failed to get an answer");
|
|
317
|
+
printError(error);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async function runChat(projectId, options = {}) {
|
|
321
|
+
try {
|
|
322
|
+
await ensureLoggedIn();
|
|
323
|
+
const detail = await pickProject(projectId);
|
|
324
|
+
if (!detail) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (!detail.mcp) {
|
|
328
|
+
process.stderr.write(
|
|
329
|
+
`${pc4.red("That project is not ready yet.")} Check: ${pc4.bold("doc2mcp list")}
|
|
330
|
+
`
|
|
331
|
+
);
|
|
332
|
+
process.exitCode = 1;
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const { mcp } = detail;
|
|
336
|
+
if (options.message) {
|
|
337
|
+
await answerOnce(mcp, options.message);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
intro(
|
|
341
|
+
`${pc4.bold(`Chatting with ${detail.project.name}`)} ${pc4.dim("\u2014 ask anything about these docs")}`
|
|
342
|
+
);
|
|
343
|
+
process.stdout.write(
|
|
344
|
+
`${pc4.dim("Type your question. Use /exit to leave.")}
|
|
345
|
+
`
|
|
346
|
+
);
|
|
347
|
+
let active = true;
|
|
348
|
+
while (active) {
|
|
349
|
+
const question = await text({
|
|
350
|
+
message: "You",
|
|
351
|
+
placeholder: "How do I authenticate requests?"
|
|
352
|
+
});
|
|
353
|
+
if (isCancel(question)) {
|
|
354
|
+
active = false;
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
const trimmed = String(question).trim();
|
|
358
|
+
if (!trimmed) {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
if (trimmed === "/exit" || trimmed === "/quit") {
|
|
362
|
+
active = false;
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
await answerOnce(mcp, trimmed);
|
|
366
|
+
}
|
|
367
|
+
outro(pc4.dim("Bye \u2014 your docs MCP stays live for your editor."));
|
|
368
|
+
} catch (error) {
|
|
369
|
+
printError(error);
|
|
370
|
+
process.exitCode = 1;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/commands/convert.ts
|
|
375
|
+
import pc6 from "picocolors";
|
|
376
|
+
|
|
233
377
|
// src/commands/install.ts
|
|
234
378
|
import { confirm, multiselect } from "@clack/prompts";
|
|
235
|
-
import
|
|
379
|
+
import pc5 from "picocolors";
|
|
236
380
|
|
|
237
381
|
// src/installers/detect.ts
|
|
238
382
|
import { access } from "fs/promises";
|
|
@@ -358,28 +502,35 @@ function mergeVscodeMcp(existing, incoming) {
|
|
|
358
502
|
}
|
|
359
503
|
|
|
360
504
|
// src/installers/install.ts
|
|
505
|
+
function unwrapConfig(value) {
|
|
506
|
+
const nested = value.config;
|
|
507
|
+
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
508
|
+
return nested;
|
|
509
|
+
}
|
|
510
|
+
return value;
|
|
511
|
+
}
|
|
361
512
|
async function installToClient(client, configPath, payload) {
|
|
362
513
|
if (client === "cursor") {
|
|
363
514
|
const existing = await readJsonFile(configPath);
|
|
364
|
-
const merged = mergeMcpServers(existing, payload.cursor);
|
|
515
|
+
const merged = mergeMcpServers(existing, unwrapConfig(payload.cursor));
|
|
365
516
|
await writeJsonFile(configPath, merged);
|
|
366
517
|
return;
|
|
367
518
|
}
|
|
368
519
|
if (client === "vscode") {
|
|
369
520
|
const existing = await readJsonFile(configPath);
|
|
370
|
-
const merged = mergeVscodeMcp(existing, payload.vscode);
|
|
521
|
+
const merged = mergeVscodeMcp(existing, unwrapConfig(payload.vscode));
|
|
371
522
|
await writeJsonFile(configPath, merged);
|
|
372
523
|
return;
|
|
373
524
|
}
|
|
374
525
|
if (client === "windsurf") {
|
|
375
526
|
const existing = await readJsonFile(configPath);
|
|
376
|
-
const merged = mergeMcpServers(existing, payload.windsurf);
|
|
527
|
+
const merged = mergeMcpServers(existing, unwrapConfig(payload.windsurf));
|
|
377
528
|
await writeJsonFile(configPath, merged);
|
|
378
529
|
return;
|
|
379
530
|
}
|
|
380
531
|
if (client === "claude") {
|
|
381
532
|
const existing = await readJsonFile(configPath);
|
|
382
|
-
const merged = mergeMcpServers(existing, payload.claude);
|
|
533
|
+
const merged = mergeMcpServers(existing, unwrapConfig(payload.claude));
|
|
383
534
|
await writeJsonFile(configPath, merged);
|
|
384
535
|
}
|
|
385
536
|
}
|
|
@@ -412,8 +563,8 @@ async function promptInstall(install) {
|
|
|
412
563
|
}
|
|
413
564
|
await installToClient(client.id, client.configPath, install);
|
|
414
565
|
process.stdout.write(
|
|
415
|
-
`${
|
|
416
|
-
${
|
|
566
|
+
`${pc5.green("Installed")} ${client.label}
|
|
567
|
+
${pc5.dim(client.configPath)}
|
|
417
568
|
`
|
|
418
569
|
);
|
|
419
570
|
}
|
|
@@ -423,7 +574,7 @@ async function runInstallCommand(projectId) {
|
|
|
423
574
|
await ensureLoggedIn();
|
|
424
575
|
const detail = await apiFetch(`/api/cli/projects/${projectId}`);
|
|
425
576
|
if (!detail.install) {
|
|
426
|
-
process.stderr.write(`${
|
|
577
|
+
process.stderr.write(`${pc5.red("Project is not ready or missing install bundle.")}
|
|
427
578
|
`);
|
|
428
579
|
process.exitCode = 1;
|
|
429
580
|
return;
|
|
@@ -444,19 +595,19 @@ function sleep2(ms) {
|
|
|
444
595
|
function printStatus(detail) {
|
|
445
596
|
const { project } = detail;
|
|
446
597
|
process.stdout.write(
|
|
447
|
-
`\r${
|
|
598
|
+
`\r${pc6.cyan("Status:")} ${project.status.padEnd(12)} ${pc6.dim(project.name)}`
|
|
448
599
|
);
|
|
449
600
|
}
|
|
450
601
|
async function runConvert(sourceUrl) {
|
|
451
602
|
try {
|
|
452
603
|
await ensureLoggedIn();
|
|
453
|
-
process.stdout.write(`${
|
|
604
|
+
process.stdout.write(`${pc6.bold("Converting")} ${sourceUrl}
|
|
454
605
|
`);
|
|
455
606
|
const created = await apiFetch("/api/cli/convert", {
|
|
456
607
|
method: "POST",
|
|
457
608
|
body: JSON.stringify({ sourceUrl })
|
|
458
609
|
});
|
|
459
|
-
process.stdout.write(`${
|
|
610
|
+
process.stdout.write(`${pc6.dim("Project:")} ${created.id}
|
|
460
611
|
`);
|
|
461
612
|
let delayMs = 2e3;
|
|
462
613
|
const terminal = /* @__PURE__ */ new Set(["ready", "error"]);
|
|
@@ -478,29 +629,29 @@ async function runConvert(sourceUrl) {
|
|
|
478
629
|
if (finalDetail.project.status === "error") {
|
|
479
630
|
const lastLog = finalDetail.project.logs.at(-1);
|
|
480
631
|
process.stderr.write(
|
|
481
|
-
`${
|
|
632
|
+
`${pc6.red("Conversion failed.")}${lastLog ? ` ${lastLog.message}` : ""}
|
|
482
633
|
`
|
|
483
634
|
);
|
|
484
635
|
process.exitCode = 1;
|
|
485
636
|
return;
|
|
486
637
|
}
|
|
487
638
|
if (!finalDetail.mcp || !finalDetail.install) {
|
|
488
|
-
process.stderr.write(`${
|
|
639
|
+
process.stderr.write(`${pc6.red("MCP ready but missing install bundle.")}
|
|
489
640
|
`);
|
|
490
641
|
process.exitCode = 1;
|
|
491
642
|
return;
|
|
492
643
|
}
|
|
493
644
|
process.stdout.write(`
|
|
494
|
-
${
|
|
645
|
+
${pc6.green("MCP ready")}
|
|
495
646
|
`);
|
|
496
|
-
process.stdout.write(`${
|
|
647
|
+
process.stdout.write(`${pc6.bold("Server:")} ${finalDetail.mcp.serverName}
|
|
497
648
|
`);
|
|
498
|
-
process.stdout.write(`${
|
|
649
|
+
process.stdout.write(`${pc6.bold("URL:")} ${finalDetail.mcp.url}
|
|
499
650
|
`);
|
|
500
|
-
process.stdout.write(`${
|
|
651
|
+
process.stdout.write(`${pc6.bold("Token:")} ${finalDetail.mcp.token}
|
|
501
652
|
`);
|
|
502
653
|
process.stdout.write(
|
|
503
|
-
`${
|
|
654
|
+
`${pc6.dim("Also listed in the doc2mcp marketplace when ready.")}
|
|
504
655
|
`
|
|
505
656
|
);
|
|
506
657
|
await promptInstall(finalDetail.install);
|
|
@@ -514,16 +665,16 @@ async function runList() {
|
|
|
514
665
|
await ensureLoggedIn();
|
|
515
666
|
const data = await apiFetch("/api/cli/projects");
|
|
516
667
|
if (data.projects.length === 0) {
|
|
517
|
-
process.stdout.write(`${
|
|
668
|
+
process.stdout.write(`${pc6.dim("No projects yet.")}
|
|
518
669
|
`);
|
|
519
670
|
return;
|
|
520
671
|
}
|
|
521
672
|
for (const project of data.projects) {
|
|
522
673
|
process.stdout.write(
|
|
523
|
-
`${
|
|
674
|
+
`${pc6.bold(project.name)} ${pc6.dim(`[${project.status}]`)} ${project.source}
|
|
524
675
|
`
|
|
525
676
|
);
|
|
526
|
-
process.stdout.write(` ${
|
|
677
|
+
process.stdout.write(` ${pc6.dim(project.id)} ${project.sourceUrl ?? ""}
|
|
527
678
|
`);
|
|
528
679
|
}
|
|
529
680
|
} catch (error) {
|
|
@@ -534,7 +685,7 @@ async function runList() {
|
|
|
534
685
|
|
|
535
686
|
// src/index.ts
|
|
536
687
|
var program = new Command();
|
|
537
|
-
program.name("doc2mcp").description("Generate documentation MCP servers from your terminal").version("0.1.
|
|
688
|
+
program.name("doc2mcp").description("Generate documentation MCP servers from your terminal").version("0.1.17", "-v, --version", "Print the installed CLI version");
|
|
538
689
|
program.command("login").description("Authorize the CLI via browser").action(async () => {
|
|
539
690
|
await runLogin();
|
|
540
691
|
});
|
|
@@ -550,6 +701,9 @@ program.command("list").description("List your MCP projects").action(async () =>
|
|
|
550
701
|
program.command("install <projectId>").description("Install an existing MCP into Cursor, VS Code, Claude, or Windsurf").action(async (projectId) => {
|
|
551
702
|
await runInstallCommand(projectId);
|
|
552
703
|
});
|
|
704
|
+
program.command("chat [projectId]").description("Chat with your docs in the terminal (AI answers from your MCP)").option("-m, --message <text>", "Ask a single question and exit").action(async (projectId, options) => {
|
|
705
|
+
await runChat(projectId, options);
|
|
706
|
+
});
|
|
553
707
|
program.argument("[url]", "Documentation URL to convert").action(async (url) => {
|
|
554
708
|
if (!url) {
|
|
555
709
|
program.help();
|
|
@@ -562,7 +716,7 @@ program.argument("[url]", "Documentation URL to convert").action(async (url) =>
|
|
|
562
716
|
}
|
|
563
717
|
} catch {
|
|
564
718
|
process.stderr.write(
|
|
565
|
-
`${
|
|
719
|
+
`${pc7.red("Error:")} Invalid URL. Example: doc2mcp https://docs.example.com
|
|
566
720
|
`
|
|
567
721
|
);
|
|
568
722
|
process.exitCode = 1;
|
|
@@ -572,7 +726,7 @@ program.argument("[url]", "Documentation URL to convert").action(async (url) =>
|
|
|
572
726
|
});
|
|
573
727
|
program.parseAsync(process.argv).catch((error) => {
|
|
574
728
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
575
|
-
process.stderr.write(`${
|
|
729
|
+
process.stderr.write(`${pc7.red("Error:")} ${message}
|
|
576
730
|
`);
|
|
577
731
|
process.exit(1);
|
|
578
732
|
});
|
package/package.json
CHANGED