@plaud-ai/mcp 0.1.58 → 0.2.0

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.
@@ -0,0 +1,92 @@
1
+ // src/skills.ts
2
+ import { readdir, readFile } from "fs/promises";
3
+ import { statSync } from "fs";
4
+ import { join, dirname, resolve } from "path";
5
+ import { fileURLToPath } from "url";
6
+ function parseFrontmatter(raw) {
7
+ if (!raw.startsWith("---\n")) return { meta: {}, body: raw };
8
+ const end = raw.indexOf("\n---\n", 4);
9
+ if (end === -1) return { meta: {}, body: raw };
10
+ const yaml = raw.slice(4, end);
11
+ const body = raw.slice(end + 5);
12
+ const meta = {};
13
+ let currentKey = null;
14
+ for (const line of yaml.split("\n")) {
15
+ if (!line.trim()) continue;
16
+ const topMatch = line.match(/^([a-zA-Z_][\w-]*):\s*(.*)$/);
17
+ if (topMatch && !line.startsWith(" ")) {
18
+ const [, k, v] = topMatch;
19
+ currentKey = k;
20
+ if (v !== "") {
21
+ const unq = v.replace(/^["']|["']$/g, "");
22
+ meta[k] = unq;
23
+ currentKey = null;
24
+ } else {
25
+ meta[k] = {};
26
+ }
27
+ }
28
+ }
29
+ return { meta, body };
30
+ }
31
+ function findSkillsDir() {
32
+ const here = dirname(fileURLToPath(import.meta.url));
33
+ const candidates = [
34
+ resolve(here, "..", "skills"),
35
+ resolve(here, "..", "..", "skills")
36
+ ];
37
+ for (const c of candidates) {
38
+ try {
39
+ if (statSync(c).isDirectory()) return c;
40
+ } catch {
41
+ }
42
+ }
43
+ return candidates[0];
44
+ }
45
+ var cached = null;
46
+ async function loadSkills() {
47
+ if (cached) return cached;
48
+ const dir = findSkillsDir();
49
+ let entries;
50
+ try {
51
+ entries = await readdir(dir);
52
+ } catch {
53
+ cached = [];
54
+ return cached;
55
+ }
56
+ const skills = [];
57
+ for (const name of entries) {
58
+ try {
59
+ const skillPath = join(dir, name, "SKILL.md");
60
+ const raw = await readFile(skillPath, "utf-8");
61
+ const { meta, body } = parseFrontmatter(raw);
62
+ const skillName = typeof meta.name === "string" ? meta.name : name;
63
+ const description = typeof meta.description === "string" ? meta.description : "";
64
+ const version = typeof meta.version === "string" ? meta.version : "0.0.0";
65
+ skills.push({
66
+ name: skillName,
67
+ version,
68
+ description,
69
+ body: body.trimStart(),
70
+ content: raw,
71
+ supported: true
72
+ });
73
+ } catch {
74
+ }
75
+ }
76
+ skills.sort((a, b) => {
77
+ if (a.name === "plaud-shared") return -1;
78
+ if (b.name === "plaud-shared") return 1;
79
+ return a.name.localeCompare(b.name);
80
+ });
81
+ cached = skills;
82
+ return cached;
83
+ }
84
+ async function skillsCombined() {
85
+ const skills = await loadSkills();
86
+ return skills.map((s) => s.content).join("\n\n---\n\n");
87
+ }
88
+
89
+ export {
90
+ loadSkills,
91
+ skillsCombined
92
+ };
@@ -0,0 +1,33 @@
1
+ import {
2
+ PlaudClient
3
+ } from "./chunk-SNSGVRCU.js";
4
+
5
+ // src/config.ts
6
+ function buildExtraHeaders() {
7
+ const headers = {};
8
+ if (process.env.PLAUD_ENV) headers["x-pld-env"] = process.env.PLAUD_ENV;
9
+ if (process.env.PLAUD_REGION) headers["x-pld-region"] = process.env.PLAUD_REGION;
10
+ return headers;
11
+ }
12
+ var CONFIG = {
13
+ clientId: process.env.PLAUD_MCP_CLIENT_ID ?? process.env.PLAUD_CLIENT_ID ?? "client_9c501dad-8a0d-40b2-a7b0-d1cb8787f674",
14
+ clientSecret: process.env.PLAUD_CLIENT_SECRET ?? "",
15
+ redirectUri: "http://localhost:8199/auth/callback",
16
+ tokenFile: "tokens-mcp.json",
17
+ apiBase: process.env.PLAUD_API_BASE,
18
+ authorizationUrl: process.env.PLAUD_AUTH_URL,
19
+ tokenUrl: process.env.PLAUD_TOKEN_URL,
20
+ refreshUrl: process.env.PLAUD_REFRESH_URL,
21
+ extraHeaders: buildExtraHeaders()
22
+ };
23
+ var client = null;
24
+ function getClient() {
25
+ if (!client) {
26
+ client = new PlaudClient(CONFIG);
27
+ }
28
+ return client;
29
+ }
30
+
31
+ export {
32
+ getClient
33
+ };
@@ -0,0 +1,151 @@
1
+ // src/logger.ts
2
+ import pino from "pino";
3
+ var logger = pino(
4
+ { level: process.env.LOG_LEVEL ?? "info" },
5
+ pino.destination(2)
6
+ );
7
+
8
+ // src/tools/index.ts
9
+ import { z } from "zod";
10
+ var MAX_FILTER_PAGES = 5;
11
+ var FILTER_PAGE_SIZE = 100;
12
+ function parseDate(s) {
13
+ if (!s) return null;
14
+ const d = new Date(s);
15
+ if (Number.isNaN(d.getTime())) return null;
16
+ return d.getTime();
17
+ }
18
+ function registerTools(server, client) {
19
+ server.tool(
20
+ "list_files",
21
+ "List Plaud recordings. Supports optional client-side filtering: `query` (case-insensitive name substring), `date_from`/`date_to` (YYYY-MM-DD, inclusive). When any filter is set, paginates up to 5 pages \xD7 100 recordings and returns all matches.",
22
+ {
23
+ page: z.number().optional().default(1).describe("Page number (ignored when filters are set)"),
24
+ page_size: z.number().optional().default(20).describe("Items per page (ignored when filters are set)"),
25
+ query: z.string().optional().describe("Case-insensitive substring match on recording name"),
26
+ date_from: z.string().optional().describe("Start date inclusive, YYYY-MM-DD"),
27
+ date_to: z.string().optional().describe("End date inclusive, YYYY-MM-DD")
28
+ },
29
+ async ({ page, page_size, query, date_from, date_to }) => {
30
+ const start = Date.now();
31
+ const hasFilter = Boolean(query || date_from || date_to);
32
+ logger.info({ event: "tool_call", tool: "list_files", has_filter: hasFilter });
33
+ try {
34
+ if (!hasFilter) {
35
+ const result = await client.listFiles(page, page_size);
36
+ logger.info({ event: "tool_call_end", tool: "list_files", duration_ms: Date.now() - start });
37
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
38
+ }
39
+ const q = query?.toLowerCase();
40
+ const from = parseDate(date_from);
41
+ const toRaw = parseDate(date_to);
42
+ const to = toRaw !== null ? toRaw + 24 * 60 * 60 * 1e3 - 1 : null;
43
+ const matches = [];
44
+ let scanned = 0;
45
+ let truncated = false;
46
+ for (let p = 1; p <= MAX_FILTER_PAGES; p++) {
47
+ const pageResult = await client.listFiles(p, FILTER_PAGE_SIZE);
48
+ const items = pageResult.data;
49
+ scanned += items.length;
50
+ for (const item of items) {
51
+ if (q && !(item.name ?? "").toLowerCase().includes(q)) continue;
52
+ if (from !== null || to !== null) {
53
+ const created = parseDate(item.created_at);
54
+ if (created === null) continue;
55
+ if (from !== null && created < from) continue;
56
+ if (to !== null && created > to) continue;
57
+ }
58
+ matches.push(item);
59
+ }
60
+ if (items.length < FILTER_PAGE_SIZE) break;
61
+ if (p === MAX_FILTER_PAGES) truncated = true;
62
+ }
63
+ logger.info({ event: "tool_call_end", tool: "list_files", duration_ms: Date.now() - start, scanned, matched: matches.length, truncated });
64
+ return {
65
+ content: [{ type: "text", text: JSON.stringify({
66
+ data: matches,
67
+ scanned,
68
+ matched: matches.length,
69
+ truncated,
70
+ note: truncated ? `Scanned first ${MAX_FILTER_PAGES * FILTER_PAGE_SIZE} recordings; narrow filters for a complete match.` : void 0
71
+ }, null, 2) }]
72
+ };
73
+ } catch (err) {
74
+ logger.error({ event: "tool_call_error", tool: "list_files", duration_ms: Date.now() - start, error: String(err) });
75
+ return { content: [{ type: "text", text: `Failed to list files: ${err}` }], isError: true };
76
+ }
77
+ }
78
+ );
79
+ server.tool(
80
+ "get_file",
81
+ "Get details of a specific Plaud recording by ID",
82
+ { file_id: z.string().describe("The file ID to retrieve") },
83
+ async ({ file_id }) => {
84
+ const start = Date.now();
85
+ logger.info({ event: "tool_call", tool: "get_file", file_id });
86
+ try {
87
+ const file = await client.getFile(file_id);
88
+ logger.info({ event: "tool_call_end", tool: "get_file", duration_ms: Date.now() - start });
89
+ return { content: [{ type: "text", text: JSON.stringify(file, null, 2) }] };
90
+ } catch (err) {
91
+ logger.error({ event: "tool_call_error", tool: "get_file", duration_ms: Date.now() - start, error: String(err) });
92
+ return { content: [{ type: "text", text: `Failed to get file: ${err}` }], isError: true };
93
+ }
94
+ }
95
+ );
96
+ server.tool(
97
+ "get_note",
98
+ "Fetch AI-generated notes for a Plaud recording \u2014 compact summary, action items, and key topics",
99
+ { file_id: z.string().describe("The file ID to retrieve notes for") },
100
+ async ({ file_id }) => {
101
+ const start = Date.now();
102
+ logger.info({ event: "tool_call", tool: "get_note", file_id });
103
+ try {
104
+ const file = await client.getFile(file_id);
105
+ logger.info({ event: "tool_call_end", tool: "get_note", duration_ms: Date.now() - start });
106
+ return { content: [{ type: "text", text: JSON.stringify(file.note_list ?? [], null, 2) }] };
107
+ } catch (err) {
108
+ logger.error({ event: "tool_call_error", tool: "get_note", duration_ms: Date.now() - start, error: String(err) });
109
+ return { content: [{ type: "text", text: `Failed to get note: ${err}` }], isError: true };
110
+ }
111
+ }
112
+ );
113
+ server.tool(
114
+ "get_transcript",
115
+ "Fetch the full timestamped transcript with speaker attribution for a Plaud recording",
116
+ { file_id: z.string().describe("The file ID to retrieve transcript for") },
117
+ async ({ file_id }) => {
118
+ const start = Date.now();
119
+ logger.info({ event: "tool_call", tool: "get_transcript", file_id });
120
+ try {
121
+ const file = await client.getFile(file_id);
122
+ logger.info({ event: "tool_call_end", tool: "get_transcript", duration_ms: Date.now() - start });
123
+ return { content: [{ type: "text", text: JSON.stringify(file.source_list ?? [], null, 2) }] };
124
+ } catch (err) {
125
+ logger.error({ event: "tool_call_error", tool: "get_transcript", duration_ms: Date.now() - start, error: String(err) });
126
+ return { content: [{ type: "text", text: `Failed to get transcript: ${err}` }], isError: true };
127
+ }
128
+ }
129
+ );
130
+ server.tool(
131
+ "get_current_user",
132
+ "Get current authenticated user info",
133
+ async () => {
134
+ const start = Date.now();
135
+ logger.info({ event: "tool_call", tool: "get_current_user" });
136
+ try {
137
+ const user = await client.getCurrentUser();
138
+ logger.info({ event: "tool_call_end", tool: "get_current_user", duration_ms: Date.now() - start });
139
+ return { content: [{ type: "text", text: JSON.stringify(user, null, 2) }] };
140
+ } catch (err) {
141
+ logger.error({ event: "tool_call_error", tool: "get_current_user", duration_ms: Date.now() - start, error: String(err) });
142
+ return { content: [{ type: "text", text: `Failed to get user info: ${err}` }], isError: true };
143
+ }
144
+ }
145
+ );
146
+ }
147
+
148
+ export {
149
+ logger,
150
+ registerTools
151
+ };
@@ -229,106 +229,6 @@ var PlaudClient = class {
229
229
  }
230
230
  };
231
231
 
232
- // src/logger.ts
233
- import pino from "pino";
234
- var logger = pino({
235
- level: process.env.LOG_LEVEL ?? "info"
236
- });
237
-
238
- // src/tools/index.ts
239
- import { z } from "zod";
240
- function registerTools(server, client) {
241
- server.tool(
242
- "list_files",
243
- "List Plaud recordings",
244
- {
245
- page: z.number().optional().default(1).describe("Page number"),
246
- page_size: z.number().optional().default(20).describe("Items per page")
247
- },
248
- async ({ page, page_size }) => {
249
- const start = Date.now();
250
- logger.info({ event: "tool_call", tool: "list_files" });
251
- try {
252
- const result = await client.listFiles(page, page_size);
253
- logger.info({ event: "tool_call_end", tool: "list_files", duration_ms: Date.now() - start });
254
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
255
- } catch (err) {
256
- logger.error({ event: "tool_call_error", tool: "list_files", duration_ms: Date.now() - start, error: String(err) });
257
- return { content: [{ type: "text", text: `Failed to list files: ${err}` }], isError: true };
258
- }
259
- }
260
- );
261
- server.tool(
262
- "get_file",
263
- "Get details of a specific Plaud recording by ID",
264
- { file_id: z.string().describe("The file ID to retrieve") },
265
- async ({ file_id }) => {
266
- const start = Date.now();
267
- logger.info({ event: "tool_call", tool: "get_file", file_id });
268
- try {
269
- const file = await client.getFile(file_id);
270
- logger.info({ event: "tool_call_end", tool: "get_file", duration_ms: Date.now() - start });
271
- return { content: [{ type: "text", text: JSON.stringify(file, null, 2) }] };
272
- } catch (err) {
273
- logger.error({ event: "tool_call_error", tool: "get_file", duration_ms: Date.now() - start, error: String(err) });
274
- return { content: [{ type: "text", text: `Failed to get file: ${err}` }], isError: true };
275
- }
276
- }
277
- );
278
- server.tool(
279
- "get_note",
280
- "Fetch AI-generated notes for a Plaud recording \u2014 compact summary, action items, and key topics",
281
- { file_id: z.string().describe("The file ID to retrieve notes for") },
282
- async ({ file_id }) => {
283
- const start = Date.now();
284
- logger.info({ event: "tool_call", tool: "get_note", file_id });
285
- try {
286
- const file = await client.getFile(file_id);
287
- logger.info({ event: "tool_call_end", tool: "get_note", duration_ms: Date.now() - start });
288
- return { content: [{ type: "text", text: JSON.stringify(file.note_list ?? [], null, 2) }] };
289
- } catch (err) {
290
- logger.error({ event: "tool_call_error", tool: "get_note", duration_ms: Date.now() - start, error: String(err) });
291
- return { content: [{ type: "text", text: `Failed to get note: ${err}` }], isError: true };
292
- }
293
- }
294
- );
295
- server.tool(
296
- "get_transcript",
297
- "Fetch the full timestamped transcript with speaker attribution for a Plaud recording",
298
- { file_id: z.string().describe("The file ID to retrieve transcript for") },
299
- async ({ file_id }) => {
300
- const start = Date.now();
301
- logger.info({ event: "tool_call", tool: "get_transcript", file_id });
302
- try {
303
- const file = await client.getFile(file_id);
304
- logger.info({ event: "tool_call_end", tool: "get_transcript", duration_ms: Date.now() - start });
305
- return { content: [{ type: "text", text: JSON.stringify(file.source_list ?? [], null, 2) }] };
306
- } catch (err) {
307
- logger.error({ event: "tool_call_error", tool: "get_transcript", duration_ms: Date.now() - start, error: String(err) });
308
- return { content: [{ type: "text", text: `Failed to get transcript: ${err}` }], isError: true };
309
- }
310
- }
311
- );
312
- server.tool(
313
- "get_current_user",
314
- "Get current authenticated user info",
315
- async () => {
316
- const start = Date.now();
317
- logger.info({ event: "tool_call", tool: "get_current_user" });
318
- try {
319
- const user = await client.getCurrentUser();
320
- logger.info({ event: "tool_call_end", tool: "get_current_user", duration_ms: Date.now() - start });
321
- return { content: [{ type: "text", text: JSON.stringify(user, null, 2) }] };
322
- } catch (err) {
323
- logger.error({ event: "tool_call_error", tool: "get_current_user", duration_ms: Date.now() - start, error: String(err) });
324
- return { content: [{ type: "text", text: `Failed to get user info: ${err}` }], isError: true };
325
- }
326
- }
327
- );
328
- }
329
-
330
232
  export {
331
- PlaudClient,
332
- logger,
333
- registerTools
233
+ PlaudClient
334
234
  };
@@ -0,0 +1,70 @@
1
+ import {
2
+ skillsCombined
3
+ } from "./chunk-4QBEOJPX.js";
4
+
5
+ // src/install-utils.ts
6
+ import { readFile, writeFile, mkdir } from "fs/promises";
7
+ import { join, dirname } from "path";
8
+ import { homedir, platform } from "os";
9
+ import { spawnSync } from "child_process";
10
+ var SKILLS_MARKER_START = "<!-- plaud-skills:start -->";
11
+ var SKILLS_MARKER_END = "<!-- plaud-skills:end -->";
12
+ function getMcpEntry() {
13
+ return {
14
+ command: "npx",
15
+ args: ["-y", "@plaud-ai/mcp@latest"]
16
+ };
17
+ }
18
+ function copyToClipboard(content) {
19
+ if (platform() === "win32") {
20
+ return spawnSync("clip", [], { input: content }).status === 0;
21
+ }
22
+ if (platform() === "darwin") {
23
+ return spawnSync("pbcopy", [], { input: content }).status === 0;
24
+ }
25
+ return false;
26
+ }
27
+ async function writeSkillsToClaudeCode() {
28
+ const claudeMdPath = join(homedir(), ".claude", "CLAUDE.md");
29
+ const combined = await skillsCombined();
30
+ const block = `${SKILLS_MARKER_START}
31
+ ${combined}
32
+ ${SKILLS_MARKER_END}`;
33
+ let existing = "";
34
+ try {
35
+ existing = await readFile(claudeMdPath, "utf-8");
36
+ } catch {
37
+ }
38
+ if (existing.includes(SKILLS_MARKER_START)) {
39
+ const updated = existing.replace(
40
+ new RegExp(`${SKILLS_MARKER_START}[\\s\\S]*?${SKILLS_MARKER_END}`),
41
+ block
42
+ );
43
+ await mkdir(dirname(claudeMdPath), { recursive: true });
44
+ await writeFile(claudeMdPath, updated, "utf-8");
45
+ } else {
46
+ await mkdir(dirname(claudeMdPath), { recursive: true });
47
+ await writeFile(claudeMdPath, existing + (existing.endsWith("\n") ? "" : "\n") + block + "\n", "utf-8");
48
+ }
49
+ }
50
+ async function removeSkillsFromClaudeCode() {
51
+ const claudeMdPath = join(homedir(), ".claude", "CLAUDE.md");
52
+ let existing = "";
53
+ try {
54
+ existing = await readFile(claudeMdPath, "utf-8");
55
+ } catch {
56
+ return;
57
+ }
58
+ if (!existing.includes(SKILLS_MARKER_START)) {
59
+ return;
60
+ }
61
+ const updated = existing.replace(new RegExp(`\\n?${SKILLS_MARKER_START}[\\s\\S]*?${SKILLS_MARKER_END}\\n?`), "").trimEnd();
62
+ await writeFile(claudeMdPath, updated ? updated + "\n" : "", "utf-8");
63
+ }
64
+
65
+ export {
66
+ getMcpEntry,
67
+ copyToClipboard,
68
+ writeSkillsToClaudeCode,
69
+ removeSkillsFromClaudeCode
70
+ };
package/dist/index.js CHANGED
@@ -1,58 +1,33 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- ACTIVE_SKILLS
4
- } from "./chunk-7PYQFJJW.js";
3
+ getClient
4
+ } from "./chunk-7KGB7GSZ.js";
5
+ import {
6
+ loadSkills
7
+ } from "./chunk-4QBEOJPX.js";
5
8
  import {
6
- PlaudClient,
7
9
  registerTools
8
- } from "./chunk-YMQLKZLW.js";
10
+ } from "./chunk-MPCF6HMK.js";
11
+ import "./chunk-SNSGVRCU.js";
9
12
 
10
13
  // src/index.ts
11
14
  import { createServer } from "http";
12
15
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
13
16
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
14
17
  import open from "open";
15
-
16
- // src/config.ts
17
- function buildExtraHeaders() {
18
- const headers = {};
19
- if (process.env.PLAUD_ENV) headers["x-pld-env"] = process.env.PLAUD_ENV;
20
- if (process.env.PLAUD_REGION) headers["x-pld-region"] = process.env.PLAUD_REGION;
21
- return headers;
22
- }
23
- var CONFIG = {
24
- clientId: process.env.PLAUD_MCP_CLIENT_ID ?? process.env.PLAUD_CLIENT_ID ?? "client_9c501dad-8a0d-40b2-a7b0-d1cb8787f674",
25
- clientSecret: process.env.PLAUD_CLIENT_SECRET ?? "",
26
- redirectUri: "http://localhost:8199/auth/callback",
27
- tokenFile: "tokens-mcp.json",
28
- apiBase: process.env.PLAUD_API_BASE,
29
- authorizationUrl: process.env.PLAUD_AUTH_URL,
30
- tokenUrl: process.env.PLAUD_TOKEN_URL,
31
- refreshUrl: process.env.PLAUD_REFRESH_URL,
32
- extraHeaders: buildExtraHeaders()
33
- };
34
- var client = null;
35
- function getClient() {
36
- if (!client) {
37
- client = new PlaudClient(CONFIG);
38
- }
39
- return client;
40
- }
41
-
42
- // src/index.ts
43
18
  var server = new McpServer({
44
19
  name: "plaud",
45
- version: "0.1.0"
20
+ version: "0.2.0"
46
21
  });
47
22
  var CALLBACK_PORT = 8199;
48
23
  var LOGIN_TIMEOUT_MS = 12e4;
49
24
  server.tool("login", "Log in, sign in, or authenticate with Plaud account via OAuth (opens browser)", async () => {
50
- const client2 = getClient();
51
- const existingToken = await client2.auth.getAccessToken();
25
+ const client = getClient();
26
+ const existingToken = await client.auth.getAccessToken();
52
27
  if (existingToken) {
53
28
  return { content: [{ type: "text", text: "Already logged in." }] };
54
29
  }
55
- const { url, codeVerifier, state } = client2.auth.createAuthorizationRequest();
30
+ const { url, codeVerifier, state } = client.auth.createAuthorizationRequest();
56
31
  return new Promise((resolve) => {
57
32
  const httpServer = createServer(async (req, res) => {
58
33
  const reqUrl = new URL(req.url, `http://localhost:${CALLBACK_PORT}`);
@@ -73,7 +48,7 @@ server.tool("login", "Log in, sign in, or authenticate with Plaud account via OA
73
48
  return;
74
49
  }
75
50
  try {
76
- await client2.auth.exchangeCode(code, codeVerifier, state);
51
+ await client.auth.exchangeCode(code, codeVerifier, state);
77
52
  res.writeHead(200, { "Content-Type": "text/html" });
78
53
  res.end("<h1>Authentication successful!</h1><p>You can close this tab.</p>");
79
54
  cleanup();
@@ -125,56 +100,87 @@ ${url}` }],
125
100
  });
126
101
  registerTools(server, getClient());
127
102
  server.tool("logout", "Log out, sign out, revoke authorization, and disconnect from Plaud account", async () => {
128
- const client2 = getClient();
129
- const existingToken = await client2.auth.getAccessToken();
103
+ const client = getClient();
104
+ const existingToken = await client.auth.getAccessToken();
130
105
  if (!existingToken) {
131
106
  return { content: [{ type: "text", text: "Already logged out." }] };
132
107
  }
133
108
  try {
134
- await client2.revokeCurrentUser();
109
+ await client.revokeCurrentUser();
135
110
  } catch {
136
111
  }
137
- await client2.auth.logout();
112
+ await client.auth.logout();
138
113
  return {
139
114
  content: [{ type: "text", text: "Logged out and revoked authorization." }]
140
115
  };
141
116
  });
142
- for (const skill of ACTIVE_SKILLS) {
143
- server.prompt(skill.name, skill.description, () => ({
144
- messages: [{ role: "user", content: { type: "text", text: skill.content } }]
145
- }));
117
+ async function registerSkillPrompts() {
118
+ const skills = await loadSkills();
119
+ for (const skill of skills) {
120
+ server.prompt(skill.name, skill.description, () => ({
121
+ messages: [{ role: "user", content: { type: "text", text: skill.content } }]
122
+ }));
123
+ }
146
124
  }
147
125
  async function main() {
148
- if (process.argv[2] === "clean-plugin") {
149
- const { runCleanPlugin } = await import("./setup-KGUMS567.js");
126
+ const sub = process.argv[2];
127
+ const sub2 = process.argv[3];
128
+ if (sub === "install") {
129
+ const { runInstall } = await import("./install-TU2Y3ARS.js");
130
+ const args = process.argv.slice(3);
131
+ const yes = args.some((a) => a === "--yes" || a === "-y");
132
+ const noLogin = args.some((a) => a === "--no-login");
133
+ await runInstall({ yes, noLogin });
134
+ return;
135
+ }
136
+ if (sub === "clean-plugin") {
137
+ const { runCleanPlugin } = await import("./setup-7JTG3C2W.js");
150
138
  await runCleanPlugin();
151
139
  return;
152
140
  }
153
- if (process.argv[2] === "setup" && process.argv[3] === "codex") {
154
- const { runSetupCodex } = await import("./setup-KGUMS567.js");
141
+ if (sub === "setup" && sub2 === "codex") {
142
+ const { runSetupCodex } = await import("./setup-7JTG3C2W.js");
155
143
  await runSetupCodex();
156
144
  return;
157
145
  }
158
- if (process.argv[2] === "unsetup" && process.argv[3] === "codex") {
159
- const { runUnsetupCodex } = await import("./setup-KGUMS567.js");
146
+ if (sub === "unsetup" && sub2 === "codex") {
147
+ const { runUnsetupCodex } = await import("./setup-7JTG3C2W.js");
160
148
  await runUnsetupCodex();
161
149
  return;
162
150
  }
163
- if (process.argv[2] === "setup") {
164
- const { runSetup } = await import("./setup-KGUMS567.js");
151
+ if (sub === "setup") {
152
+ const { runSetup } = await import("./setup-7JTG3C2W.js");
165
153
  await runSetup();
166
154
  return;
167
155
  }
168
- if (process.argv[2] === "unsetup") {
169
- const { runUnsetup } = await import("./setup-KGUMS567.js");
156
+ if (sub === "unsetup") {
157
+ const { runUnsetup } = await import("./setup-7JTG3C2W.js");
170
158
  await runUnsetup();
171
159
  return;
172
160
  }
173
- if (process.argv[2] === "http") {
174
- const { startHttpServer } = await import("./server-5L7BYLYR.js");
161
+ if (sub === "http") {
162
+ const { startHttpServer } = await import("./server-3256GMAD.js");
175
163
  startHttpServer();
176
164
  return;
177
165
  }
166
+ if (sub === "--help" || sub === "-h") {
167
+ console.log(`plaud-mcp \u2014 Plaud MCP server
168
+
169
+ Usage:
170
+ plaud-mcp start MCP over stdio
171
+ plaud-mcp install detect AI clients, configure them, and run OAuth inline (recommended)
172
+ plaud-mcp install --yes non-interactive; auto-configure every detected client (for agent-driven install)
173
+ plaud-mcp install --no-login skip the OAuth step (for CI / headless setup)
174
+ plaud-mcp http start HTTP MCP server (advanced)
175
+ plaud-mcp setup [deprecated] alias for install (Claude Desktop only)
176
+ plaud-mcp setup codex [deprecated] alias for install (Codex only)
177
+ plaud-mcp unsetup remove Plaud from Claude Desktop
178
+ plaud-mcp unsetup codex remove Plaud from Codex Desktop
179
+ plaud-mcp clean-plugin clear Claude Code plugin cache
180
+ `);
181
+ return;
182
+ }
183
+ await registerSkillPrompts();
178
184
  const transport = new StdioServerTransport();
179
185
  await server.connect(transport);
180
186
  }