@affset/mcp 0.1.1 → 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 (63) hide show
  1. package/.env.example +5 -0
  2. package/README.md +114 -37
  3. package/dist/client.d.ts +43 -0
  4. package/dist/client.js +15 -2
  5. package/dist/config.d.ts +7 -0
  6. package/dist/config.js +15 -54
  7. package/dist/core.d.ts +18 -0
  8. package/dist/core.js +18 -0
  9. package/dist/docs.d.ts +39 -0
  10. package/dist/docs.js +105 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/lib/format.d.ts +46 -0
  13. package/dist/lib/format.js +3 -0
  14. package/dist/lib/integrationUrls.d.ts +57 -0
  15. package/dist/lib/linkArgs.d.ts +27 -0
  16. package/dist/lib/patch.d.ts +10 -0
  17. package/dist/lib/payoutRules.d.ts +38 -0
  18. package/dist/lib/readBody.d.ts +17 -0
  19. package/dist/lib/readBody.js +69 -0
  20. package/dist/lib/targeting.d.ts +51 -0
  21. package/dist/lib/time.d.ts +38 -0
  22. package/dist/lib/toolResult.d.ts +7 -0
  23. package/dist/lib/urls.d.ts +2 -0
  24. package/dist/lib/zones.d.ts +24 -0
  25. package/dist/registerTools.d.ts +40 -0
  26. package/dist/registerTools.js +401 -0
  27. package/dist/runtimeConfig.d.ts +37 -0
  28. package/dist/runtimeConfig.js +93 -0
  29. package/dist/server.d.ts +4 -0
  30. package/dist/server.js +3 -318
  31. package/dist/tools/createCampaign.d.ts +25 -0
  32. package/dist/tools/createTeamMember.d.ts +26 -0
  33. package/dist/tools/createZone.d.ts +22 -0
  34. package/dist/tools/cutZones.d.ts +29 -0
  35. package/dist/tools/deletePayoutRule.d.ts +16 -0
  36. package/dist/tools/getCampaign.d.ts +12 -0
  37. package/dist/tools/getCampaign.js +150 -0
  38. package/dist/tools/getStats.d.ts +40 -0
  39. package/dist/tools/getStats.js +37 -2
  40. package/dist/tools/getTrackingLink.d.ts +23 -0
  41. package/dist/tools/getZoneUrl.d.ts +21 -0
  42. package/dist/tools/listCampaigns.d.ts +23 -0
  43. package/dist/tools/listConversions.d.ts +29 -0
  44. package/dist/tools/listPayoutRules.d.ts +12 -0
  45. package/dist/tools/listSubLabels.d.ts +5 -0
  46. package/dist/tools/listTargetingRules.d.ts +12 -0
  47. package/dist/tools/listTargetingTypes.d.ts +5 -0
  48. package/dist/tools/listTeam.d.ts +14 -0
  49. package/dist/tools/listZones.d.ts +23 -0
  50. package/dist/tools/removeTargetingRule.d.ts +21 -0
  51. package/dist/tools/setCampaignStatus.d.ts +18 -0
  52. package/dist/tools/setPayoutGoal.d.ts +16 -0
  53. package/dist/tools/setPayoutRule.d.ts +18 -0
  54. package/dist/tools/setSubLabels.d.ts +22 -0
  55. package/dist/tools/setTargetingRule.d.ts +21 -0
  56. package/dist/tools/updateCampaign.d.ts +35 -0
  57. package/dist/tools/updateZone.d.ts +25 -0
  58. package/dist/tools/whoami.d.ts +6 -0
  59. package/dist/types.d.ts +210 -0
  60. package/dist/types.js +1 -0
  61. package/dist/version.d.ts +7 -0
  62. package/dist/version.js +8 -0
  63. package/package.json +15 -2
package/dist/server.js CHANGED
@@ -1,328 +1,13 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { AffsetClient } from "./client.js";
3
- import { getStats, getStatsInputSchema, GET_STATS_DESCRIPTION } from "./tools/getStats.js";
4
- import { cutZones, cutZonesInputSchema, CUT_ZONES_DESCRIPTION } from "./tools/cutZones.js";
5
- import { createCampaign, createCampaignInputSchema, CREATE_CAMPAIGN_DESCRIPTION, } from "./tools/createCampaign.js";
6
- import { listCampaigns, listCampaignsInputSchema, LIST_CAMPAIGNS_DESCRIPTION, } from "./tools/listCampaigns.js";
7
- import { listZones, listZonesInputSchema, LIST_ZONES_DESCRIPTION } from "./tools/listZones.js";
8
- import { listTeam, listTeamInputSchema, LIST_TEAM_DESCRIPTION } from "./tools/listTeam.js";
9
- import { createTeamMember, createTeamMemberInputSchema, CREATE_TEAM_MEMBER_DESCRIPTION, } from "./tools/createTeamMember.js";
10
- import { createZone, createZoneInputSchema, CREATE_ZONE_DESCRIPTION } from "./tools/createZone.js";
11
- import { getZoneUrl, getZoneUrlInputSchema, GET_ZONE_URL_DESCRIPTION } from "./tools/getZoneUrl.js";
12
- import { getTrackingLink, getTrackingLinkInputSchema, GET_TRACKING_LINK_DESCRIPTION, } from "./tools/getTrackingLink.js";
13
- import { updateZone, updateZoneInputSchema, UPDATE_ZONE_DESCRIPTION } from "./tools/updateZone.js";
14
- import { updateCampaign, updateCampaignInputSchema, UPDATE_CAMPAIGN_DESCRIPTION, } from "./tools/updateCampaign.js";
15
- import { setCampaignStatus, setCampaignStatusInputSchema, SET_CAMPAIGN_STATUS_DESCRIPTION, } from "./tools/setCampaignStatus.js";
16
- import { listPayoutRules, listPayoutRulesInputSchema, LIST_PAYOUT_RULES_DESCRIPTION, } from "./tools/listPayoutRules.js";
17
- import { setPayoutRule, setPayoutRuleInputSchema, SET_PAYOUT_RULE_DESCRIPTION, } from "./tools/setPayoutRule.js";
18
- import { deletePayoutRule, deletePayoutRuleInputSchema, DELETE_PAYOUT_RULE_DESCRIPTION, } from "./tools/deletePayoutRule.js";
19
- import { setPayoutGoal, setPayoutGoalInputSchema, SET_PAYOUT_GOAL_DESCRIPTION, } from "./tools/setPayoutGoal.js";
20
- import { listTargetingTypes, listTargetingTypesInputSchema, LIST_TARGETING_TYPES_DESCRIPTION, } from "./tools/listTargetingTypes.js";
21
- import { listTargetingRules, listTargetingRulesInputSchema, LIST_TARGETING_RULES_DESCRIPTION, } from "./tools/listTargetingRules.js";
22
- import { setTargetingRule, setTargetingRuleInputSchema, SET_TARGETING_RULE_DESCRIPTION, } from "./tools/setTargetingRule.js";
23
- import { removeTargetingRule, removeTargetingRuleInputSchema, REMOVE_TARGETING_RULE_DESCRIPTION, } from "./tools/removeTargetingRule.js";
24
- import { listSubLabels, listSubLabelsInputSchema, LIST_SUB_LABELS_DESCRIPTION, } from "./tools/listSubLabels.js";
25
- import { setSubLabels, setSubLabelsInputSchema, SET_SUB_LABELS_DESCRIPTION, } from "./tools/setSubLabels.js";
26
- import { listConversions, listConversionsInputSchema, LIST_CONVERSIONS_DESCRIPTION, } from "./tools/listConversions.js";
27
- import { whoami, whoamiInputSchema, WHOAMI_DESCRIPTION } from "./tools/whoami.js";
28
- import { createRequire } from "node:module";
29
- const require = createRequire(import.meta.url);
30
- const { version: VERSION } = require("../package.json");
2
+ import { registerAffsetTools } from "./registerTools.js";
3
+ import { VERSION } from "./version.js";
31
4
  /** Build the MCP server with the affset tools registered against `config`. */
32
5
  export function createServer(config) {
33
- const client = new AffsetClient(config);
34
6
  const server = new McpServer({
35
7
  name: "affset-mcp",
36
8
  version: VERSION,
37
9
  });
38
- // Registers every tool as normal, then immediately removes anything that isn't
39
- // readOnlyHint:true when AFFSET_READ_ONLY is set — a mutation tool never has a
40
- // chance to appear in tools/list or be called. See AFFSET_READ_ONLY in the README
41
- // for why this exists (untrusted third-party data can reach model context via
42
- // list_conversions/get_stats, so mutation tools are an injection blast-radius
43
- // control, not just a UI nicety).
44
- const registerTool = (name, toolConfig, cb) => {
45
- const tool = server.registerTool(name, toolConfig, cb);
46
- if (config.readOnly && toolConfig.annotations?.readOnlyHint !== true) {
47
- tool.remove();
48
- }
49
- return tool;
50
- };
51
- registerTool("whoami", {
52
- title: "Show the tenant this MCP is bound to",
53
- description: WHOAMI_DESCRIPTION,
54
- inputSchema: whoamiInputSchema,
55
- annotations: {
56
- readOnlyHint: true,
57
- destructiveHint: false,
58
- idempotentHint: true,
59
- openWorldHint: true,
60
- },
61
- }, () => whoami(client, config));
62
- registerTool("get_stats", {
63
- title: "Get affset stats",
64
- description: GET_STATS_DESCRIPTION,
65
- inputSchema: getStatsInputSchema,
66
- annotations: {
67
- readOnlyHint: true,
68
- destructiveHint: false,
69
- idempotentHint: true,
70
- openWorldHint: true,
71
- },
72
- }, (args) => getStats(client, args));
73
- registerTool("list_campaigns", {
74
- title: "List campaigns",
75
- description: LIST_CAMPAIGNS_DESCRIPTION,
76
- inputSchema: listCampaignsInputSchema,
77
- annotations: {
78
- readOnlyHint: true,
79
- destructiveHint: false,
80
- idempotentHint: true,
81
- openWorldHint: true,
82
- },
83
- }, (args) => listCampaigns(client, args));
84
- registerTool("list_zones", {
85
- title: "List zones",
86
- description: LIST_ZONES_DESCRIPTION,
87
- inputSchema: listZonesInputSchema,
88
- annotations: {
89
- readOnlyHint: true,
90
- destructiveHint: false,
91
- idempotentHint: true,
92
- openWorldHint: true,
93
- },
94
- }, (args) => listZones(client, args));
95
- registerTool("list_team", {
96
- title: "List team members",
97
- description: LIST_TEAM_DESCRIPTION,
98
- inputSchema: listTeamInputSchema,
99
- annotations: {
100
- readOnlyHint: true,
101
- destructiveHint: false,
102
- idempotentHint: true,
103
- openWorldHint: true,
104
- },
105
- }, (args) => listTeam(client, args));
106
- registerTool("create_team_member", {
107
- title: "Invite a team member",
108
- description: CREATE_TEAM_MEMBER_DESCRIPTION,
109
- inputSchema: createTeamMemberInputSchema,
110
- annotations: {
111
- readOnlyHint: false,
112
- destructiveHint: false,
113
- idempotentHint: false,
114
- openWorldHint: true,
115
- },
116
- }, (args) => createTeamMember(client, args));
117
- registerTool("get_zone_url", {
118
- title: "Get the zone URL for a traffic source",
119
- description: GET_ZONE_URL_DESCRIPTION,
120
- inputSchema: getZoneUrlInputSchema,
121
- annotations: {
122
- readOnlyHint: true,
123
- destructiveHint: false,
124
- idempotentHint: true,
125
- openWorldHint: true,
126
- },
127
- }, (args) => getZoneUrl(client, config, args));
128
- registerTool("get_tracking_link", {
129
- title: "Get a campaign's tracking link",
130
- description: GET_TRACKING_LINK_DESCRIPTION,
131
- inputSchema: getTrackingLinkInputSchema,
132
- annotations: {
133
- readOnlyHint: true,
134
- destructiveHint: false,
135
- idempotentHint: true,
136
- openWorldHint: true,
137
- },
138
- }, (args) => getTrackingLink(client, config, args));
139
- registerTool("create_campaign", {
140
- title: "Create a campaign",
141
- description: CREATE_CAMPAIGN_DESCRIPTION,
142
- inputSchema: createCampaignInputSchema,
143
- annotations: {
144
- readOnlyHint: false,
145
- destructiveHint: false,
146
- idempotentHint: false,
147
- openWorldHint: true,
148
- },
149
- }, (args) => createCampaign(client, config, args));
150
- registerTool("update_campaign", {
151
- title: "Update a campaign",
152
- description: UPDATE_CAMPAIGN_DESCRIPTION,
153
- inputSchema: updateCampaignInputSchema,
154
- annotations: {
155
- readOnlyHint: false,
156
- destructiveHint: true,
157
- idempotentHint: false,
158
- openWorldHint: true,
159
- },
160
- }, (args) => updateCampaign(client, args));
161
- registerTool("set_campaign_status", {
162
- title: "Run or pause a campaign",
163
- description: SET_CAMPAIGN_STATUS_DESCRIPTION,
164
- inputSchema: setCampaignStatusInputSchema,
165
- annotations: {
166
- readOnlyHint: false,
167
- destructiveHint: true,
168
- idempotentHint: false,
169
- openWorldHint: true,
170
- },
171
- }, (args) => setCampaignStatus(client, args));
172
- registerTool("create_zone", {
173
- title: "Create a zone",
174
- description: CREATE_ZONE_DESCRIPTION,
175
- inputSchema: createZoneInputSchema,
176
- annotations: {
177
- readOnlyHint: false,
178
- destructiveHint: false,
179
- idempotentHint: false,
180
- openWorldHint: true,
181
- },
182
- }, (args) => createZone(client, args));
183
- registerTool("update_zone", {
184
- title: "Update a zone",
185
- description: UPDATE_ZONE_DESCRIPTION,
186
- inputSchema: updateZoneInputSchema,
187
- annotations: {
188
- readOnlyHint: false,
189
- destructiveHint: true,
190
- idempotentHint: false,
191
- openWorldHint: true,
192
- },
193
- }, (args) => updateZone(client, args));
194
- registerTool("cut_zones", {
195
- title: "Cut underperforming zones",
196
- description: CUT_ZONES_DESCRIPTION,
197
- inputSchema: cutZonesInputSchema,
198
- annotations: {
199
- readOnlyHint: false,
200
- destructiveHint: true,
201
- idempotentHint: false,
202
- openWorldHint: true,
203
- },
204
- }, (args) => cutZones(client, args));
205
- registerTool("list_payout_rules", {
206
- title: "List payout rules",
207
- description: LIST_PAYOUT_RULES_DESCRIPTION,
208
- inputSchema: listPayoutRulesInputSchema,
209
- annotations: {
210
- readOnlyHint: true,
211
- destructiveHint: false,
212
- idempotentHint: true,
213
- openWorldHint: true,
214
- },
215
- }, (args) => listPayoutRules(client, args));
216
- registerTool("set_payout_rule", {
217
- title: "Set a payout rule",
218
- description: SET_PAYOUT_RULE_DESCRIPTION,
219
- inputSchema: setPayoutRuleInputSchema,
220
- annotations: {
221
- readOnlyHint: false,
222
- destructiveHint: true,
223
- idempotentHint: false,
224
- openWorldHint: true,
225
- },
226
- }, (args) => setPayoutRule(client, args));
227
- registerTool("delete_payout_rule", {
228
- title: "Delete a payout rule",
229
- description: DELETE_PAYOUT_RULE_DESCRIPTION,
230
- inputSchema: deletePayoutRuleInputSchema,
231
- annotations: {
232
- readOnlyHint: false,
233
- destructiveHint: true,
234
- idempotentHint: false,
235
- openWorldHint: true,
236
- },
237
- }, (args) => deletePayoutRule(client, args));
238
- registerTool("set_payout_goal", {
239
- title: "Set payout goal type",
240
- description: SET_PAYOUT_GOAL_DESCRIPTION,
241
- inputSchema: setPayoutGoalInputSchema,
242
- annotations: {
243
- readOnlyHint: false,
244
- destructiveHint: true,
245
- idempotentHint: false,
246
- openWorldHint: true,
247
- },
248
- }, (args) => setPayoutGoal(client, args));
249
- registerTool("list_targeting_types", {
250
- title: "List targeting rule types",
251
- description: LIST_TARGETING_TYPES_DESCRIPTION,
252
- inputSchema: listTargetingTypesInputSchema,
253
- annotations: {
254
- readOnlyHint: true,
255
- destructiveHint: false,
256
- idempotentHint: true,
257
- openWorldHint: true,
258
- },
259
- }, () => listTargetingTypes(client));
260
- registerTool("list_targeting_rules", {
261
- title: "List campaign targeting rules",
262
- description: LIST_TARGETING_RULES_DESCRIPTION,
263
- inputSchema: listTargetingRulesInputSchema,
264
- annotations: {
265
- readOnlyHint: true,
266
- destructiveHint: false,
267
- idempotentHint: true,
268
- openWorldHint: true,
269
- },
270
- }, (args) => listTargetingRules(client, args));
271
- registerTool("set_targeting_rule", {
272
- title: "Set a targeting rule",
273
- description: SET_TARGETING_RULE_DESCRIPTION,
274
- inputSchema: setTargetingRuleInputSchema,
275
- annotations: {
276
- readOnlyHint: false,
277
- destructiveHint: true,
278
- idempotentHint: false,
279
- openWorldHint: true,
280
- },
281
- }, (args) => setTargetingRule(client, args));
282
- registerTool("remove_targeting_rule", {
283
- title: "Remove a targeting rule",
284
- description: REMOVE_TARGETING_RULE_DESCRIPTION,
285
- inputSchema: removeTargetingRuleInputSchema,
286
- annotations: {
287
- readOnlyHint: false,
288
- destructiveHint: true,
289
- idempotentHint: false,
290
- openWorldHint: true,
291
- },
292
- }, (args) => removeTargetingRule(client, args));
293
- registerTool("list_sub_labels", {
294
- title: "List sub labels",
295
- description: LIST_SUB_LABELS_DESCRIPTION,
296
- inputSchema: listSubLabelsInputSchema,
297
- annotations: {
298
- readOnlyHint: true,
299
- destructiveHint: false,
300
- idempotentHint: true,
301
- openWorldHint: true,
302
- },
303
- }, () => listSubLabels(client));
304
- registerTool("set_sub_labels", {
305
- title: "Set sub labels",
306
- description: SET_SUB_LABELS_DESCRIPTION,
307
- inputSchema: setSubLabelsInputSchema,
308
- annotations: {
309
- readOnlyHint: false,
310
- destructiveHint: true,
311
- idempotentHint: false,
312
- openWorldHint: true,
313
- },
314
- }, (args) => setSubLabels(client, args));
315
- registerTool("list_conversions", {
316
- title: "List conversions",
317
- description: LIST_CONVERSIONS_DESCRIPTION,
318
- inputSchema: listConversionsInputSchema,
319
- annotations: {
320
- readOnlyHint: true,
321
- destructiveHint: false,
322
- idempotentHint: true,
323
- openWorldHint: true,
324
- },
325
- }, (args) => listConversions(client, args));
10
+ registerAffsetTools(server, config);
326
11
  return server;
327
12
  }
328
13
  //# sourceMappingURL=server.js.map
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import { type AffsetClient } from "../client.js";
4
+ import type { Config } from "../runtimeConfig.js";
5
+ export declare const CREATE_CAMPAIGN_DESCRIPTION: string;
6
+ export declare const createCampaignInputSchema: {
7
+ user_email: z.ZodString;
8
+ offer_url: z.ZodString;
9
+ name: z.ZodOptional<z.ZodString>;
10
+ geo: z.ZodOptional<z.ZodArray<z.ZodString, "atleastone">>;
11
+ payout: z.ZodOptional<z.ZodNumber>;
12
+ zone_id: z.ZodOptional<z.ZodString>;
13
+ confirm: z.ZodDefault<z.ZodBoolean>;
14
+ };
15
+ type CreateCampaignArgs = {
16
+ user_email: string;
17
+ offer_url: string;
18
+ name?: string;
19
+ geo?: string[];
20
+ payout?: number;
21
+ zone_id?: string;
22
+ confirm: boolean;
23
+ };
24
+ export declare function createCampaign(client: AffsetClient, config: Config, args: CreateCampaignArgs): Promise<CallToolResult>;
25
+ export {};
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import type { AffsetClient } from "../client.js";
4
+ /** Matches lite-adserver's TENANT_ROLES. */
5
+ declare const TENANT_ROLES: readonly ["owner", "manager", "advertiser_manager", "publisher_manager", "advertiser", "publisher"];
6
+ type TenantRole = (typeof TENANT_ROLES)[number];
7
+ declare const PERMISSION_VALUES: readonly ["read", "write"];
8
+ export declare const CREATE_TEAM_MEMBER_DESCRIPTION: string;
9
+ export declare const createTeamMemberInputSchema: {
10
+ email: z.ZodString;
11
+ role: z.ZodEnum<["owner", "manager", "advertiser_manager", "publisher_manager", "advertiser", "publisher"]>;
12
+ manager_email: z.ZodOptional<z.ZodString>;
13
+ permissions: z.ZodOptional<z.ZodArray<z.ZodEnum<["read", "write"]>, "atleastone">>;
14
+ expires_at: z.ZodOptional<z.ZodNumber>;
15
+ confirm: z.ZodDefault<z.ZodBoolean>;
16
+ };
17
+ type CreateTeamMemberArgs = {
18
+ email: string;
19
+ role: TenantRole;
20
+ manager_email?: string;
21
+ permissions?: (typeof PERMISSION_VALUES)[number][];
22
+ expires_at?: number;
23
+ confirm: boolean;
24
+ };
25
+ export declare function createTeamMember(client: AffsetClient, args: CreateTeamMemberArgs): Promise<CallToolResult>;
26
+ export {};
@@ -0,0 +1,22 @@
1
+ import { z } from "zod";
2
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import type { AffsetClient } from "../client.js";
4
+ export declare const CREATE_ZONE_DESCRIPTION: string;
5
+ export declare const createZoneInputSchema: {
6
+ name: z.ZodString;
7
+ postback_url: z.ZodOptional<z.ZodString>;
8
+ site_url: z.ZodOptional<z.ZodString>;
9
+ traffic_back_url: z.ZodOptional<z.ZodString>;
10
+ user_email: z.ZodOptional<z.ZodString>;
11
+ confirm: z.ZodDefault<z.ZodBoolean>;
12
+ };
13
+ type CreateZoneArgs = {
14
+ name: string;
15
+ postback_url?: string;
16
+ site_url?: string;
17
+ traffic_back_url?: string;
18
+ user_email?: string;
19
+ confirm: boolean;
20
+ };
21
+ export declare function createZone(client: AffsetClient, args: CreateZoneArgs): Promise<CallToolResult>;
22
+ export {};
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import type { AffsetClient } from "../client.js";
4
+ import { RANGE_PRESETS } from "../lib/time.js";
5
+ export declare const CUT_ZONES_DESCRIPTION: string;
6
+ export declare const cutZonesInputSchema: {
7
+ campaign_id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
8
+ cr_max: z.ZodOptional<z.ZodNumber>;
9
+ spend_min: z.ZodOptional<z.ZodNumber>;
10
+ roi_max: z.ZodOptional<z.ZodNumber>;
11
+ min_clicks: z.ZodDefault<z.ZodNumber>;
12
+ range: z.ZodOptional<z.ZodEnum<["today", "yesterday", "last_7_days", "last_30_days", "this_month"]>>;
13
+ from: z.ZodOptional<z.ZodString>;
14
+ to: z.ZodOptional<z.ZodString>;
15
+ confirm: z.ZodDefault<z.ZodBoolean>;
16
+ };
17
+ type CutZonesArgs = {
18
+ campaign_id: string | number;
19
+ cr_max?: number;
20
+ spend_min?: number;
21
+ roi_max?: number;
22
+ min_clicks: number;
23
+ range?: (typeof RANGE_PRESETS)[number];
24
+ from?: string;
25
+ to?: string;
26
+ confirm: boolean;
27
+ };
28
+ export declare function cutZones(client: AffsetClient, args: CutZonesArgs): Promise<CallToolResult>;
29
+ export {};
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import { type AffsetClient } from "../client.js";
4
+ export declare const DELETE_PAYOUT_RULE_DESCRIPTION: string;
5
+ export declare const deletePayoutRuleInputSchema: {
6
+ campaign_id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
7
+ zone_id: z.ZodOptional<z.ZodString>;
8
+ confirm: z.ZodDefault<z.ZodBoolean>;
9
+ };
10
+ type DeletePayoutRuleArgs = {
11
+ campaign_id: string | number;
12
+ zone_id?: string;
13
+ confirm: boolean;
14
+ };
15
+ export declare function deletePayoutRule(client: AffsetClient, args: DeletePayoutRuleArgs): Promise<CallToolResult>;
16
+ export {};
@@ -0,0 +1,12 @@
1
+ import { z } from "zod";
2
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import { type AffsetClient } from "../client.js";
4
+ export declare const GET_CAMPAIGN_DESCRIPTION: string;
5
+ export declare const getCampaignInputSchema: {
6
+ campaign_id: z.ZodUnion<[z.ZodEffects<z.ZodString, string, string>, z.ZodNumber]>;
7
+ };
8
+ type GetCampaignArgs = {
9
+ campaign_id: string | number;
10
+ };
11
+ export declare function getCampaign(client: AffsetClient, args: GetCampaignArgs): Promise<CallToolResult>;
12
+ export {};
@@ -0,0 +1,150 @@
1
+ import { z } from "zod";
2
+ import { AffsetApiError } from "../client.js";
3
+ import { formatInstant } from "../lib/time.js";
4
+ import { mdCell, money, moneyPrecise } from "../lib/format.js";
5
+ import { fetchPayoutRules } from "../lib/payoutRules.js";
6
+ import { fetchTargetingRules, fetchTargetingTypes, UNENFORCED_TYPES } from "../lib/targeting.js";
7
+ import { errorResult, textError, textResult } from "../lib/toolResult.js";
8
+ export const GET_CAMPAIGN_DESCRIPTION = "Get one campaign's full record: every field (including the untruncated offer URL, " +
9
+ "exact schedule, budgets/pacing, silent-conversions flag, payout goal type) plus its " +
10
+ "targeting rules and payout rules in one call. `list_campaigns` renders a summary table " +
11
+ "(offer URL truncated, no dates/pacing/silent) meant for scanning many campaigns; use " +
12
+ "this when you need one campaign's complete data — e.g. before recreating it as a new " +
13
+ "campaign, or before editing it with `update_campaign`.";
14
+ export const getCampaignInputSchema = {
15
+ campaign_id: z
16
+ .union([
17
+ z
18
+ .string()
19
+ .trim()
20
+ .regex(/^[1-9]\d*$/, "campaign_id must be a positive integer")
21
+ .refine((value) => Number.isSafeInteger(Number(value)), "campaign_id is too large"),
22
+ z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
23
+ ])
24
+ .describe("Campaign id to fetch."),
25
+ };
26
+ export async function getCampaign(client, args) {
27
+ try {
28
+ const campaignId = String(args.campaign_id).trim();
29
+ if (!campaignId)
30
+ return textError("campaign_id is required.");
31
+ let campaign;
32
+ try {
33
+ campaign = await client.get(`/api/campaigns/${encodeURIComponent(campaignId)}`);
34
+ }
35
+ catch (err) {
36
+ if (err instanceof AffsetApiError && err.status === 404) {
37
+ return textError(`Campaign \`${campaignId}\` not found in this namespace.`);
38
+ }
39
+ throw err;
40
+ }
41
+ const [targetingRules, payoutRules, targetingTypes, timeZone] = await Promise.all([
42
+ fetchTargetingRules(client, campaignId),
43
+ fetchPayoutRules(client, campaignId),
44
+ // Names are a nicety; the rule table still works with bare type ids.
45
+ fetchTargetingTypes(client).catch(() => []),
46
+ client.getTenantTimezone(),
47
+ ]);
48
+ const typeById = new Map(targetingTypes.map((t) => [t.id, t]));
49
+ const fmt = (ms) => ms == null ? "—" : `${formatInstant(ms, timeZone)} ${mdCell(timeZone)} (${ms} epoch ms)`;
50
+ const deadTargetingRules = targetingRules.filter((rule) => {
51
+ const name = typeById.get(rule.targeting_rule_type_id)?.name.toLowerCase();
52
+ return name !== undefined && UNENFORCED_TYPES[name] !== undefined;
53
+ });
54
+ const payoutGoal = campaign.payout_goal_type?.trim();
55
+ const fields = [
56
+ "| Field | Value |",
57
+ "|---|---|",
58
+ `| Id | ${campaign.id} |`,
59
+ `| Name | ${mdCell(campaign.name)} |`,
60
+ `| Status | ${mdCell(campaign.status)} |`,
61
+ `| Advertiser | ${mdCell(campaign.user_email ?? "—")} |`,
62
+ `| Offer URL | ${mdCell(campaign.redirect_url ?? "—")} |`,
63
+ `| Model | ${mdCell(campaign.payment_model ?? "—")} |`,
64
+ `| Rate | ${campaign.rate != null ? moneyPrecise(campaign.rate) : "—"} |`,
65
+ `| Start date | ${fmt(campaign.start_date)} |`,
66
+ `| End date | ${fmt(campaign.end_date)} |`,
67
+ `| Daily budget | ${money(campaign.daily_budget)} |`,
68
+ `| Total budget | ${money(campaign.total_budget)} |`,
69
+ `| Pacing | ${mdCell(campaign.pacing ?? "—")} |`,
70
+ `| Budget paused | ${formatBudgetPaused(campaign)} |`,
71
+ `| Silent conversions | ${formatFlag(campaign.silent)} |`,
72
+ `| Payout goal type | ${payoutGoal ? mdCell(payoutGoal) : "_none — every conversion type gets the resolved payout_"} |`,
73
+ `| Created | ${fmt(campaign.created_at)} |`,
74
+ `| Updated | ${fmt(campaign.updated_at)} |`,
75
+ ];
76
+ return textResult([
77
+ `**Campaign** \`${campaign.id}\` — ${mdCell(campaign.name)}`,
78
+ "",
79
+ fields.join("\n"),
80
+ "",
81
+ `**Targeting rules** (${targetingRules.length})`,
82
+ "",
83
+ renderTargetingRules(targetingRules, typeById),
84
+ ...(deadTargetingRules.length
85
+ ? ["", ...renderDeadTargetingWarnings(deadTargetingRules, typeById)]
86
+ : []),
87
+ "",
88
+ `**Payout rules** (${payoutRules.length})`,
89
+ "",
90
+ renderPayoutRules(payoutRules),
91
+ "",
92
+ "_Recreate elsewhere with `create_campaign` + `update_campaign`, then " +
93
+ "`set_targeting_rule` / `set_payout_rule` for each rule above._",
94
+ "_Manage this campaign with `update_campaign`, `set_campaign_status`, " +
95
+ "`set_targeting_rule`, `set_payout_rule`, `set_payout_goal`._",
96
+ ].join("\n"));
97
+ }
98
+ catch (err) {
99
+ return errorResult(err);
100
+ }
101
+ }
102
+ function formatFlag(value) {
103
+ if (value == null)
104
+ return "—";
105
+ return value ? "yes" : "no";
106
+ }
107
+ function formatBudgetPaused(campaign) {
108
+ if (campaign.budget_paused == null)
109
+ return "—";
110
+ if (!campaign.budget_paused)
111
+ return "no";
112
+ const reason = campaign.budget_pause_reason?.trim();
113
+ return reason ? `yes (${mdCell(reason)})` : "yes (reason unavailable)";
114
+ }
115
+ function renderTargetingRules(rules, typeById) {
116
+ if (rules.length === 0) {
117
+ return "_No targeting rules — campaign is unrestricted on /serve._";
118
+ }
119
+ const lines = ["| Id | Type | Method | Rule |", "|---|---|---|---|"];
120
+ for (const r of rules) {
121
+ const t = typeById.get(r.targeting_rule_type_id);
122
+ const typeLabel = t
123
+ ? `${mdCell(t.name)} (${r.targeting_rule_type_id})`
124
+ : String(r.targeting_rule_type_id);
125
+ const inert = t && UNENFORCED_TYPES[t.name.toLowerCase()] ? " ⚠️" : "";
126
+ lines.push(`| ${r.id ?? "—"} | ${typeLabel}${inert} | ${mdCell(r.targeting_method)} | ${mdCell(r.rule)} |`);
127
+ }
128
+ return lines.join("\n");
129
+ }
130
+ function renderDeadTargetingWarnings(rules, typeById) {
131
+ const names = [...new Set(rules.map((rule) => typeById.get(rule.targeting_rule_type_id).name))];
132
+ return names.map((name) => `⚠️ \`${mdCell(name)}\` — ${UNENFORCED_TYPES[name.toLowerCase()]}. This rule has no effect.`);
133
+ }
134
+ function renderPayoutRules(rules) {
135
+ if (rules.length === 0) {
136
+ return "_No payout rules — conversions resolve to $0 until you set one._";
137
+ }
138
+ const lines = ["| Scope | Zone | Payout | Rule id |", "|---|---|--:|---|"];
139
+ for (const r of rules) {
140
+ const scope = r.zone_id == null ? "global" : "zone";
141
+ const zone = r.zone_id == null ? "—" : `\`${r.zone_id}\``;
142
+ lines.push(`| ${scope} | ${zone} | ${moneyPrecise(r.payout)} | \`${r.id}\` |`);
143
+ }
144
+ if (!rules.some((rule) => rule.zone_id == null)) {
145
+ lines.push("");
146
+ lines.push("_⚠️ No global rule — conversions from any zone without an override resolve to **$0**._");
147
+ }
148
+ return lines.join("\n");
149
+ }
150
+ //# sourceMappingURL=getCampaign.js.map
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import type { AffsetClient } from "../client.js";
4
+ import { RANGE_PRESETS } from "../lib/time.js";
5
+ import { type GroupBy } from "../types.js";
6
+ export declare const GET_STATS_DESCRIPTION: string;
7
+ export declare const getStatsInputSchema: {
8
+ group_by: z.ZodDefault<z.ZodEnum<["date", "campaign_id", "zone_id", "country", "conversion_type", "publisher_email", "advertiser_email", "sub1", "sub2", "sub3", "sub4", "sub5"]>>;
9
+ range: z.ZodOptional<z.ZodEnum<["today", "yesterday", "last_7_days", "last_30_days", "this_month"]>>;
10
+ from: z.ZodOptional<z.ZodString>;
11
+ to: z.ZodOptional<z.ZodString>;
12
+ campaign_ids: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
13
+ zone_ids: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
14
+ sub1: z.ZodOptional<z.ZodString>;
15
+ sub2: z.ZodOptional<z.ZodString>;
16
+ sub3: z.ZodOptional<z.ZodString>;
17
+ sub4: z.ZodOptional<z.ZodString>;
18
+ sub5: z.ZodOptional<z.ZodString>;
19
+ conversion_type: z.ZodOptional<z.ZodString>;
20
+ advertiser_email: z.ZodOptional<z.ZodString>;
21
+ publisher_email: z.ZodOptional<z.ZodString>;
22
+ };
23
+ type GetStatsArgs = {
24
+ group_by: GroupBy;
25
+ range?: (typeof RANGE_PRESETS)[number];
26
+ from?: string;
27
+ to?: string;
28
+ campaign_ids?: string[];
29
+ zone_ids?: string[];
30
+ sub1?: string;
31
+ sub2?: string;
32
+ sub3?: string;
33
+ sub4?: string;
34
+ sub5?: string;
35
+ conversion_type?: string;
36
+ advertiser_email?: string;
37
+ publisher_email?: string;
38
+ };
39
+ export declare function getStats(client: AffsetClient, args: GetStatsArgs): Promise<CallToolResult>;
40
+ export {};