-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathobservability.ts
More file actions
91 lines (79 loc) · 2.64 KB
/
Copy pathobservability.ts
File metadata and controls
91 lines (79 loc) · 2.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import { PostHogMCP } from "@posthog/mcp";
import type { McpMiddlewareNext, ToolsCallMiddlewareContext } from "mcp-use";
const SERVER_NAME = "remotion-mcp";
function createPostHogClient(): PostHogMCP | null {
const token = process.env.POSTHOG_PROJECT_TOKEN?.trim();
if (!token) {
if (process.env.NODE_ENV !== "production") {
console.error(
"POSTHOG_PROJECT_TOKEN variable required by PostHog is missing or un-configured, " +
"this causes events to be silently missed. " +
"This error stops appearing once POSTHOG_PROJECT_TOKEN is configured"
);
}
return null;
}
return new PostHogMCP(token, {
host: process.env.POSTHOG_HOST?.trim() || "https://eu.i.posthog.com",
enableExceptionAutocapture: true,
flushAt: 20,
flushInterval: 5000,
});
}
export const posthog = createPostHogClient();
function getDistinctId(ctx: ToolsCallMiddlewareContext): string {
const sessionId = ctx.session?.sessionId;
return sessionId ? `mcp-session:${sessionId}` : `${SERVER_NAME}:anonymous`;
}
function isErrorResult(result: unknown): boolean {
if (!result || typeof result !== "object") return false;
const r = result as Record<string, unknown>;
if (r.isError === true) return true;
const content = r.content;
if (!Array.isArray(content)) return false;
return content.some(
(item) =>
typeof item === "object" &&
item !== null &&
(item as Record<string, unknown>).type === "text" &&
typeof (item as Record<string, unknown>).text === "string" &&
((item as Record<string, unknown>).text as string).startsWith("Project error:")
);
}
export async function observeMcpToolCall(
ctx: ToolsCallMiddlewareContext,
next: McpMiddlewareNext<"tools/call">
) {
if (!posthog) return next();
const startedAt = performance.now();
const distinctId = getDistinctId(ctx);
const sessionId = ctx.session?.sessionId;
const toolName = (ctx.params.name as string) ?? "unknown";
const parameters = ctx.params.arguments as Record<string, unknown> | undefined;
try {
const result = await next();
const durationMs = Math.round(performance.now() - startedAt);
posthog.captureToolCall({
toolName,
parameters,
response: result,
durationMs,
isError: isErrorResult(result),
distinctId,
sessionId,
});
return result;
} catch (error) {
const durationMs = Math.round(performance.now() - startedAt);
posthog.captureToolCall({
toolName,
parameters,
durationMs,
isError: true,
distinctId,
sessionId,
error: error instanceof Error ? error : new Error(String(error)),
});
throw error;
}
}