@plaud-ai/mcp 0.2.0 → 0.2.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.
@@ -4,14 +4,23 @@ import {
4
4
 
5
5
  // src/install-utils.ts
6
6
  import { readFile, writeFile, mkdir } from "fs/promises";
7
+ import { existsSync } from "fs";
7
8
  import { join, dirname } from "path";
8
9
  import { homedir, platform } from "os";
9
10
  import { spawnSync } from "child_process";
10
11
  var SKILLS_MARKER_START = "<!-- plaud-skills:start -->";
11
12
  var SKILLS_MARKER_END = "<!-- plaud-skills:end -->";
13
+ function findNpxCommand() {
14
+ const npxName = platform() === "win32" ? "npx.cmd" : "npx";
15
+ const found = spawnSync(platform() === "win32" ? "where" : "which", [npxName], { encoding: "utf-8" });
16
+ const firstMatch = found.status === 0 ? found.stdout.split(/\r?\n/).find((line) => line.trim())?.trim() : void 0;
17
+ if (firstMatch) return firstMatch;
18
+ const sibling = join(dirname(process.execPath), npxName);
19
+ return existsSync(sibling) ? sibling : npxName;
20
+ }
12
21
  function getMcpEntry() {
13
22
  return {
14
- command: "npx",
23
+ command: findNpxCommand(),
15
24
  args: ["-y", "@plaud-ai/mcp@latest"]
16
25
  };
17
26
  }
package/dist/index.js CHANGED
@@ -81,10 +81,14 @@ server.tool("login", "Log in, sign in, or authenticate with Plaud account via OA
81
81
  }, LOGIN_TIMEOUT_MS);
82
82
  httpServer.listen(CALLBACK_PORT, () => {
83
83
  open(url).catch(() => {
84
- cleanup();
85
84
  resolve({
86
- content: [{ type: "text", text: `Could not open browser automatically. Please open this URL to authenticate:
87
- ${url}` }],
85
+ content: [{
86
+ type: "text",
87
+ text: `Could not open browser automatically. Open this URL within 2 minutes to authenticate:
88
+ ${url}
89
+
90
+ If this is a remote/headless machine, forward local port 8199 to this machine first, then open the URL locally.`
91
+ }],
88
92
  isError: true
89
93
  });
90
94
  });
@@ -126,7 +130,7 @@ async function main() {
126
130
  const sub = process.argv[2];
127
131
  const sub2 = process.argv[3];
128
132
  if (sub === "install") {
129
- const { runInstall } = await import("./install-TU2Y3ARS.js");
133
+ const { runInstall } = await import("./install-I2N3DJG4.js");
130
134
  const args = process.argv.slice(3);
131
135
  const yes = args.some((a) => a === "--yes" || a === "-y");
132
136
  const noLogin = args.some((a) => a === "--no-login");
@@ -134,32 +138,32 @@ async function main() {
134
138
  return;
135
139
  }
136
140
  if (sub === "clean-plugin") {
137
- const { runCleanPlugin } = await import("./setup-7JTG3C2W.js");
141
+ const { runCleanPlugin } = await import("./setup-QRUDA7ES.js");
138
142
  await runCleanPlugin();
139
143
  return;
140
144
  }
141
145
  if (sub === "setup" && sub2 === "codex") {
142
- const { runSetupCodex } = await import("./setup-7JTG3C2W.js");
146
+ const { runSetupCodex } = await import("./setup-QRUDA7ES.js");
143
147
  await runSetupCodex();
144
148
  return;
145
149
  }
146
150
  if (sub === "unsetup" && sub2 === "codex") {
147
- const { runUnsetupCodex } = await import("./setup-7JTG3C2W.js");
151
+ const { runUnsetupCodex } = await import("./setup-QRUDA7ES.js");
148
152
  await runUnsetupCodex();
149
153
  return;
150
154
  }
151
155
  if (sub === "setup") {
152
- const { runSetup } = await import("./setup-7JTG3C2W.js");
156
+ const { runSetup } = await import("./setup-QRUDA7ES.js");
153
157
  await runSetup();
154
158
  return;
155
159
  }
156
160
  if (sub === "unsetup") {
157
- const { runUnsetup } = await import("./setup-7JTG3C2W.js");
161
+ const { runUnsetup } = await import("./setup-QRUDA7ES.js");
158
162
  await runUnsetup();
159
163
  return;
160
164
  }
161
165
  if (sub === "http") {
162
- const { startHttpServer } = await import("./server-3256GMAD.js");
166
+ const { startHttpServer } = await import("./server-D3H6AMVD.js");
163
167
  startHttpServer();
164
168
  return;
165
169
  }
@@ -5,7 +5,7 @@ import {
5
5
  copyToClipboard,
6
6
  getMcpEntry,
7
7
  writeSkillsToClaudeCode
8
- } from "./chunk-UPEENHCG.js";
8
+ } from "./chunk-K22WPZ7P.js";
9
9
  import {
10
10
  skillsCombined
11
11
  } from "./chunk-4QBEOJPX.js";
@@ -32,6 +32,9 @@ function claudeDesktopConfigPath() {
32
32
  function claudeCodeDir() {
33
33
  return join(homedir(), ".claude");
34
34
  }
35
+ function claudeCodeUserConfigPath() {
36
+ return join(homedir(), ".claude.json");
37
+ }
35
38
  function codexConfigPath() {
36
39
  return join(homedir(), ".codex", "config.toml");
37
40
  }
@@ -87,24 +90,34 @@ async function installClaudeDesktop() {
87
90
  async function installClaudeCode() {
88
91
  await writeSkillsToClaudeCode();
89
92
  const { command, args } = getMcpEntry();
90
- const manualCmd = `claude mcp add --scope user plaud ${command} ${args.join(" ")}`;
93
+ const serverCommand = [command, ...args].join(" ");
94
+ const manualCmd = `claude mcp add --scope user plaud -- ${serverCommand}`;
91
95
  const cliCheck = spawnSync("which", ["claude"], { encoding: "utf-8" });
92
96
  if (cliCheck.status !== 0) {
93
- return `skills written to ~/.claude/CLAUDE.md. Claude Code CLI not on PATH \u2014 once installed, run:
97
+ const configPath = claudeCodeUserConfigPath();
98
+ let config = {};
99
+ try {
100
+ config = JSON.parse(await readFile(configPath, "utf-8"));
101
+ } catch {
102
+ if (existsSync(configPath)) {
103
+ return `failed: skills written to ~/.claude/CLAUDE.md, but ~/.claude.json could not be parsed. Run manually once Claude Code CLI is available:
94
104
  ${manualCmd}`;
105
+ }
106
+ }
107
+ const mcpServers = config.mcpServers ?? {};
108
+ config.mcpServers = { ...mcpServers, plaud: { type: "stdio", command, args, env: {} } };
109
+ await writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
110
+ return "skills written to ~/.claude/CLAUDE.md. Claude Code CLI not on PATH; MCP registered in ~/.claude.json.";
95
111
  }
96
- const existing = spawnSync("claude", ["mcp", "get", "plaud"], { encoding: "utf-8" });
97
- if (existing.status === 0) {
98
- return "skills written to ~/.claude/CLAUDE.md. MCP already registered (scope: user).";
99
- }
112
+ spawnSync("claude", ["mcp", "remove", "plaud", "--scope", "user"], { encoding: "utf-8" });
100
113
  const register = spawnSync(
101
114
  "claude",
102
- ["mcp", "add", "--scope", "user", "plaud", command, ...args],
115
+ ["mcp", "add", "--scope", "user", "plaud", "--", command, ...args],
103
116
  { encoding: "utf-8" }
104
117
  );
105
118
  if (register.status !== 0) {
106
119
  const err = (register.stderr || register.stdout || "").trim();
107
- return `skills written to ~/.claude/CLAUDE.md. Failed to auto-register MCP (${err || "unknown"}). Run manually:
120
+ return `failed: skills written to ~/.claude/CLAUDE.md, but auto-registering MCP failed (${err || "unknown"}). Run manually:
108
121
  ${manualCmd}`;
109
122
  }
110
123
  return "skills written to ~/.claude/CLAUDE.md and MCP registered at user scope.";
@@ -202,9 +215,10 @@ async function runLogin() {
202
215
  resolve({ status: "timeout" });
203
216
  }, LOGIN_TIMEOUT_MS);
204
217
  httpServer.listen(CALLBACK_PORT, () => {
218
+ console.log(` if no browser opens, open this URL while this command is still running:
219
+ ${url}`);
205
220
  open(url).catch(() => {
206
- cleanup();
207
- resolve({ status: "failed", message: `could not open browser. Visit manually: ${url}` });
221
+ console.log(" browser launch failed \u2014 waiting for a manual browser callback.");
208
222
  });
209
223
  });
210
224
  httpServer.on("error", (err) => {
@@ -360,7 +374,7 @@ function printNextSteps(clients, login) {
360
374
  console.log(" list my recent Plaud recordings");
361
375
  console.log();
362
376
  console.log(" This triggers OAuth in your browser (once). Tokens are then");
363
- console.log(" stored in ~/.plaud/tokens.json and refreshed automatically.");
377
+ console.log(" stored in ~/.plaud/tokens-mcp.json and refreshed automatically.");
364
378
  }
365
379
  console.log();
366
380
  console.log(bar);
@@ -186,7 +186,7 @@ var HTTP_PORT = Number(process.env.PLAUD_HTTP_PORT ?? 3e3);
186
186
  var HTTP_HOST = process.env.PLAUD_HTTP_HOST ?? "0.0.0.0";
187
187
  var CALLBACK_PORT = 8199;
188
188
  var CALLBACK_PATH = "/auth/callback";
189
- var CALLBACK_URL = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
189
+ var CALLBACK_URL = process.env.PLAUD_CALLBACK_URL ?? `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
190
190
  function startHttpServer() {
191
191
  const clientId = process.env.PLAUD_MCP_CLIENT_ID ?? process.env.PLAUD_CLIENT_ID ?? "client_9c501dad-8a0d-40b2-a7b0-d1cb8787f674";
192
192
  const clientSecret = process.env.PLAUD_CLIENT_SECRET ?? "";
@@ -3,7 +3,7 @@ import {
3
3
  getMcpEntry,
4
4
  removeSkillsFromClaudeCode,
5
5
  writeSkillsToClaudeCode
6
- } from "./chunk-UPEENHCG.js";
6
+ } from "./chunk-K22WPZ7P.js";
7
7
  import {
8
8
  skillsCombined
9
9
  } from "./chunk-4QBEOJPX.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plaud-ai/mcp",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -12,9 +12,13 @@
12
12
  ".mcp.json",
13
13
  "skills"
14
14
  ],
15
- "publishConfig": {
16
- "registry": "https://registry.npmjs.org/",
17
- "access": "public"
15
+ "scripts": {
16
+ "version:show": "node -p \"require('./package.json').version\"",
17
+ "prebuild": "node ../../scripts/sync-skills.mjs",
18
+ "build": "tsup",
19
+ "dev": "tsup --watch",
20
+ "clean": "rm -rf dist skills",
21
+ "prepublishOnly": "node -e \"const fs=require('fs'),v=require('./package.json').version,p=JSON.parse(fs.readFileSync('./plugin.json','utf8'));p.version=v;fs.writeFileSync('./plugin.json',JSON.stringify(p,null,2)+'\\n');\""
18
22
  },
19
23
  "dependencies": {
20
24
  "@modelcontextprotocol/sdk": "^1.12.0",
@@ -24,16 +28,9 @@
24
28
  "zod": "^4.3.6"
25
29
  },
26
30
  "devDependencies": {
31
+ "@plaud-ai/shared": "workspace:*",
27
32
  "@types/express": "^5.0.6",
28
33
  "@types/node": "^25.5.0",
29
- "typescript": "^5.7.0",
30
- "@plaud-ai/shared": "0.1.0"
31
- },
32
- "scripts": {
33
- "version:show": "node -p \"require('./package.json').version\"",
34
- "prebuild": "node ../../scripts/sync-skills.mjs",
35
- "build": "tsup",
36
- "dev": "tsup --watch",
37
- "clean": "rm -rf dist skills"
34
+ "typescript": "^5.7.0"
38
35
  }
39
- }
36
+ }
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plaud",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Access your Plaud recordings in Claude",
5
5
  "author": {
6
6
  "name": "Plaud AI"
@@ -13,7 +13,7 @@ metadata:
13
13
 
14
14
  ## Authentication
15
15
 
16
- - Plaud uses OAuth. Tokens are stored in `~/.plaud/tokens.json` and refreshed automatically.
16
+ - Plaud MCP uses OAuth. MCP tokens are stored in `~/.plaud/tokens-mcp.json` and refreshed automatically. The terminal CLI uses `~/.plaud/tokens.json` separately.
17
17
  - If any tool returns an auth error (message includes `Not authenticated` or `401`), call the `login` tool and wait for the browser callback. Do **not** retry the original tool until login returns success.
18
18
  - Never ask the user to paste tokens. The `login` tool handles the whole flow.
19
19