@mandujs/mcp 0.28.0 → 0.28.1
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/package.json +2 -2
- package/src/tools/brain.ts +66 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mandujs/mcp",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.1",
|
|
4
4
|
"description": "Mandu MCP Server - Agent-native interface for Mandu framework operations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@mandujs/core": "^0.41.
|
|
37
|
+
"@mandujs/core": "^0.41.1",
|
|
38
38
|
"@mandujs/ate": "^0.24.0",
|
|
39
39
|
"@mandujs/skills": "^0.18.0",
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.25.3"
|
package/src/tools/brain.ts
CHANGED
|
@@ -171,7 +171,7 @@ export const brainToolDefinitions: Tool[] = [
|
|
|
171
171
|
{
|
|
172
172
|
name: "mandu.brain.login",
|
|
173
173
|
description:
|
|
174
|
-
"Authenticate the brain to an LLM provider. For openai,
|
|
174
|
+
"Authenticate the brain to an LLM provider. For openai, spawns `npx @openai/codex login` which opens the user's default browser to the OpenAI OAuth page; on approval, the token lands in ~/.codex/auth.json and this tool returns. Anthropic path uses the Mandu OAuth flow with a local loopback listener.",
|
|
175
175
|
annotations: { readOnlyHint: false },
|
|
176
176
|
inputSchema: {
|
|
177
177
|
type: "object",
|
|
@@ -181,6 +181,11 @@ export const brainToolDefinitions: Tool[] = [
|
|
|
181
181
|
enum: ["openai", "anthropic"],
|
|
182
182
|
description: "Which provider to sign into. Default: openai.",
|
|
183
183
|
},
|
|
184
|
+
waitMs: {
|
|
185
|
+
type: "number",
|
|
186
|
+
description:
|
|
187
|
+
"How long to wait for auth.json to appear after spawning the OAuth flow. Default 180000 (3 min). Increase if the user takes longer to approve in the browser.",
|
|
188
|
+
},
|
|
184
189
|
},
|
|
185
190
|
required: [],
|
|
186
191
|
},
|
|
@@ -649,26 +654,28 @@ export function brainTools(projectRoot: string, server?: Server, monitor?: Activ
|
|
|
649
654
|
};
|
|
650
655
|
|
|
651
656
|
handlers["mandu.brain.login"] = async (args) => {
|
|
652
|
-
const { provider = "openai" } = args as {
|
|
653
|
-
|
|
657
|
+
const { provider = "openai", waitMs = 180000 } = args as {
|
|
658
|
+
provider?: "openai" | "anthropic";
|
|
659
|
+
waitMs?: number;
|
|
660
|
+
};
|
|
654
661
|
|
|
655
662
|
if (provider === "openai") {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
const isTty = Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
|
661
|
-
if (!isTty) {
|
|
663
|
+
const core = await import("@mandujs/core");
|
|
664
|
+
const auth = new core.ChatGPTAuth();
|
|
665
|
+
const existing = auth.locateAuthFile();
|
|
666
|
+
if (existing) {
|
|
662
667
|
return {
|
|
663
668
|
content: [
|
|
664
669
|
{
|
|
665
670
|
type: "text",
|
|
666
671
|
text: JSON.stringify(
|
|
667
672
|
{
|
|
668
|
-
ok:
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
673
|
+
ok: true,
|
|
674
|
+
provider: "openai",
|
|
675
|
+
already_authenticated: true,
|
|
676
|
+
auth_file: existing,
|
|
677
|
+
note:
|
|
678
|
+
"ChatGPT session already present. Call mandu.brain.logout + mandu.brain.login again to re-authenticate.",
|
|
672
679
|
},
|
|
673
680
|
null,
|
|
674
681
|
2,
|
|
@@ -677,26 +684,62 @@ export function brainTools(projectRoot: string, server?: Server, monitor?: Activ
|
|
|
677
684
|
],
|
|
678
685
|
};
|
|
679
686
|
}
|
|
680
|
-
|
|
681
|
-
|
|
687
|
+
|
|
688
|
+
// Spawn `npx @openai/codex login` detached from the MCP process.
|
|
689
|
+
// Codex itself opens the user's default browser (`start` on
|
|
690
|
+
// Windows, `open` on macOS, `xdg-open` on Linux) — no TTY needed
|
|
691
|
+
// on our side. We poll for ~/.codex/auth.json to appear and
|
|
692
|
+
// return once it does.
|
|
693
|
+
const { spawn } = await import("node:child_process");
|
|
694
|
+
const child = spawn("npx", ["-y", "@openai/codex", "login"], {
|
|
695
|
+
cwd: projectRoot,
|
|
696
|
+
detached: false,
|
|
697
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
682
698
|
shell: process.platform === "win32",
|
|
683
699
|
});
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
700
|
+
|
|
701
|
+
let stdoutBuffer = "";
|
|
702
|
+
let stderrBuffer = "";
|
|
703
|
+
child.stdout?.on("data", (d) => {
|
|
704
|
+
stdoutBuffer += d.toString();
|
|
705
|
+
});
|
|
706
|
+
child.stderr?.on("data", (d) => {
|
|
707
|
+
stderrBuffer += d.toString();
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
const deadline = Date.now() + Math.max(15_000, Math.min(waitMs, 600_000));
|
|
711
|
+
let file: string | null = null;
|
|
712
|
+
while (Date.now() < deadline) {
|
|
713
|
+
file = auth.locateAuthFile();
|
|
714
|
+
if (file) break;
|
|
715
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// Kill the codex process if it's still running (normally it exits
|
|
719
|
+
// on its own once auth.json is written).
|
|
720
|
+
if (!child.killed) {
|
|
721
|
+
try { child.kill(); } catch { /* ignore */ }
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
const urlMatch = stdoutBuffer.match(
|
|
725
|
+
/https:\/\/auth\.openai\.com\/oauth\/authorize\?[^\s]+/,
|
|
726
|
+
);
|
|
727
|
+
|
|
687
728
|
return {
|
|
688
729
|
content: [
|
|
689
730
|
{
|
|
690
731
|
type: "text",
|
|
691
732
|
text: JSON.stringify(
|
|
692
733
|
{
|
|
693
|
-
ok:
|
|
694
|
-
exit_code: result.status,
|
|
695
|
-
auth_file: file,
|
|
734
|
+
ok: Boolean(file),
|
|
696
735
|
provider: "openai",
|
|
736
|
+
auth_file: file,
|
|
737
|
+
oauth_url: urlMatch ? urlMatch[0] : undefined,
|
|
738
|
+
stdout_tail: stdoutBuffer.slice(-500),
|
|
739
|
+
stderr_tail: stderrBuffer.slice(-500),
|
|
697
740
|
note: file
|
|
698
|
-
? "auth.json
|
|
699
|
-
: "
|
|
741
|
+
? "auth.json written; Mandu brain will now use the OpenAI tier."
|
|
742
|
+
: "No auth.json detected before waitMs expired. If the OAuth URL is present above, open it in a browser; otherwise rerun with a larger waitMs or run `npx @openai/codex login` in your own terminal.",
|
|
700
743
|
},
|
|
701
744
|
null,
|
|
702
745
|
2,
|