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.
- package/dist/{chunk-RNKJONY3.js → chunk-QKAUM3TR.js} +38 -10
- package/dist/cli.js +12 -16
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
)
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
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-
|
|
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
|
|
10
|
-
|
|
11
|
-
".
|
|
12
|
-
|
|
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.
|
|
17
|
+
).version("0.2.2").requiredOption(
|
|
17
18
|
"--token <token>",
|
|
18
|
-
"Gateway token
|
|
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
|
|
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