@nextfreelatech/xpec-mcp 1.0.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/LICENSE +201 -0
- package/README.md +450 -0
- package/dist/cli.js +242 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.js +269 -0
- package/dist/client.js.map +1 -0
- package/dist/config.js +159 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.js +100 -0
- package/dist/errors.js.map +1 -0
- package/dist/http.js +147 -0
- package/dist/http.js.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.js +29 -0
- package/dist/logger.js.map +1 -0
- package/dist/resources.js +181 -0
- package/dist/resources.js.map +1 -0
- package/dist/server.js +84 -0
- package/dist/server.js.map +1 -0
- package/dist/tools.js +398 -0
- package/dist/tools.js.map +1 -0
- package/package.json +43 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// CLI entry point for the @nextfreelatech/xpec-mcp package.
|
|
3
|
+
//
|
|
4
|
+
// Default invocation runs the stdio MCP server, which is what desktop
|
|
5
|
+
// agents (Claude Code, Cursor, Zed) launch as a child process.
|
|
6
|
+
// `--check` performs a token-validation smoke probe and exits 0/1.
|
|
7
|
+
// `--help` prints usage.
|
|
8
|
+
import { realpathSync } from "node:fs";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { ConfigError, resolveConfig } from "./config.js";
|
|
11
|
+
import { XpecClient } from "./client.js";
|
|
12
|
+
import { McpToolError } from "./errors.js";
|
|
13
|
+
import { DEFAULT_HTTP_HOST, DEFAULT_HTTP_PORT, startHttpServer } from "./http.js";
|
|
14
|
+
import { logger } from "./logger.js";
|
|
15
|
+
import { detectLegacyBinding, runStdio } from "./server.js";
|
|
16
|
+
export function parseArgs(argv) {
|
|
17
|
+
const out = {
|
|
18
|
+
command: "serve",
|
|
19
|
+
transport: "stdio",
|
|
20
|
+
allowInsecure: false,
|
|
21
|
+
json: false,
|
|
22
|
+
port: DEFAULT_HTTP_PORT,
|
|
23
|
+
host: DEFAULT_HTTP_HOST,
|
|
24
|
+
corsOrigins: [],
|
|
25
|
+
};
|
|
26
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
27
|
+
const arg = argv[i];
|
|
28
|
+
if (arg === "--check")
|
|
29
|
+
out.command = "check";
|
|
30
|
+
else if (arg === "--help" || arg === "-h")
|
|
31
|
+
out.command = "help";
|
|
32
|
+
else if (arg === "--allow-insecure")
|
|
33
|
+
out.allowInsecure = true;
|
|
34
|
+
else if (arg === "--json")
|
|
35
|
+
out.json = true;
|
|
36
|
+
else if (arg === "--http")
|
|
37
|
+
out.transport = "http";
|
|
38
|
+
else if (arg === "--stdio")
|
|
39
|
+
out.transport = "stdio";
|
|
40
|
+
else if (arg === "--api-url") {
|
|
41
|
+
out.apiUrl = expectValue(argv, ++i, "--api-url");
|
|
42
|
+
}
|
|
43
|
+
else if (arg.startsWith("--api-url=")) {
|
|
44
|
+
out.apiUrl = arg.slice("--api-url=".length);
|
|
45
|
+
}
|
|
46
|
+
else if (arg === "--port") {
|
|
47
|
+
out.port = parsePort(expectValue(argv, ++i, "--port"));
|
|
48
|
+
}
|
|
49
|
+
else if (arg.startsWith("--port=")) {
|
|
50
|
+
out.port = parsePort(arg.slice("--port=".length));
|
|
51
|
+
}
|
|
52
|
+
else if (arg === "--host") {
|
|
53
|
+
out.host = expectValue(argv, ++i, "--host");
|
|
54
|
+
}
|
|
55
|
+
else if (arg.startsWith("--host=")) {
|
|
56
|
+
out.host = arg.slice("--host=".length);
|
|
57
|
+
}
|
|
58
|
+
else if (arg === "--cors-origin") {
|
|
59
|
+
out.corsOrigins.push(expectValue(argv, ++i, "--cors-origin"));
|
|
60
|
+
}
|
|
61
|
+
else if (arg.startsWith("--cors-origin=")) {
|
|
62
|
+
out.corsOrigins.push(arg.slice("--cors-origin=".length));
|
|
63
|
+
}
|
|
64
|
+
else if (arg === "serve") {
|
|
65
|
+
out.command = "serve";
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
function expectValue(argv, index, name) {
|
|
74
|
+
const value = argv[index];
|
|
75
|
+
if (!value)
|
|
76
|
+
throw new Error(`${name} requires a value`);
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
function parsePort(raw) {
|
|
80
|
+
const n = Number.parseInt(raw, 10);
|
|
81
|
+
if (!Number.isFinite(n) || n < 0 || n > 65535) {
|
|
82
|
+
throw new Error(`--port must be an integer in [0, 65535], got "${raw}"`);
|
|
83
|
+
}
|
|
84
|
+
return n;
|
|
85
|
+
}
|
|
86
|
+
const HELP_TEXT = `\
|
|
87
|
+
Usage: xpec-mcp [command] [options]
|
|
88
|
+
|
|
89
|
+
Commands:
|
|
90
|
+
serve Run the MCP server (default). Stdio unless --http is set.
|
|
91
|
+
--check Verify the token + API URL and exit 0/1.
|
|
92
|
+
--help, -h Show this message.
|
|
93
|
+
|
|
94
|
+
Transport flags (with serve):
|
|
95
|
+
--stdio Run over stdio for desktop agents (default).
|
|
96
|
+
--http Run as an HTTP/SSE server for hosted agents.
|
|
97
|
+
--port <n> Port for --http (default ${DEFAULT_HTTP_PORT}).
|
|
98
|
+
--host <addr> Host for --http (default ${DEFAULT_HTTP_HOST}).
|
|
99
|
+
--cors-origin <o> Origin to allow (repeatable). Without this, any
|
|
100
|
+
cross-origin browser request is rejected.
|
|
101
|
+
|
|
102
|
+
Other options:
|
|
103
|
+
--api-url <url> Override the Xpec API base URL.
|
|
104
|
+
--allow-insecure Permit a non-HTTPS apiUrl (self-hosted dev only).
|
|
105
|
+
--json Machine-readable output for --check.
|
|
106
|
+
|
|
107
|
+
Environment variables:
|
|
108
|
+
XPEC_API_TOKEN Personal Access Token (required).
|
|
109
|
+
XPEC_API_URL Override the API base URL.
|
|
110
|
+
XPEC_WORKSPACE_ID Default Workspace binding.
|
|
111
|
+
XPEC_PRODUCT_ID Default Product binding.
|
|
112
|
+
XPEC_TELEMETRY Set to "0" to disable anonymous telemetry.
|
|
113
|
+
XPEC_LOG_LEVEL debug | info | warn | error (default info).
|
|
114
|
+
`;
|
|
115
|
+
export async function main(argv = process.argv.slice(2)) {
|
|
116
|
+
let parsed;
|
|
117
|
+
try {
|
|
118
|
+
parsed = parseArgs(argv);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
process.stderr.write(`${err.message}\n${HELP_TEXT}`);
|
|
122
|
+
return 2;
|
|
123
|
+
}
|
|
124
|
+
if (parsed.command === "help") {
|
|
125
|
+
process.stdout.write(HELP_TEXT);
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
let config;
|
|
129
|
+
try {
|
|
130
|
+
config = resolveConfig({
|
|
131
|
+
apiUrl: parsed.apiUrl,
|
|
132
|
+
allowInsecure: parsed.allowInsecure,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
if (err instanceof ConfigError) {
|
|
137
|
+
process.stderr.write(`${err.message}\n`);
|
|
138
|
+
return 2;
|
|
139
|
+
}
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
if (!config.token) {
|
|
143
|
+
process.stderr.write("XPEC_API_TOKEN is required. Generate one at /settings/developer and re-run.\n");
|
|
144
|
+
return 2;
|
|
145
|
+
}
|
|
146
|
+
if (parsed.command === "check") {
|
|
147
|
+
return runCheck(config.apiUrl, config.token, parsed.json);
|
|
148
|
+
}
|
|
149
|
+
// Phase 4: probe for the legacy `.xpec.json` shape before
|
|
150
|
+
// starting any transport. The error is non-fatal at the network level
|
|
151
|
+
// (we keep listening) but the CLI prints a structured remediation and
|
|
152
|
+
// exits — same UX as a missing token.
|
|
153
|
+
try {
|
|
154
|
+
const probeClient = new XpecClient({
|
|
155
|
+
apiUrl: config.apiUrl,
|
|
156
|
+
token: config.token,
|
|
157
|
+
});
|
|
158
|
+
const legacy = await detectLegacyBinding(config, probeClient);
|
|
159
|
+
if (legacy) {
|
|
160
|
+
const failure = legacy.toFailure();
|
|
161
|
+
process.stderr.write(`${failure.code}: ${failure.message}\n${failure.remediation}\n`);
|
|
162
|
+
return 2;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
// Probe failures (network, auth) shouldn't block startup — the agent
|
|
167
|
+
// surfaces those on the first real call. Just log so they show up in
|
|
168
|
+
// diagnostics.
|
|
169
|
+
logger.warn("legacy binding probe skipped", {
|
|
170
|
+
err: err.message,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (parsed.transport === "http") {
|
|
174
|
+
const handle = await startHttpServer({
|
|
175
|
+
config,
|
|
176
|
+
port: parsed.port,
|
|
177
|
+
host: parsed.host,
|
|
178
|
+
corsOrigins: parsed.corsOrigins,
|
|
179
|
+
});
|
|
180
|
+
process.stderr.write(`Listening on http://${handle.host}:${handle.port}/mcp\n`);
|
|
181
|
+
// The HTTP server keeps the event loop alive — return 0 here only
|
|
182
|
+
// when a future shutdown signal triggers handle.close(). For now we
|
|
183
|
+
// just await indefinitely.
|
|
184
|
+
await new Promise(() => { });
|
|
185
|
+
return 0;
|
|
186
|
+
}
|
|
187
|
+
await runStdio(config);
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
async function runCheck(apiUrl, token, asJson) {
|
|
191
|
+
const client = new XpecClient({ apiUrl, token });
|
|
192
|
+
try {
|
|
193
|
+
const probe = await client.checkAuth();
|
|
194
|
+
if (asJson) {
|
|
195
|
+
process.stdout.write(`${JSON.stringify({ ok: true, apiUrl, products: probe.products })}\n`);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
process.stdout.write(`OK: ${apiUrl} reachable, ${probe.products} product(s) visible.\n`);
|
|
199
|
+
}
|
|
200
|
+
return 0;
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
const failure = err instanceof McpToolError
|
|
204
|
+
? err.toFailure()
|
|
205
|
+
: {
|
|
206
|
+
code: "INTERNAL_ERROR",
|
|
207
|
+
message: err.message,
|
|
208
|
+
remediation: "Retry; if it persists, check the API URL and token.",
|
|
209
|
+
};
|
|
210
|
+
if (asJson) {
|
|
211
|
+
process.stdout.write(`${JSON.stringify({ ok: false, ...failure })}\n`);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
process.stderr.write(`FAILED (${failure.code}): ${failure.message}\n${failure.remediation}\n`);
|
|
215
|
+
}
|
|
216
|
+
return 1;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Allow `node cli.js` direct execution while staying importable for tests.
|
|
220
|
+
// We compare realpaths because `npx -y @nextfreelatech/xpec-mcp` invokes this file
|
|
221
|
+
// through the bin symlink at `node_modules/.bin/xpec-mcp` — without
|
|
222
|
+
// realpath resolution, `process.argv[1]` (the symlink) would never equal
|
|
223
|
+
// `import.meta.url` (the real path), and `main()` would silently never run.
|
|
224
|
+
function isEntryPoint() {
|
|
225
|
+
if (!process.argv[1])
|
|
226
|
+
return false;
|
|
227
|
+
try {
|
|
228
|
+
const entryPath = realpathSync(process.argv[1]);
|
|
229
|
+
const modulePath = fileURLToPath(import.meta.url);
|
|
230
|
+
return entryPath === modulePath;
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (isEntryPoint()) {
|
|
237
|
+
main().then((code) => process.exit(code), (err) => {
|
|
238
|
+
logger.error("mcp server crashed", { err: err.message });
|
|
239
|
+
process.exit(1);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// Xpec HTTP API client. Wraps the /api/mcp/* surface so tool
|
|
2
|
+
// handlers stay focused on argument shaping. Every outbound request carries
|
|
3
|
+
// `Authorization: Bearer xpec_pat_…`; no other auth artifacts are sent
|
|
4
|
+
// (per Xpec spec "mcp-server" §5 "Auth header").
|
|
5
|
+
import { McpToolError, mapApiError } from "./errors.js";
|
|
6
|
+
export class XpecClient {
|
|
7
|
+
apiUrl;
|
|
8
|
+
token;
|
|
9
|
+
fetcher;
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
12
|
+
this.token = options.token;
|
|
13
|
+
this.fetcher = options.fetcher ?? fetch;
|
|
14
|
+
}
|
|
15
|
+
// ────────────────────────────────────────────────────────────────────
|
|
16
|
+
// Read endpoints
|
|
17
|
+
// ────────────────────────────────────────────────────────────────────
|
|
18
|
+
listProducts(options = {}) {
|
|
19
|
+
const params = new URLSearchParams();
|
|
20
|
+
if (options.workspaceId)
|
|
21
|
+
params.set("workspaceId", options.workspaceId);
|
|
22
|
+
if (options.orphan)
|
|
23
|
+
params.set("orphan", "true");
|
|
24
|
+
const qs = params.toString();
|
|
25
|
+
return this.getJson(`/api/mcp/products${qs ? `?${qs}` : ""}`);
|
|
26
|
+
}
|
|
27
|
+
listWorkspaces() {
|
|
28
|
+
return this.getJson("/api/mcp/workspaces");
|
|
29
|
+
}
|
|
30
|
+
readProduct(productId) {
|
|
31
|
+
return this.getJson(`/api/mcp/products/${encodeURIComponent(productId)}`);
|
|
32
|
+
}
|
|
33
|
+
readWorkspace(workspaceId) {
|
|
34
|
+
return this.getJson(`/api/mcp/workspaces/${encodeURIComponent(workspaceId)}`);
|
|
35
|
+
}
|
|
36
|
+
listSpecifications(productId, query = {}) {
|
|
37
|
+
const params = new URLSearchParams();
|
|
38
|
+
if (query.type)
|
|
39
|
+
params.set("type", query.type);
|
|
40
|
+
if (query.status)
|
|
41
|
+
params.set("status", query.status);
|
|
42
|
+
if (query.folder)
|
|
43
|
+
params.set("folder", query.folder);
|
|
44
|
+
if (query.query)
|
|
45
|
+
params.set("query", query.query);
|
|
46
|
+
if (query.cursor)
|
|
47
|
+
params.set("cursor", query.cursor);
|
|
48
|
+
if (typeof query.limit === "number") {
|
|
49
|
+
params.set("limit", String(query.limit));
|
|
50
|
+
}
|
|
51
|
+
if (query.tags) {
|
|
52
|
+
for (const t of query.tags)
|
|
53
|
+
params.append("tag", t);
|
|
54
|
+
}
|
|
55
|
+
const qs = params.toString();
|
|
56
|
+
return this.getJson(`/api/mcp/products/${encodeURIComponent(productId)}/specifications${qs ? `?${qs}` : ""}`);
|
|
57
|
+
}
|
|
58
|
+
searchSpecifications(productId, query) {
|
|
59
|
+
const params = new URLSearchParams({ query: query.query });
|
|
60
|
+
if (typeof query.limit === "number") {
|
|
61
|
+
params.set("limit", String(query.limit));
|
|
62
|
+
}
|
|
63
|
+
if (query.includeArchived) {
|
|
64
|
+
params.set("includeArchived", "true");
|
|
65
|
+
}
|
|
66
|
+
return this.getJson(`/api/mcp/products/${encodeURIComponent(productId)}/specifications/search?${params.toString()}`);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Phase 4: Workspace-scoped specification list. Calls the MCP workspace
|
|
70
|
+
* route which enforces workspace ownership and Free-management semantics.
|
|
71
|
+
*/
|
|
72
|
+
listSpecificationsForWorkspace(workspaceId, query = {}) {
|
|
73
|
+
const params = new URLSearchParams();
|
|
74
|
+
if (query.type)
|
|
75
|
+
params.set("type", query.type);
|
|
76
|
+
if (query.status)
|
|
77
|
+
params.set("status", query.status);
|
|
78
|
+
if (query.folder)
|
|
79
|
+
params.set("folder", query.folder);
|
|
80
|
+
if (query.query)
|
|
81
|
+
params.set("query", query.query);
|
|
82
|
+
if (query.cursor)
|
|
83
|
+
params.set("cursor", query.cursor);
|
|
84
|
+
if (typeof query.limit === "number") {
|
|
85
|
+
params.set("limit", String(query.limit));
|
|
86
|
+
}
|
|
87
|
+
if (query.tags) {
|
|
88
|
+
for (const t of query.tags)
|
|
89
|
+
params.append("tag", t);
|
|
90
|
+
}
|
|
91
|
+
const qs = params.toString();
|
|
92
|
+
return this.getJson(`/api/mcp/workspaces/${encodeURIComponent(workspaceId)}/specifications${qs ? `?${qs}` : ""}`);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Phase 4: cross-scope search. The server fans out to the Workspace's
|
|
96
|
+
* own specs and to every member Product, then merges and scores.
|
|
97
|
+
*/
|
|
98
|
+
searchSpecificationsForWorkspace(workspaceId, query) {
|
|
99
|
+
const params = new URLSearchParams({ query: query.query });
|
|
100
|
+
if (typeof query.limit === "number") {
|
|
101
|
+
params.set("limit", String(query.limit));
|
|
102
|
+
}
|
|
103
|
+
if (query.includeArchived) {
|
|
104
|
+
params.set("includeArchived", "true");
|
|
105
|
+
}
|
|
106
|
+
return this.getJson(`/api/mcp/workspaces/${encodeURIComponent(workspaceId)}/specifications/search?${params.toString()}`);
|
|
107
|
+
}
|
|
108
|
+
readSpecification(specId, query = {}) {
|
|
109
|
+
const params = new URLSearchParams();
|
|
110
|
+
if (query.format)
|
|
111
|
+
params.set("format", query.format);
|
|
112
|
+
const qs = params.toString();
|
|
113
|
+
return this.get(`/api/mcp/specifications/${encodeURIComponent(specId)}${qs ? `?${qs}` : ""}`, query.ifNoneMatch);
|
|
114
|
+
}
|
|
115
|
+
listSpecificationVersions(specId) {
|
|
116
|
+
return this.getJson(`/api/mcp/specifications/${encodeURIComponent(specId)}/versions`);
|
|
117
|
+
}
|
|
118
|
+
readSpecificationVersion(specId, revisionId, ifNoneMatch) {
|
|
119
|
+
return this.get(`/api/mcp/specifications/${encodeURIComponent(specId)}/versions/${encodeURIComponent(revisionId)}`, ifNoneMatch);
|
|
120
|
+
}
|
|
121
|
+
listOpenQuestions(specId, query = {}) {
|
|
122
|
+
const params = new URLSearchParams();
|
|
123
|
+
if (query.includeResolved)
|
|
124
|
+
params.set("includeResolved", "true");
|
|
125
|
+
const qs = params.toString();
|
|
126
|
+
return this.getJson(`/api/mcp/specifications/${encodeURIComponent(specId)}/open-questions${qs ? `?${qs}` : ""}`);
|
|
127
|
+
}
|
|
128
|
+
/** Convenience for endpoints that never send If-None-Match — narrows the
|
|
129
|
+
* union so callers don't have to discriminate on `notModified`. */
|
|
130
|
+
async getJson(path) {
|
|
131
|
+
const res = await this.get(path);
|
|
132
|
+
if ("notModified" in res) {
|
|
133
|
+
// Should not happen — getJson never asks for conditional requests.
|
|
134
|
+
throw new Error("Unexpected 304 on a non-conditional request.");
|
|
135
|
+
}
|
|
136
|
+
return res;
|
|
137
|
+
}
|
|
138
|
+
postJson(path) {
|
|
139
|
+
return this.sendJson("POST", path, undefined);
|
|
140
|
+
}
|
|
141
|
+
async sendJson(method, path, body) {
|
|
142
|
+
const headers = {
|
|
143
|
+
authorization: `Bearer ${this.token}`,
|
|
144
|
+
accept: "application/json",
|
|
145
|
+
};
|
|
146
|
+
if (body !== undefined)
|
|
147
|
+
headers["content-type"] = "application/json";
|
|
148
|
+
const res = await this.fetcher(`${this.apiUrl}${path}`, {
|
|
149
|
+
method,
|
|
150
|
+
headers,
|
|
151
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
152
|
+
});
|
|
153
|
+
const text = await res.text();
|
|
154
|
+
const parsed = text.length > 0
|
|
155
|
+
? safeParseJson(text)
|
|
156
|
+
: null;
|
|
157
|
+
if (!res.ok) {
|
|
158
|
+
throw mapApiError(res.status, parsed);
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
body: parsed,
|
|
162
|
+
etag: res.headers.get("etag"),
|
|
163
|
+
status: res.status,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* `--check` smoke probe: hits /api/mcp/products and returns the count
|
|
168
|
+
* (or throws on auth failure). Cheaper than a full preflight: the same
|
|
169
|
+
* call the agent does on its first list.
|
|
170
|
+
*/
|
|
171
|
+
async checkAuth() {
|
|
172
|
+
const res = await this.listProducts();
|
|
173
|
+
const items = res.body?.items;
|
|
174
|
+
return { ok: true, products: Array.isArray(items) ? items.length : 0 };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Phase 4: probe whether a given id resolves to a Workspace, a Product,
|
|
178
|
+
* or neither. Used at server startup to detect the legacy binding shape
|
|
179
|
+
* (`{"workspaceId": "<old id>"}` where `<old id>` is now a Product id).
|
|
180
|
+
* Errors other than 404 propagate so the caller can decide whether to
|
|
181
|
+
* keep going.
|
|
182
|
+
*/
|
|
183
|
+
async resolveIdShape(id) {
|
|
184
|
+
try {
|
|
185
|
+
await this.readWorkspace(id);
|
|
186
|
+
return "workspace";
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
if (!isNotFound(err))
|
|
190
|
+
throw err;
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
await this.readProduct(id);
|
|
194
|
+
return "product";
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
if (!isNotFound(err))
|
|
198
|
+
throw err;
|
|
199
|
+
}
|
|
200
|
+
return "unknown";
|
|
201
|
+
}
|
|
202
|
+
// ────────────────────────────────────────────────────────────────────
|
|
203
|
+
// Write endpoints
|
|
204
|
+
// ────────────────────────────────────────────────────────────────────
|
|
205
|
+
startNewVersion(specId) {
|
|
206
|
+
return this.postJson(`/api/mcp/specifications/${encodeURIComponent(specId)}/start-new-version`);
|
|
207
|
+
}
|
|
208
|
+
updateSpecificationContent(specId, body) {
|
|
209
|
+
return this.sendJson("PATCH", `/api/mcp/specifications/${encodeURIComponent(specId)}/content`, body);
|
|
210
|
+
}
|
|
211
|
+
updateSpecificationSection(specId, body) {
|
|
212
|
+
return this.sendJson("PATCH", `/api/mcp/specifications/${encodeURIComponent(specId)}/section`, body);
|
|
213
|
+
}
|
|
214
|
+
requestReview(specId) {
|
|
215
|
+
return this.postJson(`/api/mcp/specifications/${encodeURIComponent(specId)}/request-review`);
|
|
216
|
+
}
|
|
217
|
+
discardDraft(specId) {
|
|
218
|
+
return this.postJson(`/api/mcp/specifications/${encodeURIComponent(specId)}/discard-draft`);
|
|
219
|
+
}
|
|
220
|
+
createFreeSpecification(productId, body) {
|
|
221
|
+
return this.sendJson("POST", `/api/mcp/products/${encodeURIComponent(productId)}/specifications`, body);
|
|
222
|
+
}
|
|
223
|
+
// ────────────────────────────────────────────────────────────────────
|
|
224
|
+
// Internals
|
|
225
|
+
// ────────────────────────────────────────────────────────────────────
|
|
226
|
+
async get(path, ifNoneMatch) {
|
|
227
|
+
const headers = {
|
|
228
|
+
authorization: `Bearer ${this.token}`,
|
|
229
|
+
accept: "application/json",
|
|
230
|
+
};
|
|
231
|
+
if (ifNoneMatch)
|
|
232
|
+
headers["if-none-match"] = ifNoneMatch;
|
|
233
|
+
const res = await this.fetcher(`${this.apiUrl}${path}`, {
|
|
234
|
+
method: "GET",
|
|
235
|
+
headers,
|
|
236
|
+
});
|
|
237
|
+
if (res.status === 304) {
|
|
238
|
+
return {
|
|
239
|
+
notModified: true,
|
|
240
|
+
etag: res.headers.get("etag") ?? "",
|
|
241
|
+
status: 304,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const text = await res.text();
|
|
245
|
+
const body = text.length > 0
|
|
246
|
+
? safeParseJson(text)
|
|
247
|
+
: null;
|
|
248
|
+
if (!res.ok) {
|
|
249
|
+
throw mapApiError(res.status, body);
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
body,
|
|
253
|
+
etag: res.headers.get("etag"),
|
|
254
|
+
status: res.status,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function safeParseJson(text) {
|
|
259
|
+
try {
|
|
260
|
+
return JSON.parse(text);
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return { error: { message: "API returned a non-JSON payload." } };
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function isNotFound(err) {
|
|
267
|
+
return err instanceof McpToolError && err.code === "NOT_FOUND";
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|