@buygolinks/mcp 0.21.1 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/index.js +7 -3
package/README.md
CHANGED
|
@@ -77,7 +77,7 @@ Most MCP clients use the same shape. Point them at the `npx -y @buygolinks/mcp`
|
|
|
77
77
|
| `list_landers` / `create_lander` / `update_lander` / `delete_lander` | Manage landing pages. Lander URLs may contain `{clickid}` tokens which the resolver expands. |
|
|
78
78
|
| `list_traffic_sources` / `create_traffic_source` / `update_traffic_source` / `delete_traffic_source` | Manage **traffic sources** — the platforms you buy traffic from (Facebook, TikTok, Google, …). Each has a `name`, optional `platform`, and `token_params` mapping the source's click macros onto sub1..sub5 (e.g. Facebook sub1 = Ad ID `{{ad.id}}`). `list_traffic_sources` returns a `presets` catalog. Campaigns reference one via `traffic_source_id`. |
|
|
79
79
|
| `list_tracking_pixels` / `create_tracking_pixel` / `update_tracking_pixel` / `delete_tracking_pixel` | Manage ad-platform pixels (Facebook, Google, TikTok, …). Each pixel has a `default_event` (e.g. `Purchase`, `Lead`, `CompletePayment`) and, for Facebook/TikTok, an optional server-side Conversions API `capi_token`. `list_tracking_pixels` also returns a `platforms` catalog with each platform's valid `events`, `defaultEvent`, and `capi` support. Pixels fire on short-link clicks and can be chosen as a campaign's conversion pixel. |
|
|
80
|
-
| `list_campaigns` / `create_campaign` / `get_campaign` / `update_campaign` / `delete_campaign` / `duplicate_campaign` | Manage campaigns. `duplicate_campaign` deep-copies a campaign (settings + full routing flow + offer/lander pools) into a fresh short link named `COPY - {name}` (`COPY (1) - …` when copying a copy); stats and the unique direct-link
|
|
80
|
+
| `list_campaigns` / `create_campaign` / `get_campaign` / `update_campaign` / `delete_campaign` / `duplicate_campaign` | Manage campaigns. `duplicate_campaign` deep-copies a campaign (settings + full routing flow + offer/lander pools) into a fresh short link named `COPY - {name}` (`COPY (1) - …` when copying a copy); stats and the unique direct-link tags are not carried over. One campaign = one tracked short link + N offers (weighted) + N optional landers + a per-campaign postback URL + a pixel snippet. A campaign references one saved traffic source via `traffic_source_id` and an optional `conversion_pixel_id` + `conversion_event` that fires **server-side via the pixel's CAPI token** when the campaign converts (a pixel with no CAPI token can't fire back). `report_value_mode` controls the value reported back — `payout` (real), `fixed` (a set number), or `adjusted` (payout − `report_value_adjust_pct`% − `report_value_adjust_flat`) so you can withhold your margin. Each campaign also returns a `click_url` (`…/click`) — the single, campaign-agnostic lander CTA link (same on every campaign, so one lander serves many) that always resolves to an offer (never a dead page); the campaign is read from the visitor's cookie or the ad's `?utm_campaign={slug}` (matched against any of the campaign's direct-link tags) forwarded onto the CTA. As of **0.22.0**, `create_campaign`/`update_campaign` gained **`direct_slugs`** — a campaign can claim MULTIPLE direct-link tags (an array of strings or `{ slug, label }` objects, each routing through the campaign's flow) so you run traffic straight to a lander with no tracker hop (`?utm_campaign={slug}` resolves the campaign at `/click` and stitches via the property tag); handy for migrating an older campaign or turning a lander already getting direct traffic into a campaign. The legacy single `direct_slug` is deprecated but still accepted (responses mirror it to the oldest slug). `fallback_url` is the never-dead-end guarantee. |
|
|
81
81
|
| `set_campaign_offers` / `set_campaign_landers` | Replace the campaign's offer/lander split. Items are `{ offer_id, weight }` / `{ lander_id, weight }`. |
|
|
82
82
|
| `get_campaign_flow` / `set_campaign_flow` | Read/replace the campaign's **routing flow graph** (n8n-style). Nodes are `source` (one entry) / `lander` / `offer`; weighted edges go source→lander, source→offer, or lander→offer. The resolver walks this graph per click so a specific lander routes to its own specific offers — use it to split-test offers, divert a lander to a different offer, or insert a landing page before an offer. Saving also re-derives the flat offer/lander pools. |
|
|
83
83
|
| `get_campaign_stats` | Full campaign report: visits, lander views, offer clicks, conversions, revenue, cost, profit, CTR/CR/EPC/ROI, breakdowns, recent events. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buygolinks/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "MCP server for buygolinks.com — create and manage branded short links with Amazon affiliate geo-routing from any MCP-compatible AI agent (Claude Desktop, Cursor, Cline, Continue, Hermes).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/index.js
CHANGED
|
@@ -464,7 +464,8 @@ const TOOLS = [
|
|
|
464
464
|
report_value_fixed: { type: ['number', 'null'], description: 'Used when report_value_mode = "fixed": the exact value (USD) reported on every conversion regardless of real payout.' },
|
|
465
465
|
report_value_adjust_pct: { type: ['number', 'null'], description: 'Used when report_value_mode = "adjusted": percentage (0–100) subtracted from the real payout first (e.g. 10 reports payout − 10%).' },
|
|
466
466
|
report_value_adjust_flat: { type: ['number', 'null'], description: 'Used when report_value_mode = "adjusted": flat amount (USD) subtracted after the percentage.' },
|
|
467
|
-
direct_slug: { type: ['string', 'null'], description: 'Optional direct-link tag, unique per user (lowercased alnum + dashes, e.g. "bsu-fb-cold").
|
|
467
|
+
direct_slug: { type: ['string', 'null'], description: 'DEPRECATED single-tag form (still accepted) — prefer direct_slugs. Optional direct-link tag, unique per user (lowercased alnum + dashes, e.g. "bsu-fb-cold"). Returns 409 (direct_slug_taken) if another campaign already uses it. Pass null to clear.' },
|
|
468
|
+
direct_slugs: { type: 'array', description: 'Direct-link tags this campaign claims, for running traffic STRAIGHT to a lander with no tracker hop. A campaign can claim MANY utm_campaign values (an older campaign being migrated in, a lander turned into a campaign, etc.) — each routes through this campaign\'s flow. Put `?utm_campaign={slug}` on the ad URL; the lander forwards it onto the /click CTA and the property tag stitches the page view. Each item is either a string (used as both slug + label) or `{ slug, label }` where slug is sanitized (lowercased alnum+dashes, what gets matched) and label is the friendly display value (e.g. "ABO Testing Campaign"). Each slug is unique per user → 409 (direct_slug_taken) on collision. Pass [] to clear all tags.', items: { oneOf: [ { type: 'string' }, { type: 'object', properties: { slug: { type: 'string' }, label: { type: 'string' } }, required: ['slug'] } ] } },
|
|
468
469
|
fallback_url: { type: ['string', 'null'], description: 'Optional URL the click falls back to when the flow yields no live offer — the never-dead-end guarantee. Pass null to use the platform default.' },
|
|
469
470
|
offer_ids: { type: 'array', items: { type: 'number' } },
|
|
470
471
|
offer_weights: { type: 'array', items: { type: 'number' } },
|
|
@@ -501,7 +502,8 @@ const TOOLS = [
|
|
|
501
502
|
report_value_fixed: { type: ['number', 'null'], description: 'Fixed value (USD) reported on every conversion when report_value_mode = "fixed". Null to clear.' },
|
|
502
503
|
report_value_adjust_pct: { type: ['number', 'null'], description: 'Percentage (0–100) subtracted from real payout when report_value_mode = "adjusted". Null to clear.' },
|
|
503
504
|
report_value_adjust_flat: { type: ['number', 'null'], description: 'Flat USD amount subtracted (after the %) when report_value_mode = "adjusted". Null to clear.' },
|
|
504
|
-
direct_slug: { type: ['string', 'null'], description: 'Direct-link tag for utm_campaign-based stitching (unique per user), or null to clear. Returns 409 (direct_slug_taken) on collision.' },
|
|
505
|
+
direct_slug: { type: ['string', 'null'], description: 'DEPRECATED single-tag form (still accepted) — prefer direct_slugs. Direct-link tag for utm_campaign-based stitching (unique per user), or null to clear. Returns 409 (direct_slug_taken) on collision.' },
|
|
506
|
+
direct_slugs: { type: 'array', description: 'Replace this campaign\'s direct-link tags. A campaign can claim MANY utm_campaign values, each routing through its flow. Each item is a string (slug+label) or `{ slug, label }`. Slugs are unique per user → 409 (direct_slug_taken) on collision. Pass [] to clear all.', items: { oneOf: [ { type: 'string' }, { type: 'object', properties: { slug: { type: 'string' }, label: { type: 'string' } }, required: ['slug'] } ] } },
|
|
505
507
|
fallback_url: { type: ['string', 'null'], description: 'Never-dead-end fallback URL when no live offer exists, or null to use the platform default.' },
|
|
506
508
|
archived: { type: 'boolean' },
|
|
507
509
|
},
|
|
@@ -705,7 +707,7 @@ const TOOLS = [
|
|
|
705
707
|
{
|
|
706
708
|
name: 'list_observed_campaign_tags',
|
|
707
709
|
description:
|
|
708
|
-
'List the distinct `utm_campaign` values that have actually been SEEN arriving on the user\'s properties/visits over the last 90 days, most-active first. Each entry is `{ utm_campaign, events, utm_source, utm_medium, lander_url, claimed_by }` where `claimed_by` is `{ id, name }` of the BGL campaign
|
|
710
|
+
'List the distinct `utm_campaign` values that have actually been SEEN arriving on the user\'s properties/visits over the last 90 days, most-active first. Each entry is `{ utm_campaign, slug, events, utm_source, utm_medium, lander_url, claimed_by }` where `utm_campaign` is the raw value (for display, e.g. "ABO Testing Campaign"), `slug` is its sanitized form (what gets stored + matched), and `claimed_by` is `{ id, name }` of the BGL campaign that already owns that slug, or null if unclaimed. Use this to WIRE UP AN ALREADY-RUNNING DIRECT-LINK CAMPAIGN: when an ad on FB/Google points straight at a lander (no tracker hop) with `?utm_campaign={tag}`, that tag shows up here once the universal property tag reports a page view. Pick an unclaimed tag and add it to a campaign\'s `direct_slugs` (via `update_campaign`, passing `{ slug, label: utm_campaign }`) so BGL attributes that traffic — and its `/click` CTA — to the right campaign + offer. A campaign can claim several tags. Skip tags whose `claimed_by` is non-null (another campaign already owns them).',
|
|
709
711
|
inputSchema: { type: 'object', properties: {} },
|
|
710
712
|
},
|
|
711
713
|
{
|
|
@@ -991,6 +993,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
991
993
|
if ('report_value_adjust_pct' in args) body.report_value_adjust_pct = args.report_value_adjust_pct;
|
|
992
994
|
if ('report_value_adjust_flat' in args) body.report_value_adjust_flat = args.report_value_adjust_flat;
|
|
993
995
|
if ('direct_slug' in args) body.direct_slug = args.direct_slug;
|
|
996
|
+
if (Array.isArray(args.direct_slugs)) body.direct_slugs = args.direct_slugs;
|
|
994
997
|
if ('fallback_url' in args) body.fallback_url = args.fallback_url;
|
|
995
998
|
if (Array.isArray(args.offer_ids)) body.offer_ids = args.offer_ids;
|
|
996
999
|
if (Array.isArray(args.offer_weights)) body.offer_weights = args.offer_weights;
|
|
@@ -1018,6 +1021,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
1018
1021
|
if ('report_value_adjust_pct' in args) body.report_value_adjust_pct = args.report_value_adjust_pct;
|
|
1019
1022
|
if ('report_value_adjust_flat' in args) body.report_value_adjust_flat = args.report_value_adjust_flat;
|
|
1020
1023
|
if ('direct_slug' in args) body.direct_slug = args.direct_slug;
|
|
1024
|
+
if (Array.isArray(args.direct_slugs)) body.direct_slugs = args.direct_slugs;
|
|
1021
1025
|
if ('fallback_url' in args) body.fallback_url = args.fallback_url;
|
|
1022
1026
|
if (typeof args.archived === 'boolean') body.archived = args.archived;
|
|
1023
1027
|
result = await api(`/api/campaigns/${Number(args.campaign_id)}`, { method: 'PATCH', body: JSON.stringify(body) });
|