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.
- package/dist/{chunk-O5UYOIQX.js → chunk-QKAUM3TR.js} +43 -6
- 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
|
|
@@ -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
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
)
|
|
650
|
-
|
|
651
|
-
|
|
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-
|
|
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