@posthog/mcp 0.13.0 → 0.14.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.
Files changed (39) hide show
  1. package/README.md +25 -10
  2. package/dist/extensions/constants.d.ts +1 -1
  3. package/dist/extensions/constants.d.ts.map +1 -1
  4. package/dist/extensions/constants.js +1 -1
  5. package/dist/extensions/constants.mjs +1 -1
  6. package/dist/extensions/instrumentation.d.ts.map +1 -1
  7. package/dist/extensions/instrumentation.js +4 -1
  8. package/dist/extensions/instrumentation.mjs +5 -2
  9. package/dist/extensions/mcp-payloads.d.ts +10 -0
  10. package/dist/extensions/mcp-payloads.d.ts.map +1 -1
  11. package/dist/extensions/mcp-payloads.js +64 -0
  12. package/dist/extensions/mcp-payloads.mjs +62 -1
  13. package/dist/extensions/model-parameters.d.ts +20 -13
  14. package/dist/extensions/model-parameters.d.ts.map +1 -1
  15. package/dist/extensions/model-parameters.js +26 -2
  16. package/dist/extensions/model-parameters.mjs +24 -3
  17. package/dist/extensions/posthog-mcp.d.ts +3 -3
  18. package/dist/extensions/posthog-mcp.d.ts.map +1 -1
  19. package/dist/extensions/posthog-mcp.js +8 -9
  20. package/dist/extensions/posthog-mcp.mjs +9 -10
  21. package/dist/extensions/sanitization.d.ts.map +1 -1
  22. package/dist/extensions/sanitization.js +1 -1
  23. package/dist/extensions/sanitization.mjs +2 -2
  24. package/dist/types.d.ts +20 -20
  25. package/dist/types.d.ts.map +1 -1
  26. package/dist/version.d.ts +1 -1
  27. package/dist/version.js +1 -1
  28. package/dist/version.mjs +1 -1
  29. package/package.json +3 -3
  30. package/src/extensions/capture.ts +2 -2
  31. package/src/extensions/constants.ts +1 -1
  32. package/src/extensions/instrumentation.ts +6 -7
  33. package/src/extensions/mcp-payloads.ts +129 -0
  34. package/src/extensions/model-parameters.ts +50 -14
  35. package/src/extensions/posthog-events.ts +2 -2
  36. package/src/extensions/posthog-mcp.ts +11 -15
  37. package/src/extensions/sanitization.ts +8 -5
  38. package/src/types.ts +20 -20
  39. package/src/version.ts +1 -1
package/README.md CHANGED
@@ -150,19 +150,29 @@ instrument(server, posthog, {
150
150
 
151
151
  `intentFallback` is the third option: supply the intent yourself when the agent did not send one.
152
152
 
153
+ Whatever the agent narrates, the SDK redacts structured personal identifiers — email addresses, phone
154
+ numbers, IPv4/IPv6 addresses, Luhn-valid card numbers, and US SSNs — from `$mcp_intent` before it is
155
+ sent. This is always on and needs no configuration. It is best-effort for those well-defined shapes,
156
+ not for free-form personal data such as names or postal addresses, which a regex cannot catch without
157
+ over-redacting ordinary prose. It also applies only to `$mcp_intent`: structured tool `arguments` and
158
+ results are left as-is, because the same shapes are often legitimate data there. If you need a stronger
159
+ guarantee, `context: false` and the `beforeSend` hook above remain the ways to drop the field entirely.
160
+
153
161
  ### What `$mcp_llm_model` records, and when it stays empty
154
162
 
155
- `captureModel` is **off** by default. Turn it on and the SDK adds a required `llm_model` parameter to
156
- every tool it advertises — including the `get_more_tools` virtual tool — asks the agent which model
157
- it runs as, and records the answer as `$mcp_llm_model` with `$mcp_llm_model_source = "self_reported"`.
163
+ `captureModel` is **off** by default. Turn it on and the SDK records the best model id visible to the
164
+ server as `$mcp_llm_model`. Recognized client metadata wins with source `client_metadata`. Otherwise,
165
+ the SDK injects a required `llm_model` parameter and records the answer with source `self_reported`.
166
+
167
+ MCP does not standardize or attest model identity. Client metadata and self-report are both
168
+ unverified. Use the value to spot degradation across models, never for billing or access control.
169
+ Missing, blank, and `unknown` values are recorded as nothing.
158
170
 
159
- The value is self-reported and unverified, exactly like `clientInfo` in the MCP spec. Use it to spot
160
- degradation across models ("does our MCP get worse on model X?"), never for billing or access
161
- control. An agent that answers `unknown` is recorded as nothing rather than as a model called
162
- "unknown".
171
+ The recognized metadata path is Codex's `x-codex-turn-metadata.model` field inside request `_meta`.
172
+ Other clients keep using self-report until they expose a stable model field.
163
173
 
164
- Unlike `context`, this option degrades to **silence** rather than to a kept argument. Both the strip
165
- and the capture require the SDK to have confirmed the parameter is its own:
174
+ Unlike `context`, the self-report fallback degrades to **silence** rather than to a kept argument.
175
+ Its capture and stripping require the SDK to have confirmed the parameter is its own:
166
176
 
167
177
  - `instrument(server)` on a high-level `McpServer` resolves ownership for your registered tools per
168
178
  request from the live tool registry, so those work even on a fresh instance.
@@ -190,13 +200,18 @@ const posthog = new PostHogMCP(process.env.POSTHOG_PROJECT_TOKEN, { captureModel
190
200
 
191
201
  const tools = posthog.prepareToolList(serverTools)
192
202
  const originalTool = serverTools.find((tool) => tool.name === toolName)
193
- const { args, llmModel, llmModelSource } = posthog.prepareToolCall(toolName, rawArgs, { originalTool })
203
+ const { args, llmModel, llmModelSource } = posthog.prepareToolCall(toolName, rawArgs, {
204
+ originalTool,
205
+ requestMeta: request.params?._meta,
206
+ })
194
207
  const result = await dispatch(toolName, args)
195
208
 
196
209
  posthog.captureToolCall({ toolName, llmModel, llmModelSource, isError: false })
197
210
  ```
198
211
 
199
212
  A persistent single-process dispatcher can omit `originalTool` after it has prepared its tool list.
213
+ Pass `requestMeta` whenever the request supplies `_meta`; this enables recognized client metadata
214
+ without changing the arguments sent to the tool.
200
215
 
201
216
  ### If you switched to `instrument(server.server)`
202
217
 
@@ -1,5 +1,5 @@
1
1
  export declare const INACTIVITY_TIMEOUT_IN_MINUTES = 30;
2
- export declare const DEFAULT_CONTEXT_PARAMETER_DESCRIPTION = "Explain why you are calling this tool and how it fits into the user's overall goal. This parameter is used for analytics and user intent tracking. YOU MUST provide 15-25 words (count carefully). NEVER use first person ('I', 'we', 'you') - maintain third-person perspective. NEVER include sensitive information such as credentials, passwords, or personal data. Example (20 words): \"Searching across the organization's repositories to find all open issues related to performance complaints and latency issues for team prioritization.\"";
2
+ export declare const DEFAULT_CONTEXT_PARAMETER_DESCRIPTION = "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"";
3
3
  export declare const DEFAULT_MODEL_PARAMETER_DESCRIPTION = "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" \u2014 never guess.";
4
4
  export declare const DEFAULT_CONVERSATION_ID_DESCRIPTION = "Echo the conversation_id from the server's previous response. The server provides it on the first call \u2014 never invent one, and do not issue parallel tool calls until you have it.";
5
5
  export declare const POSTHOG_MCP_ANALYTICS_SOURCE = "posthog_mcp_analytics";
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/extensions/constants.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,6BAA6B,KAAK,CAAA;AAE/C,eAAO,MAAM,qCAAqC,2hBAAyhB,CAAA;AAE3kB,eAAO,MAAM,mCAAmC,gRAAqQ,CAAA;AAErT,eAAO,MAAM,mCAAmC,4LACsI,CAAA;AAEtL,eAAO,MAAM,4BAA4B,0BAA0B,CAAA;AAMnE,eAAO,MAAM,oBAAoB,qBAAqB,CAAA;AAItD,eAAO,MAAM,wBAAwB;;;;;;;;;;;;CAY3B,CAAA;AAEV,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,OAAO,wBAAwB,CAAC,CAAA;AAE/G,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;CA0B9B,CAAA;AAEV,MAAM,MAAM,2BAA2B,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,OAAO,2BAA2B,CAAC,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/extensions/constants.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,6BAA6B,KAAK,CAAA;AAE/C,eAAO,MAAM,qCAAqC,onBAA4mB,CAAA;AAE9pB,eAAO,MAAM,mCAAmC,gRAAqQ,CAAA;AAErT,eAAO,MAAM,mCAAmC,4LACsI,CAAA;AAEtL,eAAO,MAAM,4BAA4B,0BAA0B,CAAA;AAMnE,eAAO,MAAM,oBAAoB,qBAAqB,CAAA;AAItD,eAAO,MAAM,wBAAwB;;;;;;;;;;;;CAY3B,CAAA;AAEV,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,OAAO,wBAAwB,CAAC,CAAA;AAE/G,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;CA0B9B,CAAA;AAEV,MAAM,MAAM,2BAA2B,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,OAAO,2BAA2B,CAAC,CAAA"}
@@ -28,7 +28,7 @@ var __webpack_require__ = {};
28
28
  var __webpack_exports__ = {};
29
29
  __webpack_require__.r(__webpack_exports__);
30
30
  const INACTIVITY_TIMEOUT_IN_MINUTES = 30;
31
- const DEFAULT_CONTEXT_PARAMETER_DESCRIPTION = "Explain why you are calling this tool and how it fits into the user's overall goal. This parameter is used for analytics and user intent tracking. YOU MUST provide 15-25 words (count carefully). NEVER use first person ('I', 'we', 'you') - maintain third-person perspective. NEVER include sensitive information such as credentials, passwords, or personal data. Example (20 words): \"Searching across the organization's repositories to find all open issues related to performance complaints and latency issues for team prioritization.\"";
31
+ const DEFAULT_CONTEXT_PARAMETER_DESCRIPTION = 'Explain in 15-25 words, in third person, why this tool is called and how it supports the user\'s goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as "a user", "the customer", or "an account". Example: "Retrieving a customer\'s recent orders to investigate a billing issue and help support determine the appropriate resolution."';
32
32
  const DEFAULT_MODEL_PARAMETER_DESCRIPTION = 'The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. "claude-opus-4-8", "gpt-5.2"). Used for analytics only. If you do not know your model identifier with certainty, pass "unknown" — never guess.';
33
33
  const DEFAULT_CONVERSATION_ID_DESCRIPTION = "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.";
34
34
  const POSTHOG_MCP_ANALYTICS_SOURCE = 'posthog_mcp_analytics';
@@ -1,5 +1,5 @@
1
1
  const INACTIVITY_TIMEOUT_IN_MINUTES = 30;
2
- const DEFAULT_CONTEXT_PARAMETER_DESCRIPTION = "Explain why you are calling this tool and how it fits into the user's overall goal. This parameter is used for analytics and user intent tracking. YOU MUST provide 15-25 words (count carefully). NEVER use first person ('I', 'we', 'you') - maintain third-person perspective. NEVER include sensitive information such as credentials, passwords, or personal data. Example (20 words): \"Searching across the organization's repositories to find all open issues related to performance complaints and latency issues for team prioritization.\"";
2
+ const DEFAULT_CONTEXT_PARAMETER_DESCRIPTION = 'Explain in 15-25 words, in third person, why this tool is called and how it supports the user\'s goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as "a user", "the customer", or "an account". Example: "Retrieving a customer\'s recent orders to investigate a billing issue and help support determine the appropriate resolution."';
3
3
  const DEFAULT_MODEL_PARAMETER_DESCRIPTION = 'The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. "claude-opus-4-8", "gpt-5.2"). Used for analytics only. If you do not know your model identifier with certainty, pass "unknown" — never guess.';
4
4
  const DEFAULT_CONVERSATION_ID_DESCRIPTION = "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.";
5
5
  const POSTHOG_MCP_ANALYTICS_SOURCE = 'posthog_mcp_analytics';
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"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"}
@@ -123,7 +123,10 @@ async function prepareToolCallEvent(server, data, request, downstreamRequest, ex
123
123
  const requestAttribution = (0, external_internal_js_namespaceObject.withIdentity)(sessionInfo, identity);
124
124
  await (0, external_tracing_helpers_js_namespaceObject.applyResolvedMetadata)(event, data, request, extra);
125
125
  (0, external_intent_js_namespaceObject.setEventIntent)(event, await (0, external_intent_js_namespaceObject.resolveToolCallIntent)(data, request, canCaptureContextIntent, extra));
126
- if (ownership.llmModel) (0, external_model_parameters_js_namespaceObject.setEventModel)(event, (0, external_model_parameters_js_namespaceObject.getModelArgument)(request));
126
+ if ((0, external_model_parameters_js_namespaceObject.isCaptureModelEnabled)(data.options.captureModel)) {
127
+ const resolvedModel = (0, external_model_parameters_js_namespaceObject.resolveModel)(request, ownership.llmModel);
128
+ (0, external_model_parameters_js_namespaceObject.setEventModel)(event, resolvedModel?.model, resolvedModel?.source);
129
+ }
127
130
  return {
128
131
  event,
129
132
  requestAttribution
@@ -1,6 +1,6 @@
1
1
  import { getAnalyticsParameterOwnership, stripOwnedAnalyticsArguments } from "./analytics-parameters.mjs";
2
2
  import { addContextParameterToTools, getContextDescription, isContextEnabled } from "./context-parameters.mjs";
3
- import { addModelParameterToTools, getModelArgument, getModelDescription, isCaptureModelEnabled, setEventModel } from "./model-parameters.mjs";
3
+ import { addModelParameterToTools, getModelDescription, isCaptureModelEnabled, resolveModel, setEventModel } from "./model-parameters.mjs";
4
4
  import { addConversationIdToTools, canInjectConversationIdPromptBack, injectConversationIdPromptBack, resolveConversationId } from "./conversation-id.mjs";
5
5
  import { stampClientIdentity } from "./client-identity.mjs";
6
6
  import { stampTransportIdentity } from "./transport-identity.mjs";
@@ -82,7 +82,10 @@ async function prepareToolCallEvent(server, data, request, downstreamRequest, ex
82
82
  const requestAttribution = withIdentity(sessionInfo, identity);
83
83
  await applyResolvedMetadata(event, data, request, extra);
84
84
  setEventIntent(event, await resolveToolCallIntent(data, request, canCaptureContextIntent, extra));
85
- if (ownership.llmModel) setEventModel(event, getModelArgument(request));
85
+ if (isCaptureModelEnabled(data.options.captureModel)) {
86
+ const resolvedModel = resolveModel(request, ownership.llmModel);
87
+ setEventModel(event, resolvedModel?.model, resolvedModel?.source);
88
+ }
86
89
  return {
87
90
  event,
88
91
  requestAttribution
@@ -1,4 +1,14 @@
1
1
  type JsonRecord = Record<string, unknown>;
2
+ /**
3
+ * Redacts structured personal identifiers (emails, IP addresses, credit-card
4
+ * numbers, US SSNs, and phone numbers) from a free-text string. Intended for the
5
+ * agent-narrated `$mcp_intent` value only — not for structured tool parameters or
6
+ * responses, where the same shapes are often legitimate data. Horizontal Unicode
7
+ * spaces are first normalized to an ASCII space so copy-pasted identifiers still
8
+ * match. Returns a new string; leaves the input's identifiers untouched when
9
+ * nothing matches.
10
+ */
11
+ export declare function redactPii(value: string): string;
2
12
  export declare function sanitizeCapturedValue(value: unknown): unknown;
3
13
  export declare function buildCapturedMcpParameters(request: unknown): JsonRecord;
4
14
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-payloads.d.ts","sourceRoot":"","sources":["../../src/extensions/mcp-payloads.ts"],"names":[],"mappings":"AAkBA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAsCzC,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CA0B7D;AA6BD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAiBvE"}
1
+ {"version":3,"file":"mcp-payloads.d.ts","sourceRoot":"","sources":["../../src/extensions/mcp-payloads.ts"],"names":[],"mappings":"AAmEA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAiGzC;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAU/C;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CA0B7D;AA6BD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAiBvE"}
@@ -38,6 +38,15 @@ const BASE64_DATA_URL_PAYLOAD_PATTERN = /^[A-Za-z0-9+/_-]+={0,2}$/;
38
38
  const SIZE_GATE = 10240;
39
39
  const POSTHOG_TOKEN_PATTERN = /\bph[a-z]_[A-Za-z0-9_-]{20,}\b/g;
40
40
  const SENSITIVE_KEY_PATTERN = /^(authorization|cookie|set-cookie|x-api-key|api[-_]?key|api[-_]?token|access[-_]?token|refresh[-_]?token|token|password|secret|client[-_]?secret|private[-_]?key)$/i;
41
+ const UNICODE_SPACE_PATTERN = /[\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g;
42
+ const EMAIL_PATTERN = /[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,255}\.[A-Za-z]{2,24}/g;
43
+ const IPV4_PATTERN = /\b(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\b/g;
44
+ const IPV6_PATTERN = /\b(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}\b|(?<![\w:])(?:[0-9A-Fa-f]{1,4}:){1,7}:(?![\w:])|(?<![\w:])(?:[0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4}){0,5}(?![\w])|(?<![\w:])::(?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4}){0,6})(?![\w])/g;
45
+ const US_SSN_PATTERN = /\b\d{3}[ .-]\d{2}[ .-]\d{4}\b/g;
46
+ const CREDIT_CARD_CANDIDATE_PATTERN = /\b\d(?:[ ./-]?\d){12,}\b/g;
47
+ const DIGIT_GROUP_PATTERN = /\d+/g;
48
+ const PHONE_NANP_PATTERN = /(?<![\w+])(?:\+?1[ ./-]?)?(?:\(\d{3}\)[ ./-]?|\d{3}[ ./-])\d{3}[ ./-]\d{4}(?![\w])/g;
49
+ const PHONE_INTL_PATTERN = /(?<!\w)\+\d{1,3}(?:[ ./()-]{0,2}\d){7,13}(?![\w])/g;
41
50
  function isRecord(value) {
42
51
  return !!value && 'object' == typeof value && !Array.isArray(value);
43
52
  }
@@ -59,6 +68,58 @@ function sanitizeString(value) {
59
68
  if (value.length >= SIZE_GATE && (BASE64_PATTERN.test(value) || isBase64DataUrl(value) || BASE64URL_SPECIFIC_CHAR_PATTERN.test(value) && BASE64URL_PATTERN.test(value))) return BINARY_REDACTED_VALUE;
60
69
  return value.replace(POSTHOG_TOKEN_PATTERN, REDACTED_VALUE);
61
70
  }
71
+ function passesLuhn(digits) {
72
+ let sum = 0;
73
+ let double = false;
74
+ for(let index = digits.length - 1; index >= 0; index--){
75
+ let digit = digits.charCodeAt(index) - 48;
76
+ if (digit < 0 || digit > 9) return false;
77
+ if (double) {
78
+ digit *= 2;
79
+ if (digit > 9) digit -= 9;
80
+ }
81
+ sum += digit;
82
+ double = !double;
83
+ }
84
+ return sum % 10 === 0;
85
+ }
86
+ function redactCardInMatch(match) {
87
+ const groups = [];
88
+ for(let m = DIGIT_GROUP_PATTERN.exec(match); null !== m; m = DIGIT_GROUP_PATTERN.exec(match))groups.push({
89
+ digits: m[0],
90
+ start: m.index,
91
+ end: m.index + m[0].length
92
+ });
93
+ let output = '';
94
+ let cursor = 0;
95
+ let first = 0;
96
+ while(first < groups.length){
97
+ let digits = '';
98
+ let matchedLast = -1;
99
+ for(let last = first; last < groups.length; last++){
100
+ digits += groups[last].digits;
101
+ if (digits.length > 19) break;
102
+ if (digits.length >= 13 && passesLuhn(digits)) matchedLast = last;
103
+ }
104
+ if (matchedLast >= 0) {
105
+ output += match.slice(cursor, groups[first].start) + REDACTED_VALUE;
106
+ cursor = groups[matchedLast].end;
107
+ first = matchedLast + 1;
108
+ } else first++;
109
+ }
110
+ return output + match.slice(cursor);
111
+ }
112
+ function redactPii(value) {
113
+ let result = value.replace(UNICODE_SPACE_PATTERN, ' ');
114
+ result = result.replace(EMAIL_PATTERN, REDACTED_VALUE);
115
+ result = result.replace(IPV4_PATTERN, REDACTED_VALUE);
116
+ result = result.replace(IPV6_PATTERN, REDACTED_VALUE);
117
+ result = result.replace(CREDIT_CARD_CANDIDATE_PATTERN, redactCardInMatch);
118
+ result = result.replace(US_SSN_PATTERN, REDACTED_VALUE);
119
+ result = result.replace(PHONE_NANP_PATTERN, REDACTED_VALUE);
120
+ result = result.replace(PHONE_INTL_PATTERN, REDACTED_VALUE);
121
+ return result;
122
+ }
62
123
  function sanitizeCapturedValue(value) {
63
124
  if (null == value) return value;
64
125
  if ('string' == typeof value) return sanitizeString(value);
@@ -98,12 +159,15 @@ function buildCapturedMcpParameters(request) {
98
159
  }
99
160
  __webpack_require__.d(__webpack_exports__, {
100
161
  buildCapturedMcpParameters: ()=>buildCapturedMcpParameters,
162
+ redactPii: ()=>redactPii,
101
163
  sanitizeCapturedValue: ()=>sanitizeCapturedValue
102
164
  });
103
165
  exports.buildCapturedMcpParameters = __webpack_exports__.buildCapturedMcpParameters;
166
+ exports.redactPii = __webpack_exports__.redactPii;
104
167
  exports.sanitizeCapturedValue = __webpack_exports__.sanitizeCapturedValue;
105
168
  for(var __rspack_i in __webpack_exports__)if (-1 === [
106
169
  "buildCapturedMcpParameters",
170
+ "redactPii",
107
171
  "sanitizeCapturedValue"
108
172
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
109
173
  Object.defineProperty(exports, '__esModule', {
@@ -9,6 +9,15 @@ const BASE64_DATA_URL_PAYLOAD_PATTERN = /^[A-Za-z0-9+/_-]+={0,2}$/;
9
9
  const SIZE_GATE = 10240;
10
10
  const POSTHOG_TOKEN_PATTERN = /\bph[a-z]_[A-Za-z0-9_-]{20,}\b/g;
11
11
  const SENSITIVE_KEY_PATTERN = /^(authorization|cookie|set-cookie|x-api-key|api[-_]?key|api[-_]?token|access[-_]?token|refresh[-_]?token|token|password|secret|client[-_]?secret|private[-_]?key)$/i;
12
+ const UNICODE_SPACE_PATTERN = /[\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g;
13
+ const EMAIL_PATTERN = /[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,255}\.[A-Za-z]{2,24}/g;
14
+ const IPV4_PATTERN = /\b(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\b/g;
15
+ const IPV6_PATTERN = /\b(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}\b|(?<![\w:])(?:[0-9A-Fa-f]{1,4}:){1,7}:(?![\w:])|(?<![\w:])(?:[0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4}){0,5}(?![\w])|(?<![\w:])::(?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4}){0,6})(?![\w])/g;
16
+ const US_SSN_PATTERN = /\b\d{3}[ .-]\d{2}[ .-]\d{4}\b/g;
17
+ const CREDIT_CARD_CANDIDATE_PATTERN = /\b\d(?:[ ./-]?\d){12,}\b/g;
18
+ const DIGIT_GROUP_PATTERN = /\d+/g;
19
+ const PHONE_NANP_PATTERN = /(?<![\w+])(?:\+?1[ ./-]?)?(?:\(\d{3}\)[ ./-]?|\d{3}[ ./-])\d{3}[ ./-]\d{4}(?![\w])/g;
20
+ const PHONE_INTL_PATTERN = /(?<!\w)\+\d{1,3}(?:[ ./()-]{0,2}\d){7,13}(?![\w])/g;
12
21
  function isRecord(value) {
13
22
  return !!value && 'object' == typeof value && !Array.isArray(value);
14
23
  }
@@ -30,6 +39,58 @@ function sanitizeString(value) {
30
39
  if (value.length >= SIZE_GATE && (BASE64_PATTERN.test(value) || isBase64DataUrl(value) || BASE64URL_SPECIFIC_CHAR_PATTERN.test(value) && BASE64URL_PATTERN.test(value))) return BINARY_REDACTED_VALUE;
31
40
  return value.replace(POSTHOG_TOKEN_PATTERN, REDACTED_VALUE);
32
41
  }
42
+ function passesLuhn(digits) {
43
+ let sum = 0;
44
+ let double = false;
45
+ for(let index = digits.length - 1; index >= 0; index--){
46
+ let digit = digits.charCodeAt(index) - 48;
47
+ if (digit < 0 || digit > 9) return false;
48
+ if (double) {
49
+ digit *= 2;
50
+ if (digit > 9) digit -= 9;
51
+ }
52
+ sum += digit;
53
+ double = !double;
54
+ }
55
+ return sum % 10 === 0;
56
+ }
57
+ function redactCardInMatch(match) {
58
+ const groups = [];
59
+ for(let m = DIGIT_GROUP_PATTERN.exec(match); null !== m; m = DIGIT_GROUP_PATTERN.exec(match))groups.push({
60
+ digits: m[0],
61
+ start: m.index,
62
+ end: m.index + m[0].length
63
+ });
64
+ let output = '';
65
+ let cursor = 0;
66
+ let first = 0;
67
+ while(first < groups.length){
68
+ let digits = '';
69
+ let matchedLast = -1;
70
+ for(let last = first; last < groups.length; last++){
71
+ digits += groups[last].digits;
72
+ if (digits.length > 19) break;
73
+ if (digits.length >= 13 && passesLuhn(digits)) matchedLast = last;
74
+ }
75
+ if (matchedLast >= 0) {
76
+ output += match.slice(cursor, groups[first].start) + REDACTED_VALUE;
77
+ cursor = groups[matchedLast].end;
78
+ first = matchedLast + 1;
79
+ } else first++;
80
+ }
81
+ return output + match.slice(cursor);
82
+ }
83
+ function redactPii(value) {
84
+ let result = value.replace(UNICODE_SPACE_PATTERN, ' ');
85
+ result = result.replace(EMAIL_PATTERN, REDACTED_VALUE);
86
+ result = result.replace(IPV4_PATTERN, REDACTED_VALUE);
87
+ result = result.replace(IPV6_PATTERN, REDACTED_VALUE);
88
+ result = result.replace(CREDIT_CARD_CANDIDATE_PATTERN, redactCardInMatch);
89
+ result = result.replace(US_SSN_PATTERN, REDACTED_VALUE);
90
+ result = result.replace(PHONE_NANP_PATTERN, REDACTED_VALUE);
91
+ result = result.replace(PHONE_INTL_PATTERN, REDACTED_VALUE);
92
+ return result;
93
+ }
33
94
  function sanitizeCapturedValue(value) {
34
95
  if (null == value) return value;
35
96
  if ('string' == typeof value) return sanitizeString(value);
@@ -67,4 +128,4 @@ function buildCapturedMcpParameters(request) {
67
128
  request: capturedRequest
68
129
  };
69
130
  }
70
- export { buildCapturedMcpParameters, sanitizeCapturedValue };
131
+ export { buildCapturedMcpParameters, redactPii, sanitizeCapturedValue };
@@ -1,22 +1,19 @@
1
- import type { MCPAnalyticsOptions, MCPRequestLike, McpEvent } from '../types';
1
+ import type { MCPAnalyticsModelSource, MCPAnalyticsOptions, MCPRequestLike, McpEvent } from '../types';
2
2
  import { type AnalyticsInjectableJsonSchema } from './analytics-parameters';
3
3
  import { type LoggerFn } from './logger';
4
4
  /**
5
- * Self-reported model capture (`captureModel`).
5
+ * Model capture (`captureModel`).
6
6
  *
7
- * MCP keeps servers deliberately model-ignorant: the wire carries client
8
- * name/version and protocol version, never the LLM behind the client, and no
9
- * spec revision changes that. The one place the information exists on the
10
- * server side of the connection is the agent itself — harnesses inject the
11
- * model id into the system prompt, so the agent can state it the same way it
12
- * states its intent through the `context` parameter.
7
+ * MCP does not standardize model identity. Some clients expose it through
8
+ * vendor metadata, while other harnesses inject the model id into the system
9
+ * prompt so the agent can state it like intent through the `context` parameter.
13
10
  *
14
11
  * This module injects a required `llm_model` string parameter into every tool
15
12
  * (mirroring `context-parameters.ts`), strips it before the tool runs, and
16
- * captures it as `$mcp_llm_model` with `$mcp_llm_model_source = "self_reported"`.
17
- * The source property is deliberate: like `clientInfo` in the MCP spec, the
18
- * value is self-reported and unverified — right for degradation analytics
19
- * ("does our MCP get worse on model X?"), never for billing or security.
13
+ * captures the best available value as `$mcp_llm_model`. Client metadata wins
14
+ * over self-report, and `$mcp_llm_model_source` preserves that provenance.
15
+ * Both sources are unverified — right for degradation analytics ("does our MCP
16
+ * get worse on model X?"), never for billing or security.
20
17
  *
21
18
  * Reasoning effort is deliberately NOT captured: it never crosses the wire,
22
19
  * and models cannot reliably self-report it (harnesses apply it as a sampling
@@ -44,5 +41,15 @@ export declare function addModelParameterToTools<TTool extends ModelInjectableTo
44
41
  * not become a property value queries would group by.
45
42
  */
46
43
  export declare function getModelArgument(request: MCPRequestLike): string | undefined;
47
- export declare function setEventModel(event: McpEvent, model: string | undefined): void;
44
+ export interface ResolvedModel {
45
+ model: string;
46
+ source: MCPAnalyticsModelSource;
47
+ }
48
+ /**
49
+ * Resolves model identity from sources visible to an MCP server. The Codex
50
+ * request metadata is host-generated and therefore more reliable than a model
51
+ * filling an injected argument, but remains unverified client input.
52
+ */
53
+ export declare function resolveModel(request: MCPRequestLike, allowSelfReported: boolean): ResolvedModel | undefined;
54
+ export declare function setEventModel(event: McpEvent, model: string | undefined, source?: MCPAnalyticsModelSource): void;
48
55
  //# sourceMappingURL=model-parameters.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-parameters.d.ts","sourceRoot":"","sources":["../../src/extensions/model-parameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAC7E,OAAO,EAA+B,KAAK,6BAA6B,EAAE,MAAM,wBAAwB,CAAA;AAExG,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAE7C;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,6BAA6B,CAAA;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,mBAAmB,CAAC,cAAc,CAAC,GAAG,OAAO,CAEhG;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,mBAAmB,CAAC,cAAc,CAAC,GAAG,MAAM,GAAG,SAAS,CAEzG;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,SAAS,mBAAmB,EACvE,IAAI,EAAE,KAAK,EACX,wBAAwB,CAAC,EAAE,MAAM,EACjC,MAAM,GAAE,QAAc,GACrB,KAAK,CAQP;AAED,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,mBAAmB,EACxE,KAAK,EAAE,KAAK,EAAE,EACd,wBAAwB,CAAC,EAAE,MAAM,EACjC,MAAM,GAAE,QAAc,GACrB,KAAK,EAAE,CAET;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,CAE5E;AAaD,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAO9E"}
1
+ {"version":3,"file":"model-parameters.d.ts","sourceRoot":"","sources":["../../src/extensions/model-parameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACtG,OAAO,EAA+B,KAAK,6BAA6B,EAAE,MAAM,wBAAwB,CAAA;AAExG,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAE7C;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,6BAA6B,CAAA;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,mBAAmB,CAAC,cAAc,CAAC,GAAG,OAAO,CAEhG;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,mBAAmB,CAAC,cAAc,CAAC,GAAG,MAAM,GAAG,SAAS,CAEzG;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,SAAS,mBAAmB,EACvE,IAAI,EAAE,KAAK,EACX,wBAAwB,CAAC,EAAE,MAAM,EACjC,MAAM,GAAE,QAAc,GACrB,KAAK,CAQP;AAED,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,mBAAmB,EACxE,KAAK,EAAE,KAAK,EAAE,EACd,wBAAwB,CAAC,EAAE,MAAM,EACjC,MAAM,GAAE,QAAc,GACrB,KAAK,EAAE,CAET;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,CAE5E;AAID,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,uBAAuB,CAAA;CAChC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,OAAO,GAAG,aAAa,GAAG,SAAS,CAiB3G;AAiBD,wBAAgB,aAAa,CAC3B,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,MAAM,GAAE,uBAAyC,GAChD,IAAI,CAON"}
@@ -33,6 +33,7 @@ __webpack_require__.d(__webpack_exports__, {
33
33
  getModelArgument: ()=>getModelArgument,
34
34
  getModelDescription: ()=>getModelDescription,
35
35
  isCaptureModelEnabled: ()=>isCaptureModelEnabled,
36
+ resolveModel: ()=>resolveModel,
36
37
  setEventModel: ()=>setEventModel
37
38
  });
38
39
  const external_analytics_parameters_js_namespaceObject = require("./analytics-parameters.js");
@@ -53,23 +54,45 @@ function addModelParameterToTools(tools, modelDescriptionOverride, logger = exte
53
54
  function getModelArgument(request) {
54
55
  return normalizeModel(request.params?.arguments?.llm_model);
55
56
  }
57
+ const CODEX_TURN_METADATA_KEY = 'x-codex-turn-metadata';
58
+ function resolveModel(request, allowSelfReported) {
59
+ const codexMetadata = request.params?._meta?.[CODEX_TURN_METADATA_KEY];
60
+ if (isRecord(codexMetadata) && Object.prototype.hasOwnProperty.call(codexMetadata, 'model')) {
61
+ const model = normalizeModel(codexMetadata.model);
62
+ if (model) return {
63
+ model,
64
+ source: 'client_metadata'
65
+ };
66
+ }
67
+ if (allowSelfReported) {
68
+ const model = getModelArgument(request);
69
+ if (model) return {
70
+ model,
71
+ source: 'self_reported'
72
+ };
73
+ }
74
+ }
75
+ function isRecord(value) {
76
+ return 'object' == typeof value && null !== value && !Array.isArray(value);
77
+ }
56
78
  function normalizeModel(model) {
57
79
  if ('string' != typeof model) return;
58
80
  const trimmed = model.trim();
59
81
  if (!trimmed || 'unknown' === trimmed.toLowerCase()) return;
60
82
  return trimmed;
61
83
  }
62
- function setEventModel(event, model) {
84
+ function setEventModel(event, model, source = 'self_reported') {
63
85
  const normalizedModel = normalizeModel(model);
64
86
  if (!normalizedModel) return;
65
87
  event.llmModel = normalizedModel;
66
- event.llmModelSource = 'self_reported';
88
+ event.llmModelSource = source;
67
89
  }
68
90
  exports.addModelParameterToTool = __webpack_exports__.addModelParameterToTool;
69
91
  exports.addModelParameterToTools = __webpack_exports__.addModelParameterToTools;
70
92
  exports.getModelArgument = __webpack_exports__.getModelArgument;
71
93
  exports.getModelDescription = __webpack_exports__.getModelDescription;
72
94
  exports.isCaptureModelEnabled = __webpack_exports__.isCaptureModelEnabled;
95
+ exports.resolveModel = __webpack_exports__.resolveModel;
73
96
  exports.setEventModel = __webpack_exports__.setEventModel;
74
97
  for(var __rspack_i in __webpack_exports__)if (-1 === [
75
98
  "addModelParameterToTool",
@@ -77,6 +100,7 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
77
100
  "getModelArgument",
78
101
  "getModelDescription",
79
102
  "isCaptureModelEnabled",
103
+ "resolveModel",
80
104
  "setEventModel"
81
105
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
82
106
  Object.defineProperty(exports, '__esModule', {
@@ -16,16 +16,37 @@ function addModelParameterToTools(tools, modelDescriptionOverride, logger = log)
16
16
  function getModelArgument(request) {
17
17
  return normalizeModel(request.params?.arguments?.llm_model);
18
18
  }
19
+ const CODEX_TURN_METADATA_KEY = 'x-codex-turn-metadata';
20
+ function resolveModel(request, allowSelfReported) {
21
+ const codexMetadata = request.params?._meta?.[CODEX_TURN_METADATA_KEY];
22
+ if (isRecord(codexMetadata) && Object.prototype.hasOwnProperty.call(codexMetadata, 'model')) {
23
+ const model = normalizeModel(codexMetadata.model);
24
+ if (model) return {
25
+ model,
26
+ source: 'client_metadata'
27
+ };
28
+ }
29
+ if (allowSelfReported) {
30
+ const model = getModelArgument(request);
31
+ if (model) return {
32
+ model,
33
+ source: 'self_reported'
34
+ };
35
+ }
36
+ }
37
+ function isRecord(value) {
38
+ return 'object' == typeof value && null !== value && !Array.isArray(value);
39
+ }
19
40
  function normalizeModel(model) {
20
41
  if ('string' != typeof model) return;
21
42
  const trimmed = model.trim();
22
43
  if (!trimmed || 'unknown' === trimmed.toLowerCase()) return;
23
44
  return trimmed;
24
45
  }
25
- function setEventModel(event, model) {
46
+ function setEventModel(event, model, source = 'self_reported') {
26
47
  const normalizedModel = normalizeModel(model);
27
48
  if (!normalizedModel) return;
28
49
  event.llmModel = normalizedModel;
29
- event.llmModelSource = 'self_reported';
50
+ event.llmModelSource = source;
30
51
  }
31
- export { addModelParameterToTool, addModelParameterToTools, getModelArgument, getModelDescription, isCaptureModelEnabled, setEventModel };
52
+ export { addModelParameterToTool, addModelParameterToTools, getModelArgument, getModelDescription, isCaptureModelEnabled, resolveModel, setEventModel };
@@ -14,8 +14,8 @@ export interface PostHogMCPOptions extends PostHogOptions {
14
14
  */
15
15
  missingCapabilityToolName?: string;
16
16
  /**
17
- * Inject a required `llm_model` argument into advertised tools and capture
18
- * the agent's self-reported value. Off by default.
17
+ * Capture the calling model from recognized client metadata, with an injected
18
+ * `llm_model` argument as fallback. Off by default.
19
19
  */
20
20
  captureModel?: MCPAnalyticsOptions['captureModel'];
21
21
  }
@@ -112,7 +112,7 @@ export declare class PostHogMCP extends PostHog {
112
112
  * @example
113
113
  * ```ts
114
114
  * const { intent, intentSource, llmModel, llmModelSource, args, isMissingCapability } =
115
- * posthog.prepareToolCall(name, rawArgs)
115
+ * posthog.prepareToolCall(name, rawArgs, { requestMeta: request.params?._meta })
116
116
  * if (isMissingCapability) {
117
117
  * posthog.captureMissingCapability({ context: intent, llmModel, llmModelSource, ...identity })
118
118
  * return getMoreToolsResult()
@@ -1 +1 @@
1
- {"version":3,"file":"posthog-mcp.d.ts","sourceRoot":"","sources":["../../src/extensions/posthog-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAE3D,OAAO,KAAK,EACV,qBAAqB,EAErB,mBAAmB,EAGnB,4BAA4B,EAC5B,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,UAAU,CAAA;AAEjB,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAA;AAgB7B;;;GAGG;AACH,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;CACnD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,qBAAa,UAAW,SAAQ,OAAO;;gBASzB,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB;IAO3D,8FAA8F;IAC9F,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI;IAqBhD,iEAAiE;IACjE,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI;IAUpD;;;;;OAKG;IACH,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI;IAclD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,eAAe,CAAC,KAAK,SAAS,qBAAqB,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,OAAO,GAAE,sBAA2B,GAAG,KAAK,EAAE;IAiCnH;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,eAAe,CACb,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,GAAE,sBAA2B,GACnC,gBAAgB;IA0BnB;;;;OAIG;IACH,wBAAwB,CAAC,IAAI,EAAE,4BAA4B,GAAG,IAAI;CAsBnE"}
1
+ {"version":3,"file":"posthog-mcp.d.ts","sourceRoot":"","sources":["../../src/extensions/posthog-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAE3D,OAAO,KAAK,EACV,qBAAqB,EAErB,mBAAmB,EAGnB,4BAA4B,EAC5B,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,UAAU,CAAA;AAEjB,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAA;AAgB7B;;;GAGG;AACH,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;CACnD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,qBAAa,UAAW,SAAQ,OAAO;;gBASzB,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB;IAO3D,8FAA8F;IAC9F,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI;IAkBhD,iEAAiE;IACjE,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI;IAUpD;;;;;OAKG;IACH,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI;IAclD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,eAAe,CAAC,KAAK,SAAS,qBAAqB,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,OAAO,GAAE,sBAA2B,GAAG,KAAK,EAAE;IAiCnH;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,eAAe,CACb,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,GAAE,sBAA2B,GACnC,gBAAgB;IA4BnB;;;;OAIG;IACH,wBAAwB,CAAC,IAAI,EAAE,4BAA4B,GAAG,IAAI;CAmBnE"}
@@ -63,8 +63,7 @@ class PostHogMCP extends external_posthog_node_namespaceObject.PostHog {
63
63
  event.isError = data.isError;
64
64
  event.errorType = data.errorType;
65
65
  applyIntent(event, data.intent, data.intentSource);
66
- (0, external_model_parameters_js_namespaceObject.setEventModel)(event, data.llmModel);
67
- if (event.llmModel && data.llmModelSource) event.llmModelSource = data.llmModelSource;
66
+ (0, external_model_parameters_js_namespaceObject.setEventModel)(event, data.llmModel, data.llmModelSource);
68
67
  if (data.isError) event.error = (0, external_exceptions_js_namespaceObject.captureException)(data.error ?? `Tool ${data.toolName} returned an error`);
69
68
  this.#emit(event);
70
69
  }
@@ -115,17 +114,18 @@ class PostHogMCP extends external_posthog_node_namespaceObject.PostHog {
115
114
  const rawContext = args?.context;
116
115
  const intent = 'string' == typeof rawContext && rawContext.trim() ? rawContext.trim() : void 0;
117
116
  const ownsModel = (0, external_model_parameters_js_namespaceObject.isCaptureModelEnabled)(this.#captureModel) && (options.originalTool ? (0, external_analytics_parameters_js_namespaceObject.analyticsOwnsParameter)(options.originalTool.inputSchema, 'llm_model') : true === this.#modelParameterOwnership.get(name));
118
- const llmModel = ownsModel ? (0, external_model_parameters_js_namespaceObject.getModelArgument)({
117
+ const resolvedModel = (0, external_model_parameters_js_namespaceObject.isCaptureModelEnabled)(this.#captureModel) ? (0, external_model_parameters_js_namespaceObject.resolveModel)({
119
118
  params: {
120
- arguments: args
119
+ arguments: args,
120
+ _meta: options.requestMeta
121
121
  }
122
- }) : void 0;
122
+ }, ownsModel) : void 0;
123
123
  const strippedArgs = stripContext(args);
124
124
  return {
125
125
  intent,
126
126
  intentSource: intent ? 'context_parameter' : void 0,
127
- llmModel,
128
- llmModelSource: llmModel ? 'self_reported' : void 0,
127
+ llmModel: resolvedModel?.model,
128
+ llmModelSource: resolvedModel?.source,
129
129
  args: ownsModel ? (0, external_analytics_parameters_js_namespaceObject.stripOwnedAnalyticsArguments)(strippedArgs, {
130
130
  context: false,
131
131
  conversationId: false,
@@ -139,8 +139,7 @@ class PostHogMCP extends external_posthog_node_namespaceObject.PostHog {
139
139
  event.resourceName = this.#missingCapabilityToolName;
140
140
  event.parameters = data.parameters;
141
141
  applyIntent(event, data.context, 'context_parameter');
142
- (0, external_model_parameters_js_namespaceObject.setEventModel)(event, data.llmModel);
143
- if (event.llmModel && data.llmModelSource) event.llmModelSource = data.llmModelSource;
142
+ (0, external_model_parameters_js_namespaceObject.setEventModel)(event, data.llmModel, data.llmModelSource);
144
143
  this.#emit(event);
145
144
  }
146
145
  #emit(event) {