@affset/mcp 0.1.1 → 0.3.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/.env.example +5 -0
- package/README.md +191 -56
- package/dist/client.d.ts +43 -0
- package/dist/client.js +15 -2
- package/dist/config.d.ts +7 -0
- package/dist/config.js +15 -54
- package/dist/core.d.ts +18 -0
- package/dist/core.js +18 -0
- package/dist/docs.d.ts +39 -0
- package/dist/docs.js +105 -0
- package/dist/index.d.ts +2 -0
- package/dist/lib/format.d.ts +46 -0
- package/dist/lib/format.js +3 -0
- package/dist/lib/integrationUrls.d.ts +87 -0
- package/dist/lib/integrationUrls.js +84 -4
- package/dist/lib/linkArgs.d.ts +32 -0
- package/dist/lib/linkArgs.js +14 -3
- package/dist/lib/patch.d.ts +10 -0
- package/dist/lib/payoutRules.d.ts +38 -0
- package/dist/lib/readBody.d.ts +17 -0
- package/dist/lib/readBody.js +69 -0
- package/dist/lib/targeting.d.ts +51 -0
- package/dist/lib/time.d.ts +38 -0
- package/dist/lib/toolResult.d.ts +7 -0
- package/dist/lib/urls.d.ts +2 -0
- package/dist/lib/zones.d.ts +24 -0
- package/dist/lib/zones.js +9 -1
- package/dist/registerTools.d.ts +40 -0
- package/dist/registerTools.js +437 -0
- package/dist/runtimeConfig.d.ts +37 -0
- package/dist/runtimeConfig.js +93 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +3 -318
- package/dist/tools/createCampaign.d.ts +25 -0
- package/dist/tools/createCampaign.js +20 -8
- package/dist/tools/createTeamMember.d.ts +26 -0
- package/dist/tools/createTrafficSource.d.ts +25 -0
- package/dist/tools/createTrafficSource.js +191 -0
- package/dist/tools/createZone.d.ts +24 -0
- package/dist/tools/createZone.js +13 -1
- package/dist/tools/cutZones.d.ts +29 -0
- package/dist/tools/deletePayoutRule.d.ts +16 -0
- package/dist/tools/getCampaign.d.ts +12 -0
- package/dist/tools/getCampaign.js +150 -0
- package/dist/tools/getStats.d.ts +42 -0
- package/dist/tools/getStats.js +54 -3
- package/dist/tools/getTrackingLink.d.ts +23 -0
- package/dist/tools/getTrackingLink.js +26 -9
- package/dist/tools/getZoneUrl.d.ts +21 -0
- package/dist/tools/getZoneUrl.js +30 -13
- package/dist/tools/listCampaigns.d.ts +23 -0
- package/dist/tools/listConversions.d.ts +31 -0
- package/dist/tools/listConversions.js +29 -10
- package/dist/tools/listPayoutRules.d.ts +12 -0
- package/dist/tools/listSubLabels.d.ts +5 -0
- package/dist/tools/listTargetingRules.d.ts +12 -0
- package/dist/tools/listTargetingTypes.d.ts +5 -0
- package/dist/tools/listTeam.d.ts +14 -0
- package/dist/tools/listTrafficSources.d.ts +17 -0
- package/dist/tools/listTrafficSources.js +63 -0
- package/dist/tools/listZones.d.ts +23 -0
- package/dist/tools/listZones.js +10 -5
- package/dist/tools/removeTargetingRule.d.ts +21 -0
- package/dist/tools/setCampaignStatus.d.ts +18 -0
- package/dist/tools/setPayoutGoal.d.ts +16 -0
- package/dist/tools/setPayoutRule.d.ts +18 -0
- package/dist/tools/setSubLabels.d.ts +22 -0
- package/dist/tools/setTargetingRule.d.ts +21 -0
- package/dist/tools/updateCampaign.d.ts +35 -0
- package/dist/tools/updateTrafficSource.d.ts +25 -0
- package/dist/tools/updateTrafficSource.js +171 -0
- package/dist/tools/updateZone.d.ts +27 -0
- package/dist/tools/updateZone.js +13 -3
- package/dist/tools/whoami.d.ts +6 -0
- package/dist/types.d.ts +257 -0
- package/dist/types.js +2 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.js +8 -0
- package/package.json +15 -2
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { AffsetApiError } from "../client.js";
|
|
3
3
|
import { mdCell } from "../lib/format.js";
|
|
4
|
-
import { buildTrackingLink, fetchTenantIntegration, subLegend } from "../lib/integrationUrls.js";
|
|
5
|
-
import { collectSubs, linkInputSchema } from "../lib/linkArgs.js";
|
|
4
|
+
import { buildTrackingLink, fetchTenantIntegration, resolveLinkedSource, subLegend, templateHasParam, } from "../lib/integrationUrls.js";
|
|
5
|
+
import { collectSubs, hasExplicitLinkParams, linkInputSchema, } from "../lib/linkArgs.js";
|
|
6
6
|
import { errorResult, textError, textResult } from "../lib/toolResult.js";
|
|
7
7
|
import { resolveZone, zonePostbackNote } from "../lib/zones.js";
|
|
8
8
|
export const GET_TRACKING_LINK_DESCRIPTION = "Get the tracking link for an existing campaign + zone — the /track/click link that goes " +
|
|
9
9
|
"straight to that one campaign with no rotation or targeting checks. Both the campaign " +
|
|
10
10
|
"and zone must be active for the public link to work. Same link create_campaign echoes on " +
|
|
11
11
|
"create; this re-derives it later, for any " +
|
|
12
|
-
"campaign, with whatever sub values you want.
|
|
12
|
+
"campaign, with whatever sub values you want. A zone linked to a traffic source renders " +
|
|
13
|
+
"that source's tracking template instead. Uses the tenant's custom API domain when " +
|
|
13
14
|
"one is set. Read-only: builds the URL, changes nothing.";
|
|
14
15
|
export const getTrackingLinkInputSchema = {
|
|
15
16
|
campaign_id: z
|
|
@@ -45,12 +46,15 @@ export async function getTrackingLink(client, config, args) {
|
|
|
45
46
|
const { campaign } = campaignResult;
|
|
46
47
|
const { zone, inactiveWarning } = zoneResult;
|
|
47
48
|
const subs = collectSubs(args);
|
|
49
|
+
const linked = await resolveLinkedSource(client, zone, hasExplicitLinkParams(args));
|
|
48
50
|
const url = buildTrackingLink(integration.baseUrl, campaign.id, zone.id, {
|
|
49
51
|
sourceClickId: args.source_click_id,
|
|
50
52
|
subs,
|
|
51
53
|
cost: args.cost,
|
|
52
54
|
subLabels: integration.subLabels,
|
|
55
|
+
template: linked.template,
|
|
53
56
|
});
|
|
57
|
+
const templated = linked.template !== undefined;
|
|
54
58
|
const legend = subLegend(integration.subLabels, subs);
|
|
55
59
|
const statusNote = campaign.status === "active"
|
|
56
60
|
? "active — serving still depends on dates and budget state; also a /serve candidate"
|
|
@@ -67,6 +71,7 @@ export async function getTrackingLink(client, config, args) {
|
|
|
67
71
|
"",
|
|
68
72
|
"| Field | Value |",
|
|
69
73
|
"|---|---|",
|
|
74
|
+
...(linked.sourceLabel ? [`| Traffic source | ${linked.sourceLabel} |`] : []),
|
|
70
75
|
`| Campaign status | ${statusNote} |`,
|
|
71
76
|
`| Offer URL | ${mdCell(campaign.redirect_url ?? "—")} |`,
|
|
72
77
|
`| Zone status | ${zone.status} |`,
|
|
@@ -74,13 +79,16 @@ export async function getTrackingLink(client, config, args) {
|
|
|
74
79
|
...(legend ? [`| Sub slots | ${legend} |`] : []),
|
|
75
80
|
...(availabilityWarnings.length ? ["", ...availabilityWarnings] : []),
|
|
76
81
|
...(inactiveWarning ? ["", inactiveWarning] : []),
|
|
82
|
+
...linked.notes.flatMap((note) => ["", note]),
|
|
77
83
|
"",
|
|
78
|
-
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
templated
|
|
85
|
+
? "Query parameters come from the linked source's tracking template — the network " +
|
|
86
|
+
"expands its macros before the request reaches affset. Edit them with " +
|
|
87
|
+
"`update_traffic_source`; explicit link parameters on this tool override the template."
|
|
88
|
+
: "Replace each `{…}` placeholder with the source's own macro and drop the sub slots " +
|
|
89
|
+
"you don't need. Values are inserted verbatim — the network expands its macros " +
|
|
90
|
+
"before the request reaches affset.",
|
|
91
|
+
costNote(templated, linked.template, args.cost),
|
|
84
92
|
"",
|
|
85
93
|
"_Geo and other targeting rules are enforced in /serve rotation only — this link is " +
|
|
86
94
|
"not geo-gated. Use `get_zone_url` when you want affset to pick the campaign._",
|
|
@@ -90,6 +98,15 @@ export async function getTrackingLink(client, config, args) {
|
|
|
90
98
|
return errorResult(err);
|
|
91
99
|
}
|
|
92
100
|
}
|
|
101
|
+
function costNote(templated, template, costArg) {
|
|
102
|
+
const hasCost = templated ? templateHasParam(template, "cost") : Boolean(costArg);
|
|
103
|
+
if (hasCost) {
|
|
104
|
+
return "`cost` is recorded on the click row here. Use it on this link **or** on a zone URL for the same traffic, never both.";
|
|
105
|
+
}
|
|
106
|
+
return templated
|
|
107
|
+
? "Add a `cost=<network cost macro>` parameter to the source's tracking template to import media cost and get ROI in `get_stats`."
|
|
108
|
+
: "Add `cost=<network cost macro>` to import media cost and get ROI in `get_stats`.";
|
|
109
|
+
}
|
|
93
110
|
function campaignAvailabilityWarnings(campaign) {
|
|
94
111
|
const warnings = [];
|
|
95
112
|
const now = Date.now();
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
import { type LinkArgs } from "../lib/linkArgs.js";
|
|
6
|
+
export declare const GET_ZONE_URL_DESCRIPTION: string;
|
|
7
|
+
export declare const getZoneUrlInputSchema: {
|
|
8
|
+
source_click_id: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
9
|
+
cost: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
10
|
+
sub1: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
11
|
+
sub2: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
12
|
+
sub3: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
13
|
+
sub4: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
14
|
+
sub5: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
15
|
+
zone_id: z.ZodOptional<z.ZodString>;
|
|
16
|
+
};
|
|
17
|
+
type GetZoneUrlArgs = LinkArgs & {
|
|
18
|
+
zone_id?: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function getZoneUrl(client: AffsetClient, config: Config, args: GetZoneUrlArgs): Promise<CallToolResult>;
|
|
21
|
+
export {};
|
package/dist/tools/getZoneUrl.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { mdCell } from "../lib/format.js";
|
|
3
|
-
import { buildZoneUrl, fetchTenantIntegration, subLegend } from "../lib/integrationUrls.js";
|
|
4
|
-
import { collectSubs, linkInputSchema } from "../lib/linkArgs.js";
|
|
3
|
+
import { buildZoneUrl, fetchTenantIntegration, resolveLinkedSource, subLegend, templateHasParam, } from "../lib/integrationUrls.js";
|
|
4
|
+
import { collectSubs, hasExplicitLinkParams, linkInputSchema, } from "../lib/linkArgs.js";
|
|
5
5
|
import { errorResult, textError, textResult } from "../lib/toolResult.js";
|
|
6
6
|
import { resolveZone, zonePostbackNote } from "../lib/zones.js";
|
|
7
7
|
export const GET_ZONE_URL_DESCRIPTION = "Get the zone URL to paste into a traffic source's campaign settings — the /serve link " +
|
|
8
|
-
"that rotates across the zone's active campaigns.
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
8
|
+
"that rotates across the zone's active campaigns. A zone linked to a traffic source " +
|
|
9
|
+
"renders that source's tracking template; otherwise the URL is prefilled with the sub " +
|
|
10
|
+
"convention (source_click_id + sub1..sub5) and optionally the network's cost macro. " +
|
|
11
|
+
"Uses the tenant's custom API domain when one is set. Read-only: builds the URL, " +
|
|
12
|
+
"changes nothing. For a link straight to one active campaign without targeting checks, " +
|
|
13
|
+
"use get_tracking_link instead.";
|
|
13
14
|
export const getZoneUrlInputSchema = {
|
|
14
15
|
zone_id: z
|
|
15
16
|
.string()
|
|
@@ -30,16 +31,19 @@ export async function getZoneUrl(client, config, args) {
|
|
|
30
31
|
return textError(zoneResult.error);
|
|
31
32
|
const { zone, inactiveWarning } = zoneResult;
|
|
32
33
|
const subs = collectSubs(args);
|
|
34
|
+
const linked = await resolveLinkedSource(client, zone, hasExplicitLinkParams(args));
|
|
33
35
|
const url = buildZoneUrl(integration.baseUrl, zone.id, {
|
|
34
36
|
sourceClickId: args.source_click_id,
|
|
35
37
|
subs,
|
|
36
38
|
cost: args.cost,
|
|
37
39
|
subLabels: integration.subLabels,
|
|
40
|
+
template: linked.template,
|
|
38
41
|
});
|
|
39
42
|
// A zone URL with nothing to rotate serves the traffic-back / unsold path — the
|
|
40
43
|
// single most common "my link doesn't work" report, so check it up front.
|
|
41
44
|
const rotationNote = await describeRotation(client);
|
|
42
45
|
const legend = subLegend(integration.subLabels, subs);
|
|
46
|
+
const templated = linked.template !== undefined;
|
|
43
47
|
return textResult([
|
|
44
48
|
`**Zone URL** for **${mdCell(zone.name)}** (\`${zone.id}\`) — give this to the traffic source:`,
|
|
45
49
|
"",
|
|
@@ -49,19 +53,23 @@ export async function getZoneUrl(client, config, args) {
|
|
|
49
53
|
"",
|
|
50
54
|
"| Field | Value |",
|
|
51
55
|
"|---|---|",
|
|
56
|
+
...(linked.sourceLabel ? [`| Traffic source | ${linked.sourceLabel} |`] : []),
|
|
52
57
|
`| Zone status | ${zone.status} |`,
|
|
53
58
|
`| Rotation | ${rotationNote} |`,
|
|
54
59
|
`| Postback | ${zonePostbackNote(zone)} |`,
|
|
55
60
|
`| Traffic back | ${mdCell(zone.traffic_back_url ?? "—")} |`,
|
|
56
61
|
...(legend ? [`| Sub slots | ${legend} |`] : []),
|
|
57
62
|
...(inactiveWarning ? ["", inactiveWarning] : []),
|
|
63
|
+
...linked.notes.flatMap((note) => ["", note]),
|
|
58
64
|
"",
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
templated
|
|
66
|
+
? "Query parameters come from the linked source's tracking template — the network " +
|
|
67
|
+
"expands its macros before the request reaches affset. Edit them with " +
|
|
68
|
+
"`update_traffic_source`; explicit link parameters on this tool override the template."
|
|
69
|
+
: "Replace each `{…}` placeholder with the source's own macro and drop the sub slots " +
|
|
70
|
+
"you don't need. Values are inserted verbatim — the network expands its macros " +
|
|
71
|
+
"before the request reaches affset.",
|
|
72
|
+
costNote(templated, linked.template, args.cost),
|
|
65
73
|
"",
|
|
66
74
|
"_This URL rotates across the zone's **active** campaigns. For a link that goes " +
|
|
67
75
|
"straight to one active campaign without applying targeting rules, use `get_tracking_link`._",
|
|
@@ -71,6 +79,15 @@ export async function getZoneUrl(client, config, args) {
|
|
|
71
79
|
return errorResult(err);
|
|
72
80
|
}
|
|
73
81
|
}
|
|
82
|
+
function costNote(templated, template, costArg) {
|
|
83
|
+
const hasCost = templated ? templateHasParam(template, "cost") : Boolean(costArg);
|
|
84
|
+
if (hasCost) {
|
|
85
|
+
return "`cost` is recorded once per /serve, on the impression row — don't also add it to a tracking link for the same traffic.";
|
|
86
|
+
}
|
|
87
|
+
return templated
|
|
88
|
+
? "Add a `cost=<network cost macro>` parameter to the source's tracking template to import media cost and get ROI in `get_stats`."
|
|
89
|
+
: "Add `cost=<network cost macro>` to import media cost and get ROI in `get_stats`.";
|
|
90
|
+
}
|
|
74
91
|
/** Cheap active-campaign count; degrades to a neutral note rather than failing. */
|
|
75
92
|
async function describeRotation(client) {
|
|
76
93
|
try {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import type { AffsetClient } from "../client.js";
|
|
4
|
+
import { CAMPAIGN_STATUSES } from "../types.js";
|
|
5
|
+
export declare const LIST_CAMPAIGNS_DESCRIPTION: string;
|
|
6
|
+
export declare const listCampaignsInputSchema: {
|
|
7
|
+
status: z.ZodOptional<z.ZodEnum<["active", "paused", "archived"]>>;
|
|
8
|
+
name_contains: z.ZodOptional<z.ZodString>;
|
|
9
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
10
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
11
|
+
sort: z.ZodDefault<z.ZodEnum<["name", "created_at", "start_date"]>>;
|
|
12
|
+
order: z.ZodDefault<z.ZodEnum<["asc", "desc"]>>;
|
|
13
|
+
};
|
|
14
|
+
type ListCampaignsArgs = {
|
|
15
|
+
status?: (typeof CAMPAIGN_STATUSES)[number];
|
|
16
|
+
name_contains?: string;
|
|
17
|
+
limit: number;
|
|
18
|
+
offset: number;
|
|
19
|
+
sort: "name" | "created_at" | "start_date";
|
|
20
|
+
order: "asc" | "desc";
|
|
21
|
+
};
|
|
22
|
+
export declare function listCampaigns(client: AffsetClient, args: ListCampaignsArgs): Promise<CallToolResult>;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import type { AffsetClient } from "../client.js";
|
|
4
|
+
declare const SORT_FIELDS: readonly ["created_at", "ad_event_id", "click_id"];
|
|
5
|
+
export declare const LIST_CONVERSIONS_DESCRIPTION: string;
|
|
6
|
+
export declare const listConversionsInputSchema: {
|
|
7
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
8
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
9
|
+
sort: z.ZodDefault<z.ZodEnum<["created_at", "ad_event_id", "click_id"]>>;
|
|
10
|
+
order: z.ZodDefault<z.ZodEnum<["asc", "desc"]>>;
|
|
11
|
+
paid_only: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
+
click_id: z.ZodOptional<z.ZodString>;
|
|
13
|
+
source_click_id: z.ZodOptional<z.ZodString>;
|
|
14
|
+
type: z.ZodOptional<z.ZodString>;
|
|
15
|
+
payload_contains: z.ZodOptional<z.ZodString>;
|
|
16
|
+
zero_payout: z.ZodOptional<z.ZodBoolean>;
|
|
17
|
+
};
|
|
18
|
+
type ListConversionsArgs = {
|
|
19
|
+
limit: number;
|
|
20
|
+
offset: number;
|
|
21
|
+
sort: (typeof SORT_FIELDS)[number];
|
|
22
|
+
order: "asc" | "desc";
|
|
23
|
+
paid_only?: boolean;
|
|
24
|
+
click_id?: string;
|
|
25
|
+
source_click_id?: string;
|
|
26
|
+
type?: string;
|
|
27
|
+
payload_contains?: string;
|
|
28
|
+
zero_payout?: boolean;
|
|
29
|
+
};
|
|
30
|
+
export declare function listConversions(client: AffsetClient, args: ListConversionsArgs): Promise<CallToolResult>;
|
|
31
|
+
export {};
|
|
@@ -6,14 +6,26 @@ import { SUB_KEYS, } from "../types.js";
|
|
|
6
6
|
const SORT_FIELDS = ["created_at", "ad_event_id", "click_id"];
|
|
7
7
|
export const LIST_CONVERSIONS_DESCRIPTION = "List recent conversion records (audit trail) for debugging payouts and pixel params. " +
|
|
8
8
|
"Shows payout, spend, pixel `type`, source_click_id, click_id, subs, postback outcome, " +
|
|
9
|
-
"and the raw payload.
|
|
10
|
-
"
|
|
11
|
-
"
|
|
9
|
+
"and the raw payload. `paid_only: true` drops informative conversions server-side — " +
|
|
10
|
+
"rows recorded with postback_skipped=non_goal_type because the pixel type missed the " +
|
|
11
|
+
"campaign's payout_goal_type. Silent conversions and other skip reasons still come back " +
|
|
12
|
+
"(not a payout>0 filter). Default false, all rows. Beyond pagination/sort/paid_only, " +
|
|
13
|
+
"the optional click_id / source_click_id / type / payload_contains / zero_payout filters " +
|
|
14
|
+
"run client-side on the current page. Does not include campaign_id/zone_id (not returned " +
|
|
15
|
+
"by the API).";
|
|
12
16
|
export const listConversionsInputSchema = {
|
|
13
17
|
limit: z.number().int().min(1).max(100).default(20).describe("Page size (1–100). Default 20."),
|
|
14
18
|
offset: z.number().int().min(0).default(0).describe("Pagination offset. Default 0."),
|
|
15
19
|
sort: z.enum(SORT_FIELDS).default("created_at").describe("Sort field. Default created_at."),
|
|
16
20
|
order: z.enum(["asc", "desc"]).default("desc").describe("Sort order. Default desc."),
|
|
21
|
+
paid_only: z
|
|
22
|
+
.boolean()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("true drops informative conversions — rows recorded with " +
|
|
25
|
+
"postback_skipped=non_goal_type because the pixel type missed the campaign's " +
|
|
26
|
+
"payout_goal_type. Silent conversions and other skip reasons still come back " +
|
|
27
|
+
"(not a payout>0 filter). Server-side (filters the whole dataset, not just this page). " +
|
|
28
|
+
"Works without payout visibility. Default false (all rows)."),
|
|
17
29
|
click_id: z
|
|
18
30
|
.string()
|
|
19
31
|
.min(1)
|
|
@@ -42,13 +54,17 @@ export const listConversionsInputSchema = {
|
|
|
42
54
|
};
|
|
43
55
|
export async function listConversions(client, args) {
|
|
44
56
|
try {
|
|
57
|
+
const query = {
|
|
58
|
+
limit: args.limit,
|
|
59
|
+
offset: args.offset,
|
|
60
|
+
sort: args.sort,
|
|
61
|
+
order: args.order,
|
|
62
|
+
};
|
|
63
|
+
// The API accepts only the literal strings "true"/"false"; omitted = false.
|
|
64
|
+
if (args.paid_only !== undefined)
|
|
65
|
+
query.paid_only = String(args.paid_only);
|
|
45
66
|
const [data, settings] = await Promise.all([
|
|
46
|
-
client.get("/api/conversions",
|
|
47
|
-
limit: args.limit,
|
|
48
|
-
offset: args.offset,
|
|
49
|
-
sort: args.sort,
|
|
50
|
-
order: args.order,
|
|
51
|
-
}),
|
|
67
|
+
client.get("/api/conversions", query),
|
|
52
68
|
// One read covers both the sub labels and the zone timestamps are shown in.
|
|
53
69
|
client.get("/api/tenant").catch(() => ({})),
|
|
54
70
|
]);
|
|
@@ -67,6 +83,8 @@ export async function listConversions(client, args) {
|
|
|
67
83
|
const total = pagination?.total ?? all.length;
|
|
68
84
|
const clientFiltered = filtered.length !== all.length;
|
|
69
85
|
const filterBits = [];
|
|
86
|
+
if (args.paid_only)
|
|
87
|
+
filterBits.push("paid_only");
|
|
70
88
|
if (args.click_id)
|
|
71
89
|
filterBits.push(`click_id=${args.click_id}`);
|
|
72
90
|
if (args.source_click_id)
|
|
@@ -98,7 +116,8 @@ export async function listConversions(client, args) {
|
|
|
98
116
|
]
|
|
99
117
|
: []),
|
|
100
118
|
"",
|
|
101
|
-
"_API has no campaign/zone/date filters
|
|
119
|
+
"_API has no campaign/zone/date filters. `paid_only` is server-side; other optional " +
|
|
120
|
+
"filters apply to this page. Page with limit/offset._",
|
|
102
121
|
payoutHidden
|
|
103
122
|
? "_`payout` is hidden for this role — the column shows `—` for every row._"
|
|
104
123
|
: "_`$0` payout with a non-empty type often means payout_goal_type mismatch or no payout rule._",
|
|
@@ -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 LIST_PAYOUT_RULES_DESCRIPTION: string;
|
|
5
|
+
export declare const listPayoutRulesInputSchema: {
|
|
6
|
+
campaign_id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
|
|
7
|
+
};
|
|
8
|
+
type ListPayoutRulesArgs = {
|
|
9
|
+
campaign_id: string | number;
|
|
10
|
+
};
|
|
11
|
+
export declare function listPayoutRules(client: AffsetClient, args: ListPayoutRulesArgs): Promise<CallToolResult>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import type { AffsetClient } from "../client.js";
|
|
3
|
+
export declare const LIST_SUB_LABELS_DESCRIPTION: string;
|
|
4
|
+
export declare const listSubLabelsInputSchema: {};
|
|
5
|
+
export declare function listSubLabels(client: AffsetClient): Promise<CallToolResult>;
|
|
@@ -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 LIST_TARGETING_RULES_DESCRIPTION: string;
|
|
5
|
+
export declare const listTargetingRulesInputSchema: {
|
|
6
|
+
campaign_id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
|
|
7
|
+
};
|
|
8
|
+
type ListTargetingRulesArgs = {
|
|
9
|
+
campaign_id: string | number;
|
|
10
|
+
};
|
|
11
|
+
export declare function listTargetingRules(client: AffsetClient, args: ListTargetingRulesArgs): Promise<CallToolResult>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import type { AffsetClient } from "../client.js";
|
|
3
|
+
export declare const LIST_TARGETING_TYPES_DESCRIPTION: string;
|
|
4
|
+
export declare const listTargetingTypesInputSchema: {};
|
|
5
|
+
export declare function listTargetingTypes(client: AffsetClient): Promise<CallToolResult>;
|
|
@@ -0,0 +1,14 @@
|
|
|
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 LIST_TEAM_DESCRIPTION: string;
|
|
5
|
+
export declare const listTeamInputSchema: {
|
|
6
|
+
role: z.ZodOptional<z.ZodString>;
|
|
7
|
+
include_expired: z.ZodDefault<z.ZodBoolean>;
|
|
8
|
+
};
|
|
9
|
+
type ListTeamArgs = {
|
|
10
|
+
role?: string;
|
|
11
|
+
include_expired: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare function listTeam(client: AffsetClient, args: ListTeamArgs): Promise<CallToolResult>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import type { AffsetClient } from "../client.js";
|
|
4
|
+
import { TRAFFIC_SOURCE_STATUSES } from "../types.js";
|
|
5
|
+
export declare const LIST_TRAFFIC_SOURCES_DESCRIPTION: string;
|
|
6
|
+
export declare const listTrafficSourcesInputSchema: {
|
|
7
|
+
status: z.ZodOptional<z.ZodEnum<["active", "archived"]>>;
|
|
8
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
9
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
10
|
+
};
|
|
11
|
+
type ListTrafficSourcesArgs = {
|
|
12
|
+
status?: (typeof TRAFFIC_SOURCE_STATUSES)[number];
|
|
13
|
+
limit: number;
|
|
14
|
+
offset: number;
|
|
15
|
+
};
|
|
16
|
+
export declare function listTrafficSources(client: AffsetClient, args: ListTrafficSourcesArgs): Promise<CallToolResult>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { capUntrusted, mdCell } from "../lib/format.js";
|
|
3
|
+
import { errorResult, textResult } from "../lib/toolResult.js";
|
|
4
|
+
import { TRAFFIC_SOURCE_STATUSES } from "../types.js";
|
|
5
|
+
/** Templates run to 2000 chars server-side; the table shows enough to identify one. */
|
|
6
|
+
const TEMPLATE_PREVIEW_MAX = 150;
|
|
7
|
+
export const LIST_TRAFFIC_SOURCES_DESCRIPTION = "List the tenant's traffic sources — the ad networks bought from, each with the " +
|
|
8
|
+
"tracking template its linked zones render in get_zone_url/get_tracking_link and an " +
|
|
9
|
+
"optional postback template. The stored network API token is write-only and shown " +
|
|
10
|
+
"only as set/none. Read-only.";
|
|
11
|
+
export const listTrafficSourcesInputSchema = {
|
|
12
|
+
status: z
|
|
13
|
+
.enum(TRAFFIC_SOURCE_STATUSES)
|
|
14
|
+
.optional()
|
|
15
|
+
.describe("Filter by status. Omit for all sources."),
|
|
16
|
+
limit: z.number().int().min(1).max(100).default(50).describe("Sources per page (1–100)."),
|
|
17
|
+
offset: z.number().int().min(0).default(0).describe("Pagination offset."),
|
|
18
|
+
};
|
|
19
|
+
export async function listTrafficSources(client, args) {
|
|
20
|
+
try {
|
|
21
|
+
const query = {
|
|
22
|
+
limit: args.limit,
|
|
23
|
+
offset: args.offset,
|
|
24
|
+
sort: "created_at",
|
|
25
|
+
order: "desc",
|
|
26
|
+
};
|
|
27
|
+
if (args.status)
|
|
28
|
+
query.status = args.status;
|
|
29
|
+
const res = await client.get("/api/traffic-sources", query);
|
|
30
|
+
const sources = res.traffic_sources ?? [];
|
|
31
|
+
const total = res.pagination?.total ?? sources.length;
|
|
32
|
+
if (sources.length === 0) {
|
|
33
|
+
return textResult(args.status
|
|
34
|
+
? `No ${args.status} traffic sources.`
|
|
35
|
+
: "No traffic sources yet. Create one with `create_traffic_source` — start from " +
|
|
36
|
+
"a preset to get the network's tracking template ready-made, then link zones " +
|
|
37
|
+
"to it via `create_zone`/`update_zone` `traffic_source_id`.");
|
|
38
|
+
}
|
|
39
|
+
const rows = sources.map((s) => [
|
|
40
|
+
`| ${mdCell(s.name)} `,
|
|
41
|
+
`| \`${mdCell(s.id)}\` `,
|
|
42
|
+
`| ${s.preset ? mdCell(s.preset) : "—"} `,
|
|
43
|
+
`| ${mdCell(s.status)} `,
|
|
44
|
+
`| ${s.has_api_token ? "set" : "—"} `,
|
|
45
|
+
`| ${s.tracking_template ? mdCell(capUntrusted(s.tracking_template, TEMPLATE_PREVIEW_MAX)) : "—"} `,
|
|
46
|
+
`| ${s.postback_template ? mdCell(capUntrusted(s.postback_template, TEMPLATE_PREVIEW_MAX)) : "—"} |`,
|
|
47
|
+
].join(""));
|
|
48
|
+
return textResult([
|
|
49
|
+
`**Traffic sources** (${sources.length} of ${total}):`,
|
|
50
|
+
"",
|
|
51
|
+
"| Name | Id | Preset | Status | API token | Tracking template | Postback template |",
|
|
52
|
+
"|---|---|---|---|---|---|---|",
|
|
53
|
+
...rows,
|
|
54
|
+
"",
|
|
55
|
+
"_Zones linked to a source render its tracking template in `get_zone_url` / " +
|
|
56
|
+
"`get_tracking_link`. Edit a source with `update_traffic_source`._",
|
|
57
|
+
].join("\n"));
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
return errorResult(err);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=listTrafficSources.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import type { AffsetClient } from "../client.js";
|
|
4
|
+
import { ZONE_STATUSES } from "../types.js";
|
|
5
|
+
export declare const LIST_ZONES_DESCRIPTION: string;
|
|
6
|
+
export declare const listZonesInputSchema: {
|
|
7
|
+
status: z.ZodOptional<z.ZodEnum<["active", "inactive"]>>;
|
|
8
|
+
name_contains: z.ZodOptional<z.ZodString>;
|
|
9
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
10
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
11
|
+
sort: z.ZodDefault<z.ZodEnum<["name", "created_at", "site_url"]>>;
|
|
12
|
+
order: z.ZodDefault<z.ZodEnum<["asc", "desc"]>>;
|
|
13
|
+
};
|
|
14
|
+
type ListZonesArgs = {
|
|
15
|
+
status?: (typeof ZONE_STATUSES)[number];
|
|
16
|
+
name_contains?: string;
|
|
17
|
+
limit: number;
|
|
18
|
+
offset: number;
|
|
19
|
+
sort: "name" | "created_at" | "site_url";
|
|
20
|
+
order: "asc" | "desc";
|
|
21
|
+
};
|
|
22
|
+
export declare function listZones(client: AffsetClient, args: ListZonesArgs): Promise<CallToolResult>;
|
|
23
|
+
export {};
|
package/dist/tools/listZones.js
CHANGED
|
@@ -3,8 +3,8 @@ import { mdCell } from "../lib/format.js";
|
|
|
3
3
|
import { errorResult } from "../lib/toolResult.js";
|
|
4
4
|
import { ZONE_STATUSES } from "../types.js";
|
|
5
5
|
export const LIST_ZONES_DESCRIPTION = "List traffic-source zones in the current namespace. Filter by status and optionally " +
|
|
6
|
-
"by name (client-side contains match). Returns id, name,
|
|
7
|
-
"site_url, publisher. Paginated (default 20, max 100).";
|
|
6
|
+
"by name (client-side contains match). Returns id, name, linked traffic source, " +
|
|
7
|
+
"status, postback_url, site_url, publisher. Paginated (default 20, max 100).";
|
|
8
8
|
export const listZonesInputSchema = {
|
|
9
9
|
status: z.enum(ZONE_STATUSES).optional().describe("Filter by zone status."),
|
|
10
10
|
name_contains: z
|
|
@@ -54,11 +54,16 @@ function renderTable(zones) {
|
|
|
54
54
|
if (zones.length === 0)
|
|
55
55
|
return "_No zones matched._";
|
|
56
56
|
const lines = [
|
|
57
|
-
"| ID | Name | Status | Postback | Site | Publisher |",
|
|
58
|
-
"
|
|
57
|
+
"| ID | Name | Source | Status | Postback | Site | Publisher |",
|
|
58
|
+
"|---|---|---|---|---|---|---|",
|
|
59
59
|
];
|
|
60
60
|
for (const z of zones) {
|
|
61
|
-
|
|
61
|
+
const source = z.traffic_source_name
|
|
62
|
+
? mdCell(z.traffic_source_name)
|
|
63
|
+
: z.traffic_source_id
|
|
64
|
+
? `\`${mdCell(z.traffic_source_id)}\``
|
|
65
|
+
: "—";
|
|
66
|
+
lines.push(`| \`${z.id}\` | ${mdCell(z.name)} | ${source} | ${z.status} | ${z.postback_url ? mdCell(shortUrl(z.postback_url)) : "⚠️ none"} | ${mdCell(shortUrl(z.site_url))} | ${mdCell(z.user_email ?? "—")} |`);
|
|
62
67
|
}
|
|
63
68
|
return lines.join("\n");
|
|
64
69
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { type AffsetClient } from "../client.js";
|
|
4
|
+
import { type TargetingMethod } from "../lib/targeting.js";
|
|
5
|
+
export declare const REMOVE_TARGETING_RULE_DESCRIPTION: string;
|
|
6
|
+
export declare const removeTargetingRuleInputSchema: {
|
|
7
|
+
campaign_id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
|
|
8
|
+
rule_id: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
type: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
10
|
+
method: z.ZodOptional<z.ZodEnum<["whitelist", "blacklist"]>>;
|
|
11
|
+
confirm: z.ZodDefault<z.ZodBoolean>;
|
|
12
|
+
};
|
|
13
|
+
type RemoveTargetingRuleArgs = {
|
|
14
|
+
campaign_id: string | number;
|
|
15
|
+
rule_id?: number;
|
|
16
|
+
type?: string | number;
|
|
17
|
+
method?: TargetingMethod;
|
|
18
|
+
confirm: boolean;
|
|
19
|
+
};
|
|
20
|
+
export declare function removeTargetingRule(client: AffsetClient, args: RemoveTargetingRuleArgs): Promise<CallToolResult>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import type { AffsetClient } from "../client.js";
|
|
4
|
+
/** Media-buyer verbs → API status. */
|
|
5
|
+
export declare const CAMPAIGN_ACTIONS: readonly ["run", "pause"];
|
|
6
|
+
export declare const SET_CAMPAIGN_STATUS_DESCRIPTION: string;
|
|
7
|
+
export declare const setCampaignStatusInputSchema: {
|
|
8
|
+
campaign_id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
|
|
9
|
+
action: z.ZodEnum<["run", "pause"]>;
|
|
10
|
+
confirm: z.ZodDefault<z.ZodBoolean>;
|
|
11
|
+
};
|
|
12
|
+
type SetCampaignStatusArgs = {
|
|
13
|
+
campaign_id: string | number;
|
|
14
|
+
action: (typeof CAMPAIGN_ACTIONS)[number];
|
|
15
|
+
confirm: boolean;
|
|
16
|
+
};
|
|
17
|
+
export declare function setCampaignStatus(client: AffsetClient, args: SetCampaignStatusArgs): Promise<CallToolResult>;
|
|
18
|
+
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 SET_PAYOUT_GOAL_DESCRIPTION: string;
|
|
5
|
+
export declare const setPayoutGoalInputSchema: {
|
|
6
|
+
campaign_id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
|
|
7
|
+
goal_type: z.ZodUnion<[z.ZodString, z.ZodNull]>;
|
|
8
|
+
confirm: z.ZodDefault<z.ZodBoolean>;
|
|
9
|
+
};
|
|
10
|
+
type SetPayoutGoalArgs = {
|
|
11
|
+
campaign_id: string | number;
|
|
12
|
+
goal_type: string | null;
|
|
13
|
+
confirm: boolean;
|
|
14
|
+
};
|
|
15
|
+
export declare function setPayoutGoal(client: AffsetClient, args: SetPayoutGoalArgs): Promise<CallToolResult>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
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 SET_PAYOUT_RULE_DESCRIPTION: string;
|
|
5
|
+
export declare const setPayoutRuleInputSchema: {
|
|
6
|
+
campaign_id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
|
|
7
|
+
payout: z.ZodNumber;
|
|
8
|
+
zone_id: z.ZodOptional<z.ZodString>;
|
|
9
|
+
confirm: z.ZodDefault<z.ZodBoolean>;
|
|
10
|
+
};
|
|
11
|
+
type SetPayoutRuleArgs = {
|
|
12
|
+
campaign_id: string | number;
|
|
13
|
+
payout: number;
|
|
14
|
+
zone_id?: string;
|
|
15
|
+
confirm: boolean;
|
|
16
|
+
};
|
|
17
|
+
export declare function setPayoutRule(client: AffsetClient, args: SetPayoutRuleArgs): Promise<CallToolResult>;
|
|
18
|
+
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 SET_SUB_LABELS_DESCRIPTION: string;
|
|
5
|
+
export declare const setSubLabelsInputSchema: {
|
|
6
|
+
sub1: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNull]>>;
|
|
7
|
+
sub2: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNull]>>;
|
|
8
|
+
sub3: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNull]>>;
|
|
9
|
+
sub4: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNull]>>;
|
|
10
|
+
sub5: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNull]>>;
|
|
11
|
+
confirm: z.ZodDefault<z.ZodBoolean>;
|
|
12
|
+
};
|
|
13
|
+
type SetSubLabelsArgs = {
|
|
14
|
+
sub1?: string | null;
|
|
15
|
+
sub2?: string | null;
|
|
16
|
+
sub3?: string | null;
|
|
17
|
+
sub4?: string | null;
|
|
18
|
+
sub5?: string | null;
|
|
19
|
+
confirm: boolean;
|
|
20
|
+
};
|
|
21
|
+
export declare function setSubLabels(client: AffsetClient, args: SetSubLabelsArgs): Promise<CallToolResult>;
|
|
22
|
+
export {};
|