@ontos-ai/knowhere-mcp 0.2.0 → 0.3.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 CHANGED
@@ -41,10 +41,12 @@ npx -y @ontos-ai/knowhere-mcp logout
41
41
 
42
42
  `knowhere-mcp status` shows the stored Permission for the current login.
43
43
 
44
- Set `KNOWHERE_DASHBOARD_URL` when logging in through a non-default dashboard.
45
- Set `KNOWHERE_BASE_URL` only when using a non-default Knowhere API endpoint.
46
- `KNOWHERE_API_KEY` is still supported as a manual fallback and takes precedence
47
- over the local dashboard login. API-key authentication runs with full access.
44
+ Set `KNOWHERE_BASE_URL` (or `--base-url`) to the Knowhere site base URL when
45
+ using a non-default environment, e.g. `https://staging.knowhereto.ai`; it
46
+ defaults to `https://knowhereto.ai`. The API and login routes are derived from
47
+ it. `KNOWHERE_API_KEY` is still supported as a manual fallback and takes
48
+ precedence over the local dashboard login. API-key authentication runs with
49
+ full access.
48
50
 
49
51
  ## Connect From MCP Hosts
50
52
 
package/dist/stdio.js CHANGED
@@ -342,17 +342,26 @@ var import_os = __toESM(require("os"));
342
342
  var import_path = __toESM(require("path"));
343
343
  var import_promises = require("fs/promises");
344
344
  var import_knowhere_sdk2 = require("@ontos-ai/knowhere-sdk");
345
- var DEFAULT_DASHBOARD_URL = "https://knowhereto.ai";
345
+ var DEFAULT_BASE_URL = "https://knowhereto.ai";
346
346
  var AUTH_FILE_ENV = "KNOWHERE_MCP_AUTH_FILE";
347
- var DASHBOARD_URL_ENV = "KNOWHERE_DASHBOARD_URL";
348
- var API_BASE_URL_ENV = "KNOWHERE_BASE_URL";
347
+ var BASE_URL_ENV = "KNOWHERE_BASE_URL";
349
348
  var API_KEY_ENV = "KNOWHERE_API_KEY";
350
349
  var TOKEN_REFRESH_SKEW_MS = 5 * 60 * 1e3;
351
350
  var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
352
351
  var RANDOM_BYTE_LENGTH = 32;
353
- var DEFAULT_CLIENT_NAME = "knowhere-cli";
352
+ var DEFAULT_CLIENT_NAME = "knowhere-mcp";
354
353
  var DEFAULT_PERMISSION = "full_access";
355
354
  var PERMISSION_VALUES = /* @__PURE__ */ new Set(["read_only", "full_access"]);
355
+ function resolveMcpUrls(base) {
356
+ const normalized = base.replace(/\/+$/, "");
357
+ return {
358
+ base: normalized,
359
+ api: `${normalized}/api`,
360
+ mcpLogin: `${normalized}/mcp/login`,
361
+ token: `${normalized}/api/oauth/token`,
362
+ revoke: `${normalized}/api/oauth/revoke`
363
+ };
364
+ }
356
365
  var McpCredentialManager = class {
357
366
  authFilePath;
358
367
  refreshPromise;
@@ -367,7 +376,7 @@ var McpCredentialManager = class {
367
376
  return {
368
377
  source: "api_key",
369
378
  authFilePath: this.authFilePath,
370
- apiBaseUrl: process.env[API_BASE_URL_ENV],
379
+ baseUrl: process.env[BASE_URL_ENV],
371
380
  permission: DEFAULT_PERMISSION
372
381
  };
373
382
  }
@@ -378,8 +387,7 @@ var McpCredentialManager = class {
378
387
  return {
379
388
  source: "stored_login",
380
389
  authFilePath: this.authFilePath,
381
- dashboardUrl: storedAuth.dashboardUrl,
382
- apiBaseUrl: process.env[API_BASE_URL_ENV] ?? storedAuth.apiBaseUrl,
390
+ baseUrl: process.env[BASE_URL_ENV] ?? storedAuth.baseUrl,
383
391
  permission: storedAuth.permission,
384
392
  refreshTokenExpiresAt: storedAuth.refreshTokenExpiresAt,
385
393
  accessTokenExpiresAt: storedAuth.accessTokenExpiresAt
@@ -406,17 +414,17 @@ var McpCredentialManager = class {
406
414
  return this.refreshPromise;
407
415
  }
408
416
  async login(options = {}) {
409
- const dashboardUrl = normalizeDashboardUrl(
410
- options.dashboardUrl ?? process.env[DASHBOARD_URL_ENV] ?? DEFAULT_DASHBOARD_URL
417
+ const baseUrl = normalizeBaseUrl(
418
+ options.baseUrl ?? process.env[BASE_URL_ENV] ?? DEFAULT_BASE_URL
411
419
  );
412
- const apiBaseUrl = options.baseURL ?? process.env[API_BASE_URL_ENV];
420
+ const urls = resolveMcpUrls(baseUrl);
413
421
  const codeVerifier = createRandomToken();
414
422
  const state = createRandomToken();
415
423
  const codeChallenge = createPkceChallenge(codeVerifier);
416
424
  const callback = await createLoopbackCallback(state);
417
425
  try {
418
426
  const loginUrl = buildLoginUrl({
419
- dashboardUrl,
427
+ loginEndpoint: urls.mcpLogin,
420
428
  redirectUri: callback.redirectUri,
421
429
  state,
422
430
  codeChallenge,
@@ -427,23 +435,21 @@ var McpCredentialManager = class {
427
435
  openBrowser(loginUrl);
428
436
  }
429
437
  const code = await callback.waitForCode();
430
- const tokenResponse = await requestToken(dashboardUrl, {
438
+ const tokenResponse = await requestToken(urls.token, {
431
439
  grant_type: "authorization_code",
432
440
  code,
433
441
  code_verifier: codeVerifier,
434
442
  client_name: options.clientName ?? DEFAULT_CLIENT_NAME
435
443
  });
436
444
  const storedAuth = buildStoredAuth({
437
- dashboardUrl,
438
- apiBaseUrl,
445
+ baseUrl,
439
446
  tokenResponse,
440
447
  previous: await this.readAuth()
441
448
  });
442
449
  await this.writeAuth(storedAuth);
443
450
  return {
444
451
  authFilePath: this.authFilePath,
445
- dashboardUrl,
446
- apiBaseUrl,
452
+ baseUrl,
447
453
  permission: tokenResponse.permission,
448
454
  refreshTokenExpiresAt: tokenResponse.refreshTokenExpiresAt
449
455
  };
@@ -456,7 +462,7 @@ var McpCredentialManager = class {
456
462
  let revokeError;
457
463
  if (storedAuth) {
458
464
  try {
459
- await requestRevoke(storedAuth.dashboardUrl, storedAuth.refreshToken);
465
+ await requestRevoke(resolveMcpUrls(storedAuth.baseUrl).revoke, storedAuth.refreshToken);
460
466
  } catch (error) {
461
467
  revokeError = error instanceof Error ? error.message : "Failed to revoke MCP login";
462
468
  }
@@ -469,16 +475,20 @@ var McpCredentialManager = class {
469
475
  };
470
476
  }
471
477
  async resolveBaseURL() {
472
- return process.env[API_BASE_URL_ENV] ?? (await this.readAuth())?.apiBaseUrl;
478
+ const envBase = process.env[BASE_URL_ENV];
479
+ if (envBase) {
480
+ return resolveMcpUrls(envBase).api;
481
+ }
482
+ const storedAuth = await this.readAuth();
483
+ return storedAuth ? resolveMcpUrls(storedAuth.baseUrl).api : void 0;
473
484
  }
474
485
  async refreshAccessToken(storedAuth) {
475
- const tokenResponse = await requestToken(storedAuth.dashboardUrl, {
486
+ const tokenResponse = await requestToken(resolveMcpUrls(storedAuth.baseUrl).token, {
476
487
  grant_type: "refresh_token",
477
488
  refresh_token: storedAuth.refreshToken
478
489
  });
479
490
  const refreshedAuth = buildStoredAuth({
480
- dashboardUrl: storedAuth.dashboardUrl,
481
- apiBaseUrl: storedAuth.apiBaseUrl,
491
+ baseUrl: storedAuth.baseUrl,
482
492
  tokenResponse,
483
493
  previous: storedAuth
484
494
  });
@@ -516,8 +526,7 @@ function isUsableAccessToken(storedAuth) {
516
526
  return Number.isFinite(expiresAt) && expiresAt - Date.now() > TOKEN_REFRESH_SKEW_MS;
517
527
  }
518
528
  function buildStoredAuth({
519
- dashboardUrl,
520
- apiBaseUrl,
529
+ baseUrl,
521
530
  tokenResponse,
522
531
  previous
523
532
  }) {
@@ -530,8 +539,7 @@ function buildStoredAuth({
530
539
  throw new Error("Knowhere MCP token response did not include a refresh token");
531
540
  }
532
541
  return {
533
- dashboardUrl,
534
- apiBaseUrl,
542
+ baseUrl,
535
543
  permission: tokenResponse.permission,
536
544
  refreshToken,
537
545
  refreshTokenExpiresAt: tokenResponse.refreshTokenExpiresAt ?? previous?.refreshTokenExpiresAt,
@@ -545,13 +553,12 @@ function parseStoredAuth(value) {
545
553
  if (!isRecord(value)) {
546
554
  throw new Error("Invalid Knowhere MCP auth file");
547
555
  }
548
- const dashboardUrl = readRequiredString(value, "dashboardUrl");
556
+ const baseUrl = readRequiredString(value, "baseUrl");
549
557
  const refreshToken = readRequiredString(value, "refreshToken");
550
558
  const createdAt = readRequiredString(value, "createdAt");
551
559
  const updatedAt = readRequiredString(value, "updatedAt");
552
560
  return {
553
- dashboardUrl,
554
- apiBaseUrl: readOptionalString(value, "apiBaseUrl"),
561
+ baseUrl,
555
562
  permission: normalizePermission(readOptionalString(value, "permission")),
556
563
  refreshToken,
557
564
  refreshTokenExpiresAt: readOptionalString(value, "refreshTokenExpiresAt"),
@@ -586,13 +593,13 @@ function createPkceChallenge(codeVerifier) {
586
593
  return import_crypto.default.createHash("sha256").update(codeVerifier).digest("base64url");
587
594
  }
588
595
  function buildLoginUrl({
589
- dashboardUrl,
596
+ loginEndpoint,
590
597
  redirectUri,
591
598
  state,
592
599
  codeChallenge,
593
600
  clientName
594
601
  }) {
595
- const url = new URL("/mcp/login", dashboardUrl);
602
+ const url = new URL(loginEndpoint);
596
603
  url.searchParams.set("redirect_uri", redirectUri);
597
604
  url.searchParams.set("state", state);
598
605
  url.searchParams.set("code_challenge", codeChallenge);
@@ -692,8 +699,8 @@ function handleCallbackRequest({
692
699
  );
693
700
  resolveCode(code);
694
701
  }
695
- async function requestToken(dashboardUrl, body) {
696
- const response = await fetch(new URL("/api/mcp/token", dashboardUrl), {
702
+ async function requestToken(tokenUrl, body) {
703
+ const response = await fetch(tokenUrl, {
697
704
  method: "POST",
698
705
  headers: { "Content-Type": "application/json" },
699
706
  body: JSON.stringify(body)
@@ -704,8 +711,8 @@ async function requestToken(dashboardUrl, body) {
704
711
  }
705
712
  return parseTokenResponse(responseBody);
706
713
  }
707
- async function requestRevoke(dashboardUrl, refreshToken) {
708
- const response = await fetch(new URL("/api/mcp/revoke", dashboardUrl), {
714
+ async function requestRevoke(revokeUrl, refreshToken) {
715
+ const response = await fetch(revokeUrl, {
709
716
  method: "POST",
710
717
  headers: { "Content-Type": "application/json" },
711
718
  body: JSON.stringify({ refresh_token: refreshToken })
@@ -751,12 +758,12 @@ function getResponseMessage(responseBody, fallback) {
751
758
  }
752
759
  return fallback;
753
760
  }
754
- function normalizeDashboardUrl(value) {
761
+ function normalizeBaseUrl(value) {
755
762
  const url = new URL(value);
756
763
  url.pathname = "/";
757
764
  url.search = "";
758
765
  url.hash = "";
759
- return url.toString();
766
+ return url.toString().replace(/\/+$/, "");
760
767
  }
761
768
  function normalizePermission(value) {
762
769
  if (value && PERMISSION_VALUES.has(value)) {
@@ -827,8 +834,7 @@ async function runLogin(args) {
827
834
  const options = parseLoginArgs(args);
828
835
  const credentialManager = new McpCredentialManager(options.authFilePath);
829
836
  const result = await credentialManager.login({
830
- dashboardUrl: options.dashboardUrl,
831
- baseURL: options.baseURL,
837
+ baseUrl: options.baseUrl,
832
838
  openBrowser: options.openBrowser,
833
839
  clientName: options.clientName,
834
840
  onLoginUrl: (url) => {
@@ -866,12 +872,8 @@ function parseLoginArgs(args) {
866
872
  for (let index = 0; index < args.length; index += 1) {
867
873
  const arg = args[index];
868
874
  switch (arg) {
869
- case "--dashboard-url":
870
- options.dashboardUrl = readFlagValue(args, index, arg);
871
- index += 1;
872
- break;
873
875
  case "--base-url":
874
- options.baseURL = readFlagValue(args, index, arg);
876
+ options.baseUrl = readFlagValue(args, index, arg);
875
877
  index += 1;
876
878
  break;
877
879
  case "--auth-file":
@@ -910,8 +912,7 @@ function formatStatus(status) {
910
912
  return [
911
913
  "Knowhere MCP is authenticated with dashboard login",
912
914
  `Auth file: ${status.authFilePath}`,
913
- `Dashboard: ${status.dashboardUrl ?? "unknown"}`,
914
- `API base URL: ${status.apiBaseUrl ?? "default"}`,
915
+ `Base URL: ${status.baseUrl ?? "unknown"}`,
915
916
  `Permission: ${status.permission ?? "full_access"}`,
916
917
  `Refresh token expires: ${status.refreshTokenExpiresAt ?? "unknown"}`,
917
918
  `Access token expires: ${status.accessTokenExpiresAt ?? "not cached"}`
@@ -931,8 +932,7 @@ function printHelp() {
931
932
  knowhere-mcp logout Remove and revoke local MCP login
932
933
 
933
934
  Login options:
934
- --dashboard-url <url> Dashboard URL, defaults to KNOWHERE_DASHBOARD_URL or https://knowhereto.ai
935
- --base-url <url> Knowhere API URL, defaults to KNOWHERE_BASE_URL or SDK default
935
+ --base-url <url> Knowhere site base URL, defaults to KNOWHERE_BASE_URL or https://knowhereto.ai
936
936
  --auth-file <path> Override local auth file path
937
937
  --client-name <name> Label shown in dashboard token records
938
938
  --no-open Print login URL without opening a browser`);
package/dist/stdio.mjs CHANGED
@@ -11,17 +11,26 @@ import os from "os";
11
11
  import path from "path";
12
12
  import { mkdir, readFile, rm, writeFile, chmod } from "fs/promises";
13
13
  import { ValidationError } from "@ontos-ai/knowhere-sdk";
14
- var DEFAULT_DASHBOARD_URL = "https://knowhereto.ai";
14
+ var DEFAULT_BASE_URL = "https://knowhereto.ai";
15
15
  var AUTH_FILE_ENV = "KNOWHERE_MCP_AUTH_FILE";
16
- var DASHBOARD_URL_ENV = "KNOWHERE_DASHBOARD_URL";
17
- var API_BASE_URL_ENV = "KNOWHERE_BASE_URL";
16
+ var BASE_URL_ENV = "KNOWHERE_BASE_URL";
18
17
  var API_KEY_ENV = "KNOWHERE_API_KEY";
19
18
  var TOKEN_REFRESH_SKEW_MS = 5 * 60 * 1e3;
20
19
  var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
21
20
  var RANDOM_BYTE_LENGTH = 32;
22
- var DEFAULT_CLIENT_NAME = "knowhere-cli";
21
+ var DEFAULT_CLIENT_NAME = "knowhere-mcp";
23
22
  var DEFAULT_PERMISSION = "full_access";
24
23
  var PERMISSION_VALUES = /* @__PURE__ */ new Set(["read_only", "full_access"]);
24
+ function resolveMcpUrls(base) {
25
+ const normalized = base.replace(/\/+$/, "");
26
+ return {
27
+ base: normalized,
28
+ api: `${normalized}/api`,
29
+ mcpLogin: `${normalized}/mcp/login`,
30
+ token: `${normalized}/api/oauth/token`,
31
+ revoke: `${normalized}/api/oauth/revoke`
32
+ };
33
+ }
25
34
  var McpCredentialManager = class {
26
35
  authFilePath;
27
36
  refreshPromise;
@@ -36,7 +45,7 @@ var McpCredentialManager = class {
36
45
  return {
37
46
  source: "api_key",
38
47
  authFilePath: this.authFilePath,
39
- apiBaseUrl: process.env[API_BASE_URL_ENV],
48
+ baseUrl: process.env[BASE_URL_ENV],
40
49
  permission: DEFAULT_PERMISSION
41
50
  };
42
51
  }
@@ -47,8 +56,7 @@ var McpCredentialManager = class {
47
56
  return {
48
57
  source: "stored_login",
49
58
  authFilePath: this.authFilePath,
50
- dashboardUrl: storedAuth.dashboardUrl,
51
- apiBaseUrl: process.env[API_BASE_URL_ENV] ?? storedAuth.apiBaseUrl,
59
+ baseUrl: process.env[BASE_URL_ENV] ?? storedAuth.baseUrl,
52
60
  permission: storedAuth.permission,
53
61
  refreshTokenExpiresAt: storedAuth.refreshTokenExpiresAt,
54
62
  accessTokenExpiresAt: storedAuth.accessTokenExpiresAt
@@ -75,17 +83,17 @@ var McpCredentialManager = class {
75
83
  return this.refreshPromise;
76
84
  }
77
85
  async login(options = {}) {
78
- const dashboardUrl = normalizeDashboardUrl(
79
- options.dashboardUrl ?? process.env[DASHBOARD_URL_ENV] ?? DEFAULT_DASHBOARD_URL
86
+ const baseUrl = normalizeBaseUrl(
87
+ options.baseUrl ?? process.env[BASE_URL_ENV] ?? DEFAULT_BASE_URL
80
88
  );
81
- const apiBaseUrl = options.baseURL ?? process.env[API_BASE_URL_ENV];
89
+ const urls = resolveMcpUrls(baseUrl);
82
90
  const codeVerifier = createRandomToken();
83
91
  const state = createRandomToken();
84
92
  const codeChallenge = createPkceChallenge(codeVerifier);
85
93
  const callback = await createLoopbackCallback(state);
86
94
  try {
87
95
  const loginUrl = buildLoginUrl({
88
- dashboardUrl,
96
+ loginEndpoint: urls.mcpLogin,
89
97
  redirectUri: callback.redirectUri,
90
98
  state,
91
99
  codeChallenge,
@@ -96,23 +104,21 @@ var McpCredentialManager = class {
96
104
  openBrowser(loginUrl);
97
105
  }
98
106
  const code = await callback.waitForCode();
99
- const tokenResponse = await requestToken(dashboardUrl, {
107
+ const tokenResponse = await requestToken(urls.token, {
100
108
  grant_type: "authorization_code",
101
109
  code,
102
110
  code_verifier: codeVerifier,
103
111
  client_name: options.clientName ?? DEFAULT_CLIENT_NAME
104
112
  });
105
113
  const storedAuth = buildStoredAuth({
106
- dashboardUrl,
107
- apiBaseUrl,
114
+ baseUrl,
108
115
  tokenResponse,
109
116
  previous: await this.readAuth()
110
117
  });
111
118
  await this.writeAuth(storedAuth);
112
119
  return {
113
120
  authFilePath: this.authFilePath,
114
- dashboardUrl,
115
- apiBaseUrl,
121
+ baseUrl,
116
122
  permission: tokenResponse.permission,
117
123
  refreshTokenExpiresAt: tokenResponse.refreshTokenExpiresAt
118
124
  };
@@ -125,7 +131,7 @@ var McpCredentialManager = class {
125
131
  let revokeError;
126
132
  if (storedAuth) {
127
133
  try {
128
- await requestRevoke(storedAuth.dashboardUrl, storedAuth.refreshToken);
134
+ await requestRevoke(resolveMcpUrls(storedAuth.baseUrl).revoke, storedAuth.refreshToken);
129
135
  } catch (error) {
130
136
  revokeError = error instanceof Error ? error.message : "Failed to revoke MCP login";
131
137
  }
@@ -138,16 +144,20 @@ var McpCredentialManager = class {
138
144
  };
139
145
  }
140
146
  async resolveBaseURL() {
141
- return process.env[API_BASE_URL_ENV] ?? (await this.readAuth())?.apiBaseUrl;
147
+ const envBase = process.env[BASE_URL_ENV];
148
+ if (envBase) {
149
+ return resolveMcpUrls(envBase).api;
150
+ }
151
+ const storedAuth = await this.readAuth();
152
+ return storedAuth ? resolveMcpUrls(storedAuth.baseUrl).api : void 0;
142
153
  }
143
154
  async refreshAccessToken(storedAuth) {
144
- const tokenResponse = await requestToken(storedAuth.dashboardUrl, {
155
+ const tokenResponse = await requestToken(resolveMcpUrls(storedAuth.baseUrl).token, {
145
156
  grant_type: "refresh_token",
146
157
  refresh_token: storedAuth.refreshToken
147
158
  });
148
159
  const refreshedAuth = buildStoredAuth({
149
- dashboardUrl: storedAuth.dashboardUrl,
150
- apiBaseUrl: storedAuth.apiBaseUrl,
160
+ baseUrl: storedAuth.baseUrl,
151
161
  tokenResponse,
152
162
  previous: storedAuth
153
163
  });
@@ -185,8 +195,7 @@ function isUsableAccessToken(storedAuth) {
185
195
  return Number.isFinite(expiresAt) && expiresAt - Date.now() > TOKEN_REFRESH_SKEW_MS;
186
196
  }
187
197
  function buildStoredAuth({
188
- dashboardUrl,
189
- apiBaseUrl,
198
+ baseUrl,
190
199
  tokenResponse,
191
200
  previous
192
201
  }) {
@@ -199,8 +208,7 @@ function buildStoredAuth({
199
208
  throw new Error("Knowhere MCP token response did not include a refresh token");
200
209
  }
201
210
  return {
202
- dashboardUrl,
203
- apiBaseUrl,
211
+ baseUrl,
204
212
  permission: tokenResponse.permission,
205
213
  refreshToken,
206
214
  refreshTokenExpiresAt: tokenResponse.refreshTokenExpiresAt ?? previous?.refreshTokenExpiresAt,
@@ -214,13 +222,12 @@ function parseStoredAuth(value) {
214
222
  if (!isRecord(value)) {
215
223
  throw new Error("Invalid Knowhere MCP auth file");
216
224
  }
217
- const dashboardUrl = readRequiredString(value, "dashboardUrl");
225
+ const baseUrl = readRequiredString(value, "baseUrl");
218
226
  const refreshToken = readRequiredString(value, "refreshToken");
219
227
  const createdAt = readRequiredString(value, "createdAt");
220
228
  const updatedAt = readRequiredString(value, "updatedAt");
221
229
  return {
222
- dashboardUrl,
223
- apiBaseUrl: readOptionalString(value, "apiBaseUrl"),
230
+ baseUrl,
224
231
  permission: normalizePermission(readOptionalString(value, "permission")),
225
232
  refreshToken,
226
233
  refreshTokenExpiresAt: readOptionalString(value, "refreshTokenExpiresAt"),
@@ -255,13 +262,13 @@ function createPkceChallenge(codeVerifier) {
255
262
  return crypto.createHash("sha256").update(codeVerifier).digest("base64url");
256
263
  }
257
264
  function buildLoginUrl({
258
- dashboardUrl,
265
+ loginEndpoint,
259
266
  redirectUri,
260
267
  state,
261
268
  codeChallenge,
262
269
  clientName
263
270
  }) {
264
- const url = new URL("/mcp/login", dashboardUrl);
271
+ const url = new URL(loginEndpoint);
265
272
  url.searchParams.set("redirect_uri", redirectUri);
266
273
  url.searchParams.set("state", state);
267
274
  url.searchParams.set("code_challenge", codeChallenge);
@@ -361,8 +368,8 @@ function handleCallbackRequest({
361
368
  );
362
369
  resolveCode(code);
363
370
  }
364
- async function requestToken(dashboardUrl, body) {
365
- const response = await fetch(new URL("/api/mcp/token", dashboardUrl), {
371
+ async function requestToken(tokenUrl, body) {
372
+ const response = await fetch(tokenUrl, {
366
373
  method: "POST",
367
374
  headers: { "Content-Type": "application/json" },
368
375
  body: JSON.stringify(body)
@@ -373,8 +380,8 @@ async function requestToken(dashboardUrl, body) {
373
380
  }
374
381
  return parseTokenResponse(responseBody);
375
382
  }
376
- async function requestRevoke(dashboardUrl, refreshToken) {
377
- const response = await fetch(new URL("/api/mcp/revoke", dashboardUrl), {
383
+ async function requestRevoke(revokeUrl, refreshToken) {
384
+ const response = await fetch(revokeUrl, {
378
385
  method: "POST",
379
386
  headers: { "Content-Type": "application/json" },
380
387
  body: JSON.stringify({ refresh_token: refreshToken })
@@ -420,12 +427,12 @@ function getResponseMessage(responseBody, fallback) {
420
427
  }
421
428
  return fallback;
422
429
  }
423
- function normalizeDashboardUrl(value) {
430
+ function normalizeBaseUrl(value) {
424
431
  const url = new URL(value);
425
432
  url.pathname = "/";
426
433
  url.search = "";
427
434
  url.hash = "";
428
- return url.toString();
435
+ return url.toString().replace(/\/+$/, "");
429
436
  }
430
437
  function normalizePermission(value) {
431
438
  if (value && PERMISSION_VALUES.has(value)) {
@@ -496,8 +503,7 @@ async function runLogin(args) {
496
503
  const options = parseLoginArgs(args);
497
504
  const credentialManager = new McpCredentialManager(options.authFilePath);
498
505
  const result = await credentialManager.login({
499
- dashboardUrl: options.dashboardUrl,
500
- baseURL: options.baseURL,
506
+ baseUrl: options.baseUrl,
501
507
  openBrowser: options.openBrowser,
502
508
  clientName: options.clientName,
503
509
  onLoginUrl: (url) => {
@@ -535,12 +541,8 @@ function parseLoginArgs(args) {
535
541
  for (let index = 0; index < args.length; index += 1) {
536
542
  const arg = args[index];
537
543
  switch (arg) {
538
- case "--dashboard-url":
539
- options.dashboardUrl = readFlagValue(args, index, arg);
540
- index += 1;
541
- break;
542
544
  case "--base-url":
543
- options.baseURL = readFlagValue(args, index, arg);
545
+ options.baseUrl = readFlagValue(args, index, arg);
544
546
  index += 1;
545
547
  break;
546
548
  case "--auth-file":
@@ -579,8 +581,7 @@ function formatStatus(status) {
579
581
  return [
580
582
  "Knowhere MCP is authenticated with dashboard login",
581
583
  `Auth file: ${status.authFilePath}`,
582
- `Dashboard: ${status.dashboardUrl ?? "unknown"}`,
583
- `API base URL: ${status.apiBaseUrl ?? "default"}`,
584
+ `Base URL: ${status.baseUrl ?? "unknown"}`,
584
585
  `Permission: ${status.permission ?? "full_access"}`,
585
586
  `Refresh token expires: ${status.refreshTokenExpiresAt ?? "unknown"}`,
586
587
  `Access token expires: ${status.accessTokenExpiresAt ?? "not cached"}`
@@ -600,8 +601,7 @@ function printHelp() {
600
601
  knowhere-mcp logout Remove and revoke local MCP login
601
602
 
602
603
  Login options:
603
- --dashboard-url <url> Dashboard URL, defaults to KNOWHERE_DASHBOARD_URL or https://knowhereto.ai
604
- --base-url <url> Knowhere API URL, defaults to KNOWHERE_BASE_URL or SDK default
604
+ --base-url <url> Knowhere site base URL, defaults to KNOWHERE_BASE_URL or https://knowhereto.ai
605
605
  --auth-file <path> Override local auth file path
606
606
  --client-name <name> Label shown in dashboard token records
607
607
  --no-open Print login URL without opening a browser`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ontos-ai/knowhere-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "MCP wrapper for the Knowhere Node.js SDK local knowledge tools",
5
5
  "keywords": [
6
6
  "knowhere",