clawdcall-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 +108 -0
- package/dist/client.d.ts +28 -0
- package/dist/client.js +64 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +6 -0
- package/dist/format.d.ts +7 -0
- package/dist/format.js +10 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -0
- package/dist/tools.d.ts +3 -0
- package/dist/tools.js +77 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ClawdCall
|
|
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,108 @@
|
|
|
1
|
+
# ClawdCall MCP Server
|
|
2
|
+
|
|
3
|
+
Give AI agents access to ClawdCall's agent-facing phone execution API through the Model Context Protocol.
|
|
4
|
+
|
|
5
|
+
`clawdcall-mcp` exposes the confirmed ClawdCall workflow:
|
|
6
|
+
|
|
7
|
+
- send signup OTP
|
|
8
|
+
- verify signup OTP
|
|
9
|
+
- place outbound calls
|
|
10
|
+
- fetch call transcripts
|
|
11
|
+
|
|
12
|
+
The API base URL defaults to `https://api.clawdcall.com`.
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
### 1. Add ClawdCall to your MCP client
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"mcpServers": {
|
|
21
|
+
"clawdcall": {
|
|
22
|
+
"command": "npx",
|
|
23
|
+
"args": ["-y", "clawdcall-mcp"],
|
|
24
|
+
"env": {
|
|
25
|
+
"CLAWDCALL_API_KEY": "sk_live_your_key_here"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`CLAWDCALL_API_KEY` is required for outbound calls and transcript retrieval. Signup OTP tools do not require an existing key.
|
|
33
|
+
|
|
34
|
+
For staging or self-hosted API routing:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"clawdcall": {
|
|
40
|
+
"command": "npx",
|
|
41
|
+
"args": ["-y", "clawdcall-mcp"],
|
|
42
|
+
"env": {
|
|
43
|
+
"CLAWDCALL_API_KEY": "sk_live_your_key_here",
|
|
44
|
+
"CLAWDCALL_BASE_URL": "https://api.clawdcall.com"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Example Prompts
|
|
52
|
+
|
|
53
|
+
- "Sign me up for ClawdCall and send a verification code."
|
|
54
|
+
- "Verify this ClawdCall OTP and tell me what credential I need to store securely."
|
|
55
|
+
- "Call this restaurant and ask if they have a table for two tonight."
|
|
56
|
+
- "Fetch the transcript for this ClawdCall call ID."
|
|
57
|
+
|
|
58
|
+
## Tools
|
|
59
|
+
|
|
60
|
+
| Tool | Confirmed endpoint | Description |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| `send_signup_otp` | `POST /cc/signup/send-otp` | Send a phone verification OTP for signup. |
|
|
63
|
+
| `verify_signup_otp` | `POST /cc/signup/verify-otp` | Verify the OTP and receive account/API-key details. |
|
|
64
|
+
| `place_outbound_call` | `POST /external/v1/agent/outbound?conversionFlag=1` | Place an outbound voice-agent call. |
|
|
65
|
+
| `get_call_transcript` | `GET /cc/v1/calls/{id}/transcript` | Fetch a transcript by call ID or campaign ID. |
|
|
66
|
+
|
|
67
|
+
## Environment Variables
|
|
68
|
+
|
|
69
|
+
| Variable | Required | Default | Description |
|
|
70
|
+
| --- | --- | --- | --- |
|
|
71
|
+
| `CLAWDCALL_API_KEY` | For call/transcript tools | | ClawdCall API key. |
|
|
72
|
+
| `CLAWDCALL_BASE_URL` | No | `https://api.clawdcall.com` | API base URL. |
|
|
73
|
+
|
|
74
|
+
## Development
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
git clone https://github.com/dialgoodian/clawdcall-mcp.git
|
|
78
|
+
cd clawdcall-mcp
|
|
79
|
+
npm install
|
|
80
|
+
npm run dev
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Build:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm run build
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Run the built server:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
CLAWDCALL_API_KEY=sk_live_your_key_here npm start
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## API Contract
|
|
96
|
+
|
|
97
|
+
This server tracks the ClawdCall agent-facing OpenAPI contract currently published by the ClawdCall UI repo:
|
|
98
|
+
|
|
99
|
+
- `POST /cc/signup/send-otp`
|
|
100
|
+
- `POST /cc/signup/verify-otp`
|
|
101
|
+
- `POST /external/v1/agent/outbound?conversionFlag=1`
|
|
102
|
+
- `GET /cc/v1/calls/{id}/transcript`
|
|
103
|
+
|
|
104
|
+
Do not add MCP tools for agents, number purchase, SMS, conversations, voices, or general webhooks until those routes exist in ClawdCall's API contract.
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
2
|
+
export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
3
|
+
export type JsonObject = {
|
|
4
|
+
[key: string]: JsonValue | undefined;
|
|
5
|
+
};
|
|
6
|
+
export declare class ClawdCallApiError extends Error {
|
|
7
|
+
readonly status: number;
|
|
8
|
+
readonly body: string;
|
|
9
|
+
constructor(status: number, body: string);
|
|
10
|
+
}
|
|
11
|
+
export interface ClawdCallClientOptions {
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class ClawdCallClient {
|
|
16
|
+
private readonly apiKey?;
|
|
17
|
+
private readonly baseUrl;
|
|
18
|
+
constructor(options: ClawdCallClientOptions);
|
|
19
|
+
get(path: string, query?: Record<string, string | number | boolean | undefined>, options?: RequestOptions): Promise<JsonValue>;
|
|
20
|
+
post(path: string, body?: JsonObject, options?: RequestOptions): Promise<JsonValue>;
|
|
21
|
+
patch(path: string, body?: JsonObject, options?: RequestOptions): Promise<JsonValue>;
|
|
22
|
+
delete(path: string, options?: RequestOptions): Promise<JsonValue>;
|
|
23
|
+
private request;
|
|
24
|
+
}
|
|
25
|
+
interface RequestOptions {
|
|
26
|
+
authenticated?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export class ClawdCallApiError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
body;
|
|
4
|
+
constructor(status, body) {
|
|
5
|
+
super(`ClawdCall API request failed with status ${status}: ${body}`);
|
|
6
|
+
this.name = "ClawdCallApiError";
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.body = body;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class ClawdCallClient {
|
|
12
|
+
apiKey;
|
|
13
|
+
baseUrl;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.apiKey = options.apiKey;
|
|
16
|
+
this.baseUrl = normalizeBaseUrl(options.baseUrl ?? "https://api.clawdcall.com");
|
|
17
|
+
}
|
|
18
|
+
async get(path, query, options) {
|
|
19
|
+
return this.request("GET", path, undefined, query, options);
|
|
20
|
+
}
|
|
21
|
+
async post(path, body, options) {
|
|
22
|
+
return this.request("POST", path, body, undefined, options);
|
|
23
|
+
}
|
|
24
|
+
async patch(path, body, options) {
|
|
25
|
+
return this.request("PATCH", path, body, undefined, options);
|
|
26
|
+
}
|
|
27
|
+
async delete(path, options) {
|
|
28
|
+
return this.request("DELETE", path, undefined, undefined, options);
|
|
29
|
+
}
|
|
30
|
+
async request(method, path, body, query, options) {
|
|
31
|
+
const url = new URL(`${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`);
|
|
32
|
+
const authenticated = options?.authenticated ?? true;
|
|
33
|
+
if (authenticated && !this.apiKey) {
|
|
34
|
+
throw new Error("CLAWDCALL_API_KEY is required for this tool");
|
|
35
|
+
}
|
|
36
|
+
if (query) {
|
|
37
|
+
for (const [key, value] of Object.entries(query)) {
|
|
38
|
+
if (value !== undefined) {
|
|
39
|
+
url.searchParams.set(key, String(value));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const response = await fetch(url, {
|
|
44
|
+
method,
|
|
45
|
+
headers: {
|
|
46
|
+
...(authenticated ? { Authorization: `Bearer ${this.apiKey}` } : {}),
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
"User-Agent": "clawdcall-mcp/0.1.0",
|
|
49
|
+
},
|
|
50
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
51
|
+
});
|
|
52
|
+
const text = await response.text();
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
throw new ClawdCallApiError(response.status, text);
|
|
55
|
+
}
|
|
56
|
+
if (!text) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return JSON.parse(text);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function normalizeBaseUrl(baseUrl) {
|
|
63
|
+
return baseUrl.replace(/\/+$/, "");
|
|
64
|
+
}
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
package/dist/format.d.ts
ADDED
package/dist/format.js
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { ClawdCallClient } from "./client.js";
|
|
5
|
+
import { loadConfig } from "./config.js";
|
|
6
|
+
import { registerTools } from "./tools.js";
|
|
7
|
+
async function main() {
|
|
8
|
+
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
9
|
+
printHelp();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const config = loadConfig();
|
|
13
|
+
const client = new ClawdCallClient(config);
|
|
14
|
+
const server = new McpServer({
|
|
15
|
+
name: "clawdcall",
|
|
16
|
+
version: "0.1.0",
|
|
17
|
+
});
|
|
18
|
+
registerTools(server, client);
|
|
19
|
+
const transport = new StdioServerTransport();
|
|
20
|
+
await server.connect(transport);
|
|
21
|
+
}
|
|
22
|
+
function printHelp() {
|
|
23
|
+
process.stdout.write(`clawdcall-mcp
|
|
24
|
+
|
|
25
|
+
Run a ClawdCall MCP server over stdio.
|
|
26
|
+
|
|
27
|
+
Environment:
|
|
28
|
+
CLAWDCALL_API_KEY API key required for call and transcript tools.
|
|
29
|
+
CLAWDCALL_BASE_URL Optional API base URL. Defaults to https://api.clawdcall.com.
|
|
30
|
+
|
|
31
|
+
Usage:
|
|
32
|
+
CLAWDCALL_API_KEY=sk_live_xxx npx clawdcall-mcp
|
|
33
|
+
`);
|
|
34
|
+
}
|
|
35
|
+
main().catch((error) => {
|
|
36
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
37
|
+
process.stderr.write(`${message}\n`);
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
});
|
package/dist/tools.d.ts
ADDED
package/dist/tools.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { jsonResponse } from "./format.js";
|
|
3
|
+
const optionalString = z.string().min(1).optional();
|
|
4
|
+
export function registerTools(server, client) {
|
|
5
|
+
server.tool("send_signup_otp", "Send a ClawdCall signup phone verification OTP. Does not require an API key.", {
|
|
6
|
+
email: z.string().email(),
|
|
7
|
+
phone_number: z.string().min(1).describe("Human phone number to verify."),
|
|
8
|
+
}, async ({ email, phone_number }) => {
|
|
9
|
+
return jsonResponse(await client.post("/cc/signup/send-otp", {
|
|
10
|
+
email,
|
|
11
|
+
phoneNumber: phone_number,
|
|
12
|
+
}, { authenticated: false }));
|
|
13
|
+
});
|
|
14
|
+
server.tool("verify_signup_otp", "Verify a ClawdCall signup OTP and receive account/API-key details. Does not require an existing API key.", {
|
|
15
|
+
email: z.string().email(),
|
|
16
|
+
phone_number: z.string().min(1).describe("Human phone number used for signup."),
|
|
17
|
+
otp: z.string().min(1).describe("OTP code received by the human."),
|
|
18
|
+
}, async ({ email, phone_number, otp }) => {
|
|
19
|
+
return jsonResponse(await client.post("/cc/signup/verify-otp", {
|
|
20
|
+
email,
|
|
21
|
+
phoneNumber: phone_number,
|
|
22
|
+
otp,
|
|
23
|
+
}, { authenticated: false }));
|
|
24
|
+
});
|
|
25
|
+
server.tool("place_outbound_call", "Place an outbound ClawdCall agent call. Requires CLAWDCALL_API_KEY.", {
|
|
26
|
+
target: z.string().min(1).describe("E.164 phone number to call."),
|
|
27
|
+
tasks: z.string().min(1).describe("Full voice-agent instruction set for the call."),
|
|
28
|
+
intro_message: optionalString.describe("Optional opening line for the voice agent."),
|
|
29
|
+
openclaw_webhook_url: optionalString.describe("Optional OpenClaw /agent/run webhook URL for completion events."),
|
|
30
|
+
openclaw_webhook_authorization: optionalString.describe("Optional Authorization header value for the OpenClaw webhook."),
|
|
31
|
+
conversation_id: optionalString.describe("Optional OpenClaw conversation ID for event correlation."),
|
|
32
|
+
user_id: optionalString.describe("Optional user ID for webhook correlation."),
|
|
33
|
+
context: optionalString.describe("Optional extra context to include in the webhook payload."),
|
|
34
|
+
}, async (args) => {
|
|
35
|
+
return jsonResponse(await client.post("/external/v1/agent/outbound?conversionFlag=1", compact({
|
|
36
|
+
target: args.target,
|
|
37
|
+
tasks: args.tasks,
|
|
38
|
+
raw: args.intro_message ? { introMessage: args.intro_message } : undefined,
|
|
39
|
+
openclaw: buildOpenClawPayload(args),
|
|
40
|
+
})));
|
|
41
|
+
});
|
|
42
|
+
server.tool("get_call_transcript", "Fetch a ClawdCall transcript by call ID or campaign ID. Requires CLAWDCALL_API_KEY.", {
|
|
43
|
+
id: z.string().min(1).describe("Call ID or campaign ID returned by ClawdCall."),
|
|
44
|
+
}, async ({ id }) => {
|
|
45
|
+
return jsonResponse(await client.get(`/cc/v1/calls/${encodeURIComponent(id)}/transcript`));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function buildOpenClawPayload(args) {
|
|
49
|
+
if (!args.openclaw_webhook_url &&
|
|
50
|
+
!args.openclaw_webhook_authorization &&
|
|
51
|
+
!args.conversation_id &&
|
|
52
|
+
!args.user_id &&
|
|
53
|
+
!args.context) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
return compact({
|
|
57
|
+
webhook: args.openclaw_webhook_url
|
|
58
|
+
? compact({
|
|
59
|
+
url: args.openclaw_webhook_url,
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: args.openclaw_webhook_authorization
|
|
62
|
+
? {
|
|
63
|
+
Authorization: args.openclaw_webhook_authorization,
|
|
64
|
+
}
|
|
65
|
+
: undefined,
|
|
66
|
+
})
|
|
67
|
+
: undefined,
|
|
68
|
+
webhookPayload: compact({
|
|
69
|
+
conversation_id: args.conversation_id,
|
|
70
|
+
user_id: args.user_id,
|
|
71
|
+
context: args.context,
|
|
72
|
+
}),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function compact(values) {
|
|
76
|
+
return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== undefined));
|
|
77
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clawdcall-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for ClawdCall's agent-facing phone execution API.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"clawdcall-mcp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"dev": "tsx src/index.ts",
|
|
18
|
+
"start": "node dist/index.js",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"clawdcall",
|
|
24
|
+
"mcp",
|
|
25
|
+
"model-context-protocol",
|
|
26
|
+
"telephony",
|
|
27
|
+
"phone",
|
|
28
|
+
"voice",
|
|
29
|
+
"ai-agents",
|
|
30
|
+
"openclaw",
|
|
31
|
+
"claude-code"
|
|
32
|
+
],
|
|
33
|
+
"author": "ClawdCall",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"homepage": "https://github.com/dialgoodian/clawdcall-mcp#readme",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/dialgoodian/clawdcall-mcp.git"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/dialgoodian/clawdcall-mcp/issues"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@modelcontextprotocol/sdk": "^1.13.0",
|
|
48
|
+
"zod": "^3.25.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^22.15.0",
|
|
52
|
+
"tsx": "^4.19.0",
|
|
53
|
+
"typescript": "^5.8.0"
|
|
54
|
+
}
|
|
55
|
+
}
|