chatrail-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 +137 -0
- package/dist/index.js +81 -0
- package/package.json +50 -0
- package/tools.json +428 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ChatRail
|
|
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,137 @@
|
|
|
1
|
+
# ChatRail MCP server
|
|
2
|
+
|
|
3
|
+
Operate a [ChatRail](https://www.chatrail.dev) workspace from Claude, Cursor, VS Code and any other
|
|
4
|
+
[Model Context Protocol](https://modelcontextprotocol.io) client. Check the health of your WhatsApp
|
|
5
|
+
connections, look up groups, trace why a message failed, manage scheduled messages and replay
|
|
6
|
+
webhook deliveries without leaving your editor.
|
|
7
|
+
|
|
8
|
+
ChatRail is a WhatsApp API for developers: send and receive WhatsApp messages over HTTP from a number
|
|
9
|
+
you already have. See the [MCP documentation](https://www.chatrail.dev/mcp) for the full reference.
|
|
10
|
+
|
|
11
|
+
## Privacy by design
|
|
12
|
+
|
|
13
|
+
- Message bodies, recipient phone numbers and credentials are never returned by any tool.
|
|
14
|
+
- Tools that change state return a preview first and apply only when called again with
|
|
15
|
+
`confirm: true`.
|
|
16
|
+
- Every call is scoped to one workspace and recorded in its audit log.
|
|
17
|
+
|
|
18
|
+
## Two ways to connect
|
|
19
|
+
|
|
20
|
+
### 1. Hosted server with OAuth (recommended)
|
|
21
|
+
|
|
22
|
+
Point any client that supports remote MCP servers at:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
https://www.chatrail.dev/v1/mcp
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Your client opens a browser window where a workspace owner, admin or developer approves access.
|
|
29
|
+
Nothing to install and no key to copy.
|
|
30
|
+
|
|
31
|
+
**Claude Code**
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
claude mcp add --transport http chatrail https://www.chatrail.dev/v1/mcp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Cursor** (`~/.cursor/mcp.json`)
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"chatrail": { "url": "https://www.chatrail.dev/v1/mcp" }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**VS Code** (`.vscode/mcp.json`)
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"servers": {
|
|
52
|
+
"chatrail": { "type": "http", "url": "https://www.chatrail.dev/v1/mcp" }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 2. Local stdio server with an API key
|
|
58
|
+
|
|
59
|
+
For clients that only run local servers, or when you would rather use an API key. This package runs
|
|
60
|
+
on your machine and forwards requests to the hosted server.
|
|
61
|
+
|
|
62
|
+
1. In the [ChatRail dashboard](https://www.chatrail.dev/dashboard), create a workspace API key with
|
|
63
|
+
the `mcp:read` scope. Add `mcp:write` if the assistant may reschedule, cancel, react or replay.
|
|
64
|
+
2. Add the server to your client.
|
|
65
|
+
|
|
66
|
+
**Claude Desktop** (`claude_desktop_config.json`)
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"mcpServers": {
|
|
71
|
+
"chatrail": {
|
|
72
|
+
"command": "npx",
|
|
73
|
+
"args": ["-y", "github:chatrail/chatrail_mcp"],
|
|
74
|
+
"env": { "CHATRAIL_API_KEY": "cr_live_..." }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Docker**
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
docker build -t chatrail-mcp .
|
|
84
|
+
docker run -i --rm -e CHATRAIL_API_KEY=cr_live_... chatrail-mcp
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
| Variable | Required | Description |
|
|
88
|
+
| --- | --- | --- |
|
|
89
|
+
| `CHATRAIL_API_KEY` | Yes, to call tools | Workspace API key with `mcp:read` (and optionally `mcp:write`). |
|
|
90
|
+
| `CHATRAIL_MCP_URL` | No | Override the endpoint. Defaults to `https://www.chatrail.dev/v1/mcp`. |
|
|
91
|
+
|
|
92
|
+
Without a key the server still starts and lists its tools, so you can inspect it before signing up.
|
|
93
|
+
|
|
94
|
+
## Tools
|
|
95
|
+
|
|
96
|
+
| Tool | Scope | What it does |
|
|
97
|
+
| --- | --- | --- |
|
|
98
|
+
| `list_connections` | read | Every WhatsApp connection in the workspace with its state and health. |
|
|
99
|
+
| `get_connection` | read | One connection with its state, health and recent state history. |
|
|
100
|
+
| `list_whatsapp_groups` | read | Groups visible to a connected number, with ids and participant counts. |
|
|
101
|
+
| `get_whatsapp_group` | read | Name, description, settings and member counts for one group. |
|
|
102
|
+
| `list_messages` | read | Recent messages with their delivery state. |
|
|
103
|
+
| `get_message` | read | One message and its delivery timeline. |
|
|
104
|
+
| `explain_message_failure` | read | A structured explanation of why a message failed. |
|
|
105
|
+
| `list_scheduled_messages` | read | Messages waiting to be sent, soonest first. |
|
|
106
|
+
| `list_webhook_deliveries` | read | Recent webhook deliveries and their outcomes. |
|
|
107
|
+
| `reschedule_message` | write | Change when a scheduled message is sent. Previews first. |
|
|
108
|
+
| `cancel_scheduled_message` | write | Cancel a message that has not been sent. Previews first. |
|
|
109
|
+
| `react_to_message` | write | Set or remove an emoji reaction on a message. Previews first. |
|
|
110
|
+
| `replay_webhook` | write | Requeue a dead or skipped webhook delivery. Previews first. |
|
|
111
|
+
|
|
112
|
+
## Plans
|
|
113
|
+
|
|
114
|
+
MCP access is included on the ChatRail **Core + AI** and **Team** plans. See
|
|
115
|
+
[pricing](https://www.chatrail.dev/pricing).
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npm install
|
|
121
|
+
npm run build
|
|
122
|
+
CHATRAIL_API_KEY=cr_test_... node dist/index.js
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`tools.json` is the tool catalog served when no API key is configured. It is exported from the
|
|
126
|
+
hosted server and should be refreshed when the hosted tools change.
|
|
127
|
+
|
|
128
|
+
## Links
|
|
129
|
+
|
|
130
|
+
- Website: <https://www.chatrail.dev>
|
|
131
|
+
- MCP docs: <https://www.chatrail.dev/mcp>
|
|
132
|
+
- API reference: <https://www.chatrail.dev/api-reference>
|
|
133
|
+
- Authentication: <https://www.chatrail.dev/auth.md>
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
[MIT](LICENSE)
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
4
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
5
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
6
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
|
+
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
/**
|
|
9
|
+
* A local stdio MCP server for ChatRail.
|
|
10
|
+
*
|
|
11
|
+
* It forwards every request to the hosted ChatRail MCP endpoint, authenticated with a workspace
|
|
12
|
+
* API key. The hosted endpoint is the single source of truth for what the tools do and who may
|
|
13
|
+
* call them; this process holds no business logic and stores nothing.
|
|
14
|
+
*
|
|
15
|
+
* Without an API key it still starts and lists the bundled tool catalog, so clients and
|
|
16
|
+
* directories can inspect it. Calling a tool then explains how to configure a key.
|
|
17
|
+
*/
|
|
18
|
+
const VERSION = '0.1.0';
|
|
19
|
+
const DEFAULT_URL = 'https://www.chatrail.dev/v1/mcp';
|
|
20
|
+
const catalog = JSON.parse(readFileSync(new URL('../tools.json', import.meta.url), 'utf8'));
|
|
21
|
+
const apiKey = process.env.CHATRAIL_API_KEY?.trim() || undefined;
|
|
22
|
+
const endpoint = new URL(process.env.CHATRAIL_MCP_URL?.trim() || DEFAULT_URL);
|
|
23
|
+
const MISSING_KEY = 'CHATRAIL_API_KEY is not set. Create a workspace API key with the mcp:read scope ' +
|
|
24
|
+
'(add mcp:write to allow changes) at https://www.chatrail.dev/dashboard and pass it to ' +
|
|
25
|
+
'this server as the CHATRAIL_API_KEY environment variable.';
|
|
26
|
+
/** Turn the hosted endpoint's HTTP refusals into messages a person can act on. */
|
|
27
|
+
function explain(err) {
|
|
28
|
+
const status = err.code;
|
|
29
|
+
if (status === 401) {
|
|
30
|
+
return new McpError(ErrorCode.InvalidRequest, 'ChatRail rejected the API key. Check that CHATRAIL_API_KEY is a current workspace key.');
|
|
31
|
+
}
|
|
32
|
+
if (status === 403) {
|
|
33
|
+
return new McpError(ErrorCode.InvalidRequest, 'ChatRail refused the request. The API key needs the mcp:read scope (mcp:write for ' +
|
|
34
|
+
'changes), and MCP is included on the Core + AI and Team plans.');
|
|
35
|
+
}
|
|
36
|
+
return err;
|
|
37
|
+
}
|
|
38
|
+
let upstream;
|
|
39
|
+
/** One connection to the hosted endpoint, opened on first use and reused afterwards. */
|
|
40
|
+
function connectUpstream(key) {
|
|
41
|
+
upstream ??= (async () => {
|
|
42
|
+
const client = new Client({ name: 'chatrail-mcp', version: VERSION });
|
|
43
|
+
const transport = new StreamableHTTPClientTransport(endpoint, {
|
|
44
|
+
requestInit: {
|
|
45
|
+
headers: {
|
|
46
|
+
Authorization: `Bearer ${key}`,
|
|
47
|
+
'User-Agent': `chatrail-mcp/${VERSION}`,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
await client.connect(transport);
|
|
52
|
+
return client;
|
|
53
|
+
})().catch((err) => {
|
|
54
|
+
// Let the next call try again instead of caching the failure.
|
|
55
|
+
upstream = undefined;
|
|
56
|
+
throw explain(err);
|
|
57
|
+
});
|
|
58
|
+
return upstream;
|
|
59
|
+
}
|
|
60
|
+
const server = new Server({ name: 'chatrail', version: VERSION }, { capabilities: { tools: {} }, instructions: catalog.instructions });
|
|
61
|
+
server.setRequestHandler(ListToolsRequestSchema, async (request) => {
|
|
62
|
+
if (!apiKey)
|
|
63
|
+
return { tools: catalog.tools };
|
|
64
|
+
const client = await connectUpstream(apiKey);
|
|
65
|
+
return client.listTools(request.params).catch((err) => {
|
|
66
|
+
throw explain(err);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
70
|
+
if (!apiKey) {
|
|
71
|
+
return { content: [{ type: 'text', text: MISSING_KEY }], isError: true };
|
|
72
|
+
}
|
|
73
|
+
const client = await connectUpstream(apiKey);
|
|
74
|
+
return client.callTool(request.params).catch((err) => {
|
|
75
|
+
throw explain(err);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
await server.connect(new StdioServerTransport());
|
|
79
|
+
// The client owns this process: when it closes stdin, exit rather than let the open upstream
|
|
80
|
+
// connection keep us alive.
|
|
81
|
+
process.stdin.on('close', () => process.exit(0));
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "chatrail-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for ChatRail: inspect WhatsApp connections, groups, message delivery, schedules and webhook deliveries from Claude, Cursor and other MCP clients.",
|
|
5
|
+
"mcpName": "dev.chatrail/chatrail",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"chatrail-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"tools.json"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"prepare": "npm run build",
|
|
17
|
+
"start": "node dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"model-context-protocol",
|
|
22
|
+
"whatsapp",
|
|
23
|
+
"whatsapp-api",
|
|
24
|
+
"chatrail",
|
|
25
|
+
"claude",
|
|
26
|
+
"cursor"
|
|
27
|
+
],
|
|
28
|
+
"homepage": "https://www.chatrail.dev/mcp",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/chatrail/chatrail_mcp.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/chatrail/chatrail_mcp/issues"
|
|
35
|
+
},
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=20"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@modelcontextprotocol/sdk": "^1.30.1"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^22.10.0",
|
|
48
|
+
"typescript": "^5.9.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/tools.json
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
{
|
|
2
|
+
"instructions": "Operational tools for one ChatRail workspace: connections, WhatsApp groups, message delivery, schedules and webhook deliveries. Message bodies, recipient numbers and credentials are never returned. Tools that change state return a preview first and apply only when called again with confirm: true.",
|
|
3
|
+
"tools": [
|
|
4
|
+
{
|
|
5
|
+
"name": "list_connections",
|
|
6
|
+
"title": "List connections",
|
|
7
|
+
"description": "Every WhatsApp connection in the workspace with its current state and health. Phone numbers are not included.",
|
|
8
|
+
"inputSchema": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"limit": {
|
|
12
|
+
"default": 20,
|
|
13
|
+
"type": "integer",
|
|
14
|
+
"minimum": 1,
|
|
15
|
+
"maximum": 50
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
19
|
+
},
|
|
20
|
+
"annotations": {
|
|
21
|
+
"readOnlyHint": true,
|
|
22
|
+
"destructiveHint": false,
|
|
23
|
+
"idempotentHint": true
|
|
24
|
+
},
|
|
25
|
+
"execution": {
|
|
26
|
+
"taskSupport": "forbidden"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "get_connection",
|
|
31
|
+
"title": "Get a connection",
|
|
32
|
+
"description": "One connection, with its state, health and recent state history.",
|
|
33
|
+
"inputSchema": {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"properties": {
|
|
36
|
+
"connection": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"minLength": 1,
|
|
39
|
+
"maxLength": 40
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"required": [
|
|
43
|
+
"connection"
|
|
44
|
+
],
|
|
45
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
46
|
+
},
|
|
47
|
+
"annotations": {
|
|
48
|
+
"readOnlyHint": true,
|
|
49
|
+
"destructiveHint": false,
|
|
50
|
+
"idempotentHint": true
|
|
51
|
+
},
|
|
52
|
+
"execution": {
|
|
53
|
+
"taskSupport": "forbidden"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "list_whatsapp_groups",
|
|
58
|
+
"title": "List WhatsApp groups",
|
|
59
|
+
"description": "A bounded page of groups visible to one connected WhatsApp number. Returns group names, stable group ids and participant counts when available; participant identities are never returned.",
|
|
60
|
+
"inputSchema": {
|
|
61
|
+
"type": "object",
|
|
62
|
+
"properties": {
|
|
63
|
+
"connection": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"minLength": 2,
|
|
66
|
+
"maxLength": 40
|
|
67
|
+
},
|
|
68
|
+
"limit": {
|
|
69
|
+
"default": 20,
|
|
70
|
+
"type": "integer",
|
|
71
|
+
"minimum": 1,
|
|
72
|
+
"maximum": 50
|
|
73
|
+
},
|
|
74
|
+
"offset": {
|
|
75
|
+
"default": 0,
|
|
76
|
+
"type": "integer",
|
|
77
|
+
"minimum": 0,
|
|
78
|
+
"maximum": 100000
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"required": [
|
|
82
|
+
"connection"
|
|
83
|
+
],
|
|
84
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
85
|
+
},
|
|
86
|
+
"annotations": {
|
|
87
|
+
"readOnlyHint": true,
|
|
88
|
+
"destructiveHint": false,
|
|
89
|
+
"idempotentHint": true
|
|
90
|
+
},
|
|
91
|
+
"execution": {
|
|
92
|
+
"taskSupport": "forbidden"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "get_whatsapp_group",
|
|
97
|
+
"title": "Describe a WhatsApp group",
|
|
98
|
+
"description": "Name, description, settings and member counts for one group a connected number is in. Like list_whatsapp_groups, it never returns who the members are.",
|
|
99
|
+
"inputSchema": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"properties": {
|
|
102
|
+
"connection": {
|
|
103
|
+
"type": "string",
|
|
104
|
+
"minLength": 2,
|
|
105
|
+
"maxLength": 40
|
|
106
|
+
},
|
|
107
|
+
"group_id": {
|
|
108
|
+
"type": "string",
|
|
109
|
+
"minLength": 5,
|
|
110
|
+
"maxLength": 40
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"required": [
|
|
114
|
+
"connection",
|
|
115
|
+
"group_id"
|
|
116
|
+
],
|
|
117
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
118
|
+
},
|
|
119
|
+
"annotations": {
|
|
120
|
+
"readOnlyHint": true,
|
|
121
|
+
"destructiveHint": false,
|
|
122
|
+
"idempotentHint": true
|
|
123
|
+
},
|
|
124
|
+
"execution": {
|
|
125
|
+
"taskSupport": "forbidden"
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"name": "list_messages",
|
|
130
|
+
"title": "List messages",
|
|
131
|
+
"description": "Recent messages with their delivery state. Message bodies and recipient numbers are deliberately excluded.",
|
|
132
|
+
"inputSchema": {
|
|
133
|
+
"type": "object",
|
|
134
|
+
"properties": {
|
|
135
|
+
"connection": {
|
|
136
|
+
"type": "string",
|
|
137
|
+
"minLength": 1,
|
|
138
|
+
"maxLength": 40
|
|
139
|
+
},
|
|
140
|
+
"status": {
|
|
141
|
+
"type": "string",
|
|
142
|
+
"minLength": 1,
|
|
143
|
+
"maxLength": 20
|
|
144
|
+
},
|
|
145
|
+
"direction": {
|
|
146
|
+
"type": "string",
|
|
147
|
+
"enum": [
|
|
148
|
+
"inbound",
|
|
149
|
+
"outbound"
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
"limit": {
|
|
153
|
+
"default": 20,
|
|
154
|
+
"type": "integer",
|
|
155
|
+
"minimum": 1,
|
|
156
|
+
"maximum": 50
|
|
157
|
+
},
|
|
158
|
+
"cursor": {
|
|
159
|
+
"type": "string",
|
|
160
|
+
"maxLength": 200
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
164
|
+
},
|
|
165
|
+
"annotations": {
|
|
166
|
+
"readOnlyHint": true,
|
|
167
|
+
"destructiveHint": false,
|
|
168
|
+
"idempotentHint": true
|
|
169
|
+
},
|
|
170
|
+
"execution": {
|
|
171
|
+
"taskSupport": "forbidden"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"name": "get_message",
|
|
176
|
+
"title": "Get a message",
|
|
177
|
+
"description": "One message and its delivery timeline. The body is not returned.",
|
|
178
|
+
"inputSchema": {
|
|
179
|
+
"type": "object",
|
|
180
|
+
"properties": {
|
|
181
|
+
"message_id": {
|
|
182
|
+
"type": "string",
|
|
183
|
+
"format": "uuid",
|
|
184
|
+
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
"required": [
|
|
188
|
+
"message_id"
|
|
189
|
+
],
|
|
190
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
191
|
+
},
|
|
192
|
+
"annotations": {
|
|
193
|
+
"readOnlyHint": true,
|
|
194
|
+
"destructiveHint": false,
|
|
195
|
+
"idempotentHint": true
|
|
196
|
+
},
|
|
197
|
+
"execution": {
|
|
198
|
+
"taskSupport": "forbidden"
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"name": "explain_message_failure",
|
|
203
|
+
"title": "Explain why a message failed",
|
|
204
|
+
"description": "A structured explanation derived from the failure classification recorded when the message failed. Deterministic — it does not summarise logs.",
|
|
205
|
+
"inputSchema": {
|
|
206
|
+
"type": "object",
|
|
207
|
+
"properties": {
|
|
208
|
+
"message_id": {
|
|
209
|
+
"type": "string",
|
|
210
|
+
"format": "uuid",
|
|
211
|
+
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
"required": [
|
|
215
|
+
"message_id"
|
|
216
|
+
],
|
|
217
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
218
|
+
},
|
|
219
|
+
"annotations": {
|
|
220
|
+
"readOnlyHint": true,
|
|
221
|
+
"destructiveHint": false,
|
|
222
|
+
"idempotentHint": true
|
|
223
|
+
},
|
|
224
|
+
"execution": {
|
|
225
|
+
"taskSupport": "forbidden"
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"name": "list_scheduled_messages",
|
|
230
|
+
"title": "List scheduled messages",
|
|
231
|
+
"description": "Messages waiting to be sent, soonest first.",
|
|
232
|
+
"inputSchema": {
|
|
233
|
+
"type": "object",
|
|
234
|
+
"properties": {
|
|
235
|
+
"limit": {
|
|
236
|
+
"default": 20,
|
|
237
|
+
"type": "integer",
|
|
238
|
+
"minimum": 1,
|
|
239
|
+
"maximum": 50
|
|
240
|
+
},
|
|
241
|
+
"cursor": {
|
|
242
|
+
"type": "string",
|
|
243
|
+
"maxLength": 200
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
247
|
+
},
|
|
248
|
+
"annotations": {
|
|
249
|
+
"readOnlyHint": true,
|
|
250
|
+
"destructiveHint": false,
|
|
251
|
+
"idempotentHint": true
|
|
252
|
+
},
|
|
253
|
+
"execution": {
|
|
254
|
+
"taskSupport": "forbidden"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"name": "list_webhook_deliveries",
|
|
259
|
+
"title": "List webhook deliveries",
|
|
260
|
+
"description": "Recent customer webhook deliveries and their outcomes. Payloads and endpoint URLs are not returned.",
|
|
261
|
+
"inputSchema": {
|
|
262
|
+
"type": "object",
|
|
263
|
+
"properties": {
|
|
264
|
+
"status": {
|
|
265
|
+
"type": "string",
|
|
266
|
+
"enum": [
|
|
267
|
+
"pending",
|
|
268
|
+
"delivered",
|
|
269
|
+
"failed",
|
|
270
|
+
"dead",
|
|
271
|
+
"skipped"
|
|
272
|
+
]
|
|
273
|
+
},
|
|
274
|
+
"limit": {
|
|
275
|
+
"default": 20,
|
|
276
|
+
"type": "integer",
|
|
277
|
+
"minimum": 1,
|
|
278
|
+
"maximum": 50
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
282
|
+
},
|
|
283
|
+
"annotations": {
|
|
284
|
+
"readOnlyHint": true,
|
|
285
|
+
"destructiveHint": false,
|
|
286
|
+
"idempotentHint": true
|
|
287
|
+
},
|
|
288
|
+
"execution": {
|
|
289
|
+
"taskSupport": "forbidden"
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"name": "reschedule_message",
|
|
294
|
+
"title": "Move a scheduled message",
|
|
295
|
+
"description": "Change when a scheduled message will be sent. Returns a preview of the change; pass confirm: true to apply it.",
|
|
296
|
+
"inputSchema": {
|
|
297
|
+
"type": "object",
|
|
298
|
+
"properties": {
|
|
299
|
+
"message_id": {
|
|
300
|
+
"type": "string",
|
|
301
|
+
"format": "uuid",
|
|
302
|
+
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
|
|
303
|
+
},
|
|
304
|
+
"send_at": {
|
|
305
|
+
"type": "string",
|
|
306
|
+
"minLength": 1,
|
|
307
|
+
"maxLength": 40
|
|
308
|
+
},
|
|
309
|
+
"confirm": {
|
|
310
|
+
"default": false,
|
|
311
|
+
"type": "boolean"
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
"required": [
|
|
315
|
+
"message_id",
|
|
316
|
+
"send_at"
|
|
317
|
+
],
|
|
318
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
319
|
+
},
|
|
320
|
+
"annotations": {
|
|
321
|
+
"readOnlyHint": false,
|
|
322
|
+
"destructiveHint": false,
|
|
323
|
+
"idempotentHint": false
|
|
324
|
+
},
|
|
325
|
+
"execution": {
|
|
326
|
+
"taskSupport": "forbidden"
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"name": "cancel_scheduled_message",
|
|
331
|
+
"title": "Cancel a scheduled message",
|
|
332
|
+
"description": "Cancel a message that has not yet been sent. Returns a preview; pass confirm: true to apply it.",
|
|
333
|
+
"inputSchema": {
|
|
334
|
+
"type": "object",
|
|
335
|
+
"properties": {
|
|
336
|
+
"message_id": {
|
|
337
|
+
"type": "string",
|
|
338
|
+
"format": "uuid",
|
|
339
|
+
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
|
|
340
|
+
},
|
|
341
|
+
"confirm": {
|
|
342
|
+
"default": false,
|
|
343
|
+
"type": "boolean"
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
"required": [
|
|
347
|
+
"message_id"
|
|
348
|
+
],
|
|
349
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
350
|
+
},
|
|
351
|
+
"annotations": {
|
|
352
|
+
"readOnlyHint": false,
|
|
353
|
+
"destructiveHint": false,
|
|
354
|
+
"idempotentHint": false
|
|
355
|
+
},
|
|
356
|
+
"execution": {
|
|
357
|
+
"taskSupport": "forbidden"
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"name": "react_to_message",
|
|
362
|
+
"title": "React to a message",
|
|
363
|
+
"description": "Set this number's emoji reaction on a message it sent or received, or remove it with an empty emoji. The person in the chat sees it. Returns a preview; pass confirm: true to apply.",
|
|
364
|
+
"inputSchema": {
|
|
365
|
+
"type": "object",
|
|
366
|
+
"properties": {
|
|
367
|
+
"message_id": {
|
|
368
|
+
"type": "string",
|
|
369
|
+
"format": "uuid",
|
|
370
|
+
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
|
|
371
|
+
},
|
|
372
|
+
"emoji": {
|
|
373
|
+
"type": "string",
|
|
374
|
+
"maxLength": 16
|
|
375
|
+
},
|
|
376
|
+
"confirm": {
|
|
377
|
+
"default": false,
|
|
378
|
+
"type": "boolean"
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
"required": [
|
|
382
|
+
"message_id",
|
|
383
|
+
"emoji"
|
|
384
|
+
],
|
|
385
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
386
|
+
},
|
|
387
|
+
"annotations": {
|
|
388
|
+
"readOnlyHint": false,
|
|
389
|
+
"destructiveHint": false,
|
|
390
|
+
"idempotentHint": false
|
|
391
|
+
},
|
|
392
|
+
"execution": {
|
|
393
|
+
"taskSupport": "forbidden"
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
"name": "replay_webhook",
|
|
398
|
+
"title": "Replay a failed webhook delivery",
|
|
399
|
+
"description": "Return a dead or skipped webhook delivery to the queue. Returns a preview; pass confirm: true to apply it.",
|
|
400
|
+
"inputSchema": {
|
|
401
|
+
"type": "object",
|
|
402
|
+
"properties": {
|
|
403
|
+
"delivery_id": {
|
|
404
|
+
"type": "string",
|
|
405
|
+
"minLength": 1,
|
|
406
|
+
"maxLength": 64
|
|
407
|
+
},
|
|
408
|
+
"confirm": {
|
|
409
|
+
"default": false,
|
|
410
|
+
"type": "boolean"
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
"required": [
|
|
414
|
+
"delivery_id"
|
|
415
|
+
],
|
|
416
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
417
|
+
},
|
|
418
|
+
"annotations": {
|
|
419
|
+
"readOnlyHint": false,
|
|
420
|
+
"destructiveHint": false,
|
|
421
|
+
"idempotentHint": false
|
|
422
|
+
},
|
|
423
|
+
"execution": {
|
|
424
|
+
"taskSupport": "forbidden"
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
]
|
|
428
|
+
}
|