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.
- package/LICENSE +21 -0
- package/README.md +424 -0
- package/dist/blip-client.d.ts +69 -0
- package/dist/blip-client.d.ts.map +1 -0
- package/dist/blip-client.js +187 -0
- package/dist/blip-client.js.map +1 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +197 -0
- package/dist/config.js.map +1 -0
- package/dist/env-file.d.ts +16 -0
- package/dist/env-file.d.ts.map +1 -0
- package/dist/env-file.js +70 -0
- package/dist/env-file.js.map +1 -0
- package/dist/errors.d.ts +49 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +74 -0
- package/dist/errors.js.map +1 -0
- package/dist/flow-map.d.ts +48 -0
- package/dist/flow-map.d.ts.map +1 -0
- package/dist/flow-map.js +209 -0
- package/dist/flow-map.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +143 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +18 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +42 -0
- package/dist/logger.js.map +1 -0
- package/dist/tools/ai.d.ts +3 -0
- package/dist/tools/ai.d.ts.map +1 -0
- package/dist/tools/ai.js +51 -0
- package/dist/tools/ai.js.map +1 -0
- package/dist/tools/broadcast.d.ts +3 -0
- package/dist/tools/broadcast.d.ts.map +1 -0
- package/dist/tools/broadcast.js +46 -0
- package/dist/tools/broadcast.js.map +1 -0
- package/dist/tools/buckets.d.ts +3 -0
- package/dist/tools/buckets.d.ts.map +1 -0
- package/dist/tools/buckets.js +49 -0
- package/dist/tools/buckets.js.map +1 -0
- package/dist/tools/command.d.ts +3 -0
- package/dist/tools/command.d.ts.map +1 -0
- package/dist/tools/command.js +41 -0
- package/dist/tools/command.js.map +1 -0
- package/dist/tools/contacts.d.ts +3 -0
- package/dist/tools/contacts.d.ts.map +1 -0
- package/dist/tools/contacts.js +119 -0
- package/dist/tools/contacts.js.map +1 -0
- package/dist/tools/context.d.ts +3 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +50 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/events.d.ts +3 -0
- package/dist/tools/events.d.ts.map +1 -0
- package/dist/tools/events.js +48 -0
- package/dist/tools/events.js.map +1 -0
- package/dist/tools/flow-tools.d.ts +3 -0
- package/dist/tools/flow-tools.d.ts.map +1 -0
- package/dist/tools/flow-tools.js +77 -0
- package/dist/tools/flow-tools.js.map +1 -0
- package/dist/tools/flow.d.ts +3 -0
- package/dist/tools/flow.d.ts.map +1 -0
- package/dist/tools/flow.js +33 -0
- package/dist/tools/flow.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +32 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/messages.d.ts +3 -0
- package/dist/tools/messages.d.ts.map +1 -0
- package/dist/tools/messages.js +31 -0
- package/dist/tools/messages.js.map +1 -0
- package/dist/tools/schedules.d.ts +3 -0
- package/dist/tools/schedules.d.ts.map +1 -0
- package/dist/tools/schedules.js +25 -0
- package/dist/tools/schedules.js.map +1 -0
- package/dist/tools/shared.d.ts +55 -0
- package/dist/tools/shared.d.ts.map +1 -0
- package/dist/tools/shared.js +67 -0
- package/dist/tools/shared.js.map +1 -0
- package/dist/tools/threads.d.ts +3 -0
- package/dist/tools/threads.d.ts.map +1 -0
- package/dist/tools/threads.js +39 -0
- package/dist/tools/threads.js.map +1 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michaeltsg
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
# blip-mcp
|
|
2
|
+
|
|
3
|
+
An **MCP server** for the [Take Blip](https://www.blip.ai/) platform. It exposes
|
|
4
|
+
your Blip account to any MCP client (Claude Code, Claude Desktop, Cursor, …)
|
|
5
|
+
over the **stdio** transport, on top of the official Blip **HTTP / Command API**.
|
|
6
|
+
|
|
7
|
+
You can:
|
|
8
|
+
|
|
9
|
+
- **Reach your Blip resources** — contacts (CRM), key/value buckets, broadcast
|
|
10
|
+
lists, schedules, and a generic escape hatch for *anything else*.
|
|
11
|
+
- **Ask your bot's AI / knowledge base** a question (`blip_ask_ai`).
|
|
12
|
+
- Send messages and mutate data — gated behind an explicit safety switch so you
|
|
13
|
+
don't message real users by accident.
|
|
14
|
+
|
|
15
|
+
> Built with `@modelcontextprotocol/sdk`, TypeScript (strict), `zod` validation,
|
|
16
|
+
> per-request timeouts, retry-with-backoff, and **secret redaction everywhere**.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
- **Node.js 18.17+** (uses the built-in global `fetch`).
|
|
23
|
+
- A Take Blip bot and its connection credentials (see below).
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
**Three ways for people to run it:**
|
|
30
|
+
|
|
31
|
+
1. **Straight from GitHub (no npm needed — works as soon as the repo is pushed):**
|
|
32
|
+
```bash
|
|
33
|
+
npx -y github:Michaeltsg/mcp-blip --version
|
|
34
|
+
```
|
|
35
|
+
npm clones, builds (via the `prepare` script) and runs it. This is what the
|
|
36
|
+
`.mcp.json` below uses.
|
|
37
|
+
|
|
38
|
+
2. **From npm** (smoothest `npx` UX) — once you publish it. Note: the name
|
|
39
|
+
`blip-mcp` is already taken on npm, so publish under a free name (this package
|
|
40
|
+
is set up as `take-blip-mcp`) and use `npx -y take-blip-mcp`.
|
|
41
|
+
|
|
42
|
+
3. **Clone & build** (for development or a pinned local copy):
|
|
43
|
+
```bash
|
|
44
|
+
git clone https://github.com/Michaeltsg/mcp-blip.git
|
|
45
|
+
cd mcp-blip && npm install && npm run build
|
|
46
|
+
# then point .mcp.json at: node /abs/path/to/mcp-blip/dist/index.js
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
> ⚠️ Do **not** use a bare `npx blip-mcp` — that pulls a different, unrelated
|
|
50
|
+
> package from npm. Always use the `github:Michaeltsg/mcp-blip` form (or your own
|
|
51
|
+
> published name).
|
|
52
|
+
|
|
53
|
+
## Get your Blip credentials (portal step-by-step)
|
|
54
|
+
|
|
55
|
+
1. Open your bot in the Blip portal (**https://blip.ai** → your bot).
|
|
56
|
+
2. Go to **Configurações** (Settings) → **Informações de conexão**
|
|
57
|
+
(Connection information).
|
|
58
|
+
3. Open the **HTTP Endpoints** section.
|
|
59
|
+
4. Copy the value of **"Cabeçalho de autenticação (Authorization)"**
|
|
60
|
+
(Authorization header). It already looks like:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Key bWV1Ym90OmFiYzEyMy4uLg==
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
That whole string is your `BLIP_AUTHORIZATION`.
|
|
67
|
+
5. Your **contract id / shortname** is the bot subdomain — it forms the host
|
|
68
|
+
`https://<contract>.http.msging.net`. Use it as `BLIP_CONTRACT_ID`.
|
|
69
|
+
|
|
70
|
+
> Prefer not to copy the ready-made header? You can instead provide
|
|
71
|
+
> `BLIP_BOT_IDENTIFIER` + `BLIP_ACCESS_KEY` and the server computes
|
|
72
|
+
> `Key base64("<identifier>:<accessKey>")` for you.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Multiple bots (multi-flow)
|
|
77
|
+
|
|
78
|
+
If your account has several bots (a router + sub-bots), add each as a flow.
|
|
79
|
+
For EACH bot, repeat the credential steps above to get its name (the bot Id)
|
|
80
|
+
and an access key:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
BLIP_CONTRACT_ID=mycontract
|
|
84
|
+
BLIP_FLOW_NAME=my-router-bot
|
|
85
|
+
BLIP_AUTHORIZATION="Key ..." # default flow
|
|
86
|
+
|
|
87
|
+
BLIP_FLOW_1_NAME=my-subbot
|
|
88
|
+
BLIP_FLOW_1_AUTHORIZATION="Key ..."
|
|
89
|
+
BLIP_FLOW_2_NAME=another-bot
|
|
90
|
+
BLIP_FLOW_2_AUTHORIZATION="Key ..."
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`blip_list_flows` shows everything configured (names only). When you map a flow,
|
|
94
|
+
the server checks that each key's real identity matches its configured name.
|
|
95
|
+
|
|
96
|
+
## Environment variables
|
|
97
|
+
|
|
98
|
+
| Variable | Required | Default | Description |
|
|
99
|
+
|---|---|---|---|
|
|
100
|
+
| `BLIP_AUTHORIZATION` | one of two modes | — | Ready-made header, e.g. `Key <base64>`. **Preferred.** |
|
|
101
|
+
| `BLIP_BOT_IDENTIFIER` | with access key | — | Bot identifier (credential mode 2). |
|
|
102
|
+
| `BLIP_ACCESS_KEY` | with identifier | — | Access key (credential mode 2). |
|
|
103
|
+
| `BLIP_CONTRACT_ID` | no | — | Contract / shortname → host `https://<id>.http.msging.net`. |
|
|
104
|
+
| `BLIP_SHORTNAME` | no | — | Alias for `BLIP_CONTRACT_ID`. |
|
|
105
|
+
| `BLIP_BASE_URL` | no | derived | Full base URL override (rare). |
|
|
106
|
+
| `BLIP_ALLOW_WRITES` | no | `false` | Master switch for side-effecting tools. |
|
|
107
|
+
| `BLIP_REQUEST_TIMEOUT_MS` | no | `30000` | Per-request timeout (ms). |
|
|
108
|
+
| `BLIP_MAX_RETRIES` | no | `3` | Retries on 429/5xx/network errors. |
|
|
109
|
+
| `BLIP_LOG_LEVEL` | no | `info` | `error` \| `warn` \| `info` \| `debug` (stderr only). |
|
|
110
|
+
| `BLIP_FLOW_NAME` | no | `default` | Friendly name for the default flow (e.g. your bot Id). |
|
|
111
|
+
| `BLIP_FLOW_<n>_*` | no | — | Extra flows: `_NAME`, `_AUTHORIZATION` (or `_BOT_IDENTIFIER`/`_ACCESS_KEY`), `_CONTRACT_ID`. |
|
|
112
|
+
| `BLIP_FLOWS_DIR` | no | `flows` | Where `blip_map_flow` writes componentized docs. |
|
|
113
|
+
| `BLIP_ENV_FILE` | no | `blip.env` | Path to an env file to auto-load (real env always wins). |
|
|
114
|
+
| `BLIP_DATA_DIR` | no | `.mcp-blip` | Base folder for everything blip-mcp writes. |
|
|
115
|
+
|
|
116
|
+
If no contract/host is given, the server falls back to the shared host
|
|
117
|
+
`https://http.msging.net` (for accounts not in an organization).
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Safety: read-only by default
|
|
122
|
+
|
|
123
|
+
Every tool that **sends a message** or **mutates data** is gated by
|
|
124
|
+
`BLIP_ALLOW_WRITES` (default `false`). While off:
|
|
125
|
+
|
|
126
|
+
- `blip_send_message`, `blip_set_bucket`, `blip_set_contact`,
|
|
127
|
+
`blip_delete_contact` return a **"READ-ONLY MODE"** notice instead of running.
|
|
128
|
+
- `blip_command` refuses any method other than `get`.
|
|
129
|
+
|
|
130
|
+
Start in read-only mode while you explore. Set `BLIP_ALLOW_WRITES=true` (and
|
|
131
|
+
restart the server) only when you're ready to cause real side effects.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Configure your MCP client
|
|
136
|
+
|
|
137
|
+
### Project file `.mcp.json` (recommended)
|
|
138
|
+
|
|
139
|
+
Drop a `.mcp.json` at your project root (any MCP client picks it up). Keep your
|
|
140
|
+
secrets in a gitignored `blip.env` and point the server at it:
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"mcpServers": {
|
|
145
|
+
"blip": {
|
|
146
|
+
"command": "npx",
|
|
147
|
+
"args": ["-y", "github:Michaeltsg/mcp-blip"],
|
|
148
|
+
"env": { "BLIP_ENV_FILE": "blip.env", "BLIP_ALLOW_WRITES": "false" }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Then create `blip.env` next to it with your credentials. The server also
|
|
155
|
+
auto-loads `./blip.env` even if you omit `BLIP_ENV_FILE`. See
|
|
156
|
+
[.mcp.json.example](.mcp.json.example). (Cursor uses `.cursor/mcp.json`, same shape.)
|
|
157
|
+
|
|
158
|
+
### Claude Code
|
|
159
|
+
|
|
160
|
+
Local build (works today):
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
claude mcp add blip -s user \
|
|
164
|
+
-e BLIP_AUTHORIZATION="Key xxxxx" \
|
|
165
|
+
-e BLIP_CONTRACT_ID="meu-contrato" \
|
|
166
|
+
-e BLIP_ALLOW_WRITES="false" \
|
|
167
|
+
-- node /absolute/path/to/mcp-blip/dist/index.js
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
After publishing to npm, the same with `npx`:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
claude mcp add blip -s user \
|
|
174
|
+
-e BLIP_AUTHORIZATION="Key xxxxx" \
|
|
175
|
+
-e BLIP_CONTRACT_ID="meu-contrato" \
|
|
176
|
+
-e BLIP_ALLOW_WRITES="false" \
|
|
177
|
+
-- npx -y github:Michaeltsg/mcp-blip
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Claude Desktop / Cursor (JSON)
|
|
181
|
+
|
|
182
|
+
Add to `mcpServers` (Claude Desktop: `claude_desktop_config.json`):
|
|
183
|
+
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"mcpServers": {
|
|
187
|
+
"blip": {
|
|
188
|
+
"command": "node",
|
|
189
|
+
"args": ["/absolute/path/to/mcp-blip/dist/index.js"],
|
|
190
|
+
"env": {
|
|
191
|
+
"BLIP_AUTHORIZATION": "Key xxxxx",
|
|
192
|
+
"BLIP_CONTRACT_ID": "meu-contrato",
|
|
193
|
+
"BLIP_ALLOW_WRITES": "false"
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Once published, swap `command`/`args` for `"command": "npx", "args": ["-y", "github:Michaeltsg/mcp-blip"]`.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Validate credentials (self-test)
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
BLIP_AUTHORIZATION="Key xxxxx" BLIP_CONTRACT_ID="meu-contrato" \
|
|
208
|
+
node dist/index.js --self-test
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
It performs a tiny `GET /contacts?$take=1` and prints a **masked** config
|
|
212
|
+
summary plus OK/FAILED. Your token is never printed.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Tools
|
|
217
|
+
|
|
218
|
+
### Read (safe, always available)
|
|
219
|
+
|
|
220
|
+
| Tool | What it does |
|
|
221
|
+
|---|---|
|
|
222
|
+
| `blip_list_contacts` | List CRM contacts. Args: `skip`, `take` (1–100), `filter` (OData). |
|
|
223
|
+
| `blip_get_contact` | Get one contact by `identity`. |
|
|
224
|
+
| `blip_find_contact_by_phone` | Find a contact by phone (tries 55/+/local formats). |
|
|
225
|
+
| `blip_get_bucket` | Read a value from key/value storage by `id`. |
|
|
226
|
+
| `blip_list_broadcast_lists` | List broadcast/distribution lists. *(experimental)* |
|
|
227
|
+
| `blip_list_recipients` | List recipients of a broadcast `list`. *(experimental)* |
|
|
228
|
+
| `blip_list_schedules` | List scheduled messages/commands. *(experimental)* |
|
|
229
|
+
| `blip_ask_ai` | Ask your bot's AI. `mode="knowledge"` (knowledge base) or `"intent"` (intentions/entities). *(experimental)* |
|
|
230
|
+
| `blip_command` | **Escape hatch:** run any `get` command (and writes when enabled). |
|
|
231
|
+
| `blip_get_thread` | Conversation history with a contact (what was said). |
|
|
232
|
+
| `blip_list_threads` | Recent conversations. |
|
|
233
|
+
| `blip_get_context` | A contact's **context variables** — the values flow rules evaluate against. *(experimental)* |
|
|
234
|
+
| `blip_get_context_variable` | One context variable; `stateid@{flowId}` = where the contact is in a flow. *(experimental)* |
|
|
235
|
+
| `blip_get_flow` | The published flow definition (blocks + conditions/rules). *(experimental)* |
|
|
236
|
+
| `blip_list_event_categories` | Event categories your flows track. *(experimental)* |
|
|
237
|
+
| `blip_get_event_track` | Tracked events for a category (optional date range). *(experimental)* |
|
|
238
|
+
| `blip_list_flows` | List configured flows (names/hosts only, never secrets). |
|
|
239
|
+
| `blip_map_flow` | Read a flow and write componentized docs (index + one file per block) under `flows/<flow>/`. |
|
|
240
|
+
|
|
241
|
+
### Write (require `BLIP_ALLOW_WRITES=true`)
|
|
242
|
+
|
|
243
|
+
| Tool | Side effect |
|
|
244
|
+
|---|---|
|
|
245
|
+
| `blip_send_message` | **Sends a message to a real recipient.** |
|
|
246
|
+
| `blip_set_bucket` | Writes a value to storage. |
|
|
247
|
+
| `blip_set_contact` | Creates/updates a contact (`merge`). |
|
|
248
|
+
| `blip_delete_contact` | Permanently deletes a contact. |
|
|
249
|
+
|
|
250
|
+
### Examples (natural language to your MCP client)
|
|
251
|
+
|
|
252
|
+
- "List the first 5 Blip contacts that came from WhatsApp."
|
|
253
|
+
→ `blip_list_contacts { take: 5, filter: "substringof('WhatsApp',source)" }`
|
|
254
|
+
- "Ask my bot's knowledge base: what are the opening hours?"
|
|
255
|
+
→ `blip_ask_ai { text: "what are the opening hours?", mode: "knowledge" }`
|
|
256
|
+
- "Read bucket `onboarding_state`."
|
|
257
|
+
→ `blip_get_bucket { id: "onboarding_state" }`
|
|
258
|
+
- "Run a raw command: get the active message templates."
|
|
259
|
+
→ `blip_command { method: "get", uri: "/templates" }`
|
|
260
|
+
- (writes on) "Send 'Hi!' to 5511999999999 on WhatsApp."
|
|
261
|
+
→ `blip_send_message { to: "5511999999999@wa.gw.msging.net", content: "Hi!" }`
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Experimental / unverified endpoints
|
|
266
|
+
|
|
267
|
+
These were implemented from Blip's documented patterns and the official C# SDK,
|
|
268
|
+
but **not verified against a live account**, so they're marked *experimental*:
|
|
269
|
+
|
|
270
|
+
- **AI / knowledge base** (`blip_ask_ai`): `postmaster@ai.msging.net`,
|
|
271
|
+
`SET /content/analysis` (knowledge) and `SET /analysis` (intent), resource
|
|
272
|
+
type `application/vnd.iris.ai.analysis-request+json`. The exact content
|
|
273
|
+
contract can vary per account.
|
|
274
|
+
- **Broadcast lists** (`blip_list_broadcast_lists`, `blip_list_recipients`):
|
|
275
|
+
`postmaster@broadcast.msging.net`, `/lists` and `/lists/{id}/recipients`.
|
|
276
|
+
- **Schedules** (`blip_list_schedules`): `postmaster@scheduler.msging.net`,
|
|
277
|
+
`/schedules`.
|
|
278
|
+
|
|
279
|
+
If any of these don't match your account, use `blip_command` with the exact
|
|
280
|
+
`to`/`uri`/`resource` from your Blip docs.
|
|
281
|
+
|
|
282
|
+
> **Buckets note:** bucket commands are sent to your bot's **own node** (no
|
|
283
|
+
> `to`/postmaster), which is the correct Blip behavior — this differs from the
|
|
284
|
+
> `postmaster@msging.net` mentioned in some notes. Override with `blip_command`
|
|
285
|
+
> if your setup needs it.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Debugging "why did this contact take this path?"
|
|
290
|
+
|
|
291
|
+
Blip's HTTP API does not expose a turn-by-turn condition-evaluation log, but you
|
|
292
|
+
can reconstruct the decision from a few reads and let your MCP client diff them:
|
|
293
|
+
|
|
294
|
+
1. `blip_get_flow` — the exact condition/rule on the branch in question.
|
|
295
|
+
2. `blip_get_context { identity }` — the contact's actual variable values that the
|
|
296
|
+
rule evaluated against (and `stateid@{flowId}` for where they are now).
|
|
297
|
+
3. `blip_get_thread { identity }` — what the user actually said / chose.
|
|
298
|
+
4. (optional) `blip_get_event_track` — milestones the flow logged.
|
|
299
|
+
|
|
300
|
+
Then ask, e.g.: *"Why did 5511999999999 enter the Support flow instead of Sales?"*
|
|
301
|
+
Your client reads the rule, sees (say) `origem = WhatsApp-Ads` in the context and
|
|
302
|
+
explains the match — or shows that the variable the rule needed was empty.
|
|
303
|
+
|
|
304
|
+
> These journey tools are **experimental** and sent to your bot's own node (no
|
|
305
|
+
> postmaster). The richest turn-by-turn view is still the portal's conversation
|
|
306
|
+
> history / Builder debug tool; the API gives you the raw materials to reconstruct it.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
## Multiple flows & mapping a flow into docs
|
|
310
|
+
|
|
311
|
+
`blip.env` (or your MCP env) can hold several flows (Blip bots) — a parent
|
|
312
|
+
router plus its subflows, each with its own access key:
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
BLIP_CONTRACT_ID=mycontract
|
|
316
|
+
BLIP_FLOW_NAME=my-router
|
|
317
|
+
BLIP_AUTHORIZATION="Key ..." # default flow (the parent / router)
|
|
318
|
+
|
|
319
|
+
BLIP_FLOW_1_NAME=fila-identificada
|
|
320
|
+
BLIP_FLOW_1_AUTHORIZATION="Key ..." # a subflow bot (its own access key)
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
- `blip_list_flows` shows what's configured (never the secrets).
|
|
324
|
+
- `blip_map_flow { flow: "my-router" }` reads the flow and writes a
|
|
325
|
+
**componentized** doc tree under `flows/<flow>/`, so a large flow stays browsable:
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
.mcp-blip/flows/my-router/
|
|
329
|
+
index.md overview + routing graph (block -> who it connects to)
|
|
330
|
+
index.json machine-readable map
|
|
331
|
+
blocks/
|
|
332
|
+
inicio.md what the block does (messages, HTTP/script actions) + its rules
|
|
333
|
+
roteador-de-mensagem.md
|
|
334
|
+
...
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Re-run after editing the flow in Builder (idempotent). CLI: `npm run map-flow -- --flow my-router`.
|
|
338
|
+
The `flows/` folder is gitignored by default (business logic). Mapping a subflow's
|
|
339
|
+
internals needs that subflow's own access key configured as an extra flow.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Where blip-mcp writes (`.mcp-blip/`)
|
|
344
|
+
|
|
345
|
+
Everything the server discovers or documents goes under a single `.mcp-blip/`
|
|
346
|
+
folder in your project root — e.g. `blip_map_flow` writes to
|
|
347
|
+
`.mcp-blip/flows/<flow>/`. This keeps blip-mcp's output namespaced and out of
|
|
348
|
+
the way when you connect it inside a new or existing repo.
|
|
349
|
+
|
|
350
|
+
Add it (and `blip.env`) to your project's `.gitignore`:
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
.mcp-blip/
|
|
354
|
+
blip.env
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
Override the base with `BLIP_DATA_DIR`.
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## How it works
|
|
362
|
+
|
|
363
|
+
Commands `POST` to `https://<contract>.http.msging.net/commands` with header
|
|
364
|
+
`Authorization: Key <token>` and a LIME-style envelope:
|
|
365
|
+
|
|
366
|
+
```json
|
|
367
|
+
{
|
|
368
|
+
"id": "<uuid>",
|
|
369
|
+
"to": "postmaster@crm.msging.net",
|
|
370
|
+
"method": "get",
|
|
371
|
+
"uri": "/contacts?$skip=0&$take=20"
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
A response with `status: "failure"` is converted into a clear error carrying
|
|
376
|
+
Blip's `reason.code` and `reason.description`. Messages `POST` to `/messages`.
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## Publishing to npm
|
|
381
|
+
|
|
382
|
+
A GitHub Action (`.github/workflows/publish.yml`) publishes the package whenever
|
|
383
|
+
you create a GitHub Release. One-time setup:
|
|
384
|
+
|
|
385
|
+
1. Create an npm account + an **automation** access token (npmjs.com → Access
|
|
386
|
+
Tokens → Generate New Token → Automation).
|
|
387
|
+
2. Add it as a repo secret named `NPM_TOKEN`:
|
|
388
|
+
```bash
|
|
389
|
+
gh secret set NPM_TOKEN # paste the token when prompted
|
|
390
|
+
```
|
|
391
|
+
(or GitHub → Settings → Secrets and variables → Actions).
|
|
392
|
+
3. Create a release — the Action runs typecheck + tests, builds, and publishes:
|
|
393
|
+
```bash
|
|
394
|
+
gh release create v0.1.0 --generate-notes
|
|
395
|
+
```
|
|
396
|
+
For later versions, bump first: `npm version patch && git push --follow-tags`,
|
|
397
|
+
then create the matching release.
|
|
398
|
+
|
|
399
|
+
The first publish claims the `take-blip-mcp` name. After that, users install with
|
|
400
|
+
`npx -y take-blip-mcp`. (A `ci.yml` workflow runs tests on every push/PR.)
|
|
401
|
+
|
|
402
|
+
## Development
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
npm run dev # run from source via tsx
|
|
406
|
+
npm run build # compile to dist/
|
|
407
|
+
npm run typecheck # tsc --noEmit (strict)
|
|
408
|
+
npm test # vitest (header assembly, sendCommand, failure, guardrails)
|
|
409
|
+
npm run self-test # build first, then validate credentials
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Security notes
|
|
415
|
+
|
|
416
|
+
- Credentials come **only** from environment variables; nothing is hardcoded.
|
|
417
|
+
- The authorization header value is **never logged**. All logs go to **stderr**
|
|
418
|
+
(stdout is reserved for the MCP protocol) and pass through a redactor that
|
|
419
|
+
scrubs the token and any `Key …` pattern — even from error bodies.
|
|
420
|
+
- Writes are off by default (`BLIP_ALLOW_WRITES=false`).
|
|
421
|
+
|
|
422
|
+
## License
|
|
423
|
+
|
|
424
|
+
MIT © Michaeltsg. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Logger } from "./logger.js";
|
|
2
|
+
export type CommandMethod = "get" | "set" | "merge" | "delete";
|
|
3
|
+
export interface SendCommandParams {
|
|
4
|
+
method: CommandMethod;
|
|
5
|
+
uri: string;
|
|
6
|
+
to?: string | undefined;
|
|
7
|
+
type?: string | undefined;
|
|
8
|
+
resource?: unknown;
|
|
9
|
+
}
|
|
10
|
+
export interface SendMessageParams {
|
|
11
|
+
to: string;
|
|
12
|
+
content: unknown;
|
|
13
|
+
type?: string | undefined;
|
|
14
|
+
}
|
|
15
|
+
/** Shape of a Blip command response envelope (only the fields we rely on). */
|
|
16
|
+
export interface BlipCommandResponse {
|
|
17
|
+
id?: string;
|
|
18
|
+
from?: string;
|
|
19
|
+
to?: string;
|
|
20
|
+
method?: string;
|
|
21
|
+
status?: "success" | "failure" | "pending";
|
|
22
|
+
uri?: string;
|
|
23
|
+
type?: string;
|
|
24
|
+
resource?: unknown;
|
|
25
|
+
reason?: {
|
|
26
|
+
code?: number;
|
|
27
|
+
description?: string;
|
|
28
|
+
};
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
}
|
|
31
|
+
type FetchLike = (input: string, init: RequestInit) => Promise<Response>;
|
|
32
|
+
export interface BlipClientOptions {
|
|
33
|
+
baseUrl: string;
|
|
34
|
+
authorization: string;
|
|
35
|
+
timeoutMs?: number;
|
|
36
|
+
maxRetries?: number;
|
|
37
|
+
fetchImpl?: FetchLike;
|
|
38
|
+
sleepImpl?: (ms: number) => Promise<void>;
|
|
39
|
+
logger?: Logger;
|
|
40
|
+
}
|
|
41
|
+
export declare class BlipClient {
|
|
42
|
+
private readonly baseUrl;
|
|
43
|
+
private readonly authorization;
|
|
44
|
+
private readonly timeoutMs;
|
|
45
|
+
private readonly maxRetries;
|
|
46
|
+
private readonly fetchImpl;
|
|
47
|
+
private readonly sleep;
|
|
48
|
+
private readonly logger;
|
|
49
|
+
private readonly secrets;
|
|
50
|
+
constructor(options: BlipClientOptions);
|
|
51
|
+
/** Send a command to `/commands` and return the response envelope. */
|
|
52
|
+
sendCommand(params: SendCommandParams): Promise<BlipCommandResponse>;
|
|
53
|
+
/** Send a message to `/messages`. Blip replies 2xx with no useful body. */
|
|
54
|
+
sendMessage(params: SendMessageParams): Promise<{
|
|
55
|
+
status: "accepted";
|
|
56
|
+
id: string;
|
|
57
|
+
}>;
|
|
58
|
+
private post;
|
|
59
|
+
private fetchWithTimeout;
|
|
60
|
+
private isRetryableStatus;
|
|
61
|
+
private isNetworkError;
|
|
62
|
+
private backoffDelay;
|
|
63
|
+
private readJson;
|
|
64
|
+
private errorExcerpt;
|
|
65
|
+
private safeText;
|
|
66
|
+
private drain;
|
|
67
|
+
}
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=blip-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blip-client.d.ts","sourceRoot":"","sources":["../src/blip-client.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE/D,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,8EAA8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,KAAK,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEzE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;gBAEvB,OAAO,EAAE,iBAAiB;IAmBtC,sEAAsE;IAChE,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAyB1E,2EAA2E;IACrE,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,UAAU,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;YAe3E,IAAI;YA6CJ,gBAAgB;IAa9B,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,YAAY;YAeN,QAAQ;YAUR,YAAY;YAKZ,QAAQ;YAQR,KAAK;CAGpB"}
|