@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.
Files changed (64) hide show
  1. package/README.md +78 -0
  2. package/dist/cli-utils.d.ts +4 -0
  3. package/dist/cli-utils.js +31 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +43 -0
  6. package/dist/client.d.ts +11 -0
  7. package/dist/client.js +100 -0
  8. package/dist/commands/ai.d.ts +3 -0
  9. package/dist/commands/ai.js +97 -0
  10. package/dist/commands/analytics.d.ts +3 -0
  11. package/dist/commands/analytics.js +75 -0
  12. package/dist/commands/billing.d.ts +3 -0
  13. package/dist/commands/billing.js +16 -0
  14. package/dist/commands/campaigns.d.ts +3 -0
  15. package/dist/commands/campaigns.js +123 -0
  16. package/dist/commands/channels.d.ts +3 -0
  17. package/dist/commands/channels.js +53 -0
  18. package/dist/commands/contacts.d.ts +3 -0
  19. package/dist/commands/contacts.js +120 -0
  20. package/dist/commands/conversations.d.ts +3 -0
  21. package/dist/commands/conversations.js +71 -0
  22. package/dist/commands/credits.d.ts +10 -0
  23. package/dist/commands/credits.js +38 -0
  24. package/dist/commands/discovery.d.ts +3 -0
  25. package/dist/commands/discovery.js +76 -0
  26. package/dist/commands/keys.d.ts +3 -0
  27. package/dist/commands/keys.js +70 -0
  28. package/dist/commands/messages.d.ts +3 -0
  29. package/dist/commands/messages.js +110 -0
  30. package/dist/commands/notifications.d.ts +3 -0
  31. package/dist/commands/notifications.js +66 -0
  32. package/dist/commands/webhooks.d.ts +3 -0
  33. package/dist/commands/webhooks.js +122 -0
  34. package/dist/index.d.ts +2 -0
  35. package/dist/index.js +37 -0
  36. package/dist/tools/agent-credits.d.ts +10 -0
  37. package/dist/tools/agent-credits.js +43 -0
  38. package/dist/tools/ai.d.ts +3 -0
  39. package/dist/tools/ai.js +81 -0
  40. package/dist/tools/analytics.d.ts +3 -0
  41. package/dist/tools/analytics.js +84 -0
  42. package/dist/tools/billing.d.ts +3 -0
  43. package/dist/tools/billing.js +14 -0
  44. package/dist/tools/campaigns.d.ts +3 -0
  45. package/dist/tools/campaigns.js +211 -0
  46. package/dist/tools/channels.d.ts +3 -0
  47. package/dist/tools/channels.js +49 -0
  48. package/dist/tools/contacts.d.ts +3 -0
  49. package/dist/tools/contacts.js +149 -0
  50. package/dist/tools/conversations.d.ts +3 -0
  51. package/dist/tools/conversations.js +84 -0
  52. package/dist/tools/discovery.d.ts +3 -0
  53. package/dist/tools/discovery.js +62 -0
  54. package/dist/tools/keys.d.ts +3 -0
  55. package/dist/tools/keys.js +92 -0
  56. package/dist/tools/messages.d.ts +3 -0
  57. package/dist/tools/messages.js +99 -0
  58. package/dist/tools/notifications.d.ts +3 -0
  59. package/dist/tools/notifications.js +64 -0
  60. package/dist/tools/webhooks.d.ts +3 -0
  61. package/dist/tools/webhooks.js +161 -0
  62. package/dist/types.d.ts +256 -0
  63. package/dist/types.js +2 -0
  64. package/package.json +33 -0
@@ -0,0 +1,122 @@
1
+ import { formatOutput, handleError, getFormat, parseList } from "../cli-utils.js";
2
+ export function registerWebhookCommands(program, client) {
3
+ const webhooks = program.command("webhooks").alias("w").description("manage webhook subscriptions");
4
+ webhooks
5
+ .command("list")
6
+ .description("list webhooks")
7
+ .option("-p, --page <n>", "page number", "1")
8
+ .option("-s, --page-size <n>", "items per page (max 100)", "50")
9
+ .action(async (opts) => {
10
+ try {
11
+ const params = {};
12
+ if (opts.page)
13
+ params.page = opts.page;
14
+ if (opts.pageSize)
15
+ params.page_size = opts.pageSize;
16
+ const result = await client.get("/webhooks", params);
17
+ formatOutput(result, getFormat(program.opts()));
18
+ }
19
+ catch (error) {
20
+ handleError(error);
21
+ }
22
+ });
23
+ webhooks
24
+ .command("create")
25
+ .description("create a webhook endpoint")
26
+ .requiredOption("-u, --url <url>", "HTTPS webhook URL")
27
+ .requiredOption("-e, --events <list>", "comma-separated events: campaign.created, campaign.updated, campaign.deleted, contact.created, contact.updated, contact.deleted, conversation.created, conversation.reply_received, message.sent, message.delivered, message.opened, message.bounced, message.approved, message.rejected, discovery.completed, discovery.failed (or '*' for all)", parseList)
28
+ .option("-d, --description <text>", "optional description")
29
+ .action(async (opts) => {
30
+ try {
31
+ const body = { url: opts.url, events: opts.events };
32
+ if (opts.description)
33
+ body.description = opts.description;
34
+ const result = await client.post("/webhooks", body);
35
+ formatOutput(result, getFormat(program.opts()));
36
+ }
37
+ catch (error) {
38
+ handleError(error);
39
+ }
40
+ });
41
+ webhooks
42
+ .command("get <id>")
43
+ .description("get a webhook by ID")
44
+ .action(async (id) => {
45
+ try {
46
+ const result = await client.get(`/webhooks/${id}`);
47
+ formatOutput(result, getFormat(program.opts()));
48
+ }
49
+ catch (error) {
50
+ handleError(error);
51
+ }
52
+ });
53
+ webhooks
54
+ .command("update <id>")
55
+ .description("update a webhook")
56
+ .option("-u, --url <url>", "new HTTPS webhook URL")
57
+ .option("-e, --events <list>", "new events to subscribe to", parseList)
58
+ .option("-d, --description <text>", "new description")
59
+ .option("--active", "enable the webhook")
60
+ .option("--no-active", "disable the webhook")
61
+ .action(async (id, opts) => {
62
+ try {
63
+ const body = {};
64
+ if (opts.url)
65
+ body.url = opts.url;
66
+ if (opts.events)
67
+ body.events = opts.events;
68
+ if (opts.description !== undefined)
69
+ body.description = opts.description;
70
+ if (opts.active !== undefined)
71
+ body.is_active = opts.active;
72
+ const result = await client.patch(`/webhooks/${id}`, body);
73
+ formatOutput(result, getFormat(program.opts()));
74
+ }
75
+ catch (error) {
76
+ handleError(error);
77
+ }
78
+ });
79
+ webhooks
80
+ .command("delete <id>")
81
+ .description("delete a webhook")
82
+ .action(async (id) => {
83
+ try {
84
+ await client.delete(`/webhooks/${id}`);
85
+ console.log("webhook deleted");
86
+ }
87
+ catch (error) {
88
+ handleError(error);
89
+ }
90
+ });
91
+ webhooks
92
+ .command("test <id>")
93
+ .description("send a test event to the webhook URL")
94
+ .action(async (id) => {
95
+ try {
96
+ const result = await client.post(`/webhooks/${id}/test`);
97
+ formatOutput(result, getFormat(program.opts()));
98
+ }
99
+ catch (error) {
100
+ handleError(error);
101
+ }
102
+ });
103
+ webhooks
104
+ .command("deliveries <id>")
105
+ .description("list delivery attempts for a webhook")
106
+ .option("-p, --page <n>", "page number", "1")
107
+ .option("-s, --page-size <n>", "items per page (max 100)", "50")
108
+ .action(async (id, opts) => {
109
+ try {
110
+ const params = {};
111
+ if (opts.page)
112
+ params.page = opts.page;
113
+ if (opts.pageSize)
114
+ params.page_size = opts.pageSize;
115
+ const result = await client.get(`/webhooks/${id}/deliveries`, params);
116
+ formatOutput(result, getFormat(program.opts()));
117
+ }
118
+ catch (error) {
119
+ handleError(error);
120
+ }
121
+ });
122
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
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 { IrisClient } from "./client.js";
5
+ import { registerCampaignTools } from "./tools/campaigns.js";
6
+ import { registerContactTools } from "./tools/contacts.js";
7
+ import { registerConversationTools } from "./tools/conversations.js";
8
+ import { registerMessageTools } from "./tools/messages.js";
9
+ import { registerAiTools } from "./tools/ai.js";
10
+ import { registerDiscoveryTools } from "./tools/discovery.js";
11
+ import { registerAnalyticsTools } from "./tools/analytics.js";
12
+ import { registerBillingTools } from "./tools/billing.js";
13
+ import { registerChannelTools } from "./tools/channels.js";
14
+ import { registerNotificationTools } from "./tools/notifications.js";
15
+ import { registerKeyTools } from "./tools/keys.js";
16
+ import { registerWebhookTools } from "./tools/webhooks.js";
17
+ import { registerAgentCreditTools } from "./tools/agent-credits.js";
18
+ const server = new McpServer({
19
+ name: "iris",
20
+ version: "0.2.0",
21
+ });
22
+ const client = new IrisClient();
23
+ registerCampaignTools(server, client);
24
+ registerContactTools(server, client);
25
+ registerConversationTools(server, client);
26
+ registerMessageTools(server, client);
27
+ registerAiTools(server, client);
28
+ registerDiscoveryTools(server, client);
29
+ registerAnalyticsTools(server, client);
30
+ registerBillingTools(server, client);
31
+ registerChannelTools(server, client);
32
+ registerNotificationTools(server, client);
33
+ registerKeyTools(server, client);
34
+ registerWebhookTools(server, client);
35
+ registerAgentCreditTools(server, client);
36
+ const transport = new StdioServerTransport();
37
+ await server.connect(transport);
@@ -0,0 +1,10 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { IrisClient } from "../client.js";
3
+ /**
4
+ * Agent credit tools.
5
+ *
6
+ * NOTE: credits apply only to agents authenticating via x402 (USDC on Base) or
7
+ * MPP (Stripe). When called with a regular API key (the standard MCP setup),
8
+ * the API returns a message indicating credits are not applicable.
9
+ */
10
+ export declare function registerAgentCreditTools(server: McpServer, client: IrisClient): void;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Agent credit tools.
3
+ *
4
+ * NOTE: credits apply only to agents authenticating via x402 (USDC on Base) or
5
+ * MPP (Stripe). When called with a regular API key (the standard MCP setup),
6
+ * the API returns a message indicating credits are not applicable.
7
+ */
8
+ export function registerAgentCreditTools(server, client) {
9
+ server.tool("get_credit_balance", "check the agent credit balance. returns null balance for API key users (credits are agent-only).", {}, async () => {
10
+ try {
11
+ const result = await client.get("/agent/credits");
12
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
13
+ }
14
+ catch (error) {
15
+ return {
16
+ content: [
17
+ {
18
+ type: "text",
19
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
20
+ },
21
+ ],
22
+ isError: true,
23
+ };
24
+ }
25
+ });
26
+ server.tool("purchase_credit_pack", "purchase a 5-credit pack via MPP ($12.00 USD). x402 agents use per-campaign pricing instead. API key users do not need credits.", {}, async () => {
27
+ try {
28
+ const result = await client.post("/agent/credits");
29
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
30
+ }
31
+ catch (error) {
32
+ return {
33
+ content: [
34
+ {
35
+ type: "text",
36
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
37
+ },
38
+ ],
39
+ isError: true,
40
+ };
41
+ }
42
+ });
43
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { IrisClient } from "../client.js";
3
+ export declare function registerAiTools(server: McpServer, client: IrisClient): void;
@@ -0,0 +1,81 @@
1
+ import { z } from "zod";
2
+ export function registerAiTools(server, client) {
3
+ server.tool("generate_content", "generate AI content for a specific contact conversation (email draft, follow-up, reply). requires ai:write scope.", {
4
+ contact_id: z.string().uuid().describe("contact ID"),
5
+ conversation_id: z.string().uuid().describe("conversation ID"),
6
+ generation_type: z
7
+ .enum(["initial_email", "follow_up", "reply"])
8
+ .describe("type of content to generate"),
9
+ context: z.string().max(2000).optional().describe("additional context for the AI"),
10
+ }, async (args) => {
11
+ try {
12
+ const result = await client.post("/ai/generate", args);
13
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
14
+ }
15
+ catch (error) {
16
+ return {
17
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
18
+ isError: true,
19
+ };
20
+ }
21
+ });
22
+ server.tool("generate_campaign_content", "generate AI content at the campaign level (email templates, subject lines). requires ai:write scope.", {
23
+ campaign_id: z.string().uuid().describe("campaign ID"),
24
+ content_type: z
25
+ .enum(["email_template", "subject_lines", "campaign_brief"])
26
+ .describe("type of campaign content to generate"),
27
+ }, async (args) => {
28
+ try {
29
+ const result = await client.post("/ai/generate/campaign", args);
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("analyze_response", "analyze an inbound message using AI to determine sentiment, intent, and suggested actions. requires ai:write scope.", {
40
+ conversation_id: z.string().uuid().describe("conversation ID"),
41
+ message_content: z.string().min(1).max(10000).describe("message content to analyze"),
42
+ }, async (args) => {
43
+ try {
44
+ const result = await client.post("/ai/analyze", args);
45
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
46
+ }
47
+ catch (error) {
48
+ return {
49
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
50
+ isError: true,
51
+ };
52
+ }
53
+ });
54
+ server.tool("get_ai_usage", "get AI generation usage limits and current counts for the billing period. requires ai:read scope.", {}, async () => {
55
+ try {
56
+ const result = await client.get("/ai/usage");
57
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
58
+ }
59
+ catch (error) {
60
+ return {
61
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
62
+ isError: true,
63
+ };
64
+ }
65
+ });
66
+ server.tool("get_ai_suggestions", "get AI-powered suggestions for a conversation (next steps, reply ideas). requires ai:read scope.", {
67
+ conversation_id: z.string().uuid().describe("conversation ID"),
68
+ }, async ({ conversation_id }) => {
69
+ try {
70
+ const params = { conversation_id };
71
+ const result = await client.get("/ai/suggestions", params);
72
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
73
+ }
74
+ catch (error) {
75
+ return {
76
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
77
+ isError: true,
78
+ };
79
+ }
80
+ });
81
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { IrisClient } from "../client.js";
3
+ export declare function registerAnalyticsTools(server: McpServer, client: IrisClient): void;
@@ -0,0 +1,84 @@
1
+ import { z } from "zod";
2
+ export function registerAnalyticsTools(server, client) {
3
+ server.tool("get_analytics_overview", "get a high-level overview of all campaign analytics. requires analytics:read scope.", {}, async () => {
4
+ try {
5
+ const result = await client.get("/analytics/overview");
6
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
7
+ }
8
+ catch (error) {
9
+ return {
10
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
11
+ isError: true,
12
+ };
13
+ }
14
+ });
15
+ server.tool("get_campaign_analytics", "get detailed analytics for a specific campaign. requires analytics:read scope.", {
16
+ id: z.string().uuid().describe("campaign ID"),
17
+ }, async ({ id }) => {
18
+ try {
19
+ const result = await client.get(`/analytics/campaigns/${id}`);
20
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
21
+ }
22
+ catch (error) {
23
+ return {
24
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
25
+ isError: true,
26
+ };
27
+ }
28
+ });
29
+ server.tool("get_performance_metrics", "get email performance metrics over time. requires analytics:read scope.", {
30
+ days: z
31
+ .number()
32
+ .int()
33
+ .min(1)
34
+ .max(90)
35
+ .optional()
36
+ .describe("time window in days (1–90, default 30)"),
37
+ campaign_id: z.string().uuid().optional().describe("filter by campaign ID"),
38
+ }, async ({ days, campaign_id }) => {
39
+ try {
40
+ const params = {};
41
+ if (days !== undefined)
42
+ params.days = String(days);
43
+ if (campaign_id)
44
+ params.campaign_id = campaign_id;
45
+ const result = await client.get("/analytics/performance", params);
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("get_response_time", "get average response time analytics. requires analytics:read scope.", {
56
+ campaign_id: z.string().uuid().optional().describe("filter by campaign ID"),
57
+ }, async ({ campaign_id }) => {
58
+ try {
59
+ const params = {};
60
+ if (campaign_id)
61
+ params.campaign_id = campaign_id;
62
+ const result = await client.get("/analytics/response-time", params);
63
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
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_contact_types", "get breakdown of contacts by type/source. requires analytics:read scope.", {}, async () => {
73
+ try {
74
+ const result = await client.get("/analytics/contact-types");
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,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { IrisClient } from "../client.js";
3
+ export declare function registerBillingTools(server: McpServer, client: IrisClient): void;
@@ -0,0 +1,14 @@
1
+ export function registerBillingTools(server, client) {
2
+ server.tool("get_billing_plans", "get all available billing plans with pricing and feature limits. requires billing:read scope.", {}, async () => {
3
+ try {
4
+ const result = await client.get("/billing/plans");
5
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
6
+ }
7
+ catch (error) {
8
+ return {
9
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
10
+ isError: true,
11
+ };
12
+ }
13
+ });
14
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { IrisClient } from "../client.js";
3
+ export declare function registerCampaignTools(server: McpServer, client: IrisClient): void;
@@ -0,0 +1,211 @@
1
+ import { z } from "zod";
2
+ const CAMPAIGN_STATUSES = ["draft", "active", "paused", "completed", "deleted"];
3
+ const OBJECTIVE_TYPES = ["venue_dj", "venue_host", "product_promotion", "custom"];
4
+ const TARGET_PROFILE_TYPES = [
5
+ "local_business",
6
+ "content_creator",
7
+ "influencer",
8
+ "b2b_professional",
9
+ "ecommerce",
10
+ "saas_company",
11
+ "agency",
12
+ "freelancer",
13
+ "other",
14
+ ];
15
+ export function registerCampaignTools(server, client) {
16
+ server.tool("list_campaigns", "list all campaigns with optional filtering by status. requires campaigns:read scope.", {
17
+ page: z.number().int().positive().optional().describe("page number (default 1)"),
18
+ page_size: z.number().int().min(1).max(100).optional().describe("items per page (default 50, max 100)"),
19
+ status: z.enum(CAMPAIGN_STATUSES).optional().describe("filter by campaign status"),
20
+ }, async ({ page, page_size, status }) => {
21
+ try {
22
+ const params = {};
23
+ if (page !== undefined)
24
+ params.page = String(page);
25
+ if (page_size !== undefined)
26
+ params.page_size = String(page_size);
27
+ if (status)
28
+ params.status = status;
29
+ const result = await client.get("/campaigns", params);
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("create_campaign", "create a new outreach campaign. requires campaigns:write scope.", {
40
+ name: z.string().min(1).max(100).describe("campaign name"),
41
+ objective_type: z.enum(OBJECTIVE_TYPES).describe("campaign objective type"),
42
+ product_name: z.string().max(200).optional().describe("product name (for product_promotion objective)"),
43
+ product_url: z.string().url().optional().describe("product URL (for product_promotion objective)"),
44
+ product_description: z.string().max(2000).optional().describe("product description (for product_promotion objective)"),
45
+ }, async (args) => {
46
+ try {
47
+ const result = await client.post("/campaigns", args);
48
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
49
+ }
50
+ catch (error) {
51
+ return {
52
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
53
+ isError: true,
54
+ };
55
+ }
56
+ });
57
+ server.tool("get_campaign", "get a campaign by ID with stats. requires campaigns:read scope.", {
58
+ id: z.string().uuid().describe("campaign ID"),
59
+ }, async ({ id }) => {
60
+ try {
61
+ const result = await client.get(`/campaigns/${id}`);
62
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
63
+ }
64
+ catch (error) {
65
+ return {
66
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
67
+ isError: true,
68
+ };
69
+ }
70
+ });
71
+ server.tool("update_campaign", "update a campaign's details. requires campaigns:write scope.", {
72
+ id: z.string().uuid().describe("campaign ID"),
73
+ name: z.string().min(1).max(100).optional().describe("new campaign name"),
74
+ status: z.enum(CAMPAIGN_STATUSES).optional().describe("new campaign status"),
75
+ follow_up_enabled: z.boolean().optional().describe("enable follow-up emails"),
76
+ follow_up_max_count: z.number().int().min(0).max(10).optional().describe("max follow-up count"),
77
+ follow_up_delay_days: z.number().int().min(1).max(30).optional().describe("days between follow-ups"),
78
+ }, async ({ id, ...body }) => {
79
+ try {
80
+ const result = await client.patch(`/campaigns/${id}`, body);
81
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
82
+ }
83
+ catch (error) {
84
+ return {
85
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
86
+ isError: true,
87
+ };
88
+ }
89
+ });
90
+ server.tool("delete_campaign", "soft-delete a campaign (sets status to deleted). requires campaigns:write scope.", {
91
+ id: z.string().uuid().describe("campaign ID"),
92
+ }, async ({ id }) => {
93
+ try {
94
+ await client.delete(`/campaigns/${id}`);
95
+ return { content: [{ type: "text", text: `campaign ${id} deleted` }] };
96
+ }
97
+ catch (error) {
98
+ return {
99
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
100
+ isError: true,
101
+ };
102
+ }
103
+ });
104
+ server.tool("list_campaign_contacts", "list contacts in a campaign with optional status filter. requires campaigns:read scope.", {
105
+ id: z.string().uuid().describe("campaign ID"),
106
+ page: z.number().int().positive().optional().describe("page number (default 1)"),
107
+ page_size: z.number().int().min(1).max(100).optional().describe("items per page (default 50, max 100)"),
108
+ status: z
109
+ .enum(["pending", "queued", "contacted", "responded", "converted", "bounced", "opted_out"])
110
+ .optional()
111
+ .describe("filter by contact status"),
112
+ }, async ({ id, page, page_size, status }) => {
113
+ try {
114
+ const params = {};
115
+ if (page !== undefined)
116
+ params.page = String(page);
117
+ if (page_size !== undefined)
118
+ params.page_size = String(page_size);
119
+ if (status)
120
+ params.status = status;
121
+ const result = await client.get(`/campaigns/${id}/contacts`, params);
122
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
123
+ }
124
+ catch (error) {
125
+ return {
126
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
127
+ isError: true,
128
+ };
129
+ }
130
+ });
131
+ server.tool("get_campaign_usage", "get usage limits and current counts for a campaign. requires campaigns:read scope.", {
132
+ id: z.string().uuid().describe("campaign ID"),
133
+ }, async ({ id }) => {
134
+ try {
135
+ const result = await client.get(`/campaigns/${id}/usage`);
136
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
137
+ }
138
+ catch (error) {
139
+ return {
140
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
141
+ isError: true,
142
+ };
143
+ }
144
+ });
145
+ server.tool("analyze_campaign", "trigger AI analysis of a campaign to generate target profiles and recommendations. requires campaigns:write scope.", {
146
+ id: z.string().uuid().describe("campaign ID"),
147
+ }, async ({ id }) => {
148
+ try {
149
+ const result = await client.post(`/campaigns/${id}/analyze`);
150
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
151
+ }
152
+ catch (error) {
153
+ return {
154
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
155
+ isError: true,
156
+ };
157
+ }
158
+ });
159
+ server.tool("list_target_profiles", "list target profiles for a campaign. requires campaigns:read scope.", {
160
+ id: z.string().uuid().describe("campaign ID"),
161
+ }, async ({ id }) => {
162
+ try {
163
+ const result = await client.get(`/campaigns/${id}/target-profiles`);
164
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
165
+ }
166
+ catch (error) {
167
+ return {
168
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
169
+ isError: true,
170
+ };
171
+ }
172
+ });
173
+ server.tool("create_target_profile", "create a target profile for a campaign. requires campaigns:write scope.", {
174
+ id: z.string().uuid().describe("campaign ID"),
175
+ name: z.string().min(1).max(200).describe("profile name"),
176
+ profile_type: z.enum(TARGET_PROFILE_TYPES).describe("type of target profile"),
177
+ job_titles: z.array(z.string()).optional().describe("target job titles"),
178
+ industries: z.array(z.string()).optional().describe("target industries"),
179
+ discovery_keywords: z.array(z.string()).optional().describe("keywords for contact discovery"),
180
+ recommended_channels: z
181
+ .array(z.enum(["email", "instagram", "twitter", "linkedin"]))
182
+ .optional()
183
+ .describe("recommended outreach channels"),
184
+ }, async ({ id, ...body }) => {
185
+ try {
186
+ const result = await client.post(`/campaigns/${id}/target-profiles`, body);
187
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
188
+ }
189
+ catch (error) {
190
+ return {
191
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
192
+ isError: true,
193
+ };
194
+ }
195
+ });
196
+ server.tool("delete_target_profile", "delete a target profile from a campaign. requires campaigns:write scope.", {
197
+ id: z.string().uuid().describe("campaign ID"),
198
+ profile_id: z.string().uuid().describe("target profile ID"),
199
+ }, async ({ id, profile_id }) => {
200
+ try {
201
+ await client.delete(`/campaigns/${id}/target-profiles/${profile_id}`);
202
+ return { content: [{ type: "text", text: `target profile ${profile_id} deleted` }] };
203
+ }
204
+ catch (error) {
205
+ return {
206
+ content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
207
+ isError: true,
208
+ };
209
+ }
210
+ });
211
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { IrisClient } from "../client.js";
3
+ export declare function registerChannelTools(server: McpServer, client: IrisClient): void;