kojee-mcp 0.2.0 → 0.2.2

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.
@@ -1,4 +1,5 @@
1
1
  // src/index.ts
2
+ import fs2 from "fs";
2
3
  import path2 from "path";
3
4
 
4
5
  // src/auth/auth-module.ts
@@ -532,6 +533,11 @@ var ToolRegistry = class {
532
533
  const result = await this.gateway.sendRpc("tools/list", {
533
534
  include_schema: true
534
535
  });
536
+ const maybeError = result;
537
+ if (maybeError.isError) {
538
+ const msg = maybeError.content?.[0]?.text ?? "unknown error";
539
+ throw new Error(`Gateway rejected tools/list: ${msg}`);
540
+ }
535
541
  const toolList = result?.tools;
536
542
  if (!toolList || !Array.isArray(toolList)) {
537
543
  console.error("[tools] No tools returned from gateway");
@@ -628,9 +634,27 @@ var DEFAULT_KEYSTORE_PATH = path2.join(
628
634
  ".kojee",
629
635
  "keypair.json"
630
636
  );
637
+ function isDPoPEnrollmentError(err) {
638
+ const msg = String(err?.message ?? err ?? "").toLowerCase();
639
+ if (msg.includes("invalid or expired") && msg.includes("token")) return false;
640
+ if (msg.includes("generate a new")) return false;
641
+ return msg.includes("401") || msg.includes("authentication failed") || msg.includes("dpop") || msg.includes("key enrollment") || msg.includes("kid");
642
+ }
631
643
  async function startProxy(config) {
632
644
  const keystorePath = config.keystorePath || DEFAULT_KEYSTORE_PATH;
633
645
  console.error(`[kojee-mcp] Starting proxy for ${config.url}`);
646
+ const registry = await enrollAndDiscover(config, keystorePath);
647
+ console.error(
648
+ `[kojee-mcp] Ready \u2014 ${registry.toolCount} tools available from ${config.url}`
649
+ );
650
+ const server = createMcpServer(registry);
651
+ process.stdin.on("end", () => {
652
+ console.error("[kojee-mcp] stdin closed, exiting");
653
+ process.exit(0);
654
+ });
655
+ await startMcpServer(server);
656
+ }
657
+ async function enrollAndDiscover(config, keystorePath, isRetry = false) {
634
658
  const auth = new AuthModule(config.token, config.url, keystorePath);
635
659
  const keyPair = await auth.ensureEnrolled();
636
660
  const sessionId = GatewayClient.deriveSessionId(config.token);
@@ -643,12 +667,25 @@ async function startProxy(config) {
643
667
  sessionId
644
668
  );
645
669
  const registry = new ToolRegistry(gateway);
646
- await registry.discoverTools();
647
- console.error(
648
- `[kojee-mcp] Ready \u2014 ${registry.toolCount} tools available from ${config.url}`
649
- );
650
- const server = createMcpServer(registry);
651
- await startMcpServer(server);
670
+ try {
671
+ await registry.discoverTools();
672
+ return registry;
673
+ } catch (err) {
674
+ if (isRetry || !isDPoPEnrollmentError(err)) {
675
+ throw err;
676
+ }
677
+ console.error(
678
+ "[kojee-mcp] Auth failed, attempting recovery with fresh enrollment..."
679
+ );
680
+ try {
681
+ if (fs2.existsSync(keystorePath)) {
682
+ fs2.unlinkSync(keystorePath);
683
+ }
684
+ } catch (unlinkErr) {
685
+ console.error("[kojee-mcp] Could not remove stale keystore:", unlinkErr);
686
+ }
687
+ return enrollAndDiscover(config, keystorePath, true);
688
+ }
652
689
  }
653
690
 
654
691
  export {
package/dist/cli.js CHANGED
@@ -1,40 +1,36 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startProxy
4
- } from "./chunk-O5UYOIQX.js";
4
+ } from "./chunk-QKAUM3TR.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { Command } from "commander";
8
+ import crypto from "crypto";
8
9
  import path from "path";
9
- var DEFAULT_KEYSTORE_PATH = path.join(
10
- process.env["HOME"] ?? "~",
11
- ".kojee",
12
- "keypair.json"
13
- );
10
+ var KOJEE_DIR = path.join(process.env["HOME"] ?? "~", ".kojee");
11
+ function deriveKeystorePath(token) {
12
+ const hash = crypto.createHash("sha256").update(token).digest("hex").slice(0, 12);
13
+ return path.join(KOJEE_DIR, `keypair-${hash}.json`);
14
+ }
14
15
  var program = new Command().name("kojee-mcp").description(
15
16
  "Local MCP proxy for Kojee \u2014 handles DPoP auth, tool discovery, and governance transparently"
16
- ).version("0.1.0").requiredOption(
17
+ ).version("0.2.2").requiredOption(
17
18
  "--token <token>",
18
- "Gateway token (gw_...)"
19
+ "Gateway token"
19
20
  ).requiredOption(
20
21
  "--url <url>",
21
22
  "Broker base URL (e.g. https://kojee.ai)"
22
23
  ).option(
23
24
  "--keystore-path <path>",
24
- "Path to persisted keypair file",
25
- DEFAULT_KEYSTORE_PATH
25
+ "Path to persisted keypair file (defaults to per-token path under ~/.kojee/)"
26
26
  ).action(async (opts) => {
27
- if (!opts.token.startsWith("gw_")) {
28
- console.error(
29
- "Warning: Gateway token does not start with 'gw_'. Ensure you are using a valid gateway token."
30
- );
31
- }
32
27
  const url = opts.url.replace(/\/+$/, "");
28
+ const keystorePath = opts.keystorePath ?? deriveKeystorePath(opts.token);
33
29
  try {
34
30
  await startProxy({
35
31
  token: opts.token,
36
32
  url,
37
- keystorePath: opts.keystorePath
33
+ keystorePath
38
34
  });
39
35
  } catch (err) {
40
36
  console.error("[kojee-mcp] Fatal error:", err);
package/dist/index.d.ts CHANGED
@@ -13,6 +13,9 @@ interface ProxyConfig {
13
13
  * 3. Create gateway client
14
14
  * 4. Discover tools from gateway
15
15
  * 5. Start MCP stdio server
16
+ *
17
+ * If step 4 fails with an auth error that looks like a stale keystore,
18
+ * we wipe the keystore and retry once with a fresh enrollment.
16
19
  */
17
20
  declare function startProxy(config: ProxyConfig): Promise<void>;
18
21
 
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startProxy
3
- } from "./chunk-O5UYOIQX.js";
3
+ } from "./chunk-QKAUM3TR.js";
4
4
  export {
5
5
  startProxy
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kojee-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Local MCP proxy for Kojee — handles DPoP auth, tool discovery, and governance transparently",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",