@nado-language/mcp 0.1.0 → 0.1.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/README.md CHANGED
@@ -14,6 +14,18 @@ The default MCP path is designed to avoid double charging for AI. ChatGPT, Claud
14
14
 
15
15
  ## Authentication
16
16
 
17
+ Install from npm:
18
+
19
+ ```bash
20
+ npm install --global @nado-language/mcp
21
+ ```
22
+
23
+ Install on macOS with Homebrew:
24
+
25
+ ```bash
26
+ brew install jintonyc/tap/nado-mcp
27
+ ```
28
+
17
29
  Installed package browser login:
18
30
 
19
31
  ```bash
@@ -109,6 +121,13 @@ nado-mcp connect claude
109
121
  nado-mcp connect opencode
110
122
  ```
111
123
 
124
+ For Codex, the command uses the Codex CLI when it is on `PATH`. If the user only has Codex Desktop, it writes Codex Desktop's TOML config directly:
125
+
126
+ - macOS/Linux: `~/.codex/config.toml`
127
+ - Windows: `%USERPROFILE%\.codex\config.toml`
128
+
129
+ Restart Codex Desktop after login completes.
130
+
112
131
  Setup without login:
113
132
 
114
133
  ```bash
@@ -114,7 +114,8 @@ async function setup(client, options = {}, flow = {}) {
114
114
  function setupCodex(flow = {}) {
115
115
  const check = spawnSync('codex', ['--version'], { stdio: 'ignore' });
116
116
  if (check.error || check.status !== 0) {
117
- throw new Error('Codex CLI was not found on PATH. Install/open Codex first, then run `nado-mcp setup codex` again.');
117
+ setupCodexDesktopConfig(flow, 'Codex CLI was not found on PATH.');
118
+ return;
118
119
  }
119
120
 
120
121
  const spec = stdioServerSpec();
@@ -128,6 +129,20 @@ function setupCodex(flow = {}) {
128
129
  printLoginNext(flow);
129
130
  }
130
131
 
132
+ function setupCodexDesktopConfig(flow = {}, reason = '') {
133
+ const configPath = codexDesktopConfigPath();
134
+ mkdirSync(path.dirname(configPath), { recursive: true });
135
+
136
+ const currentConfig = existsSync(configPath) ? readFileSync(configPath, 'utf8') : '';
137
+ const nextConfig = upsertTomlSection(currentConfig, `mcp_servers.${serverName}`, codexDesktopTomlSection());
138
+ writeFileSync(configPath, nextConfig);
139
+
140
+ if (reason) console.log(`${reason} Falling back to Codex Desktop config.`);
141
+ console.log(`Registered Nado Language MCP with Codex Desktop: ${configPath}`);
142
+ if (flow.loginAfter) console.log('Browser login will open next. Restart Codex Desktop after login completes.');
143
+ else console.log('Restart Codex Desktop, then run `nado-mcp login`.');
144
+ }
145
+
131
146
  function setupClaudeDesktop(options = {}, flow = {}) {
132
147
  const configPath = options.configFile || claudeDesktopConfigPath();
133
148
  mkdirSync(path.dirname(configPath), { recursive: true });
@@ -182,6 +197,7 @@ function doctor() {
182
197
  console.log(`Server: ${serverPath}${existsSync(serverPath) ? '' : ' (missing)'}`);
183
198
  console.log(`Auth CLI: ${authPath}${existsSync(authPath) ? '' : ' (missing)'}`);
184
199
  console.log(`Auth file: ${defaultUserAuthEnvFile()}${existsSync(defaultUserAuthEnvFile()) ? ' (present)' : ' (missing)'}`);
200
+ console.log(`Codex Desktop config: ${codexDesktopConfigPath()}`);
185
201
  console.log(`Claude Desktop config: ${claudeDesktopConfigPath()}`);
186
202
  console.log(`OpenCode config: ${opencodeConfigPath()}`);
187
203
  }
@@ -274,6 +290,37 @@ function opencodeConfig() {
274
290
  };
275
291
  }
276
292
 
293
+ function codexDesktopTomlSection() {
294
+ const spec = stdioServerSpec();
295
+ return [
296
+ `[mcp_servers.${serverName}]`,
297
+ `command = ${tomlString(spec.command)}`,
298
+ `args = ${tomlString(spec.args)}`,
299
+ ].join('\n');
300
+ }
301
+
302
+ function tomlString(value) {
303
+ return JSON.stringify(value);
304
+ }
305
+
306
+ function upsertTomlSection(text, sectionName, sectionText) {
307
+ const output = [];
308
+ let removing = false;
309
+
310
+ for (const line of String(text || '').split(/\r?\n/)) {
311
+ const header = line.match(/^\s*\[([^\]]+)]\s*$/);
312
+ if (header) {
313
+ const name = header[1];
314
+ removing = name === sectionName || name.startsWith(`${sectionName}.`);
315
+ }
316
+
317
+ if (!removing) output.push(line);
318
+ }
319
+
320
+ const base = output.join('\n').trimEnd();
321
+ return `${base}${base ? '\n\n' : ''}${sectionText.trimEnd()}\n`;
322
+ }
323
+
277
324
  function printConfig(format) {
278
325
  const normalized = String(format || 'all').toLowerCase();
279
326
  if (normalized === 'command' || normalized === 'stdio') {
@@ -467,6 +514,11 @@ function defaultUserAuthEnvFile() {
467
514
  return path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'nado', 'mcp', 'auth.env');
468
515
  }
469
516
 
517
+ function codexDesktopConfigPath() {
518
+ if (process.env.NADO_MCP_CODEX_CONFIG_FILE) return expandHome(process.env.NADO_MCP_CODEX_CONFIG_FILE);
519
+ return path.join(os.homedir(), '.codex', 'config.toml');
520
+ }
521
+
470
522
  function claudeDesktopConfigPath() {
471
523
  if (process.platform === 'win32') {
472
524
  return path.join(process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');
@@ -493,7 +545,7 @@ function printHelp() {
493
545
  console.log(`Nado Language MCP
494
546
 
495
547
  Usage:
496
- nado-mcp connect codex Register in Codex, then log in
548
+ nado-mcp connect codex Register in Codex CLI/Desktop, then log in
497
549
  nado-mcp connect claude Register in Claude Desktop, then log in
498
550
  nado-mcp connect opencode Register in OpenCode, then log in
499
551
  nado-mcp setup <client> Register without login
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nado-language/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Nado Language MCP server for saving AI-generated English flashcards and practicing saved materials.",
5
5
  "type": "module",
6
6
  "private": false,