@iterable/mcp 1.0.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 +318 -0
- package/TOOLS.md +133 -0
- package/dist/client-detection.d.ts +7 -0
- package/dist/client-detection.d.ts.map +1 -0
- package/dist/client-detection.js +22 -0
- package/dist/client-detection.js.map +1 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +74 -0
- package/dist/config.js.map +1 -0
- package/dist/http-headers.d.ts +5 -0
- package/dist/http-headers.d.ts.map +1 -0
- package/dist/http-headers.js +5 -0
- package/dist/http-headers.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/install.d.ts +41 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +725 -0
- package/dist/install.js.map +1 -0
- package/dist/key-manager.d.ts +236 -0
- package/dist/key-manager.d.ts.map +1 -0
- package/dist/key-manager.js +776 -0
- package/dist/key-manager.js.map +1 -0
- package/dist/keys-cli.d.ts +8 -0
- package/dist/keys-cli.d.ts.map +1 -0
- package/dist/keys-cli.js +487 -0
- package/dist/keys-cli.js.map +1 -0
- package/dist/prompts.d.ts +15 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +66 -0
- package/dist/prompts.js.map +1 -0
- package/dist/schema-utils.d.ts +22 -0
- package/dist/schema-utils.d.ts.map +1 -0
- package/dist/schema-utils.js +65 -0
- package/dist/schema-utils.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +172 -0
- package/dist/server.js.map +1 -0
- package/dist/shutdown.d.ts +5 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +68 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/tool-filter.d.ts +19 -0
- package/dist/tool-filter.d.ts.map +1 -0
- package/dist/tool-filter.js +144 -0
- package/dist/tool-filter.js.map +1 -0
- package/dist/tools/campaigns.d.ts +7 -0
- package/dist/tools/campaigns.d.ts.map +1 -0
- package/dist/tools/campaigns.js +88 -0
- package/dist/tools/campaigns.js.map +1 -0
- package/dist/tools/catalogs.d.ts +7 -0
- package/dist/tools/catalogs.d.ts.map +1 -0
- package/dist/tools/catalogs.js +85 -0
- package/dist/tools/catalogs.js.map +1 -0
- package/dist/tools/events.d.ts +7 -0
- package/dist/tools/events.d.ts.map +1 -0
- package/dist/tools/events.js +34 -0
- package/dist/tools/events.js.map +1 -0
- package/dist/tools/experiments.d.ts +7 -0
- package/dist/tools/experiments.d.ts.map +1 -0
- package/dist/tools/experiments.js +16 -0
- package/dist/tools/experiments.js.map +1 -0
- package/dist/tools/export.d.ts +7 -0
- package/dist/tools/export.d.ts.map +1 -0
- package/dist/tools/export.js +41 -0
- package/dist/tools/export.js.map +1 -0
- package/dist/tools/index.d.ts +19 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +44 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/journeys.d.ts +10 -0
- package/dist/tools/journeys.d.ts.map +1 -0
- package/dist/tools/journeys.js +25 -0
- package/dist/tools/journeys.js.map +1 -0
- package/dist/tools/lists.d.ts +7 -0
- package/dist/tools/lists.d.ts.map +1 -0
- package/dist/tools/lists.js +58 -0
- package/dist/tools/lists.js.map +1 -0
- package/dist/tools/messaging.d.ts +11 -0
- package/dist/tools/messaging.d.ts.map +1 -0
- package/dist/tools/messaging.js +103 -0
- package/dist/tools/messaging.js.map +1 -0
- package/dist/tools/snippets.d.ts +7 -0
- package/dist/tools/snippets.d.ts.map +1 -0
- package/dist/tools/snippets.js +46 -0
- package/dist/tools/snippets.js.map +1 -0
- package/dist/tools/subscriptions.d.ts +4 -0
- package/dist/tools/subscriptions.d.ts.map +1 -0
- package/dist/tools/subscriptions.js +37 -0
- package/dist/tools/subscriptions.js.map +1 -0
- package/dist/tools/templates.d.ts +7 -0
- package/dist/tools/templates.d.ts.map +1 -0
- package/dist/tools/templates.js +118 -0
- package/dist/tools/templates.js.map +1 -0
- package/dist/tools/users.d.ts +10 -0
- package/dist/tools/users.d.ts.map +1 -0
- package/dist/tools/users.js +74 -0
- package/dist/tools/users.js.map +1 -0
- package/dist/tools/webhooks.d.ts +7 -0
- package/dist/tools/webhooks.d.ts.map +1 -0
- package/dist/tools/webhooks.js +22 -0
- package/dist/tools/webhooks.js.map +1 -0
- package/dist/utils/cli-env.d.ts +11 -0
- package/dist/utils/cli-env.d.ts.map +1 -0
- package/dist/utils/cli-env.js +32 -0
- package/dist/utils/cli-env.js.map +1 -0
- package/dist/utils/endpoint-prompt.d.ts +14 -0
- package/dist/utils/endpoint-prompt.d.ts.map +1 -0
- package/dist/utils/endpoint-prompt.js +73 -0
- package/dist/utils/endpoint-prompt.js.map +1 -0
- package/dist/utils/formatting.d.ts +10 -0
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/utils/formatting.js +12 -0
- package/dist/utils/formatting.js.map +1 -0
- package/dist/utils/password-prompt.d.ts +19 -0
- package/dist/utils/password-prompt.d.ts.map +1 -0
- package/dist/utils/password-prompt.js +37 -0
- package/dist/utils/password-prompt.js.map +1 -0
- package/dist/utils/sanitize.d.ts +13 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +23 -0
- package/dist/utils/sanitize.js.map +1 -0
- package/dist/utils/tool-config.d.ts +13 -0
- package/dist/utils/tool-config.d.ts.map +1 -0
- package/dist/utils/tool-config.js +45 -0
- package/dist/utils/tool-config.js.map +1 -0
- package/dist/utils/ui.d.ts +90 -0
- package/dist/utils/ui.d.ts.map +1 -0
- package/dist/utils/ui.js +298 -0
- package/dist/utils/ui.js.map +1 -0
- package/dist/utils/url.d.ts +20 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +53 -0
- package/dist/utils/url.js.map +1 -0
- package/package.json +105 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Greg Methvin
|
|
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,318 @@
|
|
|
1
|
+
# Iterable MCP Server
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server for interacting with the Iterable marketing automation platform.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
## Security & Defaults
|
|
8
|
+
|
|
9
|
+
- API keys are stored in macOS Keychain (values), and metadata lives in `~/.iterable-mcp/keys.json` with 0600 permissions. No plaintext keys on disk.
|
|
10
|
+
- PII access, write operations, and message sends are disabled by default for safety.
|
|
11
|
+
- Enable explicitly via envs:
|
|
12
|
+
- `ITERABLE_USER_PII=true`
|
|
13
|
+
- `ITERABLE_ENABLE_WRITES=true`
|
|
14
|
+
- `ITERABLE_ENABLE_SENDS=true` (requires writes enabled as well)
|
|
15
|
+
- Custom endpoints must be HTTPS and require confirmation when not an `*.iterable.com` domain.
|
|
16
|
+
- Logs avoid printing headers/bodies and sanitize 32‑character hex keys.
|
|
17
|
+
|
|
18
|
+
## Troubleshooting
|
|
19
|
+
|
|
20
|
+
- Node.js: v18+ recommended. You’ll see a warning on older runtimes.
|
|
21
|
+
- Claude CLI missing: install `claude` CLI, then re-run `iterable-mcp setup --claude-code`.
|
|
22
|
+
- Keychain issues: Ensure Keychain is available; re-run setup. Stale locks are auto‑recovered.
|
|
23
|
+
- Emojis too noisy? Set `ITERABLE_UI_ICONS=false` (default). Enable with `ITERABLE_UI_ICONS=true`.
|
|
24
|
+
|
|
25
|
+
### Install using npx
|
|
26
|
+
|
|
27
|
+
**Prerequisites:**
|
|
28
|
+
- Node.js >= 18
|
|
29
|
+
- Iterable API key
|
|
30
|
+
- macOS (for secure keychain storage; Windows/Linux use environment variables)
|
|
31
|
+
|
|
32
|
+
**Note:** On macOS, API keys are stored securely in Keychain. The setup wizard will prompt you to name your key and store it automatically.
|
|
33
|
+
|
|
34
|
+
Click the button to install to Cursor:
|
|
35
|
+
|
|
36
|
+
<a href="https://raw.githubusercontent.com/iterable/mcp-server/gh-pages/docs/cursor-install.html"><img alt="Add Iterable MCP server to Cursor" src="https://cursor.com/deeplink/mcp-install-dark.png" style="max-height: 16px;"></a>
|
|
37
|
+
|
|
38
|
+
If the button doesn't work, install the MCP server for your preferred AI tool(s):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Configure your preferred AI tool(s)
|
|
42
|
+
npx @iterable/mcp setup --cursor --claude-desktop --claude-code
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
#### Advanced permissions (`--advanced`)
|
|
46
|
+
|
|
47
|
+
By default, the setup wizard configures the server in a safe, read‑only mode (no PII tools, no writes, no sends). To selectively enable elevated capabilities during setup, pass `--advanced`:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Example: enable advanced selection when configuring Cursor
|
|
51
|
+
npx @iterable/mcp setup --cursor --advanced
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
You will be prompted to toggle these flags:
|
|
55
|
+
- User PII (ITERABLE_USER_PII)
|
|
56
|
+
- Writes (ITERABLE_ENABLE_WRITES)
|
|
57
|
+
- Sends (ITERABLE_ENABLE_SENDS)
|
|
58
|
+
|
|
59
|
+
Notes:
|
|
60
|
+
- Sends are only allowed when both Writes and Sends are enabled.
|
|
61
|
+
- When you select an existing macOS Keychain key, the chosen flags are saved with that key for future sessions.
|
|
62
|
+
- Prompts exposed to AI tools are generated from read‑only tools for extra safety, regardless of advanced flags.
|
|
63
|
+
|
|
64
|
+
### Install package globally using pnpm
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pnpm add -g @iterable/mcp
|
|
68
|
+
iterable-mcp setup --cursor --claude-desktop --claude-code
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Note:** The setup command automatically configures the correct command path.
|
|
72
|
+
|
|
73
|
+
### Install from Source
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
git clone https://github.com/iterable/mcp-server.git
|
|
77
|
+
cd mcp-server
|
|
78
|
+
pnpm install-dev:cursor # or install-dev:claude-desktop or install-dev:claude-code
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Claude Code
|
|
82
|
+
|
|
83
|
+
The `setup --claude-code` command automatically configures Claude Code by running `claude mcp add` for you and stores your API key securely in macOS Keychain.
|
|
84
|
+
|
|
85
|
+
Alternatively, you can run it manually:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Manual installation (alternative to setup --claude-code)
|
|
89
|
+
# First, add your API key to the keychain (interactive prompts)
|
|
90
|
+
iterable-mcp keys add
|
|
91
|
+
|
|
92
|
+
# Then configure Claude Code
|
|
93
|
+
claude mcp add iterable -- npx -y @iterable/mcp
|
|
94
|
+
|
|
95
|
+
# Verify it was added
|
|
96
|
+
claude mcp list
|
|
97
|
+
|
|
98
|
+
# Optional: Configure privacy settings
|
|
99
|
+
claude mcp add iterable \
|
|
100
|
+
--env ITERABLE_USER_PII=false \
|
|
101
|
+
--env ITERABLE_ENABLE_WRITES=false \
|
|
102
|
+
-- npx -y @iterable/mcp
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
If you have already configured Claude Desktop successfully, you can run this command to copy your MCP server settings to Claude Code:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
claude mcp add-from-claude-desktop
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Note:** All of the above `claude mcp` commands will save the settings to `~/.claude.json`, which makes the configured MCP servers available across all projects. For shared, project-specific MCP configs, create a `.mcp.json` file in the root of your project.
|
|
112
|
+
|
|
113
|
+
For more information, see the [Claude Code MCP documentation](https://docs.claude.com/en/docs/claude-code/mcp).
|
|
114
|
+
|
|
115
|
+
### Manual Configuration (Cursor & Claude Desktop)
|
|
116
|
+
|
|
117
|
+
The above commands will automatically configure your AI tool to use the MCP server by editing the appropriate configuration file, but you can also manually edit the appropriate configuration file:
|
|
118
|
+
- **Claude Desktop:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
119
|
+
- **Cursor:** `~/.cursor/mcp.json`
|
|
120
|
+
|
|
121
|
+
**macOS (with Keychain):**
|
|
122
|
+
```bash
|
|
123
|
+
# First, add your API key to the keychain (interactive prompts)
|
|
124
|
+
iterable-mcp keys add
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Then edit your config file:
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"mcpServers": {
|
|
131
|
+
"iterable": {
|
|
132
|
+
"command": "npx",
|
|
133
|
+
"args": ["-y", "@iterable/mcp"]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Note: No `env` needed on macOS - API key and base URL are loaded from Keychain.
|
|
140
|
+
|
|
141
|
+
**Windows/Linux (using environment variable):**
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"mcpServers": {
|
|
145
|
+
"iterable": {
|
|
146
|
+
"command": "npx",
|
|
147
|
+
"args": ["-y", "@iterable/mcp"],
|
|
148
|
+
"env": {
|
|
149
|
+
"ITERABLE_API_KEY": "your-iterable-api-key-here",
|
|
150
|
+
"ITERABLE_BASE_URL": "https://api.iterable.com"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Using Custom Node/NPX Paths:**
|
|
158
|
+
|
|
159
|
+
If you need to use a custom path to node or npx (for example, if they are not in your PATH), you can set environment variables before running the setup command:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# Set custom paths
|
|
163
|
+
export ITERABLE_MCP_NODE_PATH="/path/to/custom/node"
|
|
164
|
+
export ITERABLE_MCP_NPX_PATH="/path/to/custom/npx"
|
|
165
|
+
|
|
166
|
+
# Then run setup
|
|
167
|
+
npx @iterable/mcp setup --cursor
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Alternatively, you can manually edit your configuration file (after adding your key to the keychain):
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"mcpServers": {
|
|
175
|
+
"iterable": {
|
|
176
|
+
"command": "/custom/path/to/npx",
|
|
177
|
+
"args": ["-y", "@iterable/mcp"]
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Note: No `env` needed on macOS - API key and base URL are loaded from Keychain.
|
|
184
|
+
|
|
185
|
+
## What You Can Do
|
|
186
|
+
|
|
187
|
+
See [TOOLS.md](TOOLS.md) for all available tools with descriptions. All tools map directly to [Iterable API endpoints](https://api.iterable.com/api/docs).
|
|
188
|
+
|
|
189
|
+
### Examples:
|
|
190
|
+
- *"How many campaigns do I have running?"*
|
|
191
|
+
- *"Get details on campaign 12345"*
|
|
192
|
+
- *"Show me events for user@example.com from the last 30 days"*
|
|
193
|
+
- *"Create a campaign called 'Holiday Sale' using template 456"*
|
|
194
|
+
- *"What email templates are available?"*
|
|
195
|
+
- *"Export all user data from January 2024"*
|
|
196
|
+
- *"List users in my 'VIP Customers' list"*
|
|
197
|
+
- *"Show me all my product catalogs"*
|
|
198
|
+
- *"What journeys are currently active?"*
|
|
199
|
+
- *"Send a welcome email to new-user@company.com"*
|
|
200
|
+
|
|
201
|
+
## Configuration
|
|
202
|
+
|
|
203
|
+
### API Key Management
|
|
204
|
+
|
|
205
|
+
**macOS Users:** API keys are stored securely in macOS Keychain. Each key is tightly coupled to its API endpoint (US vs EU vs custom).
|
|
206
|
+
|
|
207
|
+
**How Key Selection Works:**
|
|
208
|
+
- You can store multiple API keys with different names (e.g., "production", "staging", "dev")
|
|
209
|
+
- Only ONE key is marked as **active** at a time
|
|
210
|
+
- The MCP server automatically uses whichever key is currently active
|
|
211
|
+
- Your first key is automatically set as active
|
|
212
|
+
- Switch between keys using the `activate` command
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# List stored keys (shows which one is active with ● ACTIVE badge)
|
|
216
|
+
iterable-mcp keys list
|
|
217
|
+
|
|
218
|
+
# Add a new key (interactive: prompts for name, region/endpoint, and API key)
|
|
219
|
+
# Your first key becomes active automatically
|
|
220
|
+
iterable-mcp keys add
|
|
221
|
+
|
|
222
|
+
# Switch to a different key by name or ID (also switches endpoint)
|
|
223
|
+
iterable-mcp keys activate production
|
|
224
|
+
iterable-mcp keys activate staging
|
|
225
|
+
|
|
226
|
+
# Delete a key by ID (requires ID for safety)
|
|
227
|
+
# Note: Cannot delete the currently active key - activate another first
|
|
228
|
+
iterable-mcp keys delete <key-id>
|
|
229
|
+
|
|
230
|
+
# To update a key: delete the old one and add a new one with the same name
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Windows/Linux:** Use the `ITERABLE_API_KEY` and `ITERABLE_BASE_URL` environment variables (key management commands are not available on Windows/Linux).
|
|
234
|
+
|
|
235
|
+
### Environment Variables
|
|
236
|
+
|
|
237
|
+
| Variable | Required | Description |
|
|
238
|
+
|----------|----------|-------------|
|
|
239
|
+
| `ITERABLE_API_KEY` | ❌* | Your Iterable API key (*Required on non-macOS platforms, optional on macOS if using key manager) |
|
|
240
|
+
| `ITERABLE_BASE_URL` | ❌** | Base URL for the Iterable API (**Not needed on macOS when using key manager - URL is stored with each key) |
|
|
241
|
+
| `ITERABLE_DEBUG` | ❌ | Set to `true` for API request logging |
|
|
242
|
+
| `LOG_LEVEL` | ❌ | Set to `debug` for troubleshooting |
|
|
243
|
+
| `ITERABLE_USER_PII` | ❌ | Set to `true` to enable tools that access user PII data (default: `false`) |
|
|
244
|
+
| `ITERABLE_ENABLE_WRITES` | ❌ | Set to `true` to enable tools that perform write operations (default: `false`) |
|
|
245
|
+
| `ITERABLE_ENABLE_SENDS` | ❌ | Set to `true` to enable tools that can send messages (default: `false`). Requires writes to be enabled |
|
|
246
|
+
|
|
247
|
+
### Custom Endpoints
|
|
248
|
+
|
|
249
|
+
- The CLI supports selecting the US or EU region, or entering a custom endpoint.
|
|
250
|
+
- For security, HTTPS is required for custom endpoints. The only exception is localhost development:
|
|
251
|
+
- Allowed: `http://localhost:3000`, `http://127.0.0.1:8080`, `http://[::1]:4000`
|
|
252
|
+
- Not allowed: plain `http://` on non-local hosts (use `https://` instead)
|
|
253
|
+
- When a non-`*.iterable.com` domain is provided, the CLI will ask for confirmation.
|
|
254
|
+
|
|
255
|
+
## Development
|
|
256
|
+
|
|
257
|
+
### Running Tests
|
|
258
|
+
|
|
259
|
+
The project includes both unit and integration tests:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# Run all tests
|
|
263
|
+
pnpm test
|
|
264
|
+
|
|
265
|
+
# Run only unit tests (no API key required)
|
|
266
|
+
pnpm test:unit
|
|
267
|
+
|
|
268
|
+
# Run only integration tests (requires valid API key)
|
|
269
|
+
pnpm test:integration
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Integration Tests
|
|
273
|
+
|
|
274
|
+
Integration tests make real API calls to Iterable and require a valid API key.
|
|
275
|
+
|
|
276
|
+
**Setup:**
|
|
277
|
+
|
|
278
|
+
1. Set your API key as an environment variable:
|
|
279
|
+
```bash
|
|
280
|
+
export ITERABLE_API_KEY=your_actual_api_key
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
2. Or on macOS, add a key to the keychain (interactive):
|
|
284
|
+
```bash
|
|
285
|
+
iterable-mcp keys add
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Note:** The key name can be anything (e.g., "dev", "test", "staging"). The system automatically uses whichever key is marked as **active**. Your first key is automatically set as active. If you have multiple keys, use `iterable-mcp keys activate <name>` to switch between them.
|
|
289
|
+
|
|
290
|
+
3. Run the integration tests:
|
|
291
|
+
```bash
|
|
292
|
+
pnpm test:integration
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**Note:** Integration tests require a valid API key (env or active macOS Keychain key). The suite fails fast if none is found.
|
|
296
|
+
|
|
297
|
+
### Development Workflow
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
# Install dependencies
|
|
301
|
+
pnpm install
|
|
302
|
+
|
|
303
|
+
# Build the project
|
|
304
|
+
pnpm build
|
|
305
|
+
|
|
306
|
+
# Build and watch for changes
|
|
307
|
+
pnpm build:watch
|
|
308
|
+
|
|
309
|
+
# Run in development mode
|
|
310
|
+
pnpm dev
|
|
311
|
+
|
|
312
|
+
# Install locally for testing
|
|
313
|
+
pnpm run install-dev
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## License
|
|
317
|
+
|
|
318
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
package/TOOLS.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Available Iterable MCP Tools (104 tools)
|
|
2
|
+
|
|
3
|
+
**Legend:** 🔒 = Contains PII, ✏️ = Write operation
|
|
4
|
+
|
|
5
|
+
## Campaigns (13 tools)
|
|
6
|
+
- **abort_campaign** ✏️: Abort a campaign that is currently running
|
|
7
|
+
- **activate_triggered_campaign** ✏️: Activate a triggered campaign (requires API triggered campaign activation enabled)
|
|
8
|
+
- **archive_campaigns** ✏️: Archive one or more campaigns. Scheduled/recurring campaigns will be cancelled, running campaigns will be aborted.
|
|
9
|
+
- **cancel_campaign** ✏️: Cancel a scheduled or recurring campaign
|
|
10
|
+
- **create_campaign** ✏️: Create a new blast or triggered campaign from an existing template. If listIds are provided, the campaign will be a blast campaign, otherwise it will be a triggered campaign. Blast campaigns will be sent immediately if sendAt is not provided.
|
|
11
|
+
- **deactivate_triggered_campaign** ✏️: Deactivate a triggered campaign (requires API triggered campaign deactivation enabled)
|
|
12
|
+
- **get_campaign**: Get detailed information about a specific campaign
|
|
13
|
+
- **get_campaign_metrics**: Get campaign performance metrics
|
|
14
|
+
- **get_campaigns**: Retrieve campaigns
|
|
15
|
+
- **get_child_campaigns**: Get child campaigns generated by a recurring campaign
|
|
16
|
+
- **schedule_campaign** ✏️: Schedule an existing campaign to be sent at a specific time
|
|
17
|
+
- **send_campaign** ✏️: Send an existing scheduled campaign immediately
|
|
18
|
+
- **trigger_campaign** ✏️: Trigger a campaign to send to specified lists
|
|
19
|
+
|
|
20
|
+
## Catalogs (12 tools)
|
|
21
|
+
- **bulk_delete_catalog_items** ✏️: Bulk delete catalog items by their IDs
|
|
22
|
+
- **create_catalog** ✏️: Create a new catalog
|
|
23
|
+
- **delete_catalog** ✏️: Delete a catalog
|
|
24
|
+
- **delete_catalog_item** ✏️: Delete a specific catalog item by ID
|
|
25
|
+
- **get_catalog_field_mappings**: Get field mappings and data types for a catalog
|
|
26
|
+
- **get_catalog_item**: Get a specific catalog item by ID
|
|
27
|
+
- **get_catalog_items**: Get items from a catalog with optional pagination and sorting
|
|
28
|
+
- **get_catalogs**: Get list of all catalogs with optional pagination
|
|
29
|
+
- **partial_update_catalog_item** ✏️: Partial update (PATCH) a catalog item - updates only specified fields
|
|
30
|
+
- **replace_catalog_item** ✏️: Replace (PUT) a catalog item - replaces the entire item with new value
|
|
31
|
+
- **update_catalog_field_mappings** ✏️: Update catalog field mappings (data types). Valid types: boolean, date, geo_location, long, double, object, and string
|
|
32
|
+
- **update_catalog_items** ✏️: Update catalog items
|
|
33
|
+
|
|
34
|
+
## Data Export (5 tools)
|
|
35
|
+
- **cancel_export_job** 🔒✏️: Cancel a queued or running export job created with 'start_export_job'. Use the jobId returned from the start export endpoint.
|
|
36
|
+
- **get_available_export_data_types** 🔒✏️: Get the list of all available export data types that can be used with start_export_job. Returns an array of data type names that are supported by the Iterable API.
|
|
37
|
+
- **get_export_files** 🔒: Get the job status and download URLs for files from a completed export job. Files are added to the list as the export job runs. Use 'startAfter' parameter to paginate through files. Each file is up to 10MB, with exports limited to 100GB total size.
|
|
38
|
+
- **get_export_jobs** 🔒: Get a list of recent export jobs for the current project. Jobs can be filtered by state (enqueued, queued, running, completed, failed, cancelled, cancelling).
|
|
39
|
+
- **start_export_job** 🔒✏️: Start a data export job that processes as a background job. Use 'get_export_files' to check status and obtain download links. Supports many data types including: email events (emailSend, emailOpen, emailClick, emailBounce, etc.), push events (pushSend, pushOpen, etc.), SMS events (smsSend, smsBounce, etc.), WhatsApp events, in-app message events, user data, purchase events, and more. Additional requests are queued if concurrent limit is reached.
|
|
40
|
+
|
|
41
|
+
## Events (4 tools)
|
|
42
|
+
- **get_user_events_by_email** 🔒: Get event history for a user by email address
|
|
43
|
+
- **get_user_events_by_user_id** 🔒: Get event history for a user by user ID
|
|
44
|
+
- **track_bulk_events** 🔒✏️: Track multiple events in a single request for better performance
|
|
45
|
+
- **track_event** 🔒✏️: Track a custom event for a user
|
|
46
|
+
|
|
47
|
+
## Experiments (1 tools)
|
|
48
|
+
- **get_experiment_metrics**: Get experiment metrics for A/B testing analysis (currently supports email experiments only)
|
|
49
|
+
|
|
50
|
+
## Journeys (2 tools)
|
|
51
|
+
- **get_journeys**: Get journeys (workflows) with optional pagination and state filtering
|
|
52
|
+
- **trigger_journey** 🔒✏️: Trigger a journey (workflow) for a user
|
|
53
|
+
|
|
54
|
+
## Lists (8 tools)
|
|
55
|
+
- **create_list** ✏️: Create a new user list
|
|
56
|
+
- **delete_list** ✏️: Delete a user list
|
|
57
|
+
- **get_list_preview_users** 🔒: Preview users in a list (up to 5000 users)
|
|
58
|
+
- **get_list_size**: Get the count of users in a specific list
|
|
59
|
+
- **get_list_users** 🔒: Get users in a specific list
|
|
60
|
+
- **get_lists**: Retrieve user lists
|
|
61
|
+
- **subscribe_to_list** 🔒✏️: Subscribe users to a specific list
|
|
62
|
+
- **unsubscribe_from_list** 🔒✏️: Unsubscribe users from a specific list
|
|
63
|
+
|
|
64
|
+
## Messaging (16 tools)
|
|
65
|
+
- **cancel_email** 🔒✏️: Cancel scheduled email for specific user
|
|
66
|
+
- **cancel_in_app** 🔒✏️: Cancel scheduled in-app message for specific user
|
|
67
|
+
- **cancel_push** 🔒✏️: Cancel scheduled push notification for specific user
|
|
68
|
+
- **cancel_sms** 🔒✏️: Cancel scheduled SMS message for specific user
|
|
69
|
+
- **cancel_web_push** 🔒✏️: Cancel scheduled web push notification for specific user
|
|
70
|
+
- **cancel_whatsapp** 🔒✏️: Cancel scheduled WhatsApp message for specific user
|
|
71
|
+
- **get_channels**: Get all available communication channels (email, SMS, push, etc.)
|
|
72
|
+
- **get_embedded_messages** 🔒: Get embedded messages for a user, grouped by placement ID
|
|
73
|
+
- **get_in_app_messages** 🔒: Get in-app messages for a user
|
|
74
|
+
- **get_message_types**: Get all message types within the project for use in templates
|
|
75
|
+
- **send_email** 🔒✏️: Send email to user
|
|
76
|
+
- **send_in_app** 🔒✏️: Send in-app message to user
|
|
77
|
+
- **send_push** 🔒✏️: Send push notification to user
|
|
78
|
+
- **send_sms** 🔒✏️: Send SMS message to user
|
|
79
|
+
- **send_web_push** 🔒✏️: Send web push notification to user
|
|
80
|
+
- **send_whatsapp** 🔒✏️: Send WhatsApp message to user
|
|
81
|
+
|
|
82
|
+
## Snippets (5 tools)
|
|
83
|
+
- **create_snippet** ✏️: Create a new snippet with Handlebars templating support
|
|
84
|
+
- **delete_snippet** ✏️: Delete a snippet by ID (numeric) or name (string)
|
|
85
|
+
- **get_snippet**: Get a snippet by ID (numeric) or name (string)
|
|
86
|
+
- **get_snippets**: Get all snippets for the current project
|
|
87
|
+
- **update_snippet** ✏️: Update a snippet by ID (numeric) or name (string)
|
|
88
|
+
|
|
89
|
+
## Subscriptions (5 tools)
|
|
90
|
+
- **bulk_update_subscriptions** 🔒✏️: Subscribe or unsubscribe multiple users to/from a subscription group
|
|
91
|
+
- **subscribe_user_by_email** 🔒✏️: Subscribe a user to a subscription group by email
|
|
92
|
+
- **subscribe_user_by_userid** 🔒✏️: Subscribe a user to a subscription group by userId
|
|
93
|
+
- **unsubscribe_user_by_email** 🔒✏️: Unsubscribe a user from a subscription group by email
|
|
94
|
+
- **unsubscribe_user_by_userid** 🔒✏️: Unsubscribe a user from a subscription group by userId
|
|
95
|
+
|
|
96
|
+
## Templates (21 tools)
|
|
97
|
+
- **delete_templates** ✏️: Delete one or more templates by ID
|
|
98
|
+
- **get_email_template**: Get details for specific email template by ID
|
|
99
|
+
- **get_inapp_template**: Get details for specific in-app message template by ID
|
|
100
|
+
- **get_push_template**: Get details for specific push notification template by ID
|
|
101
|
+
- **get_sms_template**: Get details for specific SMS template by ID
|
|
102
|
+
- **get_template_by_client_id**: Get template by client template ID
|
|
103
|
+
- **get_templates**: Retrieve templates
|
|
104
|
+
- **preview_email_template**: Preview email template with custom data. Returns fully rendered HTML with user, event, and/or data feed data substituted.
|
|
105
|
+
- **preview_inapp_template**: Preview in-app message template with custom data. Returns fully rendered HTML with user, event, and/or data feed data substituted.
|
|
106
|
+
- **send_email_template_proof** 🔒✏️: Send a proof of a email template to a specific user
|
|
107
|
+
- **send_inapp_template_proof** 🔒✏️: Send a proof of a in-app message template to a specific user
|
|
108
|
+
- **send_push_template_proof** 🔒✏️: Send a proof of a push notification template to a specific user
|
|
109
|
+
- **send_sms_template_proof** 🔒✏️: Send a proof of a SMS template to a specific user
|
|
110
|
+
- **update_email_template** ✏️: Update existing email template by templateId
|
|
111
|
+
- **update_inapp_template** ✏️: Update existing in-app message template by templateId
|
|
112
|
+
- **update_push_template** ✏️: Update existing push notification template by templateId
|
|
113
|
+
- **update_sms_template** ✏️: Update existing SMS template by templateId
|
|
114
|
+
- **upsert_email_template** ✏️: Create or update email template. If a template with the specified clientTemplateId exists, it will be updated; otherwise, a new template will be created.
|
|
115
|
+
- **upsert_inapp_template** ✏️: Create or update in-app message template. If a template with the specified clientTemplateId exists, it will be updated; otherwise, a new template will be created.
|
|
116
|
+
- **upsert_push_template** ✏️: Create or update push notification template. If a template with the specified clientTemplateId exists, it will be updated; otherwise, a new template will be created.
|
|
117
|
+
- **upsert_sms_template** ✏️: Create or update SMS template. If a template with the specified clientTemplateId exists, it will be updated; otherwise, a new template will be created.
|
|
118
|
+
|
|
119
|
+
## Users (10 tools)
|
|
120
|
+
- **bulk_update_users** 🔒✏️: Update multiple users at once
|
|
121
|
+
- **delete_user_by_email** 🔒✏️: Delete a user by email address (asynchronous - does not prevent future data collection)
|
|
122
|
+
- **delete_user_by_user_id** 🔒✏️: Delete a user by user ID (asynchronous - does not prevent future data collection, deletes all users with same userId)
|
|
123
|
+
- **get_sent_messages** 🔒: Get messages sent to a specific user with optional filtering
|
|
124
|
+
- **get_user_by_email** 🔒: Get user profile information by email address
|
|
125
|
+
- **get_user_by_user_id** 🔒: Get user profile information by user ID
|
|
126
|
+
- **get_user_fields**: Get all user profile field definitions and their types
|
|
127
|
+
- **update_email** 🔒✏️: Update a user's email address (only use with email-based projects; for userId/hybrid projects, use update_user instead)
|
|
128
|
+
- **update_user** 🔒✏️: Update user profile information (accepts email OR userId in params)
|
|
129
|
+
- **update_user_subscriptions** 🔒✏️: Update user subscriptions (IMPORTANT: overwrites existing data for any non-null fields specified)
|
|
130
|
+
|
|
131
|
+
## Webhooks (2 tools)
|
|
132
|
+
- **get_webhooks**: Get all webhooks for the project
|
|
133
|
+
- **update_webhook** ✏️: Update a webhook configuration
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Simple client detection that uses MCP handshake information.
|
|
4
|
+
* Only checks MCP_SOURCE override, then uses client-provided name directly.
|
|
5
|
+
*/
|
|
6
|
+
export declare function detectClientName(server?: Server): string;
|
|
7
|
+
//# sourceMappingURL=client-detection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-detection.d.ts","sourceRoot":"","sources":["../src/client-detection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAExE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAiBxD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple client detection that uses MCP handshake information.
|
|
3
|
+
* Only checks MCP_SOURCE override, then uses client-provided name directly.
|
|
4
|
+
*/
|
|
5
|
+
export function detectClientName(server) {
|
|
6
|
+
// 1) Explicit override
|
|
7
|
+
if (process.env.MCP_SOURCE) {
|
|
8
|
+
return process.env.MCP_SOURCE.toLowerCase();
|
|
9
|
+
}
|
|
10
|
+
// 2) Use client info from MCP handshake
|
|
11
|
+
try {
|
|
12
|
+
const clientInfo = server?.getClientVersion();
|
|
13
|
+
if (clientInfo?.name) {
|
|
14
|
+
return clientInfo.name.toLowerCase();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Ignore handshake errors
|
|
19
|
+
}
|
|
20
|
+
return "unknown";
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=client-detection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-detection.js","sourceRoot":"","sources":["../src/client-detection.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAe;IAC9C,uBAAuB;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;IAC9C,CAAC;IAED,wCAAwC;IACxC,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,EAAE,gBAAgB,EAAE,CAAC;QAC9C,IAAI,UAAU,EAAE,IAAI,EAAE,CAAC;YACrB,OAAO,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACvC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,0BAA0B;IAC5B,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for MCP server restrictions
|
|
3
|
+
*/
|
|
4
|
+
export interface McpServerConfig {
|
|
5
|
+
/** If false, exclude tools that can access or return user PII */
|
|
6
|
+
readonly allowUserPii: boolean;
|
|
7
|
+
/** If false, exclude tools that perform write operations */
|
|
8
|
+
readonly allowWrites: boolean;
|
|
9
|
+
/** If false, exclude tools that can send messages (campaign/journey/event-triggered sends) */
|
|
10
|
+
readonly allowSends: boolean;
|
|
11
|
+
/** The active Iterable API key (optional for tests) */
|
|
12
|
+
readonly apiKey?: string;
|
|
13
|
+
/** The Iterable API base URL (defaults to https://api.iterable.com) */
|
|
14
|
+
readonly baseUrl?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function resolveAllowFlags(keyEnv: Record<string, string> | undefined, env: NodeJS.ProcessEnv): {
|
|
17
|
+
allowUserPii: boolean;
|
|
18
|
+
allowWrites: boolean;
|
|
19
|
+
allowSends: boolean;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Load configuration from environment variables and key manager
|
|
23
|
+
*/
|
|
24
|
+
export declare function loadMcpServerConfig(): Promise<McpServerConfig>;
|
|
25
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA;;GAEG;AAEH,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,8FAA8F;IAC9F,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,uDAAuD;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EAC1C,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB;IAAE,YAAY,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAKtE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,eAAe,CAAC,CAiFpE"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { logger } from "@iterable/api";
|
|
2
|
+
import { getKeyManager } from "./key-manager.js";
|
|
3
|
+
import { sanitizeString } from "./utils/sanitize.js";
|
|
4
|
+
export function resolveAllowFlags(keyEnv, env) {
|
|
5
|
+
const allowUserPii = (keyEnv?.ITERABLE_USER_PII ?? env.ITERABLE_USER_PII) === "true";
|
|
6
|
+
const allowWrites = (keyEnv?.ITERABLE_ENABLE_WRITES ?? env.ITERABLE_ENABLE_WRITES) === "true";
|
|
7
|
+
const allowSends = (keyEnv?.ITERABLE_ENABLE_SENDS ?? env.ITERABLE_ENABLE_SENDS) === "true";
|
|
8
|
+
return { allowUserPii, allowWrites, allowSends };
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Load configuration from environment variables and key manager
|
|
12
|
+
*/
|
|
13
|
+
export async function loadMcpServerConfig() {
|
|
14
|
+
let apiKey = null;
|
|
15
|
+
let baseUrl = process.env.ITERABLE_BASE_URL || "https://api.iterable.com";
|
|
16
|
+
let keyEnv;
|
|
17
|
+
// Try to load API key from KeyManager first (macOS only)
|
|
18
|
+
// SAFETY: Skip keyManager in test environments to prevent production data access
|
|
19
|
+
if (process.platform === "darwin" && process.env.NODE_ENV !== "test") {
|
|
20
|
+
try {
|
|
21
|
+
const keyManager = getKeyManager();
|
|
22
|
+
await keyManager.initialize();
|
|
23
|
+
// Check if we have stored keys
|
|
24
|
+
if (await keyManager.hasKeys()) {
|
|
25
|
+
apiKey = await keyManager.getActiveKey();
|
|
26
|
+
// Get the base URL from the active key metadata
|
|
27
|
+
const activeKeyMetadata = await keyManager.getActiveKeyMetadata();
|
|
28
|
+
if (activeKeyMetadata?.baseUrl) {
|
|
29
|
+
baseUrl = activeKeyMetadata.baseUrl;
|
|
30
|
+
}
|
|
31
|
+
if (activeKeyMetadata?.env) {
|
|
32
|
+
keyEnv = activeKeyMetadata.env;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// If no stored keys and ITERABLE_API_KEY env var exists, migrate it
|
|
36
|
+
if (!apiKey && process.env.ITERABLE_API_KEY) {
|
|
37
|
+
await keyManager.migrateLegacyKey(process.env.ITERABLE_API_KEY, baseUrl);
|
|
38
|
+
apiKey = await keyManager.getActiveKey();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
// Distinguish between expected "no keys" vs unexpected errors
|
|
43
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
44
|
+
if (errorMessage.includes("Key store not initialized") ||
|
|
45
|
+
errorMessage.includes("No API key found")) {
|
|
46
|
+
// Expected - no keys stored yet, will fall back to env
|
|
47
|
+
logger.debug("No keys in key manager, falling back to environment variable");
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Unexpected error - log more details (sanitized to prevent key leakage)
|
|
51
|
+
const sanitizedMessage = sanitizeString(errorMessage);
|
|
52
|
+
logger.error("Unexpected error loading from key manager", {
|
|
53
|
+
error: sanitizedMessage,
|
|
54
|
+
});
|
|
55
|
+
console.error("⚠️ Warning: Failed to load API key from macOS Keychain:", sanitizedMessage);
|
|
56
|
+
// Provide helpful guidance for sync issues
|
|
57
|
+
if (sanitizedMessage.includes("could not be found")) {
|
|
58
|
+
console.error("\n💡 This may be a sync issue. Restarting the server will automatically clean up orphaned keys.");
|
|
59
|
+
}
|
|
60
|
+
console.error(" Falling back to ITERABLE_API_KEY environment variable");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Fall back to environment variable if key manager didn't work
|
|
65
|
+
if (!apiKey && process.env.ITERABLE_API_KEY) {
|
|
66
|
+
apiKey = process.env.ITERABLE_API_KEY;
|
|
67
|
+
}
|
|
68
|
+
if (!apiKey) {
|
|
69
|
+
throw new Error("No API key found. Please run 'iterable-mcp setup' or set ITERABLE_API_KEY environment variable.");
|
|
70
|
+
}
|
|
71
|
+
const { allowUserPii, allowWrites, allowSends } = resolveAllowFlags(keyEnv, process.env);
|
|
72
|
+
return { allowUserPii, allowWrites, allowSends, apiKey, baseUrl };
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const HEADER_USER_AGENT = "User-Agent";
|
|
2
|
+
export declare const HEADER_CLIENT = "Iterable-MCP-Client";
|
|
3
|
+
export declare const HEADER_SESSION_ID = "Iterable-MCP-Session-Id";
|
|
4
|
+
export declare const HEADER_TOOL = "Iterable-MCP-Tool";
|
|
5
|
+
//# sourceMappingURL=http-headers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-headers.d.ts","sourceRoot":"","sources":["../src/http-headers.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,eAAe,CAAC;AAC9C,eAAO,MAAM,aAAa,wBAAwB,CAAC;AACnD,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAC3D,eAAO,MAAM,WAAW,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-headers.js","sourceRoot":"","sources":["../src/http-headers.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC;AAC9C,MAAM,CAAC,MAAM,aAAa,GAAG,qBAAqB,CAAC;AACnD,MAAM,CAAC,MAAM,iBAAiB,GAAG,yBAAyB,CAAC;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAG,mBAAmB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|