take-blip-mcp 0.1.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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +424 -0
  3. package/dist/blip-client.d.ts +69 -0
  4. package/dist/blip-client.d.ts.map +1 -0
  5. package/dist/blip-client.js +187 -0
  6. package/dist/blip-client.js.map +1 -0
  7. package/dist/config.d.ts +37 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +197 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/env-file.d.ts +16 -0
  12. package/dist/env-file.d.ts.map +1 -0
  13. package/dist/env-file.js +70 -0
  14. package/dist/env-file.js.map +1 -0
  15. package/dist/errors.d.ts +49 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +74 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/flow-map.d.ts +48 -0
  20. package/dist/flow-map.d.ts.map +1 -0
  21. package/dist/flow-map.js +209 -0
  22. package/dist/flow-map.js.map +1 -0
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +143 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/logger.d.ts +18 -0
  28. package/dist/logger.d.ts.map +1 -0
  29. package/dist/logger.js +42 -0
  30. package/dist/logger.js.map +1 -0
  31. package/dist/tools/ai.d.ts +3 -0
  32. package/dist/tools/ai.d.ts.map +1 -0
  33. package/dist/tools/ai.js +51 -0
  34. package/dist/tools/ai.js.map +1 -0
  35. package/dist/tools/broadcast.d.ts +3 -0
  36. package/dist/tools/broadcast.d.ts.map +1 -0
  37. package/dist/tools/broadcast.js +46 -0
  38. package/dist/tools/broadcast.js.map +1 -0
  39. package/dist/tools/buckets.d.ts +3 -0
  40. package/dist/tools/buckets.d.ts.map +1 -0
  41. package/dist/tools/buckets.js +49 -0
  42. package/dist/tools/buckets.js.map +1 -0
  43. package/dist/tools/command.d.ts +3 -0
  44. package/dist/tools/command.d.ts.map +1 -0
  45. package/dist/tools/command.js +41 -0
  46. package/dist/tools/command.js.map +1 -0
  47. package/dist/tools/contacts.d.ts +3 -0
  48. package/dist/tools/contacts.d.ts.map +1 -0
  49. package/dist/tools/contacts.js +119 -0
  50. package/dist/tools/contacts.js.map +1 -0
  51. package/dist/tools/context.d.ts +3 -0
  52. package/dist/tools/context.d.ts.map +1 -0
  53. package/dist/tools/context.js +50 -0
  54. package/dist/tools/context.js.map +1 -0
  55. package/dist/tools/events.d.ts +3 -0
  56. package/dist/tools/events.d.ts.map +1 -0
  57. package/dist/tools/events.js +48 -0
  58. package/dist/tools/events.js.map +1 -0
  59. package/dist/tools/flow-tools.d.ts +3 -0
  60. package/dist/tools/flow-tools.d.ts.map +1 -0
  61. package/dist/tools/flow-tools.js +77 -0
  62. package/dist/tools/flow-tools.js.map +1 -0
  63. package/dist/tools/flow.d.ts +3 -0
  64. package/dist/tools/flow.d.ts.map +1 -0
  65. package/dist/tools/flow.js +33 -0
  66. package/dist/tools/flow.js.map +1 -0
  67. package/dist/tools/index.d.ts +5 -0
  68. package/dist/tools/index.d.ts.map +1 -0
  69. package/dist/tools/index.js +32 -0
  70. package/dist/tools/index.js.map +1 -0
  71. package/dist/tools/messages.d.ts +3 -0
  72. package/dist/tools/messages.d.ts.map +1 -0
  73. package/dist/tools/messages.js +31 -0
  74. package/dist/tools/messages.js.map +1 -0
  75. package/dist/tools/schedules.d.ts +3 -0
  76. package/dist/tools/schedules.d.ts.map +1 -0
  77. package/dist/tools/schedules.js +25 -0
  78. package/dist/tools/schedules.js.map +1 -0
  79. package/dist/tools/shared.d.ts +55 -0
  80. package/dist/tools/shared.d.ts.map +1 -0
  81. package/dist/tools/shared.js +67 -0
  82. package/dist/tools/shared.js.map +1 -0
  83. package/dist/tools/threads.d.ts +3 -0
  84. package/dist/tools/threads.d.ts.map +1 -0
  85. package/dist/tools/threads.js +39 -0
  86. package/dist/tools/threads.js.map +1 -0
  87. package/package.json +60 -0
@@ -0,0 +1,32 @@
1
+ import { registerContactTools } from "./contacts.js";
2
+ import { registerBucketTools } from "./buckets.js";
3
+ import { registerBroadcastTools } from "./broadcast.js";
4
+ import { registerScheduleTools } from "./schedules.js";
5
+ import { registerAiTools } from "./ai.js";
6
+ import { registerMessageTools } from "./messages.js";
7
+ import { registerCommandTool } from "./command.js";
8
+ import { registerContextTools } from "./context.js";
9
+ import { registerThreadTools } from "./threads.js";
10
+ import { registerFlowTools } from "./flow.js";
11
+ import { registerEventTools } from "./events.js";
12
+ import { registerFlowMapTools } from "./flow-tools.js";
13
+ export function registerAllTools(ctx) {
14
+ // Contacts & storage
15
+ registerContactTools(ctx);
16
+ registerBucketTools(ctx);
17
+ // Conversation & journey debugging
18
+ registerThreadTools(ctx);
19
+ registerContextTools(ctx);
20
+ registerFlowTools(ctx);
21
+ registerEventTools(ctx);
22
+ // Flow mapping / multi-flow
23
+ registerFlowMapTools(ctx);
24
+ // Reach & automation
25
+ registerBroadcastTools(ctx);
26
+ registerScheduleTools(ctx);
27
+ registerAiTools(ctx);
28
+ registerMessageTools(ctx);
29
+ // Generic escape hatch
30
+ registerCommandTool(ctx);
31
+ }
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAIvD,MAAM,UAAU,gBAAgB,CAAC,GAAgB;IAC/C,qBAAqB;IACrB,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC1B,mBAAmB,CAAC,GAAG,CAAC,CAAC;IACzB,mCAAmC;IACnC,mBAAmB,CAAC,GAAG,CAAC,CAAC;IACzB,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC1B,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACvB,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACxB,4BAA4B;IAC5B,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC1B,qBAAqB;IACrB,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAC5B,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC3B,eAAe,CAAC,GAAG,CAAC,CAAC;IACrB,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC1B,uBAAuB;IACvB,mBAAmB,CAAC,GAAG,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type ToolContext } from "./shared.js";
2
+ export declare function registerMessageTools(ctx: ToolContext): void;
3
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/tools/messages.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAEpF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAgC3D"}
@@ -0,0 +1,31 @@
1
+ /** Message-sending tool (WRITE / SIDE EFFECT). */
2
+ import { z } from "zod";
3
+ import { attempt, jsonResult, readOnlyNotice } from "./shared.js";
4
+ export function registerMessageTools(ctx) {
5
+ const { server, client, config } = ctx;
6
+ server.registerTool("blip_send_message", {
7
+ title: "Send a message to a real recipient",
8
+ description: "WRITE / SIDE EFFECT: sends a message that REACHES A REAL USER on a real channel " +
9
+ "(e.g. 5511999999999@wa.gw.msging.net). Use with care. Requires BLIP_ALLOW_WRITES=true.",
10
+ inputSchema: {
11
+ to: z
12
+ .string()
13
+ .min(1)
14
+ .describe("Recipient identity, e.g. 5511999999999@wa.gw.msging.net."),
15
+ content: z
16
+ .union([z.string(), z.record(z.string(), z.unknown())])
17
+ .describe("Message content: a string for text/plain, or an object for rich types."),
18
+ type: z
19
+ .string()
20
+ .default("text/plain")
21
+ .describe("Content MIME type. Defaults to text/plain."),
22
+ },
23
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
24
+ }, async (args) => attempt(ctx, async () => {
25
+ if (!config.allowWrites)
26
+ return readOnlyNotice(`send a ${args.type} message to ${args.to}`);
27
+ const res = await client.sendMessage({ to: args.to, content: args.content, type: args.type });
28
+ return jsonResult(res);
29
+ }));
30
+ }
31
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/tools/messages.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAoB,MAAM,aAAa,CAAC;AAEpF,MAAM,UAAU,oBAAoB,CAAC,GAAgB;IACnD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAEvC,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,KAAK,EAAE,oCAAoC;QAC3C,WAAW,EACT,kFAAkF;YAClF,wFAAwF;QAC1F,WAAW,EAAE;YACX,EAAE,EAAE,CAAC;iBACF,MAAM,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CAAC,0DAA0D,CAAC;YACvE,OAAO,EAAE,CAAC;iBACP,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;iBACtD,QAAQ,CAAC,wEAAwE,CAAC;YACrF,IAAI,EAAE,CAAC;iBACJ,MAAM,EAAE;iBACR,OAAO,CAAC,YAAY,CAAC;iBACrB,QAAQ,CAAC,4CAA4C,CAAC;SAC1D;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE;KACxG,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CACb,OAAO,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;QACtB,IAAI,CAAC,MAAM,CAAC,WAAW;YAAE,OAAO,cAAc,CAAC,UAAU,IAAI,CAAC,IAAI,eAAe,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5F,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9F,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC,CAAC,CACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type ToolContext } from "./shared.js";
2
+ export declare function registerScheduleTools(ctx: ToolContext): void;
3
+ //# sourceMappingURL=schedules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedules.d.ts","sourceRoot":"","sources":["../../src/tools/schedules.ts"],"names":[],"mappings":"AAKA,OAAO,EAAuC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAIpF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAuB5D"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Scheduler tools (EXPERIMENTAL, read-only).
3
+ * Target postmaster: postmaster@scheduler.msging.net
4
+ */
5
+ import { z } from "zod";
6
+ import { attempt, buildListQuery, jsonResult } from "./shared.js";
7
+ const SCHEDULER = "postmaster@scheduler.msging.net";
8
+ export function registerScheduleTools(ctx) {
9
+ const { server, client } = ctx;
10
+ server.registerTool("blip_list_schedules", {
11
+ title: "List scheduled messages (experimental)",
12
+ description: "EXPERIMENTAL. List scheduled messages/commands. Read-only. " +
13
+ "If it fails for your account, use blip_command against the scheduler postmaster.",
14
+ inputSchema: {
15
+ skip: z.number().int().min(0).default(0).describe("Pagination offset."),
16
+ take: z.number().int().min(1).max(100).default(20).describe("Items to return (1-100)."),
17
+ },
18
+ annotations: { readOnlyHint: true, openWorldHint: true },
19
+ }, async (args) => attempt(ctx, async () => {
20
+ const uri = `/schedules?${buildListQuery(args.skip, args.take)}`;
21
+ const res = await client.sendCommand({ method: "get", to: SCHEDULER, uri });
22
+ return jsonResult(res.resource ?? res);
23
+ }));
24
+ }
25
+ //# sourceMappingURL=schedules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedules.js","sourceRoot":"","sources":["../../src/tools/schedules.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAoB,MAAM,aAAa,CAAC;AAEpF,MAAM,SAAS,GAAG,iCAAiC,CAAC;AAEpD,MAAM,UAAU,qBAAqB,CAAC,GAAgB;IACpD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,wCAAwC;QAC/C,WAAW,EACT,6DAA6D;YAC7D,kFAAkF;QACpF,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,oBAAoB,CAAC;YACvE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,0BAA0B,CAAC;SACxF;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;KACzD,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CACb,OAAO,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;QACtB,MAAM,GAAG,GAAG,cAAc,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACjE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5E,OAAO,UAAU,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC;IACzC,CAAC,CAAC,CACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Shared helpers and types for tool modules.
3
+ *
4
+ * Conventions:
5
+ * - Every tool handler runs inside {@link attempt}, which converts thrown
6
+ * errors into a redacted `isError` result (no secret ever escapes).
7
+ * - Read tools set `annotations.readOnlyHint`.
8
+ * - Write tools check {@link ToolContext.config}.allowWrites and, when off,
9
+ * return {@link readOnlyNotice} WITHOUT touching the network.
10
+ */
11
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
12
+ import type { BlipClient } from "../blip-client.js";
13
+ import type { BlipConfig, FlowCredential } from "../config.js";
14
+ import type { Logger } from "../logger.js";
15
+ export interface ToolContext {
16
+ server: McpServer;
17
+ /** Client for the default flow. */
18
+ client: BlipClient;
19
+ /** Get (cached) a client for a named flow; default flow when omitted. */
20
+ getClient: (flowName?: string) => BlipClient;
21
+ config: BlipConfig;
22
+ flows: FlowCredential[];
23
+ flowsDir: string;
24
+ logger: Logger;
25
+ /** Secrets to scrub from any text returned to the model. */
26
+ secrets: string[];
27
+ }
28
+ export interface ToolResult {
29
+ content: Array<{
30
+ type: "text";
31
+ text: string;
32
+ }>;
33
+ isError?: boolean;
34
+ [key: string]: unknown;
35
+ }
36
+ export declare function textResult(text: string): ToolResult;
37
+ export declare function jsonResult(data: unknown): ToolResult;
38
+ /** Friendly, non-error notice returned when a write is blocked by the guardrail. */
39
+ export declare function readOnlyNotice(attemptedAction: string): ToolResult;
40
+ export declare function errorResult(err: unknown, secrets: string[]): ToolResult;
41
+ /**
42
+ * Run a tool body, catching any error and returning a safe, redacted result.
43
+ * Keeping `args` out of this wrapper preserves the SDK's type inference.
44
+ */
45
+ export declare function attempt(ctx: ToolContext, body: () => Promise<ToolResult>): Promise<ToolResult>;
46
+ /** Build a Blip OData-style query string with literal $skip/$take/$filter keys. */
47
+ export declare function buildListQuery(skip: number, take: number, filter?: string): string;
48
+ /** Encode a bucket id for a URL path while keeping ':' literal (namespace:key). */
49
+ export declare function encodeBucketId(id: string): string;
50
+ /**
51
+ * Generate likely phoneNumber formats to search a Blip CRM, which stores them
52
+ * inconsistently (+55…, 55…, or local DDD+number). Ordered most-likely-first.
53
+ */
54
+ export declare function phoneCandidates(phone: string): string[];
55
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/tools/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,SAAS,CAAC;IAClB,mCAAmC;IACnC,MAAM,EAAE,UAAU,CAAC;IACnB,yEAAyE;IACzE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,UAAU,CAAC;IAC7C,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEnD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAGpD;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,eAAe,EAAE,MAAM,GAAG,UAAU,CAYlE;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,UAAU,CAMvE;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAOpG;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAIlF;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CASvD"}
@@ -0,0 +1,67 @@
1
+ import { redactSecrets } from "../errors.js";
2
+ export function textResult(text) {
3
+ return { content: [{ type: "text", text }] };
4
+ }
5
+ export function jsonResult(data) {
6
+ const text = typeof data === "string" ? data : JSON.stringify(data, null, 2);
7
+ return textResult(text);
8
+ }
9
+ /** Friendly, non-error notice returned when a write is blocked by the guardrail. */
10
+ export function readOnlyNotice(attemptedAction) {
11
+ return textResult([
12
+ "READ-ONLY MODE is ON, so this action was NOT executed.",
13
+ "",
14
+ `Attempted: ${attemptedAction}`,
15
+ "",
16
+ "This tool has real side effects (it can message actual users or change",
17
+ "stored data). To enable it, set BLIP_ALLOW_WRITES=true and restart the",
18
+ "MCP server.",
19
+ ].join("\n"));
20
+ }
21
+ export function errorResult(err, secrets) {
22
+ const message = err instanceof Error ? err.message : String(err);
23
+ return {
24
+ content: [{ type: "text", text: `ERROR: ${redactSecrets(message, secrets)}` }],
25
+ isError: true,
26
+ };
27
+ }
28
+ /**
29
+ * Run a tool body, catching any error and returning a safe, redacted result.
30
+ * Keeping `args` out of this wrapper preserves the SDK's type inference.
31
+ */
32
+ export async function attempt(ctx, body) {
33
+ try {
34
+ return await body();
35
+ }
36
+ catch (err) {
37
+ ctx.logger.error(`tool error: ${err instanceof Error ? err.message : String(err)}`);
38
+ return errorResult(err, ctx.secrets);
39
+ }
40
+ }
41
+ /** Build a Blip OData-style query string with literal $skip/$take/$filter keys. */
42
+ export function buildListQuery(skip, take, filter) {
43
+ const parts = [`$skip=${skip}`, `$take=${take}`];
44
+ if (filter)
45
+ parts.push(`$filter=${encodeURIComponent(filter)}`);
46
+ return parts.join("&");
47
+ }
48
+ /** Encode a bucket id for a URL path while keeping ':' literal (namespace:key). */
49
+ export function encodeBucketId(id) {
50
+ return encodeURIComponent(id).replace(/%3A/gi, ":");
51
+ }
52
+ /**
53
+ * Generate likely phoneNumber formats to search a Blip CRM, which stores them
54
+ * inconsistently (+55…, 55…, or local DDD+number). Ordered most-likely-first.
55
+ */
56
+ export function phoneCandidates(phone) {
57
+ const digits = phone.replace(/\D/g, "");
58
+ const list = [];
59
+ if (digits.startsWith("55")) {
60
+ list.push(`+${digits}`, digits, digits.slice(2), `+${digits.slice(2)}`);
61
+ }
62
+ else {
63
+ list.push(digits, `+55${digits}`, `55${digits}`, `+${digits}`);
64
+ }
65
+ return [...new Set(list)].filter((v) => v.replace(/\D/g, "").length >= 8);
66
+ }
67
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/tools/shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type ToolContext } from "./shared.js";
2
+ export declare function registerThreadTools(ctx: ToolContext): void;
3
+ //# sourceMappingURL=threads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../../src/tools/threads.ts"],"names":[],"mappings":"AAKA,OAAO,EAAuC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAEpF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CA4C1D"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Conversation history (threads) tools. Read-only.
3
+ * Sent to the bot's own node (no `to`).
4
+ */
5
+ import { z } from "zod";
6
+ import { attempt, buildListQuery, jsonResult } from "./shared.js";
7
+ export function registerThreadTools(ctx) {
8
+ const { server, client } = ctx;
9
+ server.registerTool("blip_list_threads", {
10
+ title: "List recent conversations",
11
+ description: "List recent conversation threads (one per contact). Read-only.",
12
+ inputSchema: {
13
+ skip: z.number().int().min(0).default(0).describe("Pagination offset."),
14
+ take: z.number().int().min(1).max(100).default(20).describe("Threads to return (1-100)."),
15
+ },
16
+ annotations: { readOnlyHint: true, openWorldHint: true },
17
+ }, async (args) => attempt(ctx, async () => {
18
+ const res = await client.sendCommand({
19
+ method: "get",
20
+ uri: `/threads?${buildListQuery(args.skip, args.take)}`,
21
+ });
22
+ return jsonResult(res.resource ?? res);
23
+ }));
24
+ server.registerTool("blip_get_thread", {
25
+ title: "Get a contact's conversation",
26
+ description: "Get the message history exchanged with a contact (what the user said and what the bot " +
27
+ "replied), most recent first. Read-only.",
28
+ inputSchema: {
29
+ identity: z.string().min(1).describe("Contact identity, e.g. 5511999999999@wa.gw.msging.net."),
30
+ take: z.number().int().min(1).max(100).default(20).describe("Messages to return (1-100)."),
31
+ },
32
+ annotations: { readOnlyHint: true, openWorldHint: true },
33
+ }, async (args) => attempt(ctx, async () => {
34
+ const uri = `/threads/${encodeURIComponent(args.identity)}?$take=${args.take}`;
35
+ const res = await client.sendCommand({ method: "get", uri });
36
+ return jsonResult(res.resource ?? res);
37
+ }));
38
+ }
39
+ //# sourceMappingURL=threads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threads.js","sourceRoot":"","sources":["../../src/tools/threads.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAoB,MAAM,aAAa,CAAC;AAEpF,MAAM,UAAU,mBAAmB,CAAC,GAAgB;IAClD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,KAAK,EAAE,2BAA2B;QAClC,WAAW,EAAE,gEAAgE;QAC7E,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,oBAAoB,CAAC;YACvE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,4BAA4B,CAAC;SAC1F;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;KACzD,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CACb,OAAO,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;QACtB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;YACnC,MAAM,EAAE,KAAK;YACb,GAAG,EAAE,YAAY,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE;SACxD,CAAC,CAAC;QACH,OAAO,UAAU,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC;IACzC,CAAC,CAAC,CACL,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,wFAAwF;YACxF,yCAAyC;QAC3C,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wDAAwD,CAAC;YAC9F,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;SAC3F;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;KACzD,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CACb,OAAO,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;QACtB,MAAM,GAAG,GAAG,YAAY,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/E,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAC7D,OAAO,UAAU,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC;IACzC,CAAC,CAAC,CACL,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "take-blip-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for the Take Blip platform (contacts, buckets, broadcast lists, schedules, AI knowledge base) over the Blip HTTP/Command API. stdio transport.",
5
+ "license": "MIT",
6
+ "author": "Michaeltsg",
7
+ "type": "module",
8
+ "bin": {
9
+ "blip-mcp": "dist/index.js"
10
+ },
11
+ "main": "dist/index.js",
12
+ "types": "dist/index.d.ts",
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "engines": {
19
+ "node": ">=18.17"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/Michaeltsg/mcp-blip.git"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/Michaeltsg/mcp-blip/issues"
27
+ },
28
+ "homepage": "https://github.com/Michaeltsg/mcp-blip#readme",
29
+ "scripts": {
30
+ "build": "tsc -p tsconfig.json",
31
+ "dev": "tsx src/index.ts",
32
+ "start": "node dist/index.js",
33
+ "self-test": "node dist/index.js --self-test",
34
+ "map-flow": "node scripts/map-flow.mjs",
35
+ "typecheck": "tsc -p tsconfig.json --noEmit",
36
+ "test": "vitest run",
37
+ "test:watch": "vitest",
38
+ "prepublishOnly": "npm run build",
39
+ "prepare": "npm run build"
40
+ },
41
+ "keywords": [
42
+ "mcp",
43
+ "model-context-protocol",
44
+ "take-blip",
45
+ "blip",
46
+ "chatbot",
47
+ "msging",
48
+ "lime"
49
+ ],
50
+ "dependencies": {
51
+ "@modelcontextprotocol/sdk": "^1.20.0",
52
+ "zod": "^3.25.0"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^20.19.0",
56
+ "tsx": "^4.19.0",
57
+ "typescript": "^5.6.0",
58
+ "vitest": "^2.1.0"
59
+ }
60
+ }