@jclvsh/iris 0.2.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/README.md +78 -0
- package/dist/cli-utils.d.ts +4 -0
- package/dist/cli-utils.js +31 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +43 -0
- package/dist/client.d.ts +11 -0
- package/dist/client.js +100 -0
- package/dist/commands/ai.d.ts +3 -0
- package/dist/commands/ai.js +97 -0
- package/dist/commands/analytics.d.ts +3 -0
- package/dist/commands/analytics.js +75 -0
- package/dist/commands/billing.d.ts +3 -0
- package/dist/commands/billing.js +16 -0
- package/dist/commands/campaigns.d.ts +3 -0
- package/dist/commands/campaigns.js +123 -0
- package/dist/commands/channels.d.ts +3 -0
- package/dist/commands/channels.js +53 -0
- package/dist/commands/contacts.d.ts +3 -0
- package/dist/commands/contacts.js +120 -0
- package/dist/commands/conversations.d.ts +3 -0
- package/dist/commands/conversations.js +71 -0
- package/dist/commands/credits.d.ts +10 -0
- package/dist/commands/credits.js +38 -0
- package/dist/commands/discovery.d.ts +3 -0
- package/dist/commands/discovery.js +76 -0
- package/dist/commands/keys.d.ts +3 -0
- package/dist/commands/keys.js +70 -0
- package/dist/commands/messages.d.ts +3 -0
- package/dist/commands/messages.js +110 -0
- package/dist/commands/notifications.d.ts +3 -0
- package/dist/commands/notifications.js +66 -0
- package/dist/commands/webhooks.d.ts +3 -0
- package/dist/commands/webhooks.js +122 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +37 -0
- package/dist/tools/agent-credits.d.ts +10 -0
- package/dist/tools/agent-credits.js +43 -0
- package/dist/tools/ai.d.ts +3 -0
- package/dist/tools/ai.js +81 -0
- package/dist/tools/analytics.d.ts +3 -0
- package/dist/tools/analytics.js +84 -0
- package/dist/tools/billing.d.ts +3 -0
- package/dist/tools/billing.js +14 -0
- package/dist/tools/campaigns.d.ts +3 -0
- package/dist/tools/campaigns.js +211 -0
- package/dist/tools/channels.d.ts +3 -0
- package/dist/tools/channels.js +49 -0
- package/dist/tools/contacts.d.ts +3 -0
- package/dist/tools/contacts.js +149 -0
- package/dist/tools/conversations.d.ts +3 -0
- package/dist/tools/conversations.js +84 -0
- package/dist/tools/discovery.d.ts +3 -0
- package/dist/tools/discovery.js +62 -0
- package/dist/tools/keys.d.ts +3 -0
- package/dist/tools/keys.js +92 -0
- package/dist/tools/messages.d.ts +3 -0
- package/dist/tools/messages.js +99 -0
- package/dist/tools/notifications.d.ts +3 -0
- package/dist/tools/notifications.js +64 -0
- package/dist/tools/webhooks.d.ts +3 -0
- package/dist/tools/webhooks.js +161 -0
- package/dist/types.d.ts +256 -0
- package/dist/types.js +2 -0
- package/package.json +33 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const CHANNELS = ["email", "instagram", "twitter", "linkedin"];
|
|
3
|
+
export function registerChannelTools(server, client) {
|
|
4
|
+
server.tool("list_connected_accounts", "list all connected social media accounts. requires channels:read scope.", {}, async () => {
|
|
5
|
+
try {
|
|
6
|
+
const result = await client.get("/channels/accounts");
|
|
7
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
return {
|
|
11
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
12
|
+
isError: true,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
server.tool("check_channel_availability", "check which outreach channels are available and configured. requires channels:read scope.", {}, async () => {
|
|
17
|
+
try {
|
|
18
|
+
const result = await client.get("/channels/availability");
|
|
19
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
24
|
+
isError: true,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
server.tool("send_channel_message", "send a message through a specific channel in a conversation. requires channels:write scope.", {
|
|
29
|
+
channel: z.enum(CHANNELS).describe("outreach channel to use"),
|
|
30
|
+
conversation_id: z.string().uuid().describe("conversation ID"),
|
|
31
|
+
recipient_id: z
|
|
32
|
+
.string()
|
|
33
|
+
.min(1)
|
|
34
|
+
.describe("recipient (email address for email channel; platform handle/ID for social channels)"),
|
|
35
|
+
content: z.string().min(1).max(10000).describe("message content"),
|
|
36
|
+
subject: z.string().optional().describe("subject (email channel only)"),
|
|
37
|
+
}, async (args) => {
|
|
38
|
+
try {
|
|
39
|
+
const result = await client.post("/channels/send", args);
|
|
40
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
return {
|
|
44
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
45
|
+
isError: true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerContactTools(server, client) {
|
|
3
|
+
server.tool("list_contacts", "list all contacts with optional search. requires contacts:read scope.", {
|
|
4
|
+
page: z.number().int().positive().optional().describe("page number (default 1)"),
|
|
5
|
+
page_size: z.number().int().min(1).max(100).optional().describe("items per page (default 50, max 100)"),
|
|
6
|
+
search: z.string().optional().describe("search by name, email, or company"),
|
|
7
|
+
}, async ({ page, page_size, search }) => {
|
|
8
|
+
try {
|
|
9
|
+
const params = {};
|
|
10
|
+
if (page !== undefined)
|
|
11
|
+
params.page = String(page);
|
|
12
|
+
if (page_size !== undefined)
|
|
13
|
+
params.page_size = String(page_size);
|
|
14
|
+
if (search)
|
|
15
|
+
params.search = search;
|
|
16
|
+
const result = await client.get("/contacts", params);
|
|
17
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
22
|
+
isError: true,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
server.tool("create_contact", "create a new contact. requires contacts:write scope.", {
|
|
27
|
+
email: z.string().email().describe("contact email address"),
|
|
28
|
+
first_name: z.string().max(100).optional().describe("first name"),
|
|
29
|
+
last_name: z.string().max(100).optional().describe("last name"),
|
|
30
|
+
company_name: z.string().max(200).optional().describe("company name"),
|
|
31
|
+
job_title: z.string().max(200).optional().describe("job title"),
|
|
32
|
+
phone: z.string().max(50).optional().describe("phone number"),
|
|
33
|
+
website: z.string().url().optional().describe("website URL"),
|
|
34
|
+
tags: z.array(z.string()).optional().describe("tags for categorization"),
|
|
35
|
+
}, async (args) => {
|
|
36
|
+
try {
|
|
37
|
+
const result = await client.post("/contacts", args);
|
|
38
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
43
|
+
isError: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
server.tool("get_contact", "get a contact by ID. requires contacts:read scope.", {
|
|
48
|
+
id: z.string().uuid().describe("contact ID"),
|
|
49
|
+
}, async ({ id }) => {
|
|
50
|
+
try {
|
|
51
|
+
const result = await client.get(`/contacts/${id}`);
|
|
52
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
return {
|
|
56
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
57
|
+
isError: true,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
server.tool("update_contact", "update a contact's details. requires contacts:write scope.", {
|
|
62
|
+
id: z.string().uuid().describe("contact ID"),
|
|
63
|
+
email: z.string().email().optional().describe("email address"),
|
|
64
|
+
first_name: z.string().max(100).optional().describe("first name"),
|
|
65
|
+
last_name: z.string().max(100).optional().describe("last name"),
|
|
66
|
+
company_name: z.string().max(200).optional().describe("company name"),
|
|
67
|
+
job_title: z.string().max(200).optional().describe("job title"),
|
|
68
|
+
phone: z.string().max(50).optional().describe("phone number"),
|
|
69
|
+
website: z.string().url().optional().describe("website URL"),
|
|
70
|
+
tags: z.array(z.string()).optional().describe("tags for categorization"),
|
|
71
|
+
}, async ({ id, ...body }) => {
|
|
72
|
+
try {
|
|
73
|
+
const result = await client.patch(`/contacts/${id}`, body);
|
|
74
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
79
|
+
isError: true,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
server.tool("delete_contact", "soft-delete a contact. requires contacts:write scope.", {
|
|
84
|
+
id: z.string().uuid().describe("contact ID"),
|
|
85
|
+
}, async ({ id }) => {
|
|
86
|
+
try {
|
|
87
|
+
await client.delete(`/contacts/${id}`);
|
|
88
|
+
return { content: [{ type: "text", text: `contact ${id} deleted` }] };
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
93
|
+
isError: true,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
server.tool("bulk_import_contacts", "import multiple contacts at once, optionally adding them to a campaign. requires contacts:write scope.", {
|
|
98
|
+
contacts: z
|
|
99
|
+
.array(z.object({
|
|
100
|
+
email: z.string().email().describe("contact email"),
|
|
101
|
+
first_name: z.string().optional().describe("first name"),
|
|
102
|
+
last_name: z.string().optional().describe("last name"),
|
|
103
|
+
company_name: z.string().optional().describe("company name"),
|
|
104
|
+
job_title: z.string().optional().describe("job title"),
|
|
105
|
+
tags: z.array(z.string()).optional().describe("tags"),
|
|
106
|
+
}))
|
|
107
|
+
.min(1)
|
|
108
|
+
.max(500)
|
|
109
|
+
.describe("array of contacts to import"),
|
|
110
|
+
campaign_id: z.string().uuid().optional().describe("campaign ID to add contacts to"),
|
|
111
|
+
}, async (args) => {
|
|
112
|
+
try {
|
|
113
|
+
const result = await client.post("/contacts/bulk", args);
|
|
114
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
return {
|
|
118
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
119
|
+
isError: true,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
server.tool("get_contact_usage", "get contact usage limits and current counts for the billing period. requires contacts:read scope.", {}, async () => {
|
|
124
|
+
try {
|
|
125
|
+
const result = await client.get("/contacts/usage");
|
|
126
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
return {
|
|
130
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
131
|
+
isError: true,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
server.tool("list_contact_conversations", "list all conversations for a specific contact. requires contacts:read scope.", {
|
|
136
|
+
id: z.string().uuid().describe("contact ID"),
|
|
137
|
+
}, async ({ id }) => {
|
|
138
|
+
try {
|
|
139
|
+
const result = await client.get(`/contacts/${id}/conversations`);
|
|
140
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
return {
|
|
144
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
145
|
+
isError: true,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const CONVERSATION_STATUSES = ["active", "completed", "failed", "human_review"];
|
|
3
|
+
export function registerConversationTools(server, client) {
|
|
4
|
+
server.tool("list_conversations", "list conversations with optional filtering. requires conversations:read scope.", {
|
|
5
|
+
page: z.number().int().positive().optional().describe("page number (default 1)"),
|
|
6
|
+
page_size: z.number().int().min(1).max(100).optional().describe("items per page (default 50, max 100)"),
|
|
7
|
+
status: z.enum(CONVERSATION_STATUSES).optional().describe("filter by conversation status"),
|
|
8
|
+
campaign_id: z.string().uuid().optional().describe("filter by campaign ID"),
|
|
9
|
+
}, async ({ page, page_size, status, campaign_id }) => {
|
|
10
|
+
try {
|
|
11
|
+
const params = {};
|
|
12
|
+
if (page !== undefined)
|
|
13
|
+
params.page = String(page);
|
|
14
|
+
if (page_size !== undefined)
|
|
15
|
+
params.page_size = String(page_size);
|
|
16
|
+
if (status)
|
|
17
|
+
params.status = status;
|
|
18
|
+
if (campaign_id)
|
|
19
|
+
params.campaign_id = campaign_id;
|
|
20
|
+
const result = await client.get("/conversations", params);
|
|
21
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return {
|
|
25
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
26
|
+
isError: true,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
server.tool("get_conversation", "get a conversation by ID with contact and campaign details. requires conversations:read scope.", {
|
|
31
|
+
id: z.string().uuid().describe("conversation ID"),
|
|
32
|
+
}, async ({ id }) => {
|
|
33
|
+
try {
|
|
34
|
+
const result = await client.get(`/conversations/${id}`);
|
|
35
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
40
|
+
isError: true,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
server.tool("get_conversation_messages", "get all messages in a conversation. requires conversations:read scope.", {
|
|
45
|
+
id: z.string().uuid().describe("conversation ID"),
|
|
46
|
+
}, async ({ id }) => {
|
|
47
|
+
try {
|
|
48
|
+
const result = await client.get(`/conversations/${id}/messages`);
|
|
49
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
54
|
+
isError: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
server.tool("mark_conversation_read", "mark a conversation as read. requires conversations:write scope.", {
|
|
59
|
+
id: z.string().uuid().describe("conversation ID"),
|
|
60
|
+
}, async ({ id }) => {
|
|
61
|
+
try {
|
|
62
|
+
await client.post(`/conversations/${id}/read`);
|
|
63
|
+
return { content: [{ type: "text", text: `conversation ${id} marked as read` }] };
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
return {
|
|
67
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
68
|
+
isError: true,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
server.tool("get_engagement_metrics", "get overall engagement metrics across all conversations. requires conversations:read scope.", {}, async () => {
|
|
73
|
+
try {
|
|
74
|
+
const result = await client.get("/conversations/engagement");
|
|
75
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
80
|
+
isError: true,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const DISCOVERY_SOURCES = ["google_maps", "instagram", "twitter", "linkedin"];
|
|
3
|
+
export function registerDiscoveryTools(server, client) {
|
|
4
|
+
server.tool("search_contacts", "search for new contacts using external data sources (Google Maps, social platforms). requires discovery:write scope.", {
|
|
5
|
+
query: z.string().min(1).max(500).describe("search query"),
|
|
6
|
+
source: z.enum(DISCOVERY_SOURCES).describe("data source to search"),
|
|
7
|
+
max_results: z.number().int().min(1).max(100).optional().describe("maximum number of results (default 20)"),
|
|
8
|
+
campaign_id: z.string().uuid().optional().describe("campaign to add discovered contacts to"),
|
|
9
|
+
}, async (args) => {
|
|
10
|
+
try {
|
|
11
|
+
const result = await client.post("/discovery/search", args);
|
|
12
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
return {
|
|
16
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
17
|
+
isError: true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
server.tool("search_campaign_contacts", "search for contacts matching a campaign's target profiles. requires discovery:write scope.", {
|
|
22
|
+
campaign_id: z.string().uuid().describe("campaign ID"),
|
|
23
|
+
target_profile_id: z.string().uuid().optional().describe("specific target profile to search for"),
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
try {
|
|
26
|
+
const result = await client.post("/discovery/search/campaign", args);
|
|
27
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
return {
|
|
31
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
32
|
+
isError: true,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
server.tool("get_discovery_job", "get the status and results of a discovery job. requires discovery:read scope.", {
|
|
37
|
+
id: z.string().uuid().describe("discovery job ID"),
|
|
38
|
+
}, async ({ id }) => {
|
|
39
|
+
try {
|
|
40
|
+
const result = await client.get(`/discovery/jobs/${id}`);
|
|
41
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
46
|
+
isError: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
server.tool("list_discovery_sources", "list available discovery data sources and their status. requires discovery:read scope.", {}, async () => {
|
|
51
|
+
try {
|
|
52
|
+
const result = await client.get("/discovery/sources");
|
|
53
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
58
|
+
isError: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const SCOPES = [
|
|
3
|
+
"campaigns:read",
|
|
4
|
+
"campaigns:write",
|
|
5
|
+
"contacts:read",
|
|
6
|
+
"contacts:write",
|
|
7
|
+
"conversations:read",
|
|
8
|
+
"conversations:write",
|
|
9
|
+
"messages:read",
|
|
10
|
+
"messages:write",
|
|
11
|
+
"ai:read",
|
|
12
|
+
"ai:write",
|
|
13
|
+
"discovery:read",
|
|
14
|
+
"discovery:write",
|
|
15
|
+
"analytics:read",
|
|
16
|
+
"billing:read",
|
|
17
|
+
"channels:read",
|
|
18
|
+
"channels:write",
|
|
19
|
+
"notifications:read",
|
|
20
|
+
"notifications:write",
|
|
21
|
+
"webhooks:read",
|
|
22
|
+
"webhooks:write",
|
|
23
|
+
"keys:read",
|
|
24
|
+
"keys:write",
|
|
25
|
+
];
|
|
26
|
+
export function registerKeyTools(server, client) {
|
|
27
|
+
server.tool("get_current_api_key", "get details about the currently authenticated API key. requires keys:read scope.", {}, async () => {
|
|
28
|
+
try {
|
|
29
|
+
const result = await client.get("/keys/me");
|
|
30
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
35
|
+
isError: true,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
server.tool("list_api_keys", "list all API keys for the account. requires keys:read scope.", {
|
|
40
|
+
page: z.number().int().positive().optional().describe("page number (default 1)"),
|
|
41
|
+
page_size: z.number().int().min(1).max(100).optional().describe("items per page (default 50, max 100)"),
|
|
42
|
+
}, async ({ page, page_size }) => {
|
|
43
|
+
try {
|
|
44
|
+
const params = {};
|
|
45
|
+
if (page !== undefined)
|
|
46
|
+
params.page = String(page);
|
|
47
|
+
if (page_size !== undefined)
|
|
48
|
+
params.page_size = String(page_size);
|
|
49
|
+
const result = await client.get("/keys", params);
|
|
50
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
return {
|
|
54
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
55
|
+
isError: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
server.tool("create_api_key", "create a new API key. requires keys:write scope.", {
|
|
60
|
+
name: z.string().min(1).max(100).describe("key name for identification"),
|
|
61
|
+
scopes: z
|
|
62
|
+
.array(z.enum(SCOPES))
|
|
63
|
+
.optional()
|
|
64
|
+
.describe('permission scopes (e.g. ["campaigns:read", "contacts:write"]). defaults to all scopes'),
|
|
65
|
+
expires_at: z.string().optional().describe("expiration date in ISO 8601 format"),
|
|
66
|
+
}, async (args) => {
|
|
67
|
+
try {
|
|
68
|
+
const result = await client.post("/keys", args);
|
|
69
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
return {
|
|
73
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
74
|
+
isError: true,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
server.tool("revoke_api_key", "revoke (delete) an API key. requires keys:write scope.", {
|
|
79
|
+
id: z.string().uuid().describe("API key ID to revoke"),
|
|
80
|
+
}, async ({ id }) => {
|
|
81
|
+
try {
|
|
82
|
+
await client.delete(`/keys/${id}`);
|
|
83
|
+
return { content: [{ type: "text", text: `API key ${id} revoked` }] };
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
return {
|
|
87
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
88
|
+
isError: true,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerMessageTools(server, client) {
|
|
3
|
+
server.tool("list_pending_messages", "list messages awaiting approval before sending. requires messages:read scope.", {
|
|
4
|
+
page: z.number().int().positive().optional().describe("page number (default 1)"),
|
|
5
|
+
page_size: z.number().int().min(1).max(100).optional().describe("items per page (default 50, max 100)"),
|
|
6
|
+
campaign_id: z.string().uuid().optional().describe("filter by campaign ID"),
|
|
7
|
+
}, async ({ page, page_size, campaign_id }) => {
|
|
8
|
+
try {
|
|
9
|
+
const params = {};
|
|
10
|
+
if (page !== undefined)
|
|
11
|
+
params.page = String(page);
|
|
12
|
+
if (page_size !== undefined)
|
|
13
|
+
params.page_size = String(page_size);
|
|
14
|
+
if (campaign_id)
|
|
15
|
+
params.campaign_id = campaign_id;
|
|
16
|
+
const result = await client.get("/messages/pending", params);
|
|
17
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
22
|
+
isError: true,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
server.tool("approve_message", "approve a pending message for sending. requires messages:write scope.", {
|
|
27
|
+
id: z.string().uuid().describe("message ID"),
|
|
28
|
+
}, async ({ id }) => {
|
|
29
|
+
try {
|
|
30
|
+
const result = await client.post(`/messages/${id}/approve`);
|
|
31
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
return {
|
|
35
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
36
|
+
isError: true,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
server.tool("reject_message", "reject a pending message with an optional reason. requires messages:write scope.", {
|
|
41
|
+
id: z.string().uuid().describe("message ID"),
|
|
42
|
+
reason: z.string().max(500).optional().describe("reason for rejection"),
|
|
43
|
+
}, async ({ id, reason }) => {
|
|
44
|
+
try {
|
|
45
|
+
const result = await client.post(`/messages/${id}/reject`, reason ? { reason } : undefined);
|
|
46
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
51
|
+
isError: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
server.tool("retry_message", "retry sending a failed message. requires messages:write scope.", {
|
|
56
|
+
id: z.string().uuid().describe("message ID"),
|
|
57
|
+
}, async ({ id }) => {
|
|
58
|
+
try {
|
|
59
|
+
const result = await client.post(`/messages/${id}/retry`);
|
|
60
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
return {
|
|
64
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
65
|
+
isError: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
server.tool("submit_message_feedback", "submit feedback on an AI-generated message to improve future generations. requires messages:write scope.", {
|
|
70
|
+
id: z.string().uuid().describe("message ID"),
|
|
71
|
+
feedback: z.string().min(1).max(2000).describe("feedback text"),
|
|
72
|
+
}, async ({ id, feedback }) => {
|
|
73
|
+
try {
|
|
74
|
+
const result = await client.post(`/messages/${id}/feedback`, { feedback });
|
|
75
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
80
|
+
isError: true,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
server.tool("bulk_message_action", "approve or reject multiple messages at once. requires messages:write scope.", {
|
|
85
|
+
action: z.enum(["approve", "reject"]).describe("action to perform"),
|
|
86
|
+
ids: z.array(z.string().uuid()).min(1).max(100).describe("message IDs to act on"),
|
|
87
|
+
}, async (args) => {
|
|
88
|
+
try {
|
|
89
|
+
const result = await client.post("/messages/bulk", args);
|
|
90
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return {
|
|
94
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
95
|
+
isError: true,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerNotificationTools(server, client) {
|
|
3
|
+
server.tool("list_notifications", "list user notifications. requires notifications:read scope.", {
|
|
4
|
+
page: z.number().int().positive().optional().describe("page number (default 1)"),
|
|
5
|
+
page_size: z.number().int().min(1).max(100).optional().describe("items per page (default 50, max 100)"),
|
|
6
|
+
}, async ({ page, page_size }) => {
|
|
7
|
+
try {
|
|
8
|
+
const params = {};
|
|
9
|
+
if (page !== undefined)
|
|
10
|
+
params.page = String(page);
|
|
11
|
+
if (page_size !== undefined)
|
|
12
|
+
params.page_size = String(page_size);
|
|
13
|
+
const result = await client.get("/notifications", params);
|
|
14
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
19
|
+
isError: true,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
server.tool("update_notification", "update a notification (e.g., mark as read). requires notifications:write scope.", {
|
|
24
|
+
id: z.string().uuid().describe("notification ID"),
|
|
25
|
+
read: z.boolean().optional().describe("mark as read or unread"),
|
|
26
|
+
}, async ({ id, ...body }) => {
|
|
27
|
+
try {
|
|
28
|
+
const result = await client.patch(`/notifications/${id}`, body);
|
|
29
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return {
|
|
33
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
34
|
+
isError: true,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
server.tool("delete_notification", "delete a notification. requires notifications:write scope.", {
|
|
39
|
+
id: z.string().uuid().describe("notification ID"),
|
|
40
|
+
}, async ({ id }) => {
|
|
41
|
+
try {
|
|
42
|
+
await client.delete(`/notifications/${id}`);
|
|
43
|
+
return { content: [{ type: "text", text: `notification ${id} deleted` }] };
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
48
|
+
isError: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
server.tool("mark_all_notifications_read", "mark all notifications as read. requires notifications:write scope.", {}, async () => {
|
|
53
|
+
try {
|
|
54
|
+
await client.post("/notifications/read-all");
|
|
55
|
+
return { content: [{ type: "text", text: "all notifications marked as read" }] };
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return {
|
|
59
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
60
|
+
isError: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|