@ainecto/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.
@@ -0,0 +1,586 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/core/config/endpoints.ts
4
+ var DEFAULT_ENDPOINTS = {
5
+ prod: "https://ainecto.com/mcp",
6
+ dev: "https://dev.ainecto.com/mcp"
7
+ };
8
+ function resolveEndpoint(input = {}) {
9
+ const envVars = input.envVars ?? process.env;
10
+ const env = input.env ?? "prod";
11
+ if (input.endpoint) {
12
+ return { env, endpoint: normalizeEndpoint(input.endpoint), source: "flag" };
13
+ }
14
+ if (envVars.AINECTO_MCP_ENDPOINT) {
15
+ return { env, endpoint: normalizeEndpoint(envVars.AINECTO_MCP_ENDPOINT), source: "env" };
16
+ }
17
+ return { env, endpoint: DEFAULT_ENDPOINTS[env], source: "default" };
18
+ }
19
+ function normalizeEndpoint(endpoint) {
20
+ const url = new URL(endpoint);
21
+ url.hash = "";
22
+ return url.toString().replace(/\/$/, "");
23
+ }
24
+ function assertEnv(value) {
25
+ if (value === void 0) {
26
+ return void 0;
27
+ }
28
+ if (value === "prod" || value === "dev") {
29
+ return value;
30
+ }
31
+ throw new Error(`Invalid --env value "${value}". Expected "prod" or "dev".`);
32
+ }
33
+
34
+ // src/core/auth/tokenStore.ts
35
+ import { createHash } from "crypto";
36
+ import { mkdir, readFile, rename, rm, stat, writeFile, chmod } from "fs/promises";
37
+ import { homedir } from "os";
38
+ import { dirname, join } from "path";
39
+ var FileTokenStore = class {
40
+ filePath;
41
+ constructor(rootDir = join(homedir(), ".ainecto")) {
42
+ this.filePath = join(rootDir, "tokens.json");
43
+ }
44
+ async load(endpoint) {
45
+ const file = await this.readFile();
46
+ return file[tokenKey(endpoint)];
47
+ }
48
+ async save(endpoint, token) {
49
+ const file = await this.readFile();
50
+ file[tokenKey(endpoint)] = { ...token, endpoint, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
51
+ await this.writeFile(file);
52
+ }
53
+ async delete(endpoint) {
54
+ const file = await this.readFile();
55
+ delete file[tokenKey(endpoint)];
56
+ await this.writeFile(file);
57
+ }
58
+ async readFile() {
59
+ try {
60
+ const raw = await readFile(this.filePath, "utf8");
61
+ const parsed = JSON.parse(raw);
62
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
63
+ throw new Error("Token file must contain an object.");
64
+ }
65
+ return parsed;
66
+ } catch (error) {
67
+ if (isNodeError(error, "ENOENT")) {
68
+ return {};
69
+ }
70
+ throw error;
71
+ }
72
+ }
73
+ async writeFile(file) {
74
+ await mkdir(dirname(this.filePath), { recursive: true, mode: 448 });
75
+ await chmod(dirname(this.filePath), 448);
76
+ const tmpPath = `${this.filePath}.${process.pid}.${Date.now()}.tmp`;
77
+ await writeFile(tmpPath, `${JSON.stringify(file, null, 2)}
78
+ `, { mode: 384 });
79
+ await chmod(tmpPath, 384);
80
+ await rename(tmpPath, this.filePath);
81
+ await chmod(this.filePath, 384);
82
+ }
83
+ };
84
+ function tokenKey(endpoint) {
85
+ return createHash("sha256").update(endpoint).digest("hex");
86
+ }
87
+ function isNodeError(error, code) {
88
+ return error instanceof Error && "code" in error && error.code === code;
89
+ }
90
+
91
+ // src/core/auth/oauth.ts
92
+ import { createHash as createHash2, randomBytes } from "crypto";
93
+ import { createServer } from "http";
94
+ import { spawn } from "child_process";
95
+ import { URLSearchParams } from "url";
96
+
97
+ // src/core/auth/clientRegistration.ts
98
+ async function registerPublicClient(registrationEndpoint, redirectUri, fetchImpl = fetch) {
99
+ const response = await fetchImpl(registrationEndpoint, {
100
+ method: "POST",
101
+ headers: { "content-type": "application/json", accept: "application/json" },
102
+ body: JSON.stringify({
103
+ client_name: "Ainecto CLI",
104
+ redirect_uris: [redirectUri],
105
+ token_endpoint_auth_method: "none",
106
+ grant_types: ["authorization_code", "refresh_token"],
107
+ response_types: ["code"]
108
+ })
109
+ });
110
+ if (!response.ok) {
111
+ throw new Error(`OAuth client registration failed with HTTP ${response.status}.`);
112
+ }
113
+ const body = await response.json();
114
+ if (!isRecord(body) || typeof body.client_id !== "string") {
115
+ throw new Error("OAuth client registration response did not include client_id.");
116
+ }
117
+ return {
118
+ clientId: body.client_id,
119
+ clientSecret: typeof body.client_secret === "string" ? body.client_secret : void 0
120
+ };
121
+ }
122
+ function isRecord(value) {
123
+ return typeof value === "object" && value !== null && !Array.isArray(value);
124
+ }
125
+
126
+ // src/core/auth/oauth.ts
127
+ var OAuthClient = class {
128
+ constructor(options) {
129
+ this.options = options;
130
+ this.fetchImpl = options.fetchImpl ?? fetch;
131
+ this.envVars = options.envVars ?? process.env;
132
+ this.openBrowserImpl = options.openBrowser ?? openBrowser;
133
+ }
134
+ options;
135
+ fetchImpl;
136
+ envVars;
137
+ openBrowserImpl;
138
+ async getAccessToken() {
139
+ const envToken = this.envVars.AINECTO_TOKEN;
140
+ if (envToken) {
141
+ return envToken;
142
+ }
143
+ const stored = await this.options.tokenStore.load(this.options.endpoint);
144
+ if (!stored) {
145
+ return void 0;
146
+ }
147
+ if (!shouldRefresh(stored)) {
148
+ return stored.accessToken;
149
+ }
150
+ return this.refreshStoredToken(stored);
151
+ }
152
+ async refreshAfterUnauthorized() {
153
+ const stored = await this.options.tokenStore.load(this.options.endpoint);
154
+ if (!stored?.refreshToken) {
155
+ return void 0;
156
+ }
157
+ return this.refreshStoredToken(stored);
158
+ }
159
+ async login() {
160
+ const pkce = generatePkcePair();
161
+ const state = generateOAuthState();
162
+ const loopback = await createLoopbackReceiver(state);
163
+ try {
164
+ const metadata = await discoverOAuthMetadata(this.options.endpoint, this.fetchImpl);
165
+ const registration = metadata.registrationEndpoint ? await registerPublicClient(metadata.registrationEndpoint, loopback.redirectUri, this.fetchImpl) : { clientId: "ainecto-cli" };
166
+ const authorizeUrl = new URL(metadata.authorizationEndpoint);
167
+ authorizeUrl.searchParams.set("response_type", "code");
168
+ authorizeUrl.searchParams.set("client_id", registration.clientId);
169
+ authorizeUrl.searchParams.set("redirect_uri", loopback.redirectUri);
170
+ authorizeUrl.searchParams.set("code_challenge", pkce.codeChallenge);
171
+ authorizeUrl.searchParams.set("code_challenge_method", "S256");
172
+ authorizeUrl.searchParams.set("resource", this.options.endpoint);
173
+ authorizeUrl.searchParams.set("state", state);
174
+ await this.openBrowserImpl(authorizeUrl.toString());
175
+ const code = await loopback.waitForCode();
176
+ const token = await exchangeToken(metadata.tokenEndpoint, {
177
+ grant_type: "authorization_code",
178
+ code,
179
+ redirect_uri: loopback.redirectUri,
180
+ client_id: registration.clientId,
181
+ code_verifier: pkce.codeVerifier,
182
+ resource: this.options.endpoint,
183
+ ...registration.clientSecret ? { client_secret: registration.clientSecret } : {}
184
+ }, this.fetchImpl);
185
+ const stored = toStoredToken(this.options.endpoint, token, metadata, registration);
186
+ await this.options.tokenStore.save(this.options.endpoint, stored);
187
+ return stored;
188
+ } finally {
189
+ await loopback.close();
190
+ }
191
+ }
192
+ async logout() {
193
+ await this.options.tokenStore.delete(this.options.endpoint);
194
+ }
195
+ async refreshStoredToken(stored) {
196
+ if (!stored.refreshToken) {
197
+ return stored.accessToken;
198
+ }
199
+ const metadata = await discoverOAuthMetadata(this.options.endpoint, this.fetchImpl);
200
+ const token = await exchangeToken(metadata.tokenEndpoint, {
201
+ grant_type: "refresh_token",
202
+ refresh_token: stored.refreshToken,
203
+ client_id: stored.clientId ?? "ainecto-cli",
204
+ ...stored.clientSecret ? { client_secret: stored.clientSecret } : {},
205
+ resource: this.options.endpoint
206
+ }, this.fetchImpl);
207
+ const next = toStoredToken(this.options.endpoint, token, metadata, stored);
208
+ await this.options.tokenStore.save(this.options.endpoint, next);
209
+ return next.accessToken;
210
+ }
211
+ };
212
+ function generatePkcePair() {
213
+ const codeVerifier = randomBytes(32).toString("base64url");
214
+ const codeChallenge = createHash2("sha256").update(codeVerifier).digest("base64url");
215
+ return { codeVerifier, codeChallenge };
216
+ }
217
+ function generateOAuthState() {
218
+ return randomBytes(32).toString("base64url");
219
+ }
220
+ function shouldRefresh(token, now = Date.now()) {
221
+ if (!token.expiresAt) {
222
+ return false;
223
+ }
224
+ return token.expiresAt - now < 6e4;
225
+ }
226
+ async function discoverOAuthMetadata(endpoint, fetchImpl = fetch) {
227
+ const resourceMetadataUrl = await discoverResourceMetadataUrl(endpoint, fetchImpl);
228
+ const resourceMetadata = await fetchJson(resourceMetadataUrl, fetchImpl);
229
+ const authorizationServers = resourceMetadata.authorization_servers;
230
+ if (!Array.isArray(authorizationServers) || typeof authorizationServers[0] !== "string") {
231
+ throw new Error("OAuth protected resource metadata did not include authorization_servers.");
232
+ }
233
+ const authServer = authorizationServers[0];
234
+ const metadataUrl = authServer.includes("/.well-known/") ? authServer : `${authServer.replace(/\/$/, "")}/.well-known/oauth-authorization-server`;
235
+ const metadata = await fetchJson(metadataUrl, fetchImpl);
236
+ if (typeof metadata.authorization_endpoint !== "string" || typeof metadata.token_endpoint !== "string") {
237
+ throw new Error("OAuth authorization server metadata is missing authorization_endpoint or token_endpoint.");
238
+ }
239
+ const codeChallengeMethodsSupported = parseStringArray(metadata.code_challenge_methods_supported);
240
+ if (!codeChallengeMethodsSupported.includes("S256")) {
241
+ throw new Error("OAuth authorization server metadata must support PKCE S256.");
242
+ }
243
+ return {
244
+ authorizationEndpoint: metadata.authorization_endpoint,
245
+ tokenEndpoint: metadata.token_endpoint,
246
+ registrationEndpoint: typeof metadata.registration_endpoint === "string" ? metadata.registration_endpoint : void 0,
247
+ issuer: typeof metadata.issuer === "string" ? metadata.issuer : void 0,
248
+ codeChallengeMethodsSupported
249
+ };
250
+ }
251
+ async function discoverResourceMetadataUrl(endpoint, fetchImpl) {
252
+ const challengeUrl = new URL(endpoint);
253
+ const response = await fetchImpl(challengeUrl, { method: "GET" });
254
+ const challenge = response.headers.get("www-authenticate");
255
+ const fromChallenge = challenge ? parseBearerChallengeParam(challenge, "resource_metadata") : void 0;
256
+ if (fromChallenge) {
257
+ return fromChallenge;
258
+ }
259
+ const origin = new URL(endpoint).origin;
260
+ return `${origin}/.well-known/oauth-protected-resource`;
261
+ }
262
+ function parseBearerChallengeParam(header, name) {
263
+ const pattern = new RegExp(`${name}="([^"]+)"`);
264
+ return pattern.exec(header)?.[1];
265
+ }
266
+ async function exchangeToken(tokenEndpoint, params, fetchImpl) {
267
+ const response = await fetchImpl(tokenEndpoint, {
268
+ method: "POST",
269
+ headers: { "content-type": "application/x-www-form-urlencoded" },
270
+ body: new URLSearchParams(params)
271
+ });
272
+ if (!response.ok) {
273
+ throw new Error(`OAuth token exchange failed with HTTP ${response.status}.`);
274
+ }
275
+ return response.json();
276
+ }
277
+ function toStoredToken(endpoint, token, metadata, previous) {
278
+ if (typeof token.access_token !== "string") {
279
+ throw new Error("OAuth token response did not include access_token.");
280
+ }
281
+ const expiresIn = typeof token.expires_in === "number" ? token.expires_in : void 0;
282
+ return {
283
+ endpoint,
284
+ accessToken: token.access_token,
285
+ refreshToken: typeof token.refresh_token === "string" ? token.refresh_token : previous?.refreshToken,
286
+ tokenType: typeof token.token_type === "string" ? token.token_type : previous?.tokenType,
287
+ expiresAt: expiresIn ? Date.now() + expiresIn * 1e3 : previous?.expiresAt,
288
+ scope: typeof token.scope === "string" ? token.scope : previous?.scope,
289
+ clientId: previous?.clientId ?? "ainecto-cli",
290
+ clientSecret: previous?.clientSecret,
291
+ authorizationServer: metadata.issuer,
292
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
293
+ };
294
+ }
295
+ async function createLoopbackReceiver(expectedState) {
296
+ let resolveCode;
297
+ let rejectCode;
298
+ const codePromise = new Promise((resolve, reject) => {
299
+ resolveCode = resolve;
300
+ rejectCode = reject;
301
+ });
302
+ codePromise.catch(() => void 0);
303
+ const server = createServer((req, res) => {
304
+ const url = new URL(req.url ?? "/", "http://127.0.0.1");
305
+ const error = url.searchParams.get("error");
306
+ const code = url.searchParams.get("code");
307
+ const state = url.searchParams.get("state");
308
+ if (error) {
309
+ res.writeHead(400, { "content-type": "text/plain" });
310
+ res.end("Ainecto CLI authorization failed. You can close this tab.");
311
+ rejectCode(new Error(`OAuth authorization failed: ${error}`));
312
+ return;
313
+ }
314
+ if (!state || state !== expectedState) {
315
+ res.writeHead(400, { "content-type": "text/plain" });
316
+ res.end("Ainecto CLI authorization state mismatch. You can close this tab.");
317
+ rejectCode(new Error("OAuth state mismatch."));
318
+ return;
319
+ }
320
+ if (!code) {
321
+ res.writeHead(400, { "content-type": "text/plain" });
322
+ res.end("Missing OAuth code.");
323
+ rejectCode(new Error("OAuth redirect did not include a code."));
324
+ return;
325
+ }
326
+ res.writeHead(200, { "content-type": "text/plain" });
327
+ res.end("Ainecto CLI authorization complete. You can close this tab.");
328
+ resolveCode(code);
329
+ });
330
+ await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
331
+ const address = server.address();
332
+ if (!address || typeof address === "string") {
333
+ throw new Error("Loopback OAuth server did not bind to a TCP port.");
334
+ }
335
+ return {
336
+ redirectUri: `http://127.0.0.1:${address.port}/callback`,
337
+ waitForCode: () => codePromise,
338
+ close: () => new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve()))
339
+ };
340
+ }
341
+ function parseStringArray(value) {
342
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
343
+ }
344
+ async function fetchJson(url, fetchImpl) {
345
+ const response = await fetchImpl(url);
346
+ if (!response.ok) {
347
+ throw new Error(`Failed to fetch OAuth metadata from ${url}: HTTP ${response.status}.`);
348
+ }
349
+ return response.json();
350
+ }
351
+ async function openBrowser(url) {
352
+ const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
353
+ const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
354
+ const child = spawn(command, args, { stdio: "ignore", detached: true });
355
+ child.unref();
356
+ }
357
+
358
+ // src/core/mcp/rpcClient.ts
359
+ var McpRpcError = class extends Error {
360
+ constructor(message, code, details) {
361
+ super(message);
362
+ this.code = code;
363
+ this.details = details;
364
+ }
365
+ code;
366
+ details;
367
+ };
368
+ var McpRpcClient = class {
369
+ constructor(options) {
370
+ this.options = options;
371
+ this.fetchImpl = options.fetchImpl ?? fetch;
372
+ }
373
+ options;
374
+ fetchImpl;
375
+ nextId = 1;
376
+ initialize() {
377
+ return this.request("initialize", {
378
+ protocolVersion: "2024-11-05",
379
+ capabilities: {},
380
+ clientInfo: { name: "@ainecto/mcp", version: "0.1.0" }
381
+ });
382
+ }
383
+ async toolsList() {
384
+ const result = await this.request("tools/list", {});
385
+ if (!isRecord2(result) || !Array.isArray(result.tools)) {
386
+ throw new McpRpcError("tools/list response did not include a tools array.", "MCP_PROTOCOL_ERROR", result);
387
+ }
388
+ return result.tools;
389
+ }
390
+ async toolsCall(name, args) {
391
+ return this.request("tools/call", { name, arguments: args ?? {} });
392
+ }
393
+ async request(method, params) {
394
+ const response = await this.sendRaw({
395
+ jsonrpc: "2.0",
396
+ id: this.nextId++,
397
+ method,
398
+ params
399
+ });
400
+ if (!response) {
401
+ return void 0;
402
+ }
403
+ if ("error" in response) {
404
+ throw new McpRpcError(response.error.message, "MCP_ERROR", response.error);
405
+ }
406
+ return response.result;
407
+ }
408
+ async sendRaw(request) {
409
+ const token = await this.options.tokenProvider?.getAccessToken();
410
+ let response = await this.postJson(request, token);
411
+ if (response.status === 401 && this.options.tokenProvider) {
412
+ const refreshed = await this.options.tokenProvider.refreshAfterUnauthorized();
413
+ if (refreshed) {
414
+ response = await this.postJson(request, refreshed);
415
+ }
416
+ }
417
+ if (response.status === 204 || response.status === 202) {
418
+ return void 0;
419
+ }
420
+ const text = await response.text();
421
+ if (!response.ok) {
422
+ throw new McpRpcError(`MCP HTTP request failed with HTTP ${response.status}.`, "MCP_HTTP_ERROR", {
423
+ status: response.status,
424
+ body: safeBodyPreview(text)
425
+ });
426
+ }
427
+ if (!text.trim()) {
428
+ return void 0;
429
+ }
430
+ const parsed = JSON.parse(text);
431
+ if (!isJsonRpcResponse(parsed)) {
432
+ throw new McpRpcError("MCP response was not a JSON-RPC response.", "MCP_PROTOCOL_ERROR", parsed);
433
+ }
434
+ return parsed;
435
+ }
436
+ postJson(request, token) {
437
+ const headers = {
438
+ "content-type": "application/json",
439
+ accept: "application/json"
440
+ };
441
+ if (token) {
442
+ headers.authorization = `Bearer ${token}`;
443
+ }
444
+ return this.fetchImpl(this.options.endpoint, {
445
+ method: "POST",
446
+ headers,
447
+ body: JSON.stringify(request)
448
+ });
449
+ }
450
+ };
451
+ function isJsonRpcResponse(value) {
452
+ return isRecord2(value) && value.jsonrpc === "2.0" && ("result" in value || "error" in value);
453
+ }
454
+ function isRecord2(value) {
455
+ return typeof value === "object" && value !== null && !Array.isArray(value);
456
+ }
457
+ function safeBodyPreview(body) {
458
+ return body.length > 500 ? `${body.slice(0, 500)}...` : body;
459
+ }
460
+
461
+ // src/core/mcp/stdioBridge.ts
462
+ import { createInterface } from "readline";
463
+ async function runStdioBridge(options) {
464
+ const lines = createInterface({ input: options.input, crlfDelay: Infinity });
465
+ for await (const line of lines) {
466
+ if (!line.trim()) {
467
+ continue;
468
+ }
469
+ try {
470
+ const request = parseJsonRpcRequest(line);
471
+ const response = await options.client.sendRaw(request);
472
+ if (response && request.id !== void 0) {
473
+ options.output.write(`${JSON.stringify(response)}
474
+ `);
475
+ }
476
+ } catch (error) {
477
+ const message = error instanceof Error ? error.message : String(error);
478
+ options.output.write(`${JSON.stringify({
479
+ jsonrpc: "2.0",
480
+ id: null,
481
+ error: { code: -32603, message }
482
+ })}
483
+ `);
484
+ }
485
+ }
486
+ }
487
+ function parseJsonRpcRequest(line) {
488
+ const parsed = JSON.parse(line);
489
+ if (!isRecord3(parsed) || parsed.jsonrpc !== "2.0" || typeof parsed.method !== "string") {
490
+ throw new Error("Invalid JSON-RPC request.");
491
+ }
492
+ return {
493
+ jsonrpc: "2.0",
494
+ id: typeof parsed.id === "string" || typeof parsed.id === "number" || parsed.id === null ? parsed.id : void 0,
495
+ method: parsed.method,
496
+ params: parsed.params
497
+ };
498
+ }
499
+ function isRecord3(value) {
500
+ return typeof value === "object" && value !== null && !Array.isArray(value);
501
+ }
502
+
503
+ // src/adapters/mcp/connector.ts
504
+ async function runConnector(options) {
505
+ const tokenStore = new FileTokenStore();
506
+ const auth = new OAuthClient({ endpoint: options.endpoint, tokenStore });
507
+ const client = new McpRpcClient({ endpoint: options.endpoint, tokenProvider: auth });
508
+ await runStdioBridge({
509
+ input: options.input,
510
+ output: options.output,
511
+ errorOutput: options.errorOutput,
512
+ client
513
+ });
514
+ }
515
+
516
+ // src/core/output/render.ts
517
+ function renderError(error, options = {}) {
518
+ const shape = toErrorShape(error);
519
+ if (options.json) {
520
+ return `${JSON.stringify(shape, null, 2)}
521
+ `;
522
+ }
523
+ return `Error: ${shape.error.message}
524
+ `;
525
+ }
526
+ function toErrorShape(error) {
527
+ if (error instanceof Error) {
528
+ const maybe = error;
529
+ return {
530
+ ok: false,
531
+ error: {
532
+ code: maybe.code ?? "CLI_ERROR",
533
+ message: error.message,
534
+ details: maybe.details
535
+ }
536
+ };
537
+ }
538
+ return { ok: false, error: { code: "CLI_ERROR", message: String(error) } };
539
+ }
540
+
541
+ // src/adapters/mcp/args.ts
542
+ function parseMcpArgs(argv) {
543
+ const result = { help: false };
544
+ for (let index = 0; index < argv.length; index += 1) {
545
+ const arg = argv[index];
546
+ if (!arg) {
547
+ continue;
548
+ }
549
+ if (arg === "--env") {
550
+ result.env = assertEnv(requireFlagValue(arg, argv[++index]));
551
+ } else if (arg === "--endpoint") {
552
+ result.endpoint = requireFlagValue(arg, argv[++index]);
553
+ } else if (arg === "--help" || arg === "-h") {
554
+ result.help = true;
555
+ } else {
556
+ throw new Error(`Unknown argument: ${arg}`);
557
+ }
558
+ }
559
+ return result;
560
+ }
561
+ function requireFlagValue(flag, value) {
562
+ if (!value || value.startsWith("--")) {
563
+ throw new Error(`${flag} requires a value.`);
564
+ }
565
+ return value;
566
+ }
567
+
568
+ // src/bin/mcp.ts
569
+ try {
570
+ const args = parseMcpArgs(process.argv.slice(2));
571
+ if (args.help) {
572
+ process.stdout.write("Usage: mcp [--env prod|dev] [--endpoint URL]\n");
573
+ process.exit(0);
574
+ }
575
+ const resolved = resolveEndpoint({ env: args.env, endpoint: args.endpoint });
576
+ await runConnector({
577
+ endpoint: resolved.endpoint,
578
+ input: process.stdin,
579
+ output: process.stdout,
580
+ errorOutput: process.stderr
581
+ });
582
+ } catch (error) {
583
+ process.stderr.write(renderError(error));
584
+ process.exitCode = 1;
585
+ }
586
+ //# sourceMappingURL=mcp.js.map