@spec0/cli 0.6.0 → 0.6.1
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/commands/mcp.d.ts +7 -4
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +21 -42
- package/dist/commands/mcp.js.map +1 -1
- package/package.json +1 -1
package/dist/commands/mcp.d.ts
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* spec0 mcp url | test | install
|
|
3
3
|
*
|
|
4
4
|
* Helpers for pointing MCP clients (Cursor, Claude) at the Spec0 MCP server.
|
|
5
|
-
* The server is a single Streamable HTTP endpoint
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* The server is a single Streamable HTTP endpoint that authenticates with the
|
|
6
|
+
* MCP OAuth flow: the protected-resource metadata points clients at Clerk, which
|
|
7
|
+
* dynamically registers a client and runs the browser authorization. So we
|
|
8
|
+
* register the server **without** an Authorization header — setting a static
|
|
9
|
+
* header makes clients (e.g. Claude Code) skip the OAuth flow entirely, and the
|
|
10
|
+
* org API key isn't a JWT the gateway would accept anyway. Anonymous connections
|
|
11
|
+
* get the public docs tools; signing in via the browser unlocks org-scoped ones.
|
|
9
12
|
*/
|
|
10
13
|
import { Command } from "commander";
|
|
11
14
|
export declare function registerMcpCommands(program: Command): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,QAmEnD"}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* spec0 mcp url | test | install
|
|
3
3
|
*
|
|
4
4
|
* Helpers for pointing MCP clients (Cursor, Claude) at the Spec0 MCP server.
|
|
5
|
-
* The server is a single Streamable HTTP endpoint
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* The server is a single Streamable HTTP endpoint that authenticates with the
|
|
6
|
+
* MCP OAuth flow: the protected-resource metadata points clients at Clerk, which
|
|
7
|
+
* dynamically registers a client and runs the browser authorization. So we
|
|
8
|
+
* register the server **without** an Authorization header — setting a static
|
|
9
|
+
* header makes clients (e.g. Claude Code) skip the OAuth flow entirely, and the
|
|
10
|
+
* org API key isn't a JWT the gateway would accept anyway. Anonymous connections
|
|
11
|
+
* get the public docs tools; signing in via the browser unlocks org-scoped ones.
|
|
9
12
|
*/
|
|
10
13
|
import chalk from "chalk";
|
|
11
14
|
import got from "got";
|
|
@@ -13,41 +16,26 @@ import { spawnSync } from "node:child_process";
|
|
|
13
16
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
17
|
import { homedir } from "node:os";
|
|
15
18
|
import { dirname, join } from "node:path";
|
|
16
|
-
import { getDefaultOrgId, getOrgConfig } from "../lib/config.js";
|
|
17
19
|
import { resolvedPlatformMcpBaseUrl, resolvedPlatformMcpUrl } from "../lib/platform-defaults.js";
|
|
18
20
|
import { ExitCode, exit, exitCodeForHttpStatus } from "../lib/exit-codes.js";
|
|
19
21
|
/** Server key used under `mcpServers` in every client config we write. */
|
|
20
22
|
const SERVER_KEY = "spec0";
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Canonical client config block for the Spec0 MCP server. No Authorization
|
|
25
|
+
* header: the client performs the MCP OAuth flow (browser sign-in via Clerk)
|
|
26
|
+
* on first connect.
|
|
27
|
+
*/
|
|
24
28
|
function canonicalServerConfig(mcpUrl) {
|
|
25
29
|
return {
|
|
26
30
|
url: mcpUrl,
|
|
27
|
-
headers: { Authorization: AUTH_HEADER },
|
|
28
31
|
};
|
|
29
32
|
}
|
|
30
|
-
/**
|
|
31
|
-
* Exit early (code 3) unless the user is logged in or has env credentials.
|
|
32
|
-
* Mirrors the sibling MCP commands: a default org from config, or SPEC0_TOKEN
|
|
33
|
-
* with an org id, is enough.
|
|
34
|
-
*/
|
|
35
|
-
function requireAuthOrExit() {
|
|
36
|
-
const orgId = process.env.SPEC0_ORG_ID ?? process.env.PLATFORM_ORG_ID ?? getDefaultOrgId();
|
|
37
|
-
const hasEnvToken = Boolean(process.env.SPEC0_TOKEN ?? process.env.PLATFORM_API_TOKEN);
|
|
38
|
-
const hasStoredOrg = Boolean(orgId && getOrgConfig(orgId));
|
|
39
|
-
if (!hasEnvToken && !hasStoredOrg) {
|
|
40
|
-
console.error(chalk.red("Not authenticated. Run 'spec0 auth login'."));
|
|
41
|
-
exit(ExitCode.AUTH_MISSING);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
33
|
export function registerMcpCommands(program) {
|
|
45
34
|
const mcp = program.command("mcp").description("MCP server URL and config");
|
|
46
35
|
mcp
|
|
47
36
|
.command("url")
|
|
48
37
|
.description("Print MCP server config for Cursor/Claude")
|
|
49
38
|
.action(async () => {
|
|
50
|
-
requireAuthOrExit();
|
|
51
39
|
const mcpUrl = resolvedPlatformMcpUrl();
|
|
52
40
|
console.log("Your MCP server URL:");
|
|
53
41
|
console.log(` ${mcpUrl}`);
|
|
@@ -55,13 +43,12 @@ export function registerMcpCommands(program) {
|
|
|
55
43
|
console.log("Add to your MCP client config (e.g. Cursor):");
|
|
56
44
|
console.log(JSON.stringify({ mcpServers: { [SERVER_KEY]: canonicalServerConfig(mcpUrl) } }, null, 2));
|
|
57
45
|
console.log("");
|
|
58
|
-
console.log(chalk.dim("
|
|
46
|
+
console.log(chalk.dim("No token needed here — your MCP client opens a browser to sign in (OAuth) on first connect."));
|
|
59
47
|
});
|
|
60
48
|
mcp
|
|
61
49
|
.command("test")
|
|
62
50
|
.description("Verify MCP server is responding")
|
|
63
51
|
.action(async () => {
|
|
64
|
-
requireAuthOrExit();
|
|
65
52
|
const url = `${resolvedPlatformMcpBaseUrl()}/health`;
|
|
66
53
|
try {
|
|
67
54
|
const res = await got.get(url);
|
|
@@ -78,7 +65,6 @@ export function registerMcpCommands(program) {
|
|
|
78
65
|
.description("Install the Spec0 MCP server into Cursor and/or Claude")
|
|
79
66
|
.option("--client <client>", "Target client: cursor, claude, or all", "all")
|
|
80
67
|
.action(async (opts) => {
|
|
81
|
-
requireAuthOrExit();
|
|
82
68
|
const client = opts.client.toLowerCase();
|
|
83
69
|
if (!["cursor", "claude", "all"].includes(client)) {
|
|
84
70
|
console.error(chalk.red(`Unknown client '${opts.client}'. Expected: cursor, claude, or all.`));
|
|
@@ -91,6 +77,9 @@ export function registerMcpCommands(program) {
|
|
|
91
77
|
if (client === "claude" || client === "all") {
|
|
92
78
|
installClaude(mcpUrl);
|
|
93
79
|
}
|
|
80
|
+
console.log("");
|
|
81
|
+
console.log(chalk.dim("On first use your MCP client opens a browser to sign in (OAuth via Clerk). " +
|
|
82
|
+
"Anonymous access exposes the public docs tools; signing in unlocks your org's APIs."));
|
|
94
83
|
});
|
|
95
84
|
}
|
|
96
85
|
/**
|
|
@@ -122,27 +111,17 @@ function installCursor(mcpUrl) {
|
|
|
122
111
|
}
|
|
123
112
|
/**
|
|
124
113
|
* Register the server with Claude via `claude mcp add`. The flag form follows the
|
|
125
|
-
* current Claude CLI:
|
|
126
|
-
* transport is selected explicitly (`--transport http`)
|
|
127
|
-
* passed
|
|
128
|
-
* connect time.
|
|
114
|
+
* current Claude CLI: options precede the server name and the Streamable HTTP
|
|
115
|
+
* transport is selected explicitly (`--transport http`). No Authorization header
|
|
116
|
+
* is passed — that lets the client run the MCP OAuth flow on connect.
|
|
129
117
|
*
|
|
130
118
|
* If the `claude` binary isn't on PATH (or the invocation fails for any reason)
|
|
131
119
|
* we don't hard-fail: we print the exact command plus the manual JSON so the user
|
|
132
120
|
* can finish by hand.
|
|
133
121
|
*/
|
|
134
122
|
function installClaude(mcpUrl) {
|
|
135
|
-
const args = [
|
|
136
|
-
|
|
137
|
-
"add",
|
|
138
|
-
"--transport",
|
|
139
|
-
"http",
|
|
140
|
-
SERVER_KEY,
|
|
141
|
-
mcpUrl,
|
|
142
|
-
"--header",
|
|
143
|
-
`Authorization: ${AUTH_HEADER}`,
|
|
144
|
-
];
|
|
145
|
-
const printableCommand = `claude mcp add --transport http ${SERVER_KEY} ${mcpUrl} --header "Authorization: ${AUTH_HEADER}"`;
|
|
123
|
+
const args = ["mcp", "add", "--transport", "http", SERVER_KEY, mcpUrl];
|
|
124
|
+
const printableCommand = `claude mcp add --transport http ${SERVER_KEY} ${mcpUrl}`;
|
|
146
125
|
let result;
|
|
147
126
|
try {
|
|
148
127
|
result = spawnSync("claude", args, { stdio: "inherit" });
|
package/dist/commands/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACjG,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7E,0EAA0E;AAC1E,MAAM,UAAU,GAAG,OAAO,CAAC;AAE3B;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,MAAc;IAC3C,OAAO;QACL,GAAG,EAAE,MAAM;KACZ,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,2BAA2B,CAAC,CAAC;IAE5E,GAAG;SACA,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,2CAA2C,CAAC;SACxD,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,sBAAsB,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAC5D,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,qBAAqB,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CACzF,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CACP,6FAA6F,CAC9F,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEL,GAAG;SACA,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,iCAAiC,CAAC;SAC9C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,GAAG,GAAG,GAAG,0BAA0B,EAAE,SAAS,CAAC;QACrD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,MAAM,GAAI,CAA4C,EAAE,QAAQ,EAAE,UAAU,CAAC;YACnF,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,0BAA0B,CAAC,EAAG,CAAW,CAAC,OAAO,CAAC,CAAC;YAC3E,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACxE,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,GAAG;SACA,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,wDAAwD,CAAC;SACrE,MAAM,CAAC,mBAAmB,EAAE,uCAAuC,EAAE,KAAK,CAAC;SAC3E,MAAM,CAAC,KAAK,EAAE,IAAwB,EAAE,EAAE;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACzC,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,mBAAmB,IAAI,CAAC,MAAM,sCAAsC,CAAC,CAChF,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;QAED,MAAM,MAAM,GAAG,sBAAsB,EAAE,CAAC;QACxC,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YAC5C,aAAa,CAAC,MAAM,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YAC5C,aAAa,CAAC,MAAM,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CACP,6EAA6E;YAC3E,qFAAqF,CACxF,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAEhE,IAAI,MAAM,GAAuE,EAAE,CAAC;IACpF,IAAI,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;YAC3D,IAAI,GAAG;gBAAE,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,4BAA4B,gBAAgB,6BAA6B,CAAC,CACrF,CAAC;YACF,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC,CAAC;YACrF,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;IACpD,UAAU,CAAC,UAAU,CAAC,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,CAAC;IAEzC,SAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,aAAa,CAAC,gBAAgB,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAEjF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IACvE,MAAM,gBAAgB,GAAG,mCAAmC,UAAU,IAAI,MAAM,EAAE,CAAC;IAEnF,IAAI,MAAgD,CAAC;IACrD,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,gFAAgF;IAClF,CAAC;IAED,IAAI,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,gCAAgC,CAAC,CAAC;QACtE,OAAO;IACT,CAAC;IAED,6EAA6E;IAC7E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,+CAA+C,CAAC,CAAC;IACtF,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,gBAAgB,EAAE,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,qBAAqB,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EACpF,IAAI,EACJ,CAAC,CACF,CACF,CAAC;AACJ,CAAC"}
|