@ontos-ai/knowhere-mcp 0.2.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/dist/stdio.mjs ADDED
@@ -0,0 +1,612 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runKnowhereMcpServer
4
+ } from "./chunk-ZITSXYWR.mjs";
5
+
6
+ // src/auth.ts
7
+ import { spawn } from "child_process";
8
+ import crypto from "crypto";
9
+ import { createServer } from "http";
10
+ import os from "os";
11
+ import path from "path";
12
+ import { mkdir, readFile, rm, writeFile, chmod } from "fs/promises";
13
+ import { ValidationError } from "@ontos-ai/knowhere-sdk";
14
+ var DEFAULT_DASHBOARD_URL = "https://knowhereto.ai";
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";
18
+ var API_KEY_ENV = "KNOWHERE_API_KEY";
19
+ var TOKEN_REFRESH_SKEW_MS = 5 * 60 * 1e3;
20
+ var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
21
+ var RANDOM_BYTE_LENGTH = 32;
22
+ var DEFAULT_CLIENT_NAME = "knowhere-cli";
23
+ var DEFAULT_PERMISSION = "full_access";
24
+ var PERMISSION_VALUES = /* @__PURE__ */ new Set(["read_only", "full_access"]);
25
+ var McpCredentialManager = class {
26
+ authFilePath;
27
+ refreshPromise;
28
+ constructor(authFilePath = getDefaultAuthFilePath()) {
29
+ this.authFilePath = authFilePath;
30
+ }
31
+ getAuthFilePath() {
32
+ return this.authFilePath;
33
+ }
34
+ async getStatus() {
35
+ if (process.env[API_KEY_ENV]) {
36
+ return {
37
+ source: "api_key",
38
+ authFilePath: this.authFilePath,
39
+ apiBaseUrl: process.env[API_BASE_URL_ENV],
40
+ permission: DEFAULT_PERMISSION
41
+ };
42
+ }
43
+ const storedAuth = await this.readAuth();
44
+ if (!storedAuth) {
45
+ return { source: "none", authFilePath: this.authFilePath };
46
+ }
47
+ return {
48
+ source: "stored_login",
49
+ authFilePath: this.authFilePath,
50
+ dashboardUrl: storedAuth.dashboardUrl,
51
+ apiBaseUrl: process.env[API_BASE_URL_ENV] ?? storedAuth.apiBaseUrl,
52
+ permission: storedAuth.permission,
53
+ refreshTokenExpiresAt: storedAuth.refreshTokenExpiresAt,
54
+ accessTokenExpiresAt: storedAuth.accessTokenExpiresAt
55
+ };
56
+ }
57
+ async hasStoredLogin() {
58
+ return await this.readAuth() !== void 0;
59
+ }
60
+ async getAccessToken() {
61
+ const storedAuth = await this.readAuth();
62
+ if (!storedAuth) {
63
+ throw new ValidationError(
64
+ 'Knowhere MCP is not logged in. Run "npx -y @ontos-ai/knowhere-mcp login" or set KNOWHERE_API_KEY.'
65
+ );
66
+ }
67
+ if (isUsableAccessToken(storedAuth)) {
68
+ return storedAuth.accessToken;
69
+ }
70
+ if (!this.refreshPromise) {
71
+ this.refreshPromise = this.refreshAccessToken(storedAuth).finally(() => {
72
+ this.refreshPromise = void 0;
73
+ });
74
+ }
75
+ return this.refreshPromise;
76
+ }
77
+ async login(options = {}) {
78
+ const dashboardUrl = normalizeDashboardUrl(
79
+ options.dashboardUrl ?? process.env[DASHBOARD_URL_ENV] ?? DEFAULT_DASHBOARD_URL
80
+ );
81
+ const apiBaseUrl = options.baseURL ?? process.env[API_BASE_URL_ENV];
82
+ const codeVerifier = createRandomToken();
83
+ const state = createRandomToken();
84
+ const codeChallenge = createPkceChallenge(codeVerifier);
85
+ const callback = await createLoopbackCallback(state);
86
+ try {
87
+ const loginUrl = buildLoginUrl({
88
+ dashboardUrl,
89
+ redirectUri: callback.redirectUri,
90
+ state,
91
+ codeChallenge,
92
+ clientName: options.clientName ?? DEFAULT_CLIENT_NAME
93
+ });
94
+ options.onLoginUrl?.(loginUrl);
95
+ if (options.openBrowser !== false) {
96
+ openBrowser(loginUrl);
97
+ }
98
+ const code = await callback.waitForCode();
99
+ const tokenResponse = await requestToken(dashboardUrl, {
100
+ grant_type: "authorization_code",
101
+ code,
102
+ code_verifier: codeVerifier,
103
+ client_name: options.clientName ?? DEFAULT_CLIENT_NAME
104
+ });
105
+ const storedAuth = buildStoredAuth({
106
+ dashboardUrl,
107
+ apiBaseUrl,
108
+ tokenResponse,
109
+ previous: await this.readAuth()
110
+ });
111
+ await this.writeAuth(storedAuth);
112
+ return {
113
+ authFilePath: this.authFilePath,
114
+ dashboardUrl,
115
+ apiBaseUrl,
116
+ permission: tokenResponse.permission,
117
+ refreshTokenExpiresAt: tokenResponse.refreshTokenExpiresAt
118
+ };
119
+ } finally {
120
+ await callback.close();
121
+ }
122
+ }
123
+ async logout() {
124
+ const storedAuth = await this.readAuth();
125
+ let revokeError;
126
+ if (storedAuth) {
127
+ try {
128
+ await requestRevoke(storedAuth.dashboardUrl, storedAuth.refreshToken);
129
+ } catch (error) {
130
+ revokeError = error instanceof Error ? error.message : "Failed to revoke MCP login";
131
+ }
132
+ }
133
+ await rm(this.authFilePath, { force: true });
134
+ return {
135
+ authFilePath: this.authFilePath,
136
+ hadStoredLogin: storedAuth !== void 0,
137
+ revokeError
138
+ };
139
+ }
140
+ async resolveBaseURL() {
141
+ return process.env[API_BASE_URL_ENV] ?? (await this.readAuth())?.apiBaseUrl;
142
+ }
143
+ async refreshAccessToken(storedAuth) {
144
+ const tokenResponse = await requestToken(storedAuth.dashboardUrl, {
145
+ grant_type: "refresh_token",
146
+ refresh_token: storedAuth.refreshToken
147
+ });
148
+ const refreshedAuth = buildStoredAuth({
149
+ dashboardUrl: storedAuth.dashboardUrl,
150
+ apiBaseUrl: storedAuth.apiBaseUrl,
151
+ tokenResponse,
152
+ previous: storedAuth
153
+ });
154
+ await this.writeAuth(refreshedAuth);
155
+ return refreshedAuth.accessToken ?? "";
156
+ }
157
+ async readAuth() {
158
+ try {
159
+ const rawAuth = await readFile(this.authFilePath, "utf8");
160
+ return parseStoredAuth(JSON.parse(rawAuth));
161
+ } catch (error) {
162
+ if (isFileMissingError(error)) {
163
+ return void 0;
164
+ }
165
+ throw error;
166
+ }
167
+ }
168
+ async writeAuth(storedAuth) {
169
+ await mkdir(path.dirname(this.authFilePath), { recursive: true, mode: 448 });
170
+ await writeFile(this.authFilePath, `${JSON.stringify(storedAuth, null, 2)}
171
+ `, {
172
+ mode: 384
173
+ });
174
+ await chmod(this.authFilePath, 384);
175
+ }
176
+ };
177
+ function getDefaultAuthFilePath() {
178
+ return process.env[AUTH_FILE_ENV] ?? path.join(os.homedir(), ".knowhere-node-sdk", "mcp", "auth.json");
179
+ }
180
+ function isUsableAccessToken(storedAuth) {
181
+ if (!storedAuth.accessToken || !storedAuth.accessTokenExpiresAt) {
182
+ return false;
183
+ }
184
+ const expiresAt = Date.parse(storedAuth.accessTokenExpiresAt);
185
+ return Number.isFinite(expiresAt) && expiresAt - Date.now() > TOKEN_REFRESH_SKEW_MS;
186
+ }
187
+ function buildStoredAuth({
188
+ dashboardUrl,
189
+ apiBaseUrl,
190
+ tokenResponse,
191
+ previous
192
+ }) {
193
+ const now = /* @__PURE__ */ new Date();
194
+ const accessTokenExpiresAt = new Date(
195
+ now.getTime() + tokenResponse.expiresInSeconds * 1e3
196
+ ).toISOString();
197
+ const refreshToken = tokenResponse.refreshToken ?? previous?.refreshToken;
198
+ if (!refreshToken) {
199
+ throw new Error("Knowhere MCP token response did not include a refresh token");
200
+ }
201
+ return {
202
+ dashboardUrl,
203
+ apiBaseUrl,
204
+ permission: tokenResponse.permission,
205
+ refreshToken,
206
+ refreshTokenExpiresAt: tokenResponse.refreshTokenExpiresAt ?? previous?.refreshTokenExpiresAt,
207
+ accessToken: tokenResponse.accessToken,
208
+ accessTokenExpiresAt,
209
+ createdAt: previous?.createdAt ?? now.toISOString(),
210
+ updatedAt: now.toISOString()
211
+ };
212
+ }
213
+ function parseStoredAuth(value) {
214
+ if (!isRecord(value)) {
215
+ throw new Error("Invalid Knowhere MCP auth file");
216
+ }
217
+ const dashboardUrl = readRequiredString(value, "dashboardUrl");
218
+ const refreshToken = readRequiredString(value, "refreshToken");
219
+ const createdAt = readRequiredString(value, "createdAt");
220
+ const updatedAt = readRequiredString(value, "updatedAt");
221
+ return {
222
+ dashboardUrl,
223
+ apiBaseUrl: readOptionalString(value, "apiBaseUrl"),
224
+ permission: normalizePermission(readOptionalString(value, "permission")),
225
+ refreshToken,
226
+ refreshTokenExpiresAt: readOptionalString(value, "refreshTokenExpiresAt"),
227
+ accessToken: readOptionalString(value, "accessToken"),
228
+ accessTokenExpiresAt: readOptionalString(value, "accessTokenExpiresAt"),
229
+ createdAt,
230
+ updatedAt
231
+ };
232
+ }
233
+ function readRequiredString(value, key) {
234
+ const field = value[key];
235
+ if (typeof field !== "string" || field.length === 0) {
236
+ throw new Error(`Invalid Knowhere MCP auth file: ${key} is required`);
237
+ }
238
+ return field;
239
+ }
240
+ function readOptionalString(value, key) {
241
+ const field = value[key];
242
+ return typeof field === "string" && field.length > 0 ? field : void 0;
243
+ }
244
+ function readRequiredPermission(value, key) {
245
+ const field = value[key];
246
+ if (typeof field !== "string" || field.length === 0) {
247
+ throw new Error(`Invalid Knowhere MCP token response: ${key} is required`);
248
+ }
249
+ if (!PERMISSION_VALUES.has(field)) {
250
+ throw new Error(`Invalid Knowhere MCP token response: ${key} is invalid`);
251
+ }
252
+ return field;
253
+ }
254
+ function createPkceChallenge(codeVerifier) {
255
+ return crypto.createHash("sha256").update(codeVerifier).digest("base64url");
256
+ }
257
+ function buildLoginUrl({
258
+ dashboardUrl,
259
+ redirectUri,
260
+ state,
261
+ codeChallenge,
262
+ clientName
263
+ }) {
264
+ const url = new URL("/mcp/login", dashboardUrl);
265
+ url.searchParams.set("redirect_uri", redirectUri);
266
+ url.searchParams.set("state", state);
267
+ url.searchParams.set("code_challenge", codeChallenge);
268
+ url.searchParams.set("code_challenge_method", "S256");
269
+ url.searchParams.set("client_name", clientName);
270
+ return url.toString();
271
+ }
272
+ async function createLoopbackCallback(expectedState) {
273
+ let resolveCode;
274
+ let rejectCode;
275
+ let isSettled = false;
276
+ const codePromise = new Promise((resolve, reject) => {
277
+ resolveCode = resolve;
278
+ rejectCode = reject;
279
+ });
280
+ const timeout = setTimeout(() => {
281
+ if (!isSettled) {
282
+ isSettled = true;
283
+ rejectCode?.(new Error("Timed out waiting for Dashboard login callback"));
284
+ }
285
+ }, LOGIN_TIMEOUT_MS);
286
+ const server = createServer((request, response) => {
287
+ handleCallbackRequest({
288
+ request,
289
+ response,
290
+ expectedState,
291
+ resolveCode: (code) => {
292
+ if (!isSettled) {
293
+ isSettled = true;
294
+ clearTimeout(timeout);
295
+ resolveCode?.(code);
296
+ }
297
+ },
298
+ rejectCode: (error) => {
299
+ if (!isSettled) {
300
+ isSettled = true;
301
+ clearTimeout(timeout);
302
+ rejectCode?.(error);
303
+ }
304
+ }
305
+ });
306
+ });
307
+ await new Promise((resolve, reject) => {
308
+ server.once("error", reject);
309
+ server.listen(0, "127.0.0.1", () => resolve());
310
+ });
311
+ const address = server.address();
312
+ if (!address || typeof address === "string") {
313
+ throw new Error("Failed to start loopback login callback server");
314
+ }
315
+ return {
316
+ redirectUri: `http://127.0.0.1:${address.port}/callback`,
317
+ waitForCode: () => codePromise,
318
+ close: () => new Promise((resolve, reject) => {
319
+ clearTimeout(timeout);
320
+ server.close((error) => {
321
+ if (error) {
322
+ reject(error);
323
+ return;
324
+ }
325
+ resolve();
326
+ });
327
+ })
328
+ };
329
+ }
330
+ function handleCallbackRequest({
331
+ request,
332
+ response,
333
+ expectedState,
334
+ resolveCode,
335
+ rejectCode
336
+ }) {
337
+ const requestUrl = new URL(request.url ?? "/", "http://127.0.0.1");
338
+ if (requestUrl.pathname !== "/callback") {
339
+ response.writeHead(404);
340
+ response.end("Not found");
341
+ return;
342
+ }
343
+ const code = requestUrl.searchParams.get("code");
344
+ const callbackError = requestUrl.searchParams.get("error");
345
+ const state = requestUrl.searchParams.get("state");
346
+ if (callbackError) {
347
+ response.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
348
+ response.end("Knowhere MCP login was denied. You can close this window.");
349
+ rejectCode(new Error(`Dashboard login failed: ${callbackError}`));
350
+ return;
351
+ }
352
+ if (!code || state !== expectedState) {
353
+ response.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
354
+ response.end("Knowhere MCP login failed. You can close this window.");
355
+ rejectCode(new Error("Dashboard login callback did not include a valid code and state"));
356
+ return;
357
+ }
358
+ response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
359
+ response.end(
360
+ "<!doctype html><title>Knowhere MCP</title><p>Knowhere MCP login complete. You can close this window.</p>"
361
+ );
362
+ resolveCode(code);
363
+ }
364
+ async function requestToken(dashboardUrl, body) {
365
+ const response = await fetch(new URL("/api/mcp/token", dashboardUrl), {
366
+ method: "POST",
367
+ headers: { "Content-Type": "application/json" },
368
+ body: JSON.stringify(body)
369
+ });
370
+ const responseBody = await readJsonResponse(response);
371
+ if (!response.ok) {
372
+ throw new Error(getResponseMessage(responseBody, "Knowhere MCP token request failed"));
373
+ }
374
+ return parseTokenResponse(responseBody);
375
+ }
376
+ async function requestRevoke(dashboardUrl, refreshToken) {
377
+ const response = await fetch(new URL("/api/mcp/revoke", dashboardUrl), {
378
+ method: "POST",
379
+ headers: { "Content-Type": "application/json" },
380
+ body: JSON.stringify({ refresh_token: refreshToken })
381
+ });
382
+ const responseBody = await readJsonResponse(response);
383
+ if (!response.ok) {
384
+ throw new Error(getResponseMessage(responseBody, "Knowhere MCP revoke request failed"));
385
+ }
386
+ }
387
+ async function readJsonResponse(response) {
388
+ try {
389
+ return await response.json();
390
+ } catch {
391
+ return void 0;
392
+ }
393
+ }
394
+ function parseTokenResponse(value) {
395
+ if (!isRecord(value)) {
396
+ throw new Error("Invalid Knowhere MCP token response");
397
+ }
398
+ const accessToken = readRequiredString(value, "accessToken");
399
+ const tokenType = readRequiredString(value, "tokenType");
400
+ const expiresInSeconds = value.expiresInSeconds;
401
+ const permission = readRequiredPermission(value, "permission");
402
+ if (tokenType !== "Bearer") {
403
+ throw new Error("Invalid Knowhere MCP token type");
404
+ }
405
+ if (typeof expiresInSeconds !== "number" || !Number.isFinite(expiresInSeconds)) {
406
+ throw new Error("Invalid Knowhere MCP token expiry");
407
+ }
408
+ return {
409
+ accessToken,
410
+ expiresInSeconds,
411
+ permission,
412
+ refreshToken: readOptionalString(value, "refreshToken"),
413
+ refreshTokenExpiresAt: readOptionalString(value, "refreshTokenExpiresAt"),
414
+ tokenType
415
+ };
416
+ }
417
+ function getResponseMessage(responseBody, fallback) {
418
+ if (isRecord(responseBody) && typeof responseBody.message === "string") {
419
+ return responseBody.message;
420
+ }
421
+ return fallback;
422
+ }
423
+ function normalizeDashboardUrl(value) {
424
+ const url = new URL(value);
425
+ url.pathname = "/";
426
+ url.search = "";
427
+ url.hash = "";
428
+ return url.toString();
429
+ }
430
+ function normalizePermission(value) {
431
+ if (value && PERMISSION_VALUES.has(value)) {
432
+ return value;
433
+ }
434
+ return DEFAULT_PERMISSION;
435
+ }
436
+ function openBrowser(url) {
437
+ const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
438
+ const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
439
+ const child = spawn(command, args, {
440
+ detached: true,
441
+ stdio: "ignore"
442
+ });
443
+ child.unref();
444
+ }
445
+ function createRandomToken() {
446
+ return crypto.randomBytes(RANDOM_BYTE_LENGTH).toString("base64url");
447
+ }
448
+ function isRecord(value) {
449
+ return typeof value === "object" && value !== null && !Array.isArray(value);
450
+ }
451
+ function isFileMissingError(error) {
452
+ return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
453
+ }
454
+
455
+ // src/stdio.ts
456
+ async function main() {
457
+ const [command, ...args] = process.argv.slice(2);
458
+ switch (command) {
459
+ case void 0:
460
+ case "serve":
461
+ await runKnowhereMcpServerWithAuth();
462
+ return;
463
+ case "login":
464
+ await runLogin(args);
465
+ return;
466
+ case "logout":
467
+ await runLogout();
468
+ return;
469
+ case "status":
470
+ await runStatus();
471
+ return;
472
+ case "--help":
473
+ case "-h":
474
+ case "help":
475
+ printHelp();
476
+ return;
477
+ default:
478
+ throw new Error(`Unknown knowhere-mcp command: ${command}`);
479
+ }
480
+ }
481
+ async function runKnowhereMcpServerWithAuth() {
482
+ const credentialManager = new McpCredentialManager();
483
+ const status = await credentialManager.getStatus();
484
+ if (process.env.KNOWHERE_API_KEY) {
485
+ await runKnowhereMcpServer({ permission: status.permission });
486
+ return;
487
+ }
488
+ await runKnowhereMcpServer({
489
+ authTokenProvider: () => credentialManager.getAccessToken(),
490
+ baseURL: await credentialManager.resolveBaseURL(),
491
+ permission: status.permission,
492
+ recoverPendingJobsOnStart: status.source === "stored_login"
493
+ });
494
+ }
495
+ async function runLogin(args) {
496
+ const options = parseLoginArgs(args);
497
+ const credentialManager = new McpCredentialManager(options.authFilePath);
498
+ const result = await credentialManager.login({
499
+ dashboardUrl: options.dashboardUrl,
500
+ baseURL: options.baseURL,
501
+ openBrowser: options.openBrowser,
502
+ clientName: options.clientName,
503
+ onLoginUrl: (url) => {
504
+ console.log(`Open this URL to log in to Knowhere:
505
+ ${url}`);
506
+ }
507
+ });
508
+ console.log(`Knowhere MCP login saved to ${result.authFilePath}`);
509
+ console.log(`Permission: ${result.permission}`);
510
+ if (result.refreshTokenExpiresAt) {
511
+ console.log(`Refresh token expires at ${result.refreshTokenExpiresAt}`);
512
+ }
513
+ }
514
+ async function runLogout() {
515
+ const credentialManager = new McpCredentialManager();
516
+ const result = await credentialManager.logout();
517
+ if (result.revokeError) {
518
+ console.error(
519
+ `Knowhere MCP login was removed locally, but revoke failed: ${result.revokeError}`
520
+ );
521
+ }
522
+ console.log(
523
+ result.hadStoredLogin ? `Knowhere MCP login removed from ${result.authFilePath}` : `No Knowhere MCP login found at ${result.authFilePath}`
524
+ );
525
+ }
526
+ async function runStatus() {
527
+ const credentialManager = new McpCredentialManager();
528
+ const status = await credentialManager.getStatus();
529
+ console.log(formatStatus(status));
530
+ }
531
+ function parseLoginArgs(args) {
532
+ const options = {
533
+ openBrowser: true
534
+ };
535
+ for (let index = 0; index < args.length; index += 1) {
536
+ const arg = args[index];
537
+ switch (arg) {
538
+ case "--dashboard-url":
539
+ options.dashboardUrl = readFlagValue(args, index, arg);
540
+ index += 1;
541
+ break;
542
+ case "--base-url":
543
+ options.baseURL = readFlagValue(args, index, arg);
544
+ index += 1;
545
+ break;
546
+ case "--auth-file":
547
+ options.authFilePath = readFlagValue(args, index, arg);
548
+ index += 1;
549
+ break;
550
+ case "--client-name":
551
+ options.clientName = readFlagValue(args, index, arg);
552
+ index += 1;
553
+ break;
554
+ case "--no-open":
555
+ options.openBrowser = false;
556
+ break;
557
+ default:
558
+ throw new Error(`Unknown login option: ${arg}`);
559
+ }
560
+ }
561
+ return options;
562
+ }
563
+ function readFlagValue(args, index, flag) {
564
+ const value = args[index + 1];
565
+ if (!value || value.startsWith("--")) {
566
+ throw new Error(`${flag} requires a value`);
567
+ }
568
+ return value;
569
+ }
570
+ function formatStatus(status) {
571
+ switch (status.source) {
572
+ case "api_key":
573
+ return [
574
+ "Knowhere MCP is authenticated with KNOWHERE_API_KEY",
575
+ `Auth file: ${status.authFilePath}`,
576
+ `Permission: ${status.permission ?? "full_access"}`
577
+ ].join("\n");
578
+ case "stored_login":
579
+ return [
580
+ "Knowhere MCP is authenticated with dashboard login",
581
+ `Auth file: ${status.authFilePath}`,
582
+ `Dashboard: ${status.dashboardUrl ?? "unknown"}`,
583
+ `API base URL: ${status.apiBaseUrl ?? "default"}`,
584
+ `Permission: ${status.permission ?? "full_access"}`,
585
+ `Refresh token expires: ${status.refreshTokenExpiresAt ?? "unknown"}`,
586
+ `Access token expires: ${status.accessTokenExpiresAt ?? "not cached"}`
587
+ ].join("\n");
588
+ case "none":
589
+ return `Knowhere MCP is not logged in
590
+ Run: npx -y @ontos-ai/knowhere-mcp login
591
+ Auth file: ${status.authFilePath}`;
592
+ }
593
+ }
594
+ function printHelp() {
595
+ console.log(`Usage:
596
+ knowhere-mcp Run the stdio MCP server
597
+ knowhere-mcp serve Run the stdio MCP server
598
+ knowhere-mcp login Log in through the Knowhere dashboard
599
+ knowhere-mcp status Show local MCP auth status
600
+ knowhere-mcp logout Remove and revoke local MCP login
601
+
602
+ 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
605
+ --auth-file <path> Override local auth file path
606
+ --client-name <name> Label shown in dashboard token records
607
+ --no-open Print login URL without opening a browser`);
608
+ }
609
+ main().catch((error) => {
610
+ console.error(error);
611
+ process.exit(1);
612
+ });
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@ontos-ai/knowhere-mcp",
3
+ "version": "0.2.0",
4
+ "description": "MCP wrapper for the Knowhere Node.js SDK local knowledge tools",
5
+ "keywords": [
6
+ "knowhere",
7
+ "mcp",
8
+ "model-context-protocol",
9
+ "document-parsing"
10
+ ],
11
+ "author": "Knowhere Team <team@knowhereto.ai>",
12
+ "license": "MIT",
13
+ "homepage": "https://knowhereto.ai",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/Ontos-AI/knowhere-node-sdk.git",
17
+ "directory": "packages/mcp"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/Ontos-AI/knowhere-node-sdk/issues"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "main": "./dist/index.js",
26
+ "module": "./dist/index.mjs",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.mjs",
32
+ "require": "./dist/index.js"
33
+ }
34
+ },
35
+ "bin": {
36
+ "knowhere-mcp": "./dist/stdio.js"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "README.md",
41
+ "LICENSE"
42
+ ],
43
+ "engines": {
44
+ "node": ">=20.19.0",
45
+ "npm": ">=10.0.0",
46
+ "pnpm": ">=9.0.0"
47
+ },
48
+ "dependencies": {
49
+ "@modelcontextprotocol/sdk": "^1.29.0",
50
+ "zod": "^3.25.76",
51
+ "@ontos-ai/knowhere-sdk": "0.7.0"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^25.2.3",
55
+ "tsup": "^8.0.0",
56
+ "typescript": "^5.3.0",
57
+ "vitest": "^4.0.18"
58
+ },
59
+ "scripts": {
60
+ "build": "tsup src/index.ts src/stdio.ts --format cjs,esm --dts --clean",
61
+ "dev": "tsup src/index.ts src/stdio.ts --format cjs,esm --dts --watch",
62
+ "lint": "eslint src",
63
+ "format": "prettier --write \"src/**/*.ts\"",
64
+ "format:check": "prettier --check \"src/**/*.ts\"",
65
+ "test": "vitest",
66
+ "test:ci": "vitest run",
67
+ "typecheck": "tsc --noEmit"
68
+ }
69
+ }