@alpic-ai/insights 1.175.2 → 1.176.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.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,4 @@
1
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
1
+ import { ServerContext } from "@modelcontextprotocol/server";
3
2
  //#region src/intent-middleware.d.ts
4
3
  interface PromptData {
5
4
  toolName: string;
@@ -36,8 +35,7 @@ interface Analytics {
36
35
  /** Replaces the current request user's trait snapshot (e.g. email, name, plan); the target user is resolved by Alpic from the request auth context — no id or sessionId is passed. */
37
36
  identify(traits: Record<string, string>): void;
38
37
  }
39
- /** Shape of the handler `extra` once `analyticsMiddleware()` (or `track(server)`) is installed; cast the handler's `extra` to this to access `analytics` with types. */
40
- interface AnalyticsExtra {
38
+ interface AnalyticsExtra extends ServerContext {
41
39
  analytics: Analytics;
42
40
  }
43
41
  interface AnalyticsEvent extends CaptureOptions {
@@ -69,14 +67,14 @@ export declare function feedbackMiddleware(options?: FeedbackMiddlewareOptions):
69
67
  //#endregion
70
68
  //#region src/capture-feedback.d.ts
71
69
  /** Injects a `send_feedback` tool by patching the server's `tools/list` and `tools/call` handlers, surfacing captured feedback via `options.handler` (or via the response `_meta` when `ALPIC_FEEDBACK_META_KEY` is set). */
72
- export declare const captureFeedback: (server: McpServer | Server, options?: FeedbackMiddlewareOptions) => void;
70
+ export declare const captureFeedback: (server: object, options?: FeedbackMiddlewareOptions) => void;
73
71
  //#endregion
74
72
  //#region src/capture-intents.d.ts
75
73
  /** Captures the user's natural-language intent behind each tool call by patching the server's `tools/list` and `tools/call` handlers, surfacing it via `options.handler` (or via the response `_meta` when `ALPIC_INTENT_META_KEY` is set). */
76
- export declare const captureIntents: (server: McpServer | Server, options?: IntentMiddlewareOptions) => void;
74
+ export declare const captureIntents: (server: object, options?: IntentMiddlewareOptions) => void;
77
75
  //#endregion
78
76
  //#region src/track.d.ts
79
77
  /** Enables custom analytics events by patching the server's `tools/call` handlers so tool handlers can call `extra.analytics.capture(...)` / `identify(...)`; pass `options.handler` to receive analytics when running outside Alpic. */
80
- export declare const track: (server: McpServer | Server, options?: AnalyticsMiddlewareOptions) => void;
78
+ export declare const track: (server: object, options?: AnalyticsMiddlewareOptions) => void;
81
79
  //#endregion
82
80
  export type { Analytics, AnalyticsBatch, AnalyticsEvent, AnalyticsExtra, AnalyticsMiddlewareOptions, CaptureOptions, FeedbackData, FeedbackMiddlewareOptions, IntentMiddlewareOptions, McpMiddlewareFn, PromptData };
package/dist/index.mjs CHANGED
@@ -1,4 +1,9 @@
1
- import { CallToolRequestSchema, CallToolResultSchema, ListToolsResultSchema } from "@modelcontextprotocol/sdk/types.js";
1
+ import { isSpecType } from "@modelcontextprotocol/server";
2
+ //#region src/is-record.ts
3
+ function isRecord(value) {
4
+ return value !== null && typeof value === "object" && !Array.isArray(value);
5
+ }
6
+ //#endregion
2
7
  //#region src/analytics-middleware.ts
3
8
  const MAX_EVENTS_PER_REQUEST = 50;
4
9
  function warnInDev(message) {
@@ -69,13 +74,12 @@ function analyticsMiddleware(options) {
69
74
  const eventsMetaKey = process.env.ALPIC_EVENTS_META_KEY || void 0;
70
75
  const identifyMetaKey = process.env.ALPIC_IDENTIFY_META_KEY || void 0;
71
76
  if (eventsMetaKey === void 0 && identifyMetaKey === void 0) return rawResult;
72
- if (!CallToolResultSchema.safeParse(rawResult).success) return rawResult;
73
- const result = rawResult;
74
- const meta = { ...result._meta };
77
+ if (!isSpecType.CallToolResult(rawResult)) return rawResult;
78
+ const meta = { ...isRecord(rawResult._meta) ? rawResult._meta : {} };
75
79
  if (eventsMetaKey !== void 0 && buffer.events.length > 0) meta[eventsMetaKey] = buffer.events;
76
80
  if (identifyMetaKey !== void 0 && buffer.traits !== void 0) meta[identifyMetaKey] = buffer.traits;
77
81
  return {
78
- ...result,
82
+ ...rawResult,
79
83
  _meta: meta
80
84
  };
81
85
  };
@@ -102,10 +106,9 @@ function feedbackMiddleware(options) {
102
106
  const metaKeyName = process.env.ALPIC_FEEDBACK_META_KEY;
103
107
  if (request.method === "tools/list") {
104
108
  const rawResult = await next();
105
- const parsed = ListToolsResultSchema.safeParse(rawResult);
106
- if (!parsed.success) return rawResult;
107
- if (parsed.data.tools.some((tool) => tool.name === "send_feedback")) return parsed.data;
108
- parsed.data.tools.push({
109
+ if (!isSpecType.ListToolsResult(rawResult)) return rawResult;
110
+ if (rawResult.tools.some((tool) => tool.name === "send_feedback")) return rawResult;
111
+ const feedbackTool = {
109
112
  name: FEEDBACK_TOOL_NAME,
110
113
  description: FEEDBACK_TOOL_DESCRIPTION,
111
114
  inputSchema: {
@@ -130,13 +133,15 @@ function feedbackMiddleware(options) {
130
133
  openWorldHint: false,
131
134
  idempotentHint: true
132
135
  }
133
- });
134
- return parsed.data;
136
+ };
137
+ return {
138
+ ...rawResult,
139
+ tools: [...rawResult.tools, feedbackTool]
140
+ };
135
141
  }
136
142
  if (request.method !== "tools/call") return next();
137
- const parsedRequest = CallToolRequestSchema.safeParse(request);
138
- if (!parsedRequest.success || parsedRequest.data.params.name !== "send_feedback") return next();
139
- const args = parsedRequest.data.params.arguments ?? {};
143
+ if (request.params.name !== "send_feedback") return next();
144
+ const args = isRecord(request.params.arguments) ? request.params.arguments : {};
140
145
  const content = typeof args.content === "string" ? args.content.trim() : void 0;
141
146
  const source = args.source === "user" ? "user" : "model";
142
147
  if (content === void 0 || content.length === 0) return {
@@ -221,17 +226,18 @@ function intentMiddleware(options) {
221
226
  const metaKeyName = process.env.ALPIC_INTENT_META_KEY;
222
227
  if (request.method === "tools/list") {
223
228
  const rawResult = await next();
224
- const parsed = ListToolsResultSchema.safeParse(rawResult);
225
- if (!parsed.success) return rawResult;
226
- for (const tool of parsed.data.tools) {
227
- if (toolsFilter && !toolsFilter.has(tool.name)) continue;
228
- if (tool.name === "send_feedback") continue;
229
- if (argumentNameOverride[tool.name] != null) continue;
230
- tool.inputSchema.properties = {
231
- ...tool.inputSchema.properties,
232
- [USER_INTENT_FIELD]: {
233
- type: "string",
234
- description: `A concise, natural-language summary of what the user is trying to accomplish, derived from the conversation that triggered this tool call. Base it on the user's own words.
229
+ if (!isSpecType.ListToolsResult(rawResult)) return rawResult;
230
+ const tools = rawResult.tools.map((tool) => {
231
+ if (toolsFilter && !toolsFilter.has(tool.name) || tool.name === "send_feedback" || argumentNameOverride[tool.name] != null) return tool;
232
+ return {
233
+ ...tool,
234
+ inputSchema: {
235
+ ...tool.inputSchema,
236
+ properties: {
237
+ ...tool.inputSchema.properties,
238
+ [USER_INTENT_FIELD]: {
239
+ type: "string",
240
+ description: `A concise, natural-language summary of what the user is trying to accomplish, derived from the conversation that triggered this tool call. Base it on the user's own words.
235
241
 
236
242
  This is context that helps understand the user's request and improve the tool's response; it does not trigger any destructive action.
237
243
 
@@ -242,47 +248,54 @@ Before sending, strip all personally identifiable information (names, emails, ph
242
248
  - Longer conversation: summarize the core goal, constraints, and preferences in 1-2 sentences.
243
249
  "Hi, I'm Jane (jane@mail.com), I'd love a gift under EUR1000 for my mum's birthday"
244
250
  -> "looking for a gift under EUR1000 for my mum's birthday"`
251
+ }
252
+ }
245
253
  }
246
254
  };
247
- }
248
- return parsed.data;
255
+ });
256
+ return {
257
+ ...rawResult,
258
+ tools
259
+ };
249
260
  }
250
261
  if (request.method === "tools/call") {
251
- const parsedRequest = CallToolRequestSchema.safeParse(request);
252
- if (!parsedRequest.success) return next();
253
- const toolName = parsedRequest.data.params.name;
262
+ if (typeof request.params.name !== "string") return next();
263
+ const toolName = request.params.name;
264
+ const args = isRecord(request.params.arguments) ? request.params.arguments : {};
254
265
  if (toolsFilter && !toolsFilter.has(toolName) || toolName === "send_feedback") {
255
- const args = parsedRequest.data.params.arguments ?? {};
256
266
  if (USER_INTENT_FIELD in args) {
257
- delete args[USER_INTENT_FIELD];
258
- request.params.arguments = args;
267
+ const toolArgs = { ...args };
268
+ delete toolArgs[USER_INTENT_FIELD];
269
+ request.params.arguments = toolArgs;
259
270
  }
260
271
  return next();
261
272
  }
262
273
  const promptField = argumentNameOverride[toolName] ?? USER_INTENT_FIELD;
263
- const args = parsedRequest.data.params.arguments ?? {};
264
274
  const userPrompt = typeof args[promptField] === "string" ? args[promptField] : void 0;
265
275
  const hasUserPrompt = userPrompt != null && userPrompt.length > 0;
266
276
  if (USER_INTENT_FIELD in args) {
267
- delete args[USER_INTENT_FIELD];
268
- request.params.arguments = args;
277
+ const toolArgs = { ...args };
278
+ delete toolArgs[USER_INTENT_FIELD];
279
+ request.params.arguments = toolArgs;
269
280
  }
270
281
  if (hasUserPrompt && options?.handler) try {
271
282
  await options.handler({
272
- toolName: parsedRequest.data.params.name,
283
+ toolName,
273
284
  userPrompt
274
285
  });
275
286
  } catch (error) {
276
287
  console.error("Error calling user prompt handler", error);
277
288
  }
278
289
  const rawResult = await next();
279
- const parsedResult = CallToolResultSchema.safeParse(rawResult);
280
- if (!parsedResult.success) return rawResult;
281
- if (metaKeyName && hasUserPrompt) parsedResult.data._meta = {
282
- ...parsedResult.data._meta,
283
- [metaKeyName]: userPrompt
290
+ if (!isSpecType.CallToolResult(rawResult)) return rawResult;
291
+ if (metaKeyName && hasUserPrompt) return {
292
+ ...rawResult,
293
+ _meta: {
294
+ ...isRecord(rawResult._meta) ? rawResult._meta : {},
295
+ [metaKeyName]: userPrompt
296
+ }
284
297
  };
285
- return parsedResult.data;
298
+ return rawResult;
286
299
  }
287
300
  return next();
288
301
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alpic-ai/insights",
3
- "version": "1.175.2",
3
+ "version": "1.176.0",
4
4
  "description": "User insights middlewares for Alpic-hosted MCP servers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",
@@ -22,7 +22,7 @@
22
22
  "license": "ISC",
23
23
  "peerDependencies": {
24
24
  "react": ">=18.0.0",
25
- "skybridge": "^0.36.3 || ^1.0.0 || ^2.0.0-beta.0"
25
+ "skybridge": "^0.36.3 || ^1.0.0 || ^2.0.0-beta.0 || ^2.0.0"
26
26
  },
27
27
  "peerDependenciesMeta": {
28
28
  "react": {
@@ -33,9 +33,11 @@
33
33
  }
34
34
  },
35
35
  "dependencies": {
36
- "@modelcontextprotocol/sdk": "^1.30.1"
36
+ "@modelcontextprotocol/server": "^2.2.0"
37
37
  },
38
38
  "devDependencies": {
39
+ "@modelcontextprotocol/client": "^2.2.0",
40
+ "@modelcontextprotocol/sdk": "^1.30.1",
39
41
  "@testing-library/dom": "^10.4.2",
40
42
  "@testing-library/react": "^16.3.3",
41
43
  "@total-typescript/tsconfig": "^1.0.4",
@@ -45,7 +47,7 @@
45
47
  "react": "^19.3.0",
46
48
  "react-dom": "^19.3.0",
47
49
  "shx": "^0.4.0",
48
- "skybridge": "^2.0.0",
50
+ "skybridge": "^2.0.1",
49
51
  "tsdown": "^0.23.0",
50
52
  "typescript": "^6.0.3",
51
53
  "vitest": "^5.0.2",