@jclvsh/iris 0.3.0 → 0.5.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.
@@ -1,4 +1,4 @@
1
- import { formatOutput, handleError, getFormat } from "../cli-utils.js";
1
+ import { formatOutput, handleError, getFormat, parseList } from "../cli-utils.js";
2
2
  export function registerCampaignCommands(program, client) {
3
3
  const campaigns = program.command("campaigns").alias("c").description("manage campaigns");
4
4
  campaigns
@@ -120,4 +120,62 @@ export function registerCampaignCommands(program, client) {
120
120
  handleError(error);
121
121
  }
122
122
  });
123
+ const targetProfiles = campaigns
124
+ .command("target-profiles")
125
+ .alias("tp")
126
+ .description("manage AI-generated target profiles on a campaign");
127
+ targetProfiles
128
+ .command("list <campaign-id>")
129
+ .description("list target profiles for a campaign")
130
+ .action(async (campaignId) => {
131
+ try {
132
+ const result = await client.get(`/campaigns/${campaignId}/target-profiles`);
133
+ formatOutput(result, getFormat(program.opts()));
134
+ }
135
+ catch (error) {
136
+ handleError(error);
137
+ }
138
+ });
139
+ targetProfiles
140
+ .command("create <campaign-id>")
141
+ .description("create a target profile on a campaign")
142
+ .requiredOption("-n, --name <name>", "profile name")
143
+ .requiredOption("-t, --profile-type <type>", "profile type (local_business, content_creator, influencer, b2b_professional, ecommerce, saas_company, agency, freelancer, other)")
144
+ .option("--job-titles <list>", "comma-separated target job titles", parseList)
145
+ .option("--industries <list>", "comma-separated target industries", parseList)
146
+ .option("--discovery-keywords <list>", "comma-separated discovery keywords", parseList)
147
+ .option("--recommended-channels <list>", "comma-separated recommended channels (email, instagram, twitter)", parseList)
148
+ .action(async (campaignId, opts) => {
149
+ try {
150
+ const body = {
151
+ name: opts.name,
152
+ profile_type: opts.profileType,
153
+ };
154
+ if (opts.jobTitles)
155
+ body.job_titles = opts.jobTitles;
156
+ if (opts.industries)
157
+ body.industries = opts.industries;
158
+ if (opts.discoveryKeywords)
159
+ body.discovery_keywords = opts.discoveryKeywords;
160
+ if (opts.recommendedChannels)
161
+ body.recommended_channels = opts.recommendedChannels;
162
+ const result = await client.post(`/campaigns/${campaignId}/target-profiles`, body);
163
+ formatOutput(result, getFormat(program.opts()));
164
+ }
165
+ catch (error) {
166
+ handleError(error);
167
+ }
168
+ });
169
+ targetProfiles
170
+ .command("delete <campaign-id> <profile-id>")
171
+ .description("delete a target profile from a campaign")
172
+ .action(async (campaignId, profileId) => {
173
+ try {
174
+ await client.delete(`/campaigns/${campaignId}/target-profiles/${profileId}`);
175
+ console.log("target profile deleted");
176
+ }
177
+ catch (error) {
178
+ handleError(error);
179
+ }
180
+ });
123
181
  }
@@ -1,6 +1,9 @@
1
1
  import { formatOutput, handleError, getFormat } from "../cli-utils.js";
2
2
  export function registerChannelCommands(program, client) {
3
- const channels = program.command("channels").alias("ch").description("manage outreach channels and connected accounts");
3
+ const channels = program
4
+ .command("channels")
5
+ .alias("ch")
6
+ .description("manage outreach channels and connected accounts");
4
7
  channels
5
8
  .command("accounts")
6
9
  .description("list connected social accounts")
@@ -1,8 +1,7 @@
1
1
  import { formatOutput, handleError, getFormat, parseList } from "../cli-utils.js";
2
2
  export function registerKeyCommands(program, client) {
3
3
  const keys = program.command("keys").alias("k").description("manage API keys");
4
- keys
5
- .command("me")
4
+ keys.command("me")
6
5
  .description("get current API key info")
7
6
  .action(async () => {
8
7
  try {
@@ -13,8 +12,7 @@ export function registerKeyCommands(program, client) {
13
12
  handleError(error);
14
13
  }
15
14
  });
16
- keys
17
- .command("list")
15
+ keys.command("list")
18
16
  .description("list API keys (requires admin scope)")
19
17
  .action(async () => {
20
18
  try {
@@ -25,11 +23,10 @@ export function registerKeyCommands(program, client) {
25
23
  handleError(error);
26
24
  }
27
25
  });
28
- keys
29
- .command("create")
26
+ keys.command("create")
30
27
  .description("create a new API key (requires admin scope)")
31
28
  .requiredOption("-n, --name <name>", "key name")
32
- .option("--scopes <list>", "comma-separated scopes: campaigns:read, campaigns:write, contacts:read, contacts:write, messages:read, messages:write, conversations:read, conversations:write, discovery:write, ai:write, notifications:read, notifications:write, webhooks:read, webhooks:write", parseList)
29
+ .option("--scopes <list>", "comma-separated scopes: read, write, delete, generate, send, admin (defaults to all)", parseList)
33
30
  .action(async (opts) => {
34
31
  try {
35
32
  const body = { name: opts.name };
@@ -42,8 +39,7 @@ export function registerKeyCommands(program, client) {
42
39
  handleError(error);
43
40
  }
44
41
  });
45
- keys
46
- .command("rename <id>")
42
+ keys.command("rename <id>")
47
43
  .description("rename an API key (requires admin scope)")
48
44
  .requiredOption("-n, --name <name>", "new key name")
49
45
  .action(async (id, opts) => {
@@ -55,8 +51,7 @@ export function registerKeyCommands(program, client) {
55
51
  handleError(error);
56
52
  }
57
53
  });
58
- keys
59
- .command("revoke <id>")
54
+ keys.command("revoke <id>")
60
55
  .description("permanently revoke an API key (requires admin scope)")
61
56
  .action(async (id) => {
62
57
  try {
@@ -1,6 +1,9 @@
1
1
  import { formatOutput, handleError, getFormat, parseList } from "../cli-utils.js";
2
2
  export function registerMessageCommands(program, client) {
3
- const messages = program.command("messages").alias("m").description("manage AI-generated messages and approval queue");
3
+ const messages = program
4
+ .command("messages")
5
+ .alias("m")
6
+ .description("manage AI-generated messages and approval queue");
4
7
  messages
5
8
  .command("pending")
6
9
  .description("list messages pending approval")
@@ -90,13 +93,13 @@ export function registerMessageCommands(program, client) {
90
93
  .command("bulk")
91
94
  .description("bulk approve or reject pending messages")
92
95
  .requiredOption("-a, --action <action>", "action: approve or reject")
93
- .requiredOption("--ids <list>", "comma-separated message IDs", parseList)
96
+ .requiredOption("--message-ids <list>", "comma-separated message IDs", parseList)
94
97
  .option("--reason <text>", "rejection reason (when action is reject)")
95
98
  .action(async (opts) => {
96
99
  try {
97
100
  const body = {
98
101
  action: opts.action,
99
- ids: opts.ids,
102
+ message_ids: opts.messageIds,
100
103
  };
101
104
  if (opts.reason)
102
105
  body.reason = opts.reason;
@@ -119,4 +119,16 @@ export function registerWebhookCommands(program, client) {
119
119
  handleError(error);
120
120
  }
121
121
  });
122
+ webhooks
123
+ .command("rotate-secret <id>")
124
+ .description("rotate the signing secret for a webhook (old secret invalidated immediately)")
125
+ .action(async (id) => {
126
+ try {
127
+ const result = await client.post(`/webhooks/${id}/rotate-secret`);
128
+ formatOutput(result, getFormat(program.opts()));
129
+ }
130
+ catch (error) {
131
+ handleError(error);
132
+ }
133
+ });
122
134
  }
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
2
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
5
  import { IrisClient } from "./client.js";
@@ -15,9 +16,11 @@ import { registerNotificationTools } from "./tools/notifications.js";
15
16
  import { registerKeyTools } from "./tools/keys.js";
16
17
  import { registerWebhookTools } from "./tools/webhooks.js";
17
18
  import { registerAgentCreditTools } from "./tools/agent-credits.js";
19
+ const requireFromHere = createRequire(import.meta.url);
20
+ const pkg = requireFromHere("../package.json");
18
21
  const server = new McpServer({
19
22
  name: "iris",
20
- version: "0.2.3",
23
+ version: pkg.version,
21
24
  });
22
25
  const client = new IrisClient();
23
26
  registerCampaignTools(server, client);
package/dist/tools/ai.js CHANGED
@@ -1,11 +1,9 @@
1
1
  import { z } from "zod";
2
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.", {
3
+ server.tool("generate_content", "generate AI content for a specific contact conversation (email draft, follow-up, reply). requires generate scope.", {
4
4
  contact_id: z.string().uuid().describe("contact ID"),
5
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"),
6
+ generation_type: z.enum(["initial_email", "follow_up", "reply"]).describe("type of content to generate"),
9
7
  context: z.string().max(2000).optional().describe("additional context for the AI"),
10
8
  }, async (args) => {
11
9
  try {
@@ -14,12 +12,17 @@ export function registerAiTools(server, client) {
14
12
  }
15
13
  catch (error) {
16
14
  return {
17
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
15
+ content: [
16
+ {
17
+ type: "text",
18
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
19
+ },
20
+ ],
18
21
  isError: true,
19
22
  };
20
23
  }
21
24
  });
22
- server.tool("generate_campaign_content", "generate AI content at the campaign level (email templates, subject lines). requires ai:write scope.", {
25
+ server.tool("generate_campaign_content", "generate AI content at the campaign level (email templates, subject lines). requires generate scope.", {
23
26
  campaign_id: z.string().uuid().describe("campaign ID"),
24
27
  content_type: z
25
28
  .enum(["email_template", "subject_lines", "campaign_brief"])
@@ -31,12 +34,17 @@ export function registerAiTools(server, client) {
31
34
  }
32
35
  catch (error) {
33
36
  return {
34
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
37
+ content: [
38
+ {
39
+ type: "text",
40
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
41
+ },
42
+ ],
35
43
  isError: true,
36
44
  };
37
45
  }
38
46
  });
39
- server.tool("analyze_response", "analyze an inbound message using AI to determine sentiment, intent, and suggested actions. requires ai:write scope.", {
47
+ server.tool("analyze_response", "analyze an inbound message using AI to determine sentiment, intent, and suggested actions. requires generate scope.", {
40
48
  conversation_id: z.string().uuid().describe("conversation ID"),
41
49
  message_content: z.string().min(1).max(10000).describe("message content to analyze"),
42
50
  }, async (args) => {
@@ -46,34 +54,29 @@ export function registerAiTools(server, client) {
46
54
  }
47
55
  catch (error) {
48
56
  return {
49
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
57
+ content: [
58
+ {
59
+ type: "text",
60
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
61
+ },
62
+ ],
50
63
  isError: true,
51
64
  };
52
65
  }
53
66
  });
54
- server.tool("get_ai_usage", "get AI generation usage limits and current counts for the billing period. requires ai:read scope.", {}, async () => {
67
+ server.tool("get_ai_usage", "get AI generation usage limits and current counts for the billing period. requires read scope.", {}, async () => {
55
68
  try {
56
69
  const result = await client.get("/ai/usage");
57
70
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
58
71
  }
59
72
  catch (error) {
60
73
  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)}` }],
74
+ content: [
75
+ {
76
+ type: "text",
77
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
78
+ },
79
+ ],
77
80
  isError: true,
78
81
  };
79
82
  }
@@ -1,18 +1,23 @@
1
1
  import { z } from "zod";
2
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 () => {
3
+ server.tool("get_analytics_overview", "get a high-level overview of all campaign analytics. requires read scope.", {}, async () => {
4
4
  try {
5
5
  const result = await client.get("/analytics/overview");
6
6
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
7
7
  }
8
8
  catch (error) {
9
9
  return {
10
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
10
+ content: [
11
+ {
12
+ type: "text",
13
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
14
+ },
15
+ ],
11
16
  isError: true,
12
17
  };
13
18
  }
14
19
  });
15
- server.tool("get_campaign_analytics", "get detailed analytics for a specific campaign. requires analytics:read scope.", {
20
+ server.tool("get_campaign_analytics", "get detailed analytics for a specific campaign. requires read scope.", {
16
21
  id: z.string().uuid().describe("campaign ID"),
17
22
  }, async ({ id }) => {
18
23
  try {
@@ -21,19 +26,18 @@ export function registerAnalyticsTools(server, client) {
21
26
  }
22
27
  catch (error) {
23
28
  return {
24
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
29
+ content: [
30
+ {
31
+ type: "text",
32
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
33
+ },
34
+ ],
25
35
  isError: true,
26
36
  };
27
37
  }
28
38
  });
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)"),
39
+ server.tool("get_performance_metrics", "get email performance metrics over time. requires read scope.", {
40
+ days: z.number().int().min(1).max(90).optional().describe("time window in days (1–90, default 30)"),
37
41
  campaign_id: z.string().uuid().optional().describe("filter by campaign ID"),
38
42
  }, async ({ days, campaign_id }) => {
39
43
  try {
@@ -47,12 +51,17 @@ export function registerAnalyticsTools(server, client) {
47
51
  }
48
52
  catch (error) {
49
53
  return {
50
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
54
+ content: [
55
+ {
56
+ type: "text",
57
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
58
+ },
59
+ ],
51
60
  isError: true,
52
61
  };
53
62
  }
54
63
  });
55
- server.tool("get_response_time", "get average response time analytics. requires analytics:read scope.", {
64
+ server.tool("get_response_time", "get average response time analytics. requires read scope.", {
56
65
  campaign_id: z.string().uuid().optional().describe("filter by campaign ID"),
57
66
  }, async ({ campaign_id }) => {
58
67
  try {
@@ -64,19 +73,26 @@ export function registerAnalyticsTools(server, client) {
64
73
  }
65
74
  catch (error) {
66
75
  return {
67
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
76
+ content: [
77
+ {
78
+ type: "text",
79
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
80
+ },
81
+ ],
68
82
  isError: true,
69
83
  };
70
84
  }
71
85
  });
72
- server.tool("get_contact_types", "get breakdown of contacts by type/source. requires analytics:read scope.", {}, async () => {
86
+ server.tool("get_contact_types", "get breakdown of contacts by type/source. requires read scope.", {}, async () => {
73
87
  try {
74
88
  const result = await client.get("/analytics/contact-types");
75
89
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
76
90
  }
77
91
  catch (error) {
78
92
  return {
79
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
93
+ content: [
94
+ { type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` },
95
+ ],
80
96
  isError: true,
81
97
  };
82
98
  }
@@ -1,12 +1,17 @@
1
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 () => {
2
+ server.tool("get_billing_plans", "get all available billing plans with pricing and feature limits. requires read scope.", {}, async () => {
3
3
  try {
4
4
  const result = await client.get("/billing/plans");
5
5
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
6
6
  }
7
7
  catch (error) {
8
8
  return {
9
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
9
+ content: [
10
+ {
11
+ type: "text",
12
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
13
+ },
14
+ ],
10
15
  isError: true,
11
16
  };
12
17
  }
@@ -13,7 +13,7 @@ const TARGET_PROFILE_TYPES = [
13
13
  "other",
14
14
  ];
15
15
  export function registerCampaignTools(server, client) {
16
- server.tool("list_campaigns", "list all campaigns with optional filtering by status. requires campaigns:read scope.", {
16
+ server.tool("list_campaigns", "list all campaigns with optional filtering by status. requires read scope.", {
17
17
  page: z.number().int().positive().optional().describe("page number (default 1)"),
18
18
  page_size: z.number().int().min(1).max(100).optional().describe("items per page (default 50, max 100)"),
19
19
  status: z.enum(CAMPAIGN_STATUSES).optional().describe("filter by campaign status"),
@@ -31,17 +31,26 @@ export function registerCampaignTools(server, client) {
31
31
  }
32
32
  catch (error) {
33
33
  return {
34
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
34
+ content: [
35
+ {
36
+ type: "text",
37
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
38
+ },
39
+ ],
35
40
  isError: true,
36
41
  };
37
42
  }
38
43
  });
39
- server.tool("create_campaign", "create a new outreach campaign. requires campaigns:write scope.", {
44
+ server.tool("create_campaign", "create a new outreach campaign. requires write scope.", {
40
45
  name: z.string().min(1).max(100).describe("campaign name"),
41
46
  objective_type: z.enum(OBJECTIVE_TYPES).describe("campaign objective type"),
42
47
  product_name: z.string().max(200).optional().describe("product name (for product_promotion objective)"),
43
48
  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)"),
49
+ product_description: z
50
+ .string()
51
+ .max(2000)
52
+ .optional()
53
+ .describe("product description (for product_promotion objective)"),
45
54
  }, async (args) => {
46
55
  try {
47
56
  const result = await client.post("/campaigns", args);
@@ -49,12 +58,17 @@ export function registerCampaignTools(server, client) {
49
58
  }
50
59
  catch (error) {
51
60
  return {
52
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
61
+ content: [
62
+ {
63
+ type: "text",
64
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
65
+ },
66
+ ],
53
67
  isError: true,
54
68
  };
55
69
  }
56
70
  });
57
- server.tool("get_campaign", "get a campaign by ID with stats. requires campaigns:read scope.", {
71
+ server.tool("get_campaign", "get a campaign by ID with stats. requires read scope.", {
58
72
  id: z.string().uuid().describe("campaign ID"),
59
73
  }, async ({ id }) => {
60
74
  try {
@@ -63,12 +77,17 @@ export function registerCampaignTools(server, client) {
63
77
  }
64
78
  catch (error) {
65
79
  return {
66
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
80
+ content: [
81
+ {
82
+ type: "text",
83
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
84
+ },
85
+ ],
67
86
  isError: true,
68
87
  };
69
88
  }
70
89
  });
71
- server.tool("update_campaign", "update a campaign's details. requires campaigns:write scope.", {
90
+ server.tool("update_campaign", "update a campaign's details. requires write scope.", {
72
91
  id: z.string().uuid().describe("campaign ID"),
73
92
  name: z.string().min(1).max(100).optional().describe("new campaign name"),
74
93
  status: z.enum(CAMPAIGN_STATUSES).optional().describe("new campaign status"),
@@ -82,12 +101,17 @@ export function registerCampaignTools(server, client) {
82
101
  }
83
102
  catch (error) {
84
103
  return {
85
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
104
+ content: [
105
+ {
106
+ type: "text",
107
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
108
+ },
109
+ ],
86
110
  isError: true,
87
111
  };
88
112
  }
89
113
  });
90
- server.tool("delete_campaign", "soft-delete a campaign (sets status to deleted). requires campaigns:write scope.", {
114
+ server.tool("delete_campaign", "soft-delete a campaign (sets status to deleted). requires write scope.", {
91
115
  id: z.string().uuid().describe("campaign ID"),
92
116
  }, async ({ id }) => {
93
117
  try {
@@ -96,12 +120,17 @@ export function registerCampaignTools(server, client) {
96
120
  }
97
121
  catch (error) {
98
122
  return {
99
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
123
+ content: [
124
+ {
125
+ type: "text",
126
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
127
+ },
128
+ ],
100
129
  isError: true,
101
130
  };
102
131
  }
103
132
  });
104
- server.tool("list_campaign_contacts", "list contacts in a campaign with optional status filter. requires campaigns:read scope.", {
133
+ server.tool("list_campaign_contacts", "list contacts in a campaign with optional status filter. requires read scope.", {
105
134
  id: z.string().uuid().describe("campaign ID"),
106
135
  page: z.number().int().positive().optional().describe("page number (default 1)"),
107
136
  page_size: z.number().int().min(1).max(100).optional().describe("items per page (default 50, max 100)"),
@@ -123,12 +152,17 @@ export function registerCampaignTools(server, client) {
123
152
  }
124
153
  catch (error) {
125
154
  return {
126
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
155
+ content: [
156
+ {
157
+ type: "text",
158
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
159
+ },
160
+ ],
127
161
  isError: true,
128
162
  };
129
163
  }
130
164
  });
131
- server.tool("get_campaign_usage", "get usage limits and current counts for a campaign. requires campaigns:read scope.", {
165
+ server.tool("get_campaign_usage", "get usage limits and current counts for a campaign. requires read scope.", {
132
166
  id: z.string().uuid().describe("campaign ID"),
133
167
  }, async ({ id }) => {
134
168
  try {
@@ -137,12 +171,17 @@ export function registerCampaignTools(server, client) {
137
171
  }
138
172
  catch (error) {
139
173
  return {
140
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
174
+ content: [
175
+ {
176
+ type: "text",
177
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
178
+ },
179
+ ],
141
180
  isError: true,
142
181
  };
143
182
  }
144
183
  });
145
- server.tool("analyze_campaign", "trigger AI analysis of a campaign to generate target profiles and recommendations. requires campaigns:write scope.", {
184
+ server.tool("analyze_campaign", "trigger AI analysis of a campaign to generate target profiles and recommendations. requires write scope.", {
146
185
  id: z.string().uuid().describe("campaign ID"),
147
186
  }, async ({ id }) => {
148
187
  try {
@@ -151,12 +190,17 @@ export function registerCampaignTools(server, client) {
151
190
  }
152
191
  catch (error) {
153
192
  return {
154
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
193
+ content: [
194
+ {
195
+ type: "text",
196
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
197
+ },
198
+ ],
155
199
  isError: true,
156
200
  };
157
201
  }
158
202
  });
159
- server.tool("list_target_profiles", "list target profiles for a campaign. requires campaigns:read scope.", {
203
+ server.tool("list_target_profiles", "list target profiles for a campaign. requires read scope.", {
160
204
  id: z.string().uuid().describe("campaign ID"),
161
205
  }, async ({ id }) => {
162
206
  try {
@@ -165,12 +209,17 @@ export function registerCampaignTools(server, client) {
165
209
  }
166
210
  catch (error) {
167
211
  return {
168
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
212
+ content: [
213
+ {
214
+ type: "text",
215
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
216
+ },
217
+ ],
169
218
  isError: true,
170
219
  };
171
220
  }
172
221
  });
173
- server.tool("create_target_profile", "create a target profile for a campaign. requires campaigns:write scope.", {
222
+ server.tool("create_target_profile", "create a target profile for a campaign. requires write scope.", {
174
223
  id: z.string().uuid().describe("campaign ID"),
175
224
  name: z.string().min(1).max(200).describe("profile name"),
176
225
  profile_type: z.enum(TARGET_PROFILE_TYPES).describe("type of target profile"),
@@ -188,12 +237,17 @@ export function registerCampaignTools(server, client) {
188
237
  }
189
238
  catch (error) {
190
239
  return {
191
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
240
+ content: [
241
+ {
242
+ type: "text",
243
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
244
+ },
245
+ ],
192
246
  isError: true,
193
247
  };
194
248
  }
195
249
  });
196
- server.tool("delete_target_profile", "delete a target profile from a campaign. requires campaigns:write scope.", {
250
+ server.tool("delete_target_profile", "delete a target profile from a campaign. requires write scope.", {
197
251
  id: z.string().uuid().describe("campaign ID"),
198
252
  profile_id: z.string().uuid().describe("target profile ID"),
199
253
  }, async ({ id, profile_id }) => {
@@ -203,7 +257,12 @@ export function registerCampaignTools(server, client) {
203
257
  }
204
258
  catch (error) {
205
259
  return {
206
- content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
260
+ content: [
261
+ {
262
+ type: "text",
263
+ text: `error: ${error instanceof Error ? error.message : String(error)}`,
264
+ },
265
+ ],
207
266
  isError: true,
208
267
  };
209
268
  }