@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.
- package/dist/chunk-ET3HYWAC.js +134 -0
- package/dist/index.js +12 -6
- package/dist/{setup-GXCN7XZE.js → setup-V6NJ4XKN.js} +68 -2
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/skills/plaud/SKILL.md +8 -2
- package/dist/chunk-U67V476Y.js +0 -35
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
31050
|
+
const { runUnsetup } = await import("./setup-V6NJ4XKN.js");
|
|
31045
31051
|
await runUnsetup();
|
|
31046
31052
|
return;
|
|
31047
31053
|
}
|
|
@@ -1,10 +1,68 @@
|
|
|
1
|
-
import
|
|
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
package/plugin.json
CHANGED
package/skills/plaud/SKILL.md
CHANGED
|
@@ -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
|
|
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
|
|
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)
|
package/dist/chunk-U67V476Y.js
DELETED
|
@@ -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
|
-
};
|