@ainecto/mcp 0.3.0 → 0.5.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.
- package/README.md +246 -86
- package/dist/bin/ainecto.js +1271 -414
- package/dist/bin/ainecto.js.map +1 -1
- package/dist/bin/mcp.js +186 -67
- package/dist/bin/mcp.js.map +1 -1
- package/package.json +3 -4
package/dist/bin/mcp.js
CHANGED
|
@@ -2,13 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
// src/core/config/endpoints.ts
|
|
4
4
|
var DEFAULT_ENDPOINTS = {
|
|
5
|
-
prod: "https://
|
|
5
|
+
prod: "https://ainecto.com/mcp",
|
|
6
6
|
dev: "https://dev.ai-erd.com/mcp"
|
|
7
7
|
};
|
|
8
|
+
var LEGACY_PROD_ENDPOINT = "https://ai-erd.com/mcp";
|
|
8
9
|
var LEGACY_DEFAULT_ENDPOINTS = [
|
|
9
|
-
|
|
10
|
+
LEGACY_PROD_ENDPOINT,
|
|
10
11
|
"https://dev.ainecto.com/mcp"
|
|
11
12
|
];
|
|
13
|
+
var TOKEN_SLOT_FALLBACKS = {
|
|
14
|
+
[DEFAULT_ENDPOINTS.prod]: [LEGACY_PROD_ENDPOINT]
|
|
15
|
+
};
|
|
16
|
+
function fallbackTokenEndpointsFor(endpoint) {
|
|
17
|
+
return TOKEN_SLOT_FALLBACKS[normalizeEndpoint(endpoint)] ?? [];
|
|
18
|
+
}
|
|
12
19
|
function resolveEndpoint(input = {}) {
|
|
13
20
|
const envVars = input.envVars ?? process.env;
|
|
14
21
|
const env = input.env ?? "prod";
|
|
@@ -65,23 +72,55 @@ import { createHash } from "crypto";
|
|
|
65
72
|
import { mkdir, readFile, rename, rm, stat, writeFile, chmod } from "fs/promises";
|
|
66
73
|
import { homedir } from "os";
|
|
67
74
|
import { dirname, join } from "path";
|
|
75
|
+
|
|
76
|
+
// src/core/harness/role.ts
|
|
77
|
+
var HARNESS_ROLES = ["design", "development", "test", "validation"];
|
|
78
|
+
var ROLE_SCOPE_PREFIX = "ai-erd:role:";
|
|
79
|
+
var ROLE_HEADER = "X-AI-ERD-Role";
|
|
80
|
+
var ROLE_ENV_VAR = "AINECTO_ROLE";
|
|
81
|
+
var LEGACY_ROLE_ENV_VAR = "AI_ERD_ROLE";
|
|
82
|
+
function resolveRole(input = {}) {
|
|
83
|
+
if (input.role !== void 0) {
|
|
84
|
+
return { role: assertRole(input.role), source: "flag" };
|
|
85
|
+
}
|
|
86
|
+
const envVars = input.envVars ?? process.env;
|
|
87
|
+
for (const envVar of [ROLE_ENV_VAR, LEGACY_ROLE_ENV_VAR]) {
|
|
88
|
+
const fromEnv = envVars[envVar];
|
|
89
|
+
if (fromEnv && fromEnv.trim()) {
|
|
90
|
+
return { role: assertRole(fromEnv), source: "env", envVar };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { source: "none" };
|
|
94
|
+
}
|
|
95
|
+
function assertRole(value) {
|
|
96
|
+
const normalized = value.trim().toLowerCase();
|
|
97
|
+
if (HARNESS_ROLES.includes(normalized)) {
|
|
98
|
+
return normalized;
|
|
99
|
+
}
|
|
100
|
+
throw new Error(
|
|
101
|
+
`Invalid role "${value}". Expected one of: ${HARNESS_ROLES.join(", ")}.`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/core/auth/tokenStore.ts
|
|
68
106
|
var FileTokenStore = class {
|
|
69
107
|
filePath;
|
|
70
108
|
constructor(rootDir = join(homedir(), ".ainecto")) {
|
|
71
109
|
this.filePath = join(rootDir, "tokens.json");
|
|
72
110
|
}
|
|
73
|
-
async load(endpoint
|
|
111
|
+
async load(endpoint) {
|
|
74
112
|
const file = await this.readFile();
|
|
75
|
-
return file[tokenKey(endpoint
|
|
113
|
+
return file[tokenKey(endpoint)];
|
|
76
114
|
}
|
|
77
|
-
async save(endpoint, token
|
|
115
|
+
async save(endpoint, token) {
|
|
116
|
+
assertNoRoleScope(token);
|
|
78
117
|
const file = await this.readFile();
|
|
79
|
-
file[tokenKey(endpoint
|
|
118
|
+
file[tokenKey(endpoint)] = { ...token, endpoint, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
80
119
|
await this.writeFile(file);
|
|
81
120
|
}
|
|
82
|
-
async delete(endpoint
|
|
121
|
+
async delete(endpoint) {
|
|
83
122
|
const file = await this.readFile();
|
|
84
|
-
delete file[tokenKey(endpoint
|
|
123
|
+
delete file[tokenKey(endpoint)];
|
|
85
124
|
await this.writeFile(file);
|
|
86
125
|
}
|
|
87
126
|
async readFile() {
|
|
@@ -116,9 +155,15 @@ var FileTokenStore = class {
|
|
|
116
155
|
await chmodIfPermissive(this.filePath, 384);
|
|
117
156
|
}
|
|
118
157
|
};
|
|
119
|
-
function tokenKey(endpoint
|
|
120
|
-
|
|
121
|
-
|
|
158
|
+
function tokenKey(endpoint) {
|
|
159
|
+
return createHash("sha256").update(endpoint).digest("hex");
|
|
160
|
+
}
|
|
161
|
+
function assertNoRoleScope(token) {
|
|
162
|
+
if (token.scope?.split(/\s+/).some((scope) => scope.startsWith(ROLE_SCOPE_PREFIX))) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
"Refusing to store a role-scoped access token: sign-in is one per machine and the role comes from the repository. Run `ainecto auth login` again."
|
|
165
|
+
);
|
|
166
|
+
}
|
|
122
167
|
}
|
|
123
168
|
function isNodeError(error, code) {
|
|
124
169
|
return error instanceof Error && "code" in error && error.code === code;
|
|
@@ -151,7 +196,7 @@ async function registerPublicClient(registrationEndpoint, redirectUri, fetchImpl
|
|
|
151
196
|
method: "POST",
|
|
152
197
|
headers: { "content-type": "application/json", accept: "application/json" },
|
|
153
198
|
body: JSON.stringify({
|
|
154
|
-
client_name: "
|
|
199
|
+
client_name: "AiNecto CLI",
|
|
155
200
|
redirect_uris: [redirectUri],
|
|
156
201
|
token_endpoint_auth_method: "none",
|
|
157
202
|
grant_types: ["authorization_code", "refresh_token"],
|
|
@@ -174,32 +219,16 @@ function isRecord(value) {
|
|
|
174
219
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
175
220
|
}
|
|
176
221
|
|
|
177
|
-
// src/core/harness/role.ts
|
|
178
|
-
var HARNESS_ROLES = ["design", "development", "test", "validation"];
|
|
179
|
-
var ROLE_SCOPE_PREFIX = "ai-erd:role:";
|
|
180
|
-
var ROLE_HEADER = "X-AI-ERD-Role";
|
|
181
|
-
var ROLE_ENV_VAR = "AI_ERD_ROLE";
|
|
182
|
-
function resolveRole(input = {}) {
|
|
183
|
-
if (input.role !== void 0) {
|
|
184
|
-
return { role: assertRole(input.role), source: "flag" };
|
|
185
|
-
}
|
|
186
|
-
const fromEnv = (input.envVars ?? process.env)[ROLE_ENV_VAR];
|
|
187
|
-
if (fromEnv && fromEnv.trim()) {
|
|
188
|
-
return { role: assertRole(fromEnv), source: "env" };
|
|
189
|
-
}
|
|
190
|
-
return { source: "none" };
|
|
191
|
-
}
|
|
192
|
-
function assertRole(value) {
|
|
193
|
-
const normalized = value.trim().toLowerCase();
|
|
194
|
-
if (HARNESS_ROLES.includes(normalized)) {
|
|
195
|
-
return normalized;
|
|
196
|
-
}
|
|
197
|
-
throw new Error(
|
|
198
|
-
`Invalid role "${value}". Expected one of: ${HARNESS_ROLES.join(", ")}.`
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
222
|
// src/core/auth/oauth.ts
|
|
223
|
+
var DEFAULT_LOGIN_TIMEOUT_MS = 3e5;
|
|
224
|
+
var OAuthLoginError = class extends Error {
|
|
225
|
+
constructor(code, message) {
|
|
226
|
+
super(message);
|
|
227
|
+
this.code = code;
|
|
228
|
+
this.name = "OAuthLoginError";
|
|
229
|
+
}
|
|
230
|
+
code;
|
|
231
|
+
};
|
|
203
232
|
var OAuthClient = class {
|
|
204
233
|
constructor(options) {
|
|
205
234
|
this.options = options;
|
|
@@ -217,21 +246,27 @@ var OAuthClient = class {
|
|
|
217
246
|
assertEnvTokenEndpointAllowed(this.options.endpoint, this.envVars);
|
|
218
247
|
return envToken;
|
|
219
248
|
}
|
|
220
|
-
const stored = await this.
|
|
249
|
+
const stored = await this.loadStored();
|
|
221
250
|
if (!stored) {
|
|
222
251
|
return void 0;
|
|
223
252
|
}
|
|
224
253
|
if (!shouldRefresh(stored)) {
|
|
225
254
|
return stored.accessToken;
|
|
226
255
|
}
|
|
227
|
-
|
|
256
|
+
if (this.options.readOnly) {
|
|
257
|
+
return isExpired(stored) ? void 0 : stored.accessToken;
|
|
258
|
+
}
|
|
259
|
+
if (!stored.refreshToken) {
|
|
260
|
+
return isExpired(stored) ? void 0 : stored.accessToken;
|
|
261
|
+
}
|
|
262
|
+
return this.refreshStoredToken({ ...stored, refreshToken: stored.refreshToken });
|
|
228
263
|
}
|
|
229
264
|
async refreshAfterUnauthorized() {
|
|
230
|
-
const stored = await this.
|
|
231
|
-
if (!stored?.refreshToken) {
|
|
265
|
+
const stored = await this.loadStored();
|
|
266
|
+
if (this.options.readOnly || !stored?.refreshToken) {
|
|
232
267
|
return void 0;
|
|
233
268
|
}
|
|
234
|
-
return this.refreshStoredToken(stored);
|
|
269
|
+
return this.refreshStoredToken({ ...stored, refreshToken: stored.refreshToken });
|
|
235
270
|
}
|
|
236
271
|
async login() {
|
|
237
272
|
const pkce = generatePkcePair();
|
|
@@ -248,12 +283,14 @@ var OAuthClient = class {
|
|
|
248
283
|
authorizeUrl.searchParams.set("code_challenge_method", "S256");
|
|
249
284
|
authorizeUrl.searchParams.set("resource", this.options.endpoint);
|
|
250
285
|
authorizeUrl.searchParams.set("state", state);
|
|
251
|
-
if (this.options.role) {
|
|
252
|
-
authorizeUrl.searchParams.set("scope", `mcp ${ROLE_SCOPE_PREFIX}${this.options.role}`);
|
|
253
|
-
}
|
|
254
286
|
assertTrustedEndpointUrl(authorizeUrl, "OAuth authorization URL");
|
|
255
|
-
|
|
256
|
-
|
|
287
|
+
const url = authorizeUrl.toString();
|
|
288
|
+
this.options.onAuthorizeUrl?.(url);
|
|
289
|
+
const browserFailure = this.openBrowserImpl(url).then(() => new Promise(() => void 0));
|
|
290
|
+
const code = await withTimeout(
|
|
291
|
+
Promise.race([loopback.waitForCode(), browserFailure]),
|
|
292
|
+
this.options.loginTimeoutMs ?? DEFAULT_LOGIN_TIMEOUT_MS
|
|
293
|
+
);
|
|
257
294
|
const token = await exchangeToken(metadata.tokenEndpoint, {
|
|
258
295
|
grant_type: "authorization_code",
|
|
259
296
|
code,
|
|
@@ -264,19 +301,38 @@ var OAuthClient = class {
|
|
|
264
301
|
...registration.clientSecret ? { client_secret: registration.clientSecret } : {}
|
|
265
302
|
}, this.fetchImpl);
|
|
266
303
|
const stored = toStoredToken(this.options.endpoint, token, metadata, registration);
|
|
267
|
-
await this.options.tokenStore.save(this.options.endpoint, stored
|
|
304
|
+
await this.options.tokenStore.save(this.options.endpoint, stored);
|
|
268
305
|
return stored;
|
|
269
306
|
} finally {
|
|
270
307
|
await loopback.close();
|
|
271
308
|
}
|
|
272
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* ★대체로 읽는 옛 칸도 함께 지운다. 새 칸만 지우면 다음 읽기가 곧바로 옛 칸으로 대체돼
|
|
312
|
+
* «로그아웃했는데 여전히 로그인됨»이 된다. 로그인은 기계당 한 번이므로 옛 CLI 의 칸도 같이 끝난다.
|
|
313
|
+
*/
|
|
273
314
|
async logout() {
|
|
274
|
-
await this.options.tokenStore.delete(this.options.endpoint
|
|
315
|
+
await this.options.tokenStore.delete(this.options.endpoint);
|
|
316
|
+
for (const fallback of fallbackTokenEndpointsFor(this.options.endpoint)) {
|
|
317
|
+
await this.options.tokenStore.delete(fallback);
|
|
318
|
+
}
|
|
275
319
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
320
|
+
/** 이 주소의 칸, 비었으면 옛 기본 주소의 칸({@link fallbackTokenEndpointsFor}). 쓰기는 늘 이 주소의 칸이다. */
|
|
321
|
+
async loadStored() {
|
|
322
|
+
const own = await this.options.tokenStore.load(this.options.endpoint);
|
|
323
|
+
if (own) {
|
|
324
|
+
return own;
|
|
279
325
|
}
|
|
326
|
+
for (const fallback of fallbackTokenEndpointsFor(this.options.endpoint)) {
|
|
327
|
+
const stored = await this.options.tokenStore.load(fallback);
|
|
328
|
+
if (stored) {
|
|
329
|
+
return stored;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return void 0;
|
|
333
|
+
}
|
|
334
|
+
/** 부르는 쪽이 refresh token 이 있음을 이미 확인했다 — 타입이 그것을 요구한다. */
|
|
335
|
+
async refreshStoredToken(stored) {
|
|
280
336
|
const metadata = await discoverOAuthMetadata(this.options.endpoint, this.fetchImpl);
|
|
281
337
|
const token = await exchangeToken(metadata.tokenEndpoint, {
|
|
282
338
|
grant_type: "refresh_token",
|
|
@@ -286,7 +342,7 @@ var OAuthClient = class {
|
|
|
286
342
|
resource: this.options.endpoint
|
|
287
343
|
}, this.fetchImpl);
|
|
288
344
|
const next = toStoredToken(this.options.endpoint, token, metadata, stored);
|
|
289
|
-
await this.options.tokenStore.save(this.options.endpoint, next
|
|
345
|
+
await this.options.tokenStore.save(this.options.endpoint, next);
|
|
290
346
|
return next.accessToken;
|
|
291
347
|
}
|
|
292
348
|
};
|
|
@@ -298,6 +354,27 @@ function generatePkcePair() {
|
|
|
298
354
|
function generateOAuthState() {
|
|
299
355
|
return randomBytes(32).toString("base64url");
|
|
300
356
|
}
|
|
357
|
+
function isExpired(token, now = Date.now()) {
|
|
358
|
+
return token.expiresAt !== void 0 && token.expiresAt <= now;
|
|
359
|
+
}
|
|
360
|
+
async function withTimeout(work, timeoutMs) {
|
|
361
|
+
let timer;
|
|
362
|
+
const timeout = new Promise((_, reject) => {
|
|
363
|
+
timer = setTimeout(() => {
|
|
364
|
+
const minutes = timeoutMs / 6e4;
|
|
365
|
+
const span = Number.isInteger(minutes) ? `${minutes} minute${minutes === 1 ? "" : "s"}` : `${timeoutMs} ms`;
|
|
366
|
+
reject(new OAuthLoginError(
|
|
367
|
+
"LOGIN_TIMEOUT",
|
|
368
|
+
`Sign-in was not completed within ${span}. Nothing was saved \u2014 run the same command again.`
|
|
369
|
+
));
|
|
370
|
+
}, timeoutMs);
|
|
371
|
+
});
|
|
372
|
+
try {
|
|
373
|
+
return await Promise.race([work, timeout]);
|
|
374
|
+
} finally {
|
|
375
|
+
clearTimeout(timer);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
301
378
|
function shouldRefresh(token, now = Date.now()) {
|
|
302
379
|
if (!token.expiresAt) {
|
|
303
380
|
return false;
|
|
@@ -390,7 +467,7 @@ function toStoredToken(endpoint, token, metadata, previous) {
|
|
|
390
467
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
391
468
|
};
|
|
392
469
|
}
|
|
393
|
-
async function createLoopbackReceiver(expectedState) {
|
|
470
|
+
async function createLoopbackReceiver(expectedState, host = "127.0.0.1") {
|
|
394
471
|
let resolveCode;
|
|
395
472
|
let rejectCode;
|
|
396
473
|
const codePromise = new Promise((resolve, reject) => {
|
|
@@ -405,13 +482,13 @@ async function createLoopbackReceiver(expectedState) {
|
|
|
405
482
|
const state = url.searchParams.get("state");
|
|
406
483
|
if (error) {
|
|
407
484
|
res.writeHead(400, { "content-type": "text/plain" });
|
|
408
|
-
res.end("
|
|
485
|
+
res.end("AiNecto CLI authorization failed. You can close this tab.");
|
|
409
486
|
rejectCode(new Error(`OAuth authorization failed: ${error}`));
|
|
410
487
|
return;
|
|
411
488
|
}
|
|
412
489
|
if (!state || state !== expectedState) {
|
|
413
490
|
res.writeHead(400, { "content-type": "text/plain" });
|
|
414
|
-
res.end("
|
|
491
|
+
res.end("AiNecto CLI authorization state mismatch. You can close this tab.");
|
|
415
492
|
rejectCode(new Error("OAuth state mismatch."));
|
|
416
493
|
return;
|
|
417
494
|
}
|
|
@@ -422,10 +499,16 @@ async function createLoopbackReceiver(expectedState) {
|
|
|
422
499
|
return;
|
|
423
500
|
}
|
|
424
501
|
res.writeHead(200, { "content-type": "text/plain" });
|
|
425
|
-
res.end("
|
|
502
|
+
res.end("AiNecto CLI authorization complete. You can close this tab.");
|
|
426
503
|
resolveCode(code);
|
|
427
504
|
});
|
|
428
|
-
await new Promise((resolve) =>
|
|
505
|
+
await new Promise((resolve, reject) => {
|
|
506
|
+
server.once("error", (error) => reject(new OAuthLoginError(
|
|
507
|
+
"CALLBACK_UNAVAILABLE",
|
|
508
|
+
`Could not start the local sign-in callback on ${host} (${error.message}). If this command runs in a sandbox, allow local network binding or run it outside the sandbox.`
|
|
509
|
+
)));
|
|
510
|
+
server.listen(0, host, () => resolve());
|
|
511
|
+
});
|
|
429
512
|
const address = server.address();
|
|
430
513
|
if (!address || typeof address === "string") {
|
|
431
514
|
throw new Error("Loopback OAuth server did not bind to a TCP port.");
|
|
@@ -433,7 +516,10 @@ async function createLoopbackReceiver(expectedState) {
|
|
|
433
516
|
return {
|
|
434
517
|
redirectUri: `http://127.0.0.1:${address.port}/callback`,
|
|
435
518
|
waitForCode: () => codePromise,
|
|
436
|
-
close: () => new Promise((resolve, reject) =>
|
|
519
|
+
close: () => new Promise((resolve, reject) => {
|
|
520
|
+
server.closeAllConnections?.();
|
|
521
|
+
server.close((error) => error ? reject(error) : resolve());
|
|
522
|
+
})
|
|
437
523
|
};
|
|
438
524
|
}
|
|
439
525
|
function parseStringArray(value) {
|
|
@@ -457,10 +543,39 @@ function getBrowserOpenCommand(url, platform = process.platform) {
|
|
|
457
543
|
}
|
|
458
544
|
return { command: "xdg-open", args: [url] };
|
|
459
545
|
}
|
|
460
|
-
|
|
461
|
-
const
|
|
462
|
-
const
|
|
463
|
-
|
|
546
|
+
function launchBrowser(url, deps = {}) {
|
|
547
|
+
const platform = deps.platform ?? process.platform;
|
|
548
|
+
const { command, args } = getBrowserOpenCommand(url, platform);
|
|
549
|
+
const spawnImpl = deps.spawnImpl ?? spawn;
|
|
550
|
+
return new Promise((resolve, reject) => {
|
|
551
|
+
const unavailable = (reason) => new OAuthLoginError(
|
|
552
|
+
"BROWSER_UNAVAILABLE",
|
|
553
|
+
`Could not open a browser on this machine (${command}: ${reason}). Sign-in needs a browser here.`
|
|
554
|
+
);
|
|
555
|
+
let child;
|
|
556
|
+
try {
|
|
557
|
+
child = spawnImpl(command, args, { stdio: "ignore", detached: true });
|
|
558
|
+
} catch (error) {
|
|
559
|
+
reject(unavailable(error instanceof Error ? error.message : String(error)));
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
child.once("error", (error) => reject(unavailable(error.message)));
|
|
563
|
+
if (platform === "win32") {
|
|
564
|
+
child.once("spawn", () => resolve());
|
|
565
|
+
} else {
|
|
566
|
+
child.once("exit", (code, signal) => {
|
|
567
|
+
if (code === 0) {
|
|
568
|
+
resolve();
|
|
569
|
+
} else {
|
|
570
|
+
reject(unavailable(code === null ? `stopped by ${signal ?? "a signal"}` : `exited with code ${code}`));
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
child.unref();
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
function openBrowser(url) {
|
|
578
|
+
return launchBrowser(url);
|
|
464
579
|
}
|
|
465
580
|
function assertEnvTokenEndpointAllowed(endpoint, envVars) {
|
|
466
581
|
if (envVars.AINECTO_ALLOW_CUSTOM_ENDPOINT_TOKEN === "1") {
|
|
@@ -472,6 +587,11 @@ function assertEnvTokenEndpointAllowed(endpoint, envVars) {
|
|
|
472
587
|
throw new Error("AINECTO_TOKEN can only be used with the default prod/dev endpoints. Set AINECTO_ALLOW_CUSTOM_ENDPOINT_TOKEN=1 only when you intentionally trust the custom endpoint.");
|
|
473
588
|
}
|
|
474
589
|
|
|
590
|
+
// src/core/version.ts
|
|
591
|
+
var CLI_VERSION = true ? "0.5.0" : "dev";
|
|
592
|
+
var PACKAGE_NAME = "@ainecto/mcp";
|
|
593
|
+
var CLI_USER_AGENT = `${PACKAGE_NAME} ${CLI_VERSION}`;
|
|
594
|
+
|
|
475
595
|
// src/core/mcp/rpcClient.ts
|
|
476
596
|
var McpRpcError = class extends Error {
|
|
477
597
|
constructor(message, code, details) {
|
|
@@ -494,7 +614,7 @@ var McpRpcClient = class {
|
|
|
494
614
|
return this.request("initialize", {
|
|
495
615
|
protocolVersion: "2024-11-05",
|
|
496
616
|
capabilities: {},
|
|
497
|
-
clientInfo: { name:
|
|
617
|
+
clientInfo: { name: PACKAGE_NAME, version: CLI_VERSION }
|
|
498
618
|
});
|
|
499
619
|
}
|
|
500
620
|
async toolsList() {
|
|
@@ -630,8 +750,7 @@ function isRecord3(value) {
|
|
|
630
750
|
|
|
631
751
|
// src/adapters/mcp/connector.ts
|
|
632
752
|
async function runConnector(options) {
|
|
633
|
-
const
|
|
634
|
-
const auth = new OAuthClient({ endpoint: options.endpoint, tokenStore, role: options.role });
|
|
753
|
+
const auth = new OAuthClient({ endpoint: options.endpoint, tokenStore: new FileTokenStore() });
|
|
635
754
|
const client = new McpRpcClient({
|
|
636
755
|
endpoint: options.endpoint,
|
|
637
756
|
tokenProvider: auth,
|
|
@@ -743,7 +862,7 @@ try {
|
|
|
743
862
|
const resolvedRole = resolveRole({ role: args.role });
|
|
744
863
|
await runConnector({
|
|
745
864
|
endpoint: resolved.endpoint,
|
|
746
|
-
role: resolvedRole.role,
|
|
865
|
+
role: resolvedRole.role ?? null,
|
|
747
866
|
input: process.stdin,
|
|
748
867
|
output: process.stdout,
|
|
749
868
|
errorOutput: process.stderr
|