@plaud-ai/mcp 0.1.27 → 0.1.28

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,134 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
30
+
31
+ // src/skills.ts
32
+ var SKILLS = [
33
+ {
34
+ name: "search-recordings",
35
+ description: "Search and filter Plaud recordings by date, tag, or keyword",
36
+ content: `## Plaud Skill: search-recordings
37
+
38
+ When the user wants to find, browse, filter, or search their Plaud recordings, follow this workflow:
39
+
40
+ 1. Call \`list_files\` with the appropriate filters based on the user's request:
41
+ - \`from\` / \`to\` \u2014 ISO 8601 date range (e.g. \`2026-04-01T00:00:00Z\`)
42
+ - \`tag\` \u2014 filter by tag label
43
+ - \`workspace_id\` \u2014 filter by workspace
44
+ - \`limit\` \u2014 number of results to return
45
+ 2. Present results in a clear list: recording name, date, duration, and file ID
46
+ 3. If the user wants to narrow results, refine the filters and call again
47
+
48
+ Do not fetch transcripts or notes unless the user explicitly asks to view the content of a specific recording.`
49
+ },
50
+ {
51
+ name: "extract-structured-data",
52
+ description: "Extract structured fields from a Plaud recording using a custom schema",
53
+ content: `## Plaud Skill: extract-structured-data
54
+
55
+ When the user wants to extract specific fields or structured information from a recording, follow this workflow:
56
+
57
+ 1. If no recording is specified, call \`list_files\` and ask the user to identify the target
58
+ 2. Call \`get_note\` to retrieve the AI-generated summary, action items, and key topics
59
+ 3. Call \`get_transcript\` if the extraction requires full verbatim content
60
+ 4. Apply the user's schema or field list to the content and return the extracted data
61
+ 5. Present each field clearly; flag any fields where the content is ambiguous or absent
62
+
63
+ Example schemas the user might request:
64
+ - \`{ "action_items": [], "decisions": [], "attendees": [] }\`
65
+ - \`{ "pain_points": [], "follow_ups": [], "deal_stage": "" }\`
66
+ - \`{ "diagnoses": [], "medications": [], "next_appointment": "" }\``
67
+ },
68
+ {
69
+ name: "generate-artifact",
70
+ description: "Generate a document (email, summary, SOAP note, brief) grounded in a Plaud recording",
71
+ content: `## Plaud Skill: generate-artifact
72
+
73
+ When the user wants to generate a document grounded in recording content, follow this workflow:
74
+
75
+ 1. Call \`get_note\` to retrieve AI-generated notes for the target recording
76
+ 2. Call \`get_transcript\` if the artifact requires verbatim quotes or precise detail
77
+ 3. Generate the artifact using the recording content as the source of truth
78
+ 4. Format the output to match the requested artifact type
79
+
80
+ Common artifact types:
81
+ - **Follow-up email** \u2014 summarize key points, list action items, professional tone
82
+ - **Meeting summary** \u2014 attendees, decisions made, next steps
83
+ - **SOAP note** \u2014 Subjective / Objective / Assessment / Plan format for clinical use
84
+ - **Project brief** \u2014 background, goals, scope, timeline from a planning session
85
+ - **Weekly digest** \u2014 highlights across multiple recordings from the past week`
86
+ },
87
+ {
88
+ name: "synthesize-corpus",
89
+ description: "Analyze trends and patterns across multiple Plaud recordings",
90
+ content: `## Plaud Skill: synthesize-corpus
91
+
92
+ When the user wants to analyze patterns, trends, or themes across multiple recordings, follow this workflow:
93
+
94
+ 1. Call \`list_files\` with date or tag filters to identify the target set of recordings (max 50 per call)
95
+ 2. For each recording, call \`get_note\` to retrieve the AI-generated summary
96
+ 3. Call \`get_transcript\` only if deeper analysis requires full verbatim content from specific recordings
97
+ 4. Synthesize insights across all recordings:
98
+ - Recurring themes or topics
99
+ - Trends over time
100
+ - Consistent decisions or blockers
101
+ - Patterns in action items or follow-ups
102
+ 5. Present findings with references to specific recordings as supporting evidence
103
+
104
+ Use date filters to scope the corpus (e.g., last week, last quarter, a specific project period).`
105
+ },
106
+ {
107
+ name: "push-to-destination",
108
+ description: "Send recording content or a generated artifact to Notion, HubSpot, Slack, Linear, or a webhook",
109
+ content: `## Plaud Skill: push-to-destination
110
+
111
+ When the user wants to send recording content or a generated artifact to an external system, follow this workflow:
112
+
113
+ 1. Confirm what content to send: extracted data, a generated artifact, or raw notes
114
+ 2. Confirm the destination and any required identifiers:
115
+ - **Notion** \u2014 page ID or database ID
116
+ - **HubSpot / Salesforce** \u2014 CRM object ID (deal, contact, or company)
117
+ - **Linear** \u2014 project or team ID
118
+ - **Slack** \u2014 channel name or ID
119
+ - **Webhook** \u2014 URL provided by the user
120
+ 3. Deliver the content to the destination using the appropriate integration tool or API call available in your environment
121
+ 4. Confirm successful delivery to the user
122
+
123
+ Note: Destination credentials (API tokens, webhook URLs) must be provided by the user. Do not store them in conversation history \u2014 use environment variables or the user's config.`
124
+ }
125
+ ];
126
+ var SKILLS_COMBINED = SKILLS.map((s) => s.content).join("\n\n---\n\n");
127
+
128
+ export {
129
+ __commonJS,
130
+ __export,
131
+ __toESM,
132
+ SKILLS,
133
+ SKILLS_COMBINED
134
+ };
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ SKILLS,
3
4
  __commonJS,
4
5
  __export,
5
6
  __toESM
6
- } from "./chunk-U67V476Y.js";
7
+ } from "./chunk-ET3HYWAC.js";
7
8
 
8
9
  // ../../node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/code.js
9
10
  var require_code = __commonJS({
@@ -31019,29 +31020,34 @@ server.tool("logout", "Log out, sign out, revoke authorization, and disconnect f
31019
31020
  content: [{ type: "text", text: "Logged out and revoked authorization." }]
31020
31021
  };
31021
31022
  });
31023
+ for (const skill of SKILLS) {
31024
+ server.prompt(skill.name, skill.description, () => ({
31025
+ messages: [{ role: "user", content: { type: "text", text: skill.content } }]
31026
+ }));
31027
+ }
31022
31028
  async function main() {
31023
31029
  if (process.argv[2] === "clean-plugin") {
31024
- const { runCleanPlugin } = await import("./setup-GXCN7XZE.js");
31030
+ const { runCleanPlugin } = await import("./setup-V6NJ4XKN.js");
31025
31031
  await runCleanPlugin();
31026
31032
  return;
31027
31033
  }
31028
31034
  if (process.argv[2] === "setup" && process.argv[3] === "codex") {
31029
- const { runSetupCodex } = await import("./setup-GXCN7XZE.js");
31035
+ const { runSetupCodex } = await import("./setup-V6NJ4XKN.js");
31030
31036
  await runSetupCodex();
31031
31037
  return;
31032
31038
  }
31033
31039
  if (process.argv[2] === "unsetup" && process.argv[3] === "codex") {
31034
- const { runUnsetupCodex } = await import("./setup-GXCN7XZE.js");
31040
+ const { runUnsetupCodex } = await import("./setup-V6NJ4XKN.js");
31035
31041
  await runUnsetupCodex();
31036
31042
  return;
31037
31043
  }
31038
31044
  if (process.argv[2] === "setup") {
31039
- const { runSetup } = await import("./setup-GXCN7XZE.js");
31045
+ const { runSetup } = await import("./setup-V6NJ4XKN.js");
31040
31046
  await runSetup();
31041
31047
  return;
31042
31048
  }
31043
31049
  if (process.argv[2] === "unsetup") {
31044
- const { runUnsetup } = await import("./setup-GXCN7XZE.js");
31050
+ const { runUnsetup } = await import("./setup-V6NJ4XKN.js");
31045
31051
  await runUnsetup();
31046
31052
  return;
31047
31053
  }
@@ -1,10 +1,68 @@
1
- import "./chunk-U67V476Y.js";
1
+ import {
2
+ SKILLS_COMBINED
3
+ } from "./chunk-ET3HYWAC.js";
2
4
 
3
5
  // src/setup.ts
4
6
  import { readFile, writeFile, mkdir, rm } from "fs/promises";
5
7
  import { join, dirname } from "path";
6
- import { homedir } from "os";
8
+ import { homedir, platform } from "os";
7
9
  import { fileURLToPath } from "url";
10
+ import { spawnSync } from "child_process";
11
+ var SKILLS_MARKER_START = "<!-- plaud-skills:start -->";
12
+ var SKILLS_MARKER_END = "<!-- plaud-skills:end -->";
13
+ var SKILLS_BLOCK = `${SKILLS_MARKER_START}
14
+ ${SKILLS_COMBINED}
15
+ ${SKILLS_MARKER_END}`;
16
+ async function removeSkillsFromClaudeCode() {
17
+ const claudeMdPath = join(homedir(), ".claude", "CLAUDE.md");
18
+ let existing = "";
19
+ try {
20
+ existing = await readFile(claudeMdPath, "utf-8");
21
+ } catch {
22
+ return;
23
+ }
24
+ if (!existing.includes(SKILLS_MARKER_START)) {
25
+ return;
26
+ }
27
+ const updated = existing.replace(new RegExp(`\\n?${SKILLS_MARKER_START}[\\s\\S]*?${SKILLS_MARKER_END}\\n?`), "").trimEnd();
28
+ await writeFile(claudeMdPath, updated ? updated + "\n" : "", "utf-8");
29
+ }
30
+ async function writeSkillsToClaudeCode() {
31
+ const claudeMdPath = join(homedir(), ".claude", "CLAUDE.md");
32
+ let existing = "";
33
+ try {
34
+ existing = await readFile(claudeMdPath, "utf-8");
35
+ } catch {
36
+ }
37
+ if (existing.includes(SKILLS_MARKER_START)) {
38
+ const updated = existing.replace(
39
+ new RegExp(`${SKILLS_MARKER_START}[\\s\\S]*?${SKILLS_MARKER_END}`),
40
+ SKILLS_BLOCK
41
+ );
42
+ await mkdir(dirname(claudeMdPath), { recursive: true });
43
+ await writeFile(claudeMdPath, updated, "utf-8");
44
+ } else {
45
+ await mkdir(dirname(claudeMdPath), { recursive: true });
46
+ await writeFile(claudeMdPath, existing + (existing.endsWith("\n") ? "" : "\n") + SKILLS_BLOCK + "\n", "utf-8");
47
+ }
48
+ }
49
+ function copyToClipboard(content) {
50
+ const cmd = platform() === "win32" ? "clip" : "pbcopy";
51
+ const result = spawnSync(cmd, [], { input: content });
52
+ return result.status === 0;
53
+ }
54
+ function printSkillsPasteGuide() {
55
+ const copied = copyToClipboard(SKILLS_COMBINED);
56
+ console.log("");
57
+ if (copied) {
58
+ console.log("Plaud Skills copied to clipboard.");
59
+ } else {
60
+ console.log("Could not copy to clipboard automatically.");
61
+ }
62
+ console.log("Paste into your client's custom instructions to enable Plaud Skills:");
63
+ console.log(" Claude Desktop: Settings \u2192 Profile \u2192 Custom Instructions");
64
+ console.log(" Codex Desktop: refer to client documentation");
65
+ }
8
66
  function getMcpEntry() {
9
67
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
68
  return {
@@ -66,6 +124,9 @@ args = ["${args[0]}"]
66
124
  await writeFile(configPath, content + entry, "utf-8");
67
125
  console.log("Plaud has been added to Codex Desktop.");
68
126
  console.log("Please restart Codex Desktop to complete the setup.");
127
+ await writeSkillsToClaudeCode();
128
+ console.log("Plaud Skills have been added to ~/.claude/CLAUDE.md for Claude Code.");
129
+ printSkillsPasteGuide();
69
130
  process.exit(0);
70
131
  }
71
132
  async function runUnsetupCodex() {
@@ -83,6 +144,7 @@ async function runUnsetupCodex() {
83
144
  }
84
145
  const cleaned = content.replace(/\n*\[mcp_servers\.plaud\]\n(?:(?!\[)[^\n]*\n)*/g, "");
85
146
  await writeFile(configPath, cleaned, "utf-8");
147
+ await removeSkillsFromClaudeCode();
86
148
  console.log("Plaud has been removed from Codex Desktop.");
87
149
  console.log("Please restart Codex Desktop to complete the unsetup.");
88
150
  process.exit(0);
@@ -109,6 +171,7 @@ async function runUnsetup() {
109
171
  const { plaud: _, ...rest } = mcpServers;
110
172
  config.mcpServers = rest;
111
173
  await writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
174
+ await removeSkillsFromClaudeCode();
112
175
  console.log("Plaud has been removed from Claude Desktop.");
113
176
  console.log("Please restart Claude Desktop to complete the unsetup.");
114
177
  process.exit(0);
@@ -136,6 +199,9 @@ async function runSetup() {
136
199
  await writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
137
200
  console.log("Plaud has been added to Claude Desktop.");
138
201
  console.log("Please restart Claude Desktop to complete the setup.");
202
+ await writeSkillsToClaudeCode();
203
+ console.log("Plaud Skills have been added to ~/.claude/CLAUDE.md for Claude Code.");
204
+ printSkillsPasteGuide();
139
205
  process.exit(0);
140
206
  }
141
207
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plaud-ai/mcp",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plaud",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "description": "Access your Plaud recordings in Claude",
5
5
  "author": {
6
6
  "name": "Plaud AI"
@@ -13,7 +13,9 @@ You have access to the user's Plaud recordings via MCP tools. Use them to help t
13
13
  | `logout` | User wants to sign out or disconnect |
14
14
  | `get_current_user` | User asks who is logged in, or to verify account |
15
15
  | `list_files` | User wants to browse, search, or find recordings |
16
- | `get_file` | User wants details, transcript, or summary of a specific recording |
16
+ | `get_file` | User wants full details of a specific recording (including download link) |
17
+ | `get_note` | User wants the AI-generated summary, action items, or key topics of a recording |
18
+ | `get_transcript` | User wants the full timestamped transcript with speaker labels |
17
19
 
18
20
  ## Typical workflows
19
21
 
@@ -21,7 +23,11 @@ You have access to the user's Plaud recordings via MCP tools. Use them to help t
21
23
 
22
24
  **Find a recording:** Call `list_files` to browse. Use pagination (`page`, `page_size`) if the user wants more results.
23
25
 
24
- **Review a recording:** Call `get_file` with the file ID. The response includes:
26
+ **Review notes or summary:** Call `get_note` with the file ID.
27
+
28
+ **Read transcript:** Call `get_transcript` with the file ID.
29
+
30
+ **Get full details (including download link):** Call `get_file` with the file ID. The response includes:
25
31
  - `source_list`: timestamped transcript with speaker labels
26
32
  - `note_list`: AI-generated summaries in Markdown
27
33
  - `presigned_url`: temporary download link (valid 24 hours)
@@ -1,35 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __commonJS = (cb, mod) => function __require() {
8
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
- };
10
- var __export = (target, all) => {
11
- for (var name in all)
12
- __defProp(target, name, { get: all[name], enumerable: true });
13
- };
14
- var __copyProps = (to, from, except, desc) => {
15
- if (from && typeof from === "object" || typeof from === "function") {
16
- for (let key of __getOwnPropNames(from))
17
- if (!__hasOwnProp.call(to, key) && key !== except)
18
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
- }
20
- return to;
21
- };
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
- // If the importer is in node compatibility mode or this is not an ESM
24
- // file that has been converted to a CommonJS file using a Babel-
25
- // compatible transform (i.e. "__esModule" has not been set), then set
26
- // "default" to the CommonJS "module.exports" for node compatibility.
27
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
- mod
29
- ));
30
-
31
- export {
32
- __commonJS,
33
- __export,
34
- __toESM
35
- };