kojee-mcp 0.2.1 → 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
@@ -633,9 +634,27 @@ var DEFAULT_KEYSTORE_PATH = path2.join(
633
634
  ".kojee",
634
635
  "keypair.json"
635
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
+ }
636
643
  async function startProxy(config) {
637
644
  const keystorePath = config.keystorePath || DEFAULT_KEYSTORE_PATH;
638
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) {
639
658
  const auth = new AuthModule(config.token, config.url, keystorePath);
640
659
  const keyPair = await auth.ensureEnrolled();
641
660
  const sessionId = GatewayClient.deriveSessionId(config.token);
@@ -648,16 +667,25 @@ async function startProxy(config) {
648
667
  sessionId
649
668
  );
650
669
  const registry = new ToolRegistry(gateway);
651
- await registry.discoverTools();
652
- console.error(
653
- `[kojee-mcp] Ready \u2014 ${registry.toolCount} tools available from ${config.url}`
654
- );
655
- const server = createMcpServer(registry);
656
- process.stdin.on("end", () => {
657
- console.error("[kojee-mcp] stdin closed, exiting");
658
- process.exit(0);
659
- });
660
- 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
+ }
661
689
  }
662
690
 
663
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-RNKJONY3.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-RNKJONY3.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.1",
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",