@plaud-ai/mcp 0.2.4 → 0.3.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/dist/chunk-MCKGQKYU.js +15 -0
- package/dist/chunk-NPCCDRWQ.js +10 -0
- package/dist/chunk-QJV4OLZI.js +50 -0
- package/dist/chunk-R5G6UXSI.js +20687 -0
- package/dist/chunk-RUFCT6DQ.js +60 -0
- package/dist/{chunk-BZOIX6WC.js → chunk-XA77WLYF.js} +61 -7
- package/dist/index.js +83 -15
- package/dist/{install-ALLWR7CL.js → install-42GM4XUO.js} +4 -2
- package/dist/server-BOR5EZLF.js +35 -0
- package/dist/{server-VY7ANVCH.js → server-KBYYESVJ.js} +32 -4
- package/dist/{setup-QXZHVVDP.js → setup-GLWZYNRW.js} +1 -0
- package/package.json +3 -1
- package/plugin.json +1 -1
- package/dist/chunk-3XRFIJUG.js +0 -352
- package/dist/chunk-GZ7QPRKV.js +0 -33
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// src/metrics/registry.ts
|
|
2
|
+
import { Registry, Counter, Histogram, Gauge, collectDefaultMetrics } from "prom-client";
|
|
3
|
+
var registry = new Registry();
|
|
4
|
+
collectDefaultMetrics({ register: registry });
|
|
5
|
+
var httpRequestDuration = new Histogram({
|
|
6
|
+
name: "http_request_duration_seconds",
|
|
7
|
+
help: "HTTP request latency in seconds",
|
|
8
|
+
labelNames: ["method", "handler", "status"],
|
|
9
|
+
buckets: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
|
|
10
|
+
registers: [registry]
|
|
11
|
+
});
|
|
12
|
+
var httpRequestsInProgress = new Gauge({
|
|
13
|
+
name: "http_requests_in_progress",
|
|
14
|
+
help: "Number of in-progress HTTP requests",
|
|
15
|
+
labelNames: ["method", "handler"],
|
|
16
|
+
registers: [registry]
|
|
17
|
+
});
|
|
18
|
+
var mcpToolCalls = new Counter({
|
|
19
|
+
name: "mcp_tool_calls_total",
|
|
20
|
+
help: "MCP tool invocation count",
|
|
21
|
+
labelNames: ["tool", "status"],
|
|
22
|
+
registers: [registry]
|
|
23
|
+
});
|
|
24
|
+
var mcpToolDuration = new Histogram({
|
|
25
|
+
name: "mcp_tool_duration_seconds",
|
|
26
|
+
help: "MCP tool execution latency in seconds",
|
|
27
|
+
labelNames: ["tool"],
|
|
28
|
+
buckets: [0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30],
|
|
29
|
+
registers: [registry]
|
|
30
|
+
});
|
|
31
|
+
var oauthTokenRefresh = new Counter({
|
|
32
|
+
name: "oauth_token_refresh_total",
|
|
33
|
+
help: "OAuth token refresh attempts grouped by outcome",
|
|
34
|
+
labelNames: ["result"],
|
|
35
|
+
registers: [registry]
|
|
36
|
+
});
|
|
37
|
+
var httpClientRequests = new Counter({
|
|
38
|
+
name: "http_client_requests_total",
|
|
39
|
+
help: "Outbound HTTP requests to upstream services",
|
|
40
|
+
labelNames: ["host", "endpoint", "status"],
|
|
41
|
+
registers: [registry]
|
|
42
|
+
});
|
|
43
|
+
var httpClientDuration = new Histogram({
|
|
44
|
+
name: "http_client_duration_seconds",
|
|
45
|
+
help: "Outbound HTTP request latency in seconds",
|
|
46
|
+
labelNames: ["host", "endpoint"],
|
|
47
|
+
buckets: [0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
|
|
48
|
+
registers: [registry]
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
registry,
|
|
53
|
+
httpRequestDuration,
|
|
54
|
+
httpRequestsInProgress,
|
|
55
|
+
mcpToolCalls,
|
|
56
|
+
mcpToolDuration,
|
|
57
|
+
oauthTokenRefresh,
|
|
58
|
+
httpClientRequests,
|
|
59
|
+
httpClientDuration
|
|
60
|
+
};
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import {
|
|
2
|
+
capture,
|
|
3
|
+
classifyError
|
|
4
|
+
} from "./chunk-R5G6UXSI.js";
|
|
5
|
+
import {
|
|
6
|
+
logger
|
|
7
|
+
} from "./chunk-NPCCDRWQ.js";
|
|
8
|
+
import {
|
|
9
|
+
mcpToolCalls,
|
|
10
|
+
mcpToolDuration
|
|
11
|
+
} from "./chunk-RUFCT6DQ.js";
|
|
7
12
|
|
|
8
13
|
// src/tools/index.ts
|
|
9
14
|
import { z } from "zod";
|
|
15
|
+
import { randomUUID } from "crypto";
|
|
10
16
|
var MAX_FILTER_PAGES = 5;
|
|
11
17
|
var FILTER_PAGE_SIZE = 100;
|
|
12
18
|
function parseDate(s) {
|
|
@@ -15,6 +21,38 @@ function parseDate(s) {
|
|
|
15
21
|
if (Number.isNaN(d.getTime())) return null;
|
|
16
22
|
return d.getTime();
|
|
17
23
|
}
|
|
24
|
+
function normalizeMcpHost(name) {
|
|
25
|
+
if (!name) return void 0;
|
|
26
|
+
const n = name.trim().toLowerCase();
|
|
27
|
+
if (!n) return void 0;
|
|
28
|
+
if (n === "claude-ai" || n.includes("claude desktop") || n.includes("claude-desktop")) return "claude_desktop";
|
|
29
|
+
if (n.includes("claude code") || n.includes("claude-code")) return "claude_code";
|
|
30
|
+
if (n.includes("cursor")) return "cursor";
|
|
31
|
+
if (n.includes("windsurf")) return "windsurf";
|
|
32
|
+
if (n.includes("cline")) return "cline";
|
|
33
|
+
if (n.includes("continue")) return "continue";
|
|
34
|
+
if (n.includes("vscode") || n.includes("vs code")) return "vscode";
|
|
35
|
+
return n;
|
|
36
|
+
}
|
|
37
|
+
function emitToolClick(tool, props = {}) {
|
|
38
|
+
const requestId = randomUUID();
|
|
39
|
+
capture("mcp:tool:click", { tool_name: tool, request_id: requestId, passive: false, ...props });
|
|
40
|
+
return requestId;
|
|
41
|
+
}
|
|
42
|
+
function recordToolMetric(tool, status, durationMs, requestId, props = {}, err) {
|
|
43
|
+
mcpToolCalls.inc({ tool, status });
|
|
44
|
+
mcpToolDuration.observe({ tool }, durationMs / 1e3);
|
|
45
|
+
const event = status === "success" ? "mcp:tool:success" : "mcp:tool:error";
|
|
46
|
+
const evProps = {
|
|
47
|
+
tool_name: tool,
|
|
48
|
+
request_id: requestId,
|
|
49
|
+
passive: true,
|
|
50
|
+
...props
|
|
51
|
+
};
|
|
52
|
+
if (status === "success") evProps.duration_ms = durationMs;
|
|
53
|
+
else evProps.error_type = classifyError(err);
|
|
54
|
+
capture(event, evProps);
|
|
55
|
+
}
|
|
18
56
|
function registerTools(server, client) {
|
|
19
57
|
server.registerTool(
|
|
20
58
|
"list_files",
|
|
@@ -38,9 +76,11 @@ function registerTools(server, client) {
|
|
|
38
76
|
const start = Date.now();
|
|
39
77
|
const hasFilter = Boolean(query || date_from || date_to);
|
|
40
78
|
logger.info({ event: "tool_call", tool: "list_files", has_filter: hasFilter });
|
|
79
|
+
const requestId = emitToolClick("list_files");
|
|
41
80
|
try {
|
|
42
81
|
if (!hasFilter) {
|
|
43
82
|
const result = await client.listFiles(page, page_size);
|
|
83
|
+
recordToolMetric("list_files", "success", Date.now() - start, requestId);
|
|
44
84
|
logger.info({ event: "tool_call_end", tool: "list_files", duration_ms: Date.now() - start });
|
|
45
85
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
46
86
|
}
|
|
@@ -68,6 +108,7 @@ function registerTools(server, client) {
|
|
|
68
108
|
if (items.length < FILTER_PAGE_SIZE) break;
|
|
69
109
|
if (p === MAX_FILTER_PAGES) truncated = true;
|
|
70
110
|
}
|
|
111
|
+
recordToolMetric("list_files", "success", Date.now() - start, requestId);
|
|
71
112
|
logger.info({ event: "tool_call_end", tool: "list_files", duration_ms: Date.now() - start, scanned, matched: matches.length, truncated });
|
|
72
113
|
return {
|
|
73
114
|
content: [{ type: "text", text: JSON.stringify({
|
|
@@ -79,6 +120,7 @@ function registerTools(server, client) {
|
|
|
79
120
|
}, null, 2) }]
|
|
80
121
|
};
|
|
81
122
|
} catch (err) {
|
|
123
|
+
recordToolMetric("list_files", "error", Date.now() - start, requestId, {}, err);
|
|
82
124
|
logger.error({ event: "tool_call_error", tool: "list_files", duration_ms: Date.now() - start, error: String(err) });
|
|
83
125
|
return { content: [{ type: "text", text: `Failed to list files: ${err}` }], isError: true };
|
|
84
126
|
}
|
|
@@ -99,11 +141,14 @@ function registerTools(server, client) {
|
|
|
99
141
|
async ({ file_id }) => {
|
|
100
142
|
const start = Date.now();
|
|
101
143
|
logger.info({ event: "tool_call", tool: "get_file", file_id });
|
|
144
|
+
const requestId = emitToolClick("get_file", { file_id });
|
|
102
145
|
try {
|
|
103
146
|
const file = await client.getFile(file_id);
|
|
147
|
+
recordToolMetric("get_file", "success", Date.now() - start, requestId, { file_id });
|
|
104
148
|
logger.info({ event: "tool_call_end", tool: "get_file", duration_ms: Date.now() - start });
|
|
105
149
|
return { content: [{ type: "text", text: JSON.stringify(file, null, 2) }] };
|
|
106
150
|
} catch (err) {
|
|
151
|
+
recordToolMetric("get_file", "error", Date.now() - start, requestId, { file_id }, err);
|
|
107
152
|
logger.error({ event: "tool_call_error", tool: "get_file", duration_ms: Date.now() - start, error: String(err) });
|
|
108
153
|
return { content: [{ type: "text", text: `Failed to get file: ${err}` }], isError: true };
|
|
109
154
|
}
|
|
@@ -124,11 +169,14 @@ function registerTools(server, client) {
|
|
|
124
169
|
async ({ file_id }) => {
|
|
125
170
|
const start = Date.now();
|
|
126
171
|
logger.info({ event: "tool_call", tool: "get_note", file_id });
|
|
172
|
+
const requestId = emitToolClick("get_note", { file_id });
|
|
127
173
|
try {
|
|
128
174
|
const file = await client.getFile(file_id);
|
|
175
|
+
recordToolMetric("get_note", "success", Date.now() - start, requestId, { file_id });
|
|
129
176
|
logger.info({ event: "tool_call_end", tool: "get_note", duration_ms: Date.now() - start });
|
|
130
177
|
return { content: [{ type: "text", text: JSON.stringify(file.note_list ?? [], null, 2) }] };
|
|
131
178
|
} catch (err) {
|
|
179
|
+
recordToolMetric("get_note", "error", Date.now() - start, requestId, { file_id }, err);
|
|
132
180
|
logger.error({ event: "tool_call_error", tool: "get_note", duration_ms: Date.now() - start, error: String(err) });
|
|
133
181
|
return { content: [{ type: "text", text: `Failed to get note: ${err}` }], isError: true };
|
|
134
182
|
}
|
|
@@ -149,11 +197,14 @@ function registerTools(server, client) {
|
|
|
149
197
|
async ({ file_id }) => {
|
|
150
198
|
const start = Date.now();
|
|
151
199
|
logger.info({ event: "tool_call", tool: "get_transcript", file_id });
|
|
200
|
+
const requestId = emitToolClick("get_transcript", { file_id });
|
|
152
201
|
try {
|
|
153
202
|
const file = await client.getFile(file_id);
|
|
203
|
+
recordToolMetric("get_transcript", "success", Date.now() - start, requestId, { file_id });
|
|
154
204
|
logger.info({ event: "tool_call_end", tool: "get_transcript", duration_ms: Date.now() - start });
|
|
155
205
|
return { content: [{ type: "text", text: JSON.stringify(file.source_list ?? [], null, 2) }] };
|
|
156
206
|
} catch (err) {
|
|
207
|
+
recordToolMetric("get_transcript", "error", Date.now() - start, requestId, { file_id }, err);
|
|
157
208
|
logger.error({ event: "tool_call_error", tool: "get_transcript", duration_ms: Date.now() - start, error: String(err) });
|
|
158
209
|
return { content: [{ type: "text", text: `Failed to get transcript: ${err}` }], isError: true };
|
|
159
210
|
}
|
|
@@ -173,11 +224,14 @@ function registerTools(server, client) {
|
|
|
173
224
|
async () => {
|
|
174
225
|
const start = Date.now();
|
|
175
226
|
logger.info({ event: "tool_call", tool: "get_current_user" });
|
|
227
|
+
const requestId = emitToolClick("get_current_user");
|
|
176
228
|
try {
|
|
177
229
|
const user = await client.getCurrentUser();
|
|
230
|
+
recordToolMetric("get_current_user", "success", Date.now() - start, requestId);
|
|
178
231
|
logger.info({ event: "tool_call_end", tool: "get_current_user", duration_ms: Date.now() - start });
|
|
179
232
|
return { content: [{ type: "text", text: JSON.stringify(user, null, 2) }] };
|
|
180
233
|
} catch (err) {
|
|
234
|
+
recordToolMetric("get_current_user", "error", Date.now() - start, requestId, {}, err);
|
|
181
235
|
logger.error({ event: "tool_call_error", tool: "get_current_user", duration_ms: Date.now() - start, error: String(err) });
|
|
182
236
|
return { content: [{ type: "text", text: `Failed to get user info: ${err}` }], isError: true };
|
|
183
237
|
}
|
|
@@ -186,6 +240,6 @@ function registerTools(server, client) {
|
|
|
186
240
|
}
|
|
187
241
|
|
|
188
242
|
export {
|
|
189
|
-
|
|
243
|
+
normalizeMcpHost,
|
|
190
244
|
registerTools
|
|
191
245
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
getClient
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QJV4OLZI.js";
|
|
5
5
|
import {
|
|
6
6
|
loadSkills
|
|
7
7
|
} from "./chunk-4QBEOJPX.js";
|
|
8
8
|
import {
|
|
9
|
+
normalizeMcpHost,
|
|
9
10
|
registerTools
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-XA77WLYF.js";
|
|
11
12
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
capture,
|
|
14
|
+
classifyError,
|
|
15
|
+
clearUser,
|
|
16
|
+
extractIdentity,
|
|
17
|
+
initTelemetry,
|
|
18
|
+
oauthCallbackErrorType,
|
|
19
|
+
runOAuthCallback,
|
|
20
|
+
setMcpHost,
|
|
21
|
+
setUser,
|
|
22
|
+
shutdown
|
|
23
|
+
} from "./chunk-R5G6UXSI.js";
|
|
24
|
+
import "./chunk-NPCCDRWQ.js";
|
|
25
|
+
import "./chunk-RUFCT6DQ.js";
|
|
26
|
+
import "./chunk-MCKGQKYU.js";
|
|
14
27
|
|
|
15
28
|
// src/index.ts
|
|
16
29
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -18,7 +31,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
18
31
|
import open from "open";
|
|
19
32
|
var server = new McpServer({
|
|
20
33
|
name: "plaud",
|
|
21
|
-
version: "0.
|
|
34
|
+
version: "0.3.1"
|
|
22
35
|
});
|
|
23
36
|
var CALLBACK_PORT = 8199;
|
|
24
37
|
var LOGIN_TIMEOUT_MS = 12e4;
|
|
@@ -56,8 +69,23 @@ server.registerTool("login", {
|
|
|
56
69
|
});
|
|
57
70
|
}
|
|
58
71
|
});
|
|
72
|
+
if (result.status === "success") {
|
|
73
|
+
capture("auth:oauth_callback:success", { passive: true });
|
|
74
|
+
} else {
|
|
75
|
+
capture("auth:oauth_callback:error", {
|
|
76
|
+
passive: true,
|
|
77
|
+
error_type: oauthCallbackErrorType(result.status)
|
|
78
|
+
});
|
|
79
|
+
}
|
|
59
80
|
switch (result.status) {
|
|
60
81
|
case "success":
|
|
82
|
+
try {
|
|
83
|
+
const user = await client.getCurrentUser();
|
|
84
|
+
if (user && typeof user.id === "string") {
|
|
85
|
+
await setUser(user.id, extractIdentity(user));
|
|
86
|
+
}
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
61
89
|
return { content: [{ type: "text", text: "Successfully authenticated with Plaud!" }] };
|
|
62
90
|
case "timeout":
|
|
63
91
|
return {
|
|
@@ -97,10 +125,19 @@ server.registerTool("logout", {
|
|
|
97
125
|
return { content: [{ type: "text", text: "Already logged out." }] };
|
|
98
126
|
}
|
|
99
127
|
try {
|
|
100
|
-
|
|
128
|
+
try {
|
|
129
|
+
await client.revokeCurrentUser();
|
|
130
|
+
} catch {
|
|
131
|
+
}
|
|
132
|
+
await client.auth.logout();
|
|
133
|
+
capture("auth:logout:success", { passive: true });
|
|
134
|
+
} catch (err) {
|
|
135
|
+
capture("auth:logout:error", { passive: true, error_type: classifyError(err) });
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
await clearUser();
|
|
101
139
|
} catch {
|
|
102
140
|
}
|
|
103
|
-
await client.auth.logout();
|
|
104
141
|
return {
|
|
105
142
|
content: [{ type: "text", text: "Logged out and revoked authorization." }]
|
|
106
143
|
};
|
|
@@ -117,7 +154,7 @@ async function main() {
|
|
|
117
154
|
const sub = process.argv[2];
|
|
118
155
|
const sub2 = process.argv[3];
|
|
119
156
|
if (sub === "install") {
|
|
120
|
-
const { runInstall } = await import("./install-
|
|
157
|
+
const { runInstall } = await import("./install-42GM4XUO.js");
|
|
121
158
|
const args = process.argv.slice(3);
|
|
122
159
|
const yes = args.some((a) => a === "--yes" || a === "-y");
|
|
123
160
|
const noLogin = args.some((a) => a === "--no-login");
|
|
@@ -125,32 +162,34 @@ async function main() {
|
|
|
125
162
|
return;
|
|
126
163
|
}
|
|
127
164
|
if (sub === "clean-plugin") {
|
|
128
|
-
const { runCleanPlugin } = await import("./setup-
|
|
165
|
+
const { runCleanPlugin } = await import("./setup-GLWZYNRW.js");
|
|
129
166
|
await runCleanPlugin();
|
|
130
167
|
return;
|
|
131
168
|
}
|
|
132
169
|
if (sub === "setup" && sub2 === "codex") {
|
|
133
|
-
const { runSetupCodex } = await import("./setup-
|
|
170
|
+
const { runSetupCodex } = await import("./setup-GLWZYNRW.js");
|
|
134
171
|
await runSetupCodex();
|
|
135
172
|
return;
|
|
136
173
|
}
|
|
137
174
|
if (sub === "unsetup" && sub2 === "codex") {
|
|
138
|
-
const { runUnsetupCodex } = await import("./setup-
|
|
175
|
+
const { runUnsetupCodex } = await import("./setup-GLWZYNRW.js");
|
|
139
176
|
await runUnsetupCodex();
|
|
140
177
|
return;
|
|
141
178
|
}
|
|
142
179
|
if (sub === "setup") {
|
|
143
|
-
const { runSetup } = await import("./setup-
|
|
180
|
+
const { runSetup } = await import("./setup-GLWZYNRW.js");
|
|
144
181
|
await runSetup();
|
|
145
182
|
return;
|
|
146
183
|
}
|
|
147
184
|
if (sub === "unsetup") {
|
|
148
|
-
const { runUnsetup } = await import("./setup-
|
|
185
|
+
const { runUnsetup } = await import("./setup-GLWZYNRW.js");
|
|
149
186
|
await runUnsetup();
|
|
150
187
|
return;
|
|
151
188
|
}
|
|
152
189
|
if (sub === "http") {
|
|
153
|
-
const { startHttpServer } = await import("./server-
|
|
190
|
+
const { startHttpServer } = await import("./server-KBYYESVJ.js");
|
|
191
|
+
const { startMetricsServer } = await import("./server-BOR5EZLF.js");
|
|
192
|
+
startMetricsServer();
|
|
154
193
|
startHttpServer();
|
|
155
194
|
return;
|
|
156
195
|
}
|
|
@@ -171,8 +210,37 @@ Usage:
|
|
|
171
210
|
`);
|
|
172
211
|
return;
|
|
173
212
|
}
|
|
213
|
+
try {
|
|
214
|
+
await initTelemetry({
|
|
215
|
+
surface: "mcp",
|
|
216
|
+
appVersion: "0.3.1",
|
|
217
|
+
transport: "stdio"
|
|
218
|
+
});
|
|
219
|
+
} catch {
|
|
220
|
+
}
|
|
221
|
+
const exitWithFlush = async (code) => {
|
|
222
|
+
try {
|
|
223
|
+
await shutdown();
|
|
224
|
+
} catch {
|
|
225
|
+
}
|
|
226
|
+
process.exit(code);
|
|
227
|
+
};
|
|
228
|
+
process.on("SIGINT", () => void exitWithFlush(130));
|
|
229
|
+
process.on("SIGTERM", () => void exitWithFlush(143));
|
|
174
230
|
await registerSkillPrompts();
|
|
231
|
+
server.server.oninitialized = () => {
|
|
232
|
+
try {
|
|
233
|
+
setMcpHost(normalizeMcpHost(server.server.getClientVersion()?.name));
|
|
234
|
+
} catch {
|
|
235
|
+
}
|
|
236
|
+
};
|
|
175
237
|
const transport = new StdioServerTransport();
|
|
176
|
-
|
|
238
|
+
try {
|
|
239
|
+
await server.connect(transport);
|
|
240
|
+
capture("mcp:server:success", { passive: true });
|
|
241
|
+
} catch (err) {
|
|
242
|
+
capture("mcp:server:error", { passive: true, error_type: classifyError(err) });
|
|
243
|
+
await exitWithFlush(1);
|
|
244
|
+
}
|
|
177
245
|
}
|
|
178
246
|
main().catch(console.error);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getClient
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QJV4OLZI.js";
|
|
4
4
|
import {
|
|
5
5
|
copyToClipboard,
|
|
6
6
|
getMcpEntry,
|
|
@@ -11,7 +11,9 @@ import {
|
|
|
11
11
|
} from "./chunk-4QBEOJPX.js";
|
|
12
12
|
import {
|
|
13
13
|
runOAuthCallback
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-R5G6UXSI.js";
|
|
15
|
+
import "./chunk-RUFCT6DQ.js";
|
|
16
|
+
import "./chunk-MCKGQKYU.js";
|
|
15
17
|
|
|
16
18
|
// src/install.ts
|
|
17
19
|
import { createInterface } from "readline/promises";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
logger
|
|
3
|
+
} from "./chunk-NPCCDRWQ.js";
|
|
4
|
+
import {
|
|
5
|
+
registry
|
|
6
|
+
} from "./chunk-RUFCT6DQ.js";
|
|
7
|
+
import "./chunk-MCKGQKYU.js";
|
|
8
|
+
|
|
9
|
+
// src/metrics/server.ts
|
|
10
|
+
import express from "express";
|
|
11
|
+
var METRICS_PORT = Number(process.env.PLAUD_METRICS_PORT ?? 9080);
|
|
12
|
+
var METRICS_HOST = process.env.PLAUD_METRICS_HOST ?? "0.0.0.0";
|
|
13
|
+
function startMetricsServer() {
|
|
14
|
+
const app = express();
|
|
15
|
+
app.get("/metrics", async (_req, res, next) => {
|
|
16
|
+
try {
|
|
17
|
+
res.setHeader("Content-Type", registry.contentType);
|
|
18
|
+
res.end(await registry.metrics());
|
|
19
|
+
} catch (err) {
|
|
20
|
+
next(err);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
app.get("/healthz", (_req, res) => {
|
|
24
|
+
res.status(200).send("ok");
|
|
25
|
+
});
|
|
26
|
+
const server = app.listen(METRICS_PORT, METRICS_HOST, () => {
|
|
27
|
+
logger.info({ event: "metrics_server_started", port: METRICS_PORT, host: METRICS_HOST });
|
|
28
|
+
});
|
|
29
|
+
server.on("error", (err) => {
|
|
30
|
+
logger.error({ event: "metrics_server_error", err: err.message });
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
startMetricsServer
|
|
35
|
+
};
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
-
logger,
|
|
3
2
|
registerTools
|
|
4
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XA77WLYF.js";
|
|
5
4
|
import {
|
|
6
5
|
PlaudClient
|
|
7
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-R5G6UXSI.js";
|
|
7
|
+
import {
|
|
8
|
+
logger
|
|
9
|
+
} from "./chunk-NPCCDRWQ.js";
|
|
10
|
+
import {
|
|
11
|
+
httpRequestDuration,
|
|
12
|
+
httpRequestsInProgress,
|
|
13
|
+
oauthTokenRefresh
|
|
14
|
+
} from "./chunk-RUFCT6DQ.js";
|
|
15
|
+
import "./chunk-MCKGQKYU.js";
|
|
8
16
|
|
|
9
17
|
// src/http/server.ts
|
|
10
18
|
import express from "express";
|
|
@@ -680,17 +688,21 @@ var PlaudOAuthProvider = class extends ProxyOAuthServerProvider {
|
|
|
680
688
|
}
|
|
681
689
|
logger.error({ event: "oauth_token_refresh_failed", status: fetchRes.status, body: text.slice(0, 500) });
|
|
682
690
|
if (fetchRes.status >= 500) {
|
|
691
|
+
oauthTokenRefresh.inc({ result: "upstream_error" });
|
|
683
692
|
throw new McpServerError(`Upstream refresh endpoint error: ${fetchRes.status} ${text.slice(0, 200)}`);
|
|
684
693
|
}
|
|
694
|
+
oauthTokenRefresh.inc({ result: "invalid_grant" });
|
|
685
695
|
throw new InvalidGrantError(`Plaud token refresh: ${fetchRes.status} ${text.slice(0, 200)}`);
|
|
686
696
|
}
|
|
687
697
|
let data;
|
|
688
698
|
try {
|
|
689
699
|
data = await fetchRes.json();
|
|
690
700
|
} catch (err) {
|
|
701
|
+
oauthTokenRefresh.inc({ result: "parse_failed" });
|
|
691
702
|
logger.error({ event: "oauth_refresh_json_parse_failed", error: String(err) });
|
|
692
703
|
throw new McpServerError("Refresh endpoint returned non-JSON response");
|
|
693
704
|
}
|
|
705
|
+
oauthTokenRefresh.inc({ result: "success" });
|
|
694
706
|
logger.info({
|
|
695
707
|
event: "oauth_token_refresh_ok",
|
|
696
708
|
has_refresh_token: !!data.refresh_token,
|
|
@@ -805,6 +817,22 @@ function startHttpServer() {
|
|
|
805
817
|
};
|
|
806
818
|
const app = createMcpExpressApp({ host: HTTP_HOST });
|
|
807
819
|
app.set("trust proxy", 1);
|
|
820
|
+
app.use((req, res, next) => {
|
|
821
|
+
const start = process.hrtime.bigint();
|
|
822
|
+
const method = req.method;
|
|
823
|
+
const inProgressLabels = { method, handler: req.path };
|
|
824
|
+
httpRequestsInProgress.inc(inProgressLabels);
|
|
825
|
+
res.on("finish", () => {
|
|
826
|
+
const handler = req.route?.path ?? req.path;
|
|
827
|
+
const durSec = Number(process.hrtime.bigint() - start) / 1e9;
|
|
828
|
+
httpRequestDuration.observe(
|
|
829
|
+
{ method, handler, status: String(res.statusCode) },
|
|
830
|
+
durSec
|
|
831
|
+
);
|
|
832
|
+
httpRequestsInProgress.dec(inProgressLabels);
|
|
833
|
+
});
|
|
834
|
+
next();
|
|
835
|
+
});
|
|
808
836
|
app.get("/.well-known/openai-apps-challenge", (_req, res) => {
|
|
809
837
|
res.type("text/plain").send(OPENAI_APPS_CHALLENGE_TOKEN);
|
|
810
838
|
});
|
|
@@ -982,7 +1010,7 @@ function startHttpServer() {
|
|
|
982
1010
|
apiBase,
|
|
983
1011
|
staticToken: token
|
|
984
1012
|
});
|
|
985
|
-
const mcpServer = new McpServer({ name: "plaud", version: "0.
|
|
1013
|
+
const mcpServer = new McpServer({ name: "plaud", version: "0.3.1" });
|
|
986
1014
|
registerTools(mcpServer, client);
|
|
987
1015
|
const transport = new StreamableHTTPServerTransport({
|
|
988
1016
|
sessionIdGenerator: void 0,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plaud-ai/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -25,10 +25,12 @@
|
|
|
25
25
|
"express": "^5.2.1",
|
|
26
26
|
"open": "^10.2.0",
|
|
27
27
|
"pino": "^10.3.1",
|
|
28
|
+
"prom-client": "^15.1.3",
|
|
28
29
|
"zod": "^4.3.6"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"@plaud-ai/shared": "workspace:*",
|
|
33
|
+
"@plaud-ai/telemetry": "workspace:*",
|
|
32
34
|
"@types/express": "^5.0.6",
|
|
33
35
|
"@types/node": "^25.5.0",
|
|
34
36
|
"typescript": "^5.7.0"
|