@buygolinks/mcp 0.16.0 → 0.17.1
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 +2 -2
- package/package.json +1 -1
- package/src/index.js +18 -3
package/README.md
CHANGED
|
@@ -63,7 +63,7 @@ Most MCP clients use the same shape. Point them at the `npx -y @buygolinks/mcp`
|
|
|
63
63
|
| Tool | Description |
|
|
64
64
|
|---|---|
|
|
65
65
|
| `create_link` | Create a short link. The destination URL is passed through untouched (include your own affiliate tag). |
|
|
66
|
-
| `update_link` | Edit a link's title, source label, custom domain, password, archive state, or custom alias (e.g. `summer-sale` → `https://click.example.com/summer-sale`). |
|
|
66
|
+
| `update_link` | Edit a link's destination URL, title, source label, custom domain, password, archive state, or custom alias (e.g. `summer-sale` → `https://click.example.com/summer-sale`). Repointing the destination preserves the short code, alias, and click history. |
|
|
67
67
|
| `list_links` | List your links with click counts. |
|
|
68
68
|
| `get_link_stats` | Per-link analytics (by day, country, device, browser, hour, weekday). |
|
|
69
69
|
| `get_overview_stats` | Account-wide analytics. |
|
|
@@ -76,7 +76,7 @@ Most MCP clients use the same shape. Point them at the `npx -y @buygolinks/mcp`
|
|
|
76
76
|
| `list_landers` / `create_lander` / `update_lander` / `delete_lander` | Manage landing pages. Lander URLs may contain `{clickid}` tokens which the resolver expands. |
|
|
77
77
|
| `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`. |
|
|
78
78
|
| `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. |
|
|
79
|
-
| `list_campaigns` / `create_campaign` / `get_campaign` / `update_campaign` / `delete_campaign` | Manage campaigns. 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 CAPI when configured) when the campaign converts. Each campaign also returns a `click_url` (`…/click
|
|
79
|
+
| `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 slug 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 CAPI when configured) when the campaign converts. 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={direct_slug}` forwarded onto the CTA. Set `direct_slug` to run traffic straight to a lander with no tracker hop (`?utm_campaign={direct_slug}` resolves the campaign at `/click` and stitches via the property tag); `fallback_url` is the never-dead-end guarantee. |
|
|
80
80
|
| `set_campaign_offers` / `set_campaign_landers` | Replace the campaign's offer/lander split. Items are `{ offer_id, weight }` / `{ lander_id, weight }`. |
|
|
81
81
|
| `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. |
|
|
82
82
|
| `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.17.1",
|
|
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
|
@@ -75,11 +75,12 @@ const TOOLS = [
|
|
|
75
75
|
{
|
|
76
76
|
name: 'update_link',
|
|
77
77
|
description:
|
|
78
|
-
'Update an existing short link. Supports renaming (title), changing the campaign source label, swapping the branded domain it resolves under (domain_id), setting a memorable custom alias (alias), archiving/unarchiving, and password-protecting the link. Pass `alias` to give the link a memorable URL slug on its custom domain (e.g. alias="summer-sale" → https://click.example.com/summer-sale). Aliases require the link to be on a custom domain. Setting `alias` REPLACES any previous alias — the old alias stops resolving immediately and is freed for any other link to claim. The link\'s original random short code (link.code) keeps working forever regardless of alias changes. Pass alias="" or alias=null to remove the alias. Changing the link\'s `domain_id` clears the alias automatically. To set or change the password, pass `password` as a non-empty string. To remove password protection, pass an empty string for `password`. To move the link back to the platform default (buygolinks.com), pass `domain_id: null`. Returns the updated link row including `short_domain`, `alias`, and `password_protected` (boolean — the plaintext is never returned).',
|
|
78
|
+
'Update an existing short link. Supports changing where it redirects (destination_url), renaming (title), changing the campaign source label, swapping the branded domain it resolves under (domain_id), setting a memorable custom alias (alias), archiving/unarchiving, and password-protecting the link. Pass `destination_url` to repoint the link at a new target — the short code, alias, and click history are preserved; only the redirect destination moves (the ASIN is re-extracted automatically for Amazon /dp/ URLs). Pass `alias` to give the link a memorable URL slug on its custom domain (e.g. alias="summer-sale" → https://click.example.com/summer-sale). Aliases require the link to be on a custom domain. Setting `alias` REPLACES any previous alias — the old alias stops resolving immediately and is freed for any other link to claim. The link\'s original random short code (link.code) keeps working forever regardless of alias changes. Pass alias="" or alias=null to remove the alias. Changing the link\'s `domain_id` clears the alias automatically. To set or change the password, pass `password` as a non-empty string. To remove password protection, pass an empty string for `password`. To move the link back to the platform default (buygolinks.com), pass `domain_id: null`. Returns the updated link row including `short_domain`, `alias`, and `password_protected` (boolean — the plaintext is never returned).',
|
|
79
79
|
inputSchema: {
|
|
80
80
|
type: 'object',
|
|
81
81
|
properties: {
|
|
82
82
|
link_id: { type: 'number', description: 'The numeric id of the link (from list_links / create_link).' },
|
|
83
|
+
destination_url: { type: 'string', description: 'New destination URL the short link redirects to (must be http(s)). The short code, alias, and click history are preserved.' },
|
|
83
84
|
title: { type: 'string', description: 'New display title.' },
|
|
84
85
|
source_label: { type: 'string', description: 'New source label (campaign tag).' },
|
|
85
86
|
archived: { type: 'boolean', description: 'Set true to archive the link, false to unarchive.' },
|
|
@@ -193,7 +194,7 @@ const TOOLS = [
|
|
|
193
194
|
{
|
|
194
195
|
name: 'create_affiliate_network',
|
|
195
196
|
description:
|
|
196
|
-
'Add a new affiliate network. The server mints a per-network postback URL (https://buygolinks.com/postback/n/{token}) the user pastes into the network. Returns the network row including postback_url.',
|
|
197
|
+
'Add a new affiliate network. The server mints a per-network postback URL (https://buygolinks.com/postback/n/{token}) the user pastes into the network. The postback accepts ?{conversion_param}={clickid}&{payout_param}={payout}&{currency_param}={currency}&{txid_param}={txid} — payout, currency, and txid are optional. Returns the network row including postback_url.',
|
|
197
198
|
inputSchema: {
|
|
198
199
|
type: 'object',
|
|
199
200
|
properties: {
|
|
@@ -201,6 +202,7 @@ const TOOLS = [
|
|
|
201
202
|
conversion_param: { type: 'string', description: 'What the network calls the click id in its postback (default "clickid").' },
|
|
202
203
|
payout_param: { type: 'string', description: 'What the network calls the payout amount (default "payout").' },
|
|
203
204
|
currency_param: { type: 'string', description: 'What the network calls the currency code (default "currency").' },
|
|
205
|
+
txid_param: { type: 'string', description: 'What the network calls the transaction/order id in its postback (default "txid"). Stored on the conversion for reconciliation/dedupe.' },
|
|
204
206
|
},
|
|
205
207
|
required: ['name'],
|
|
206
208
|
},
|
|
@@ -216,6 +218,7 @@ const TOOLS = [
|
|
|
216
218
|
conversion_param: { type: 'string' },
|
|
217
219
|
payout_param: { type: 'string' },
|
|
218
220
|
currency_param: { type: 'string' },
|
|
221
|
+
txid_param: { type: 'string' },
|
|
219
222
|
archived: { type: 'boolean' },
|
|
220
223
|
},
|
|
221
224
|
required: ['network_id'],
|
|
@@ -428,7 +431,7 @@ const TOOLS = [
|
|
|
428
431
|
{
|
|
429
432
|
name: 'create_campaign',
|
|
430
433
|
description:
|
|
431
|
-
'Create a campaign. A campaign mints one short link (campaign.code) that the user pastes into Facebook / TikTok / etc. The resolver mints a click_id per visit, optionally routes through a lander (weighted), then redirects to an offer (weighted). The response also includes a `click_url` (`…/click
|
|
434
|
+
'Create a campaign. A campaign mints one short link (campaign.code) that the user pastes into Facebook / TikTok / etc. The resolver mints a click_id per visit, optionally routes through a lander (weighted), then redirects to an offer (weighted). The response also includes a `click_url` (`…/click`) — the single, campaign-agnostic DEFINED lander click URL the user pastes into their lander\'s CTA button. It\'s the same on every campaign, so one lander can be reused across many; the campaign is resolved at click time from the visitor\'s `bgl_clk_{code}` cookie (short-link traffic) or the ad\'s `?utm_campaign={direct_slug}` that the lander forwards onto the CTA (direct-link). It always resolves to an offer (chosen by the flow graph), never a lander, never a dead page. For DIRECT-LINK campaigns (ad points straight at the lander, no tracker hop), set `direct_slug`, put `?utm_campaign={direct_slug}` on the ad URL, and have the lander forward that utm_campaign onto the CTA — `/click` resolves the campaign from it and the property tag stitches the page view too. `fallback_url` guarantees the click never dead-ends. Conversions come back via the campaign\'s postback URL or the affiliate network\'s postback URL. You can optionally attach offer_ids / lander_ids inline with matching offer_weights / lander_weights arrays for a one-call setup.',
|
|
432
435
|
inputSchema: {
|
|
433
436
|
type: 'object',
|
|
434
437
|
properties: {
|
|
@@ -488,6 +491,11 @@ const TOOLS = [
|
|
|
488
491
|
description: 'Delete a campaign. The short link stops resolving immediately. Tracker events for this campaign are also deleted (cascade).',
|
|
489
492
|
inputSchema: { type: 'object', properties: { campaign_id: { type: 'number' } }, required: ['campaign_id'] },
|
|
490
493
|
},
|
|
494
|
+
{
|
|
495
|
+
name: 'duplicate_campaign',
|
|
496
|
+
description: 'Deep-copy a campaign: clones the campaign settings plus its full routing flow (source → landers → offers graph and split-test weights) and its offer/lander pools. The copy gets a fresh short link + postback token and a name like "COPY - {original}" (or "COPY (1) - {original}", "COPY (2) - …" when copying a copy). Stats are NOT copied; the direct-link slug is left blank (it must be unique). Returns the new campaign, including its short_url/click_url. Useful for spinning up a new geo/angle variant of a working campaign without rebuilding the flow.',
|
|
497
|
+
inputSchema: { type: 'object', properties: { campaign_id: { type: 'number' } }, required: ['campaign_id'] },
|
|
498
|
+
},
|
|
491
499
|
{
|
|
492
500
|
name: 'set_campaign_offers',
|
|
493
501
|
description: 'Replace the campaign\'s offer split with the supplied items. Each item is { offer_id, weight }. Weight is an integer; higher = more traffic. To direct all traffic to one offer use weight=100 for that offer and don\'t include the others.',
|
|
@@ -735,6 +743,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
735
743
|
}
|
|
736
744
|
case 'update_link': {
|
|
737
745
|
const body = {};
|
|
746
|
+
if (typeof args.destination_url === 'string') body.destination_url = args.destination_url;
|
|
738
747
|
if (typeof args.title === 'string') body.title = args.title;
|
|
739
748
|
if (typeof args.source_label === 'string') body.source_label = args.source_label;
|
|
740
749
|
if (typeof args.archived === 'boolean') body.archived = args.archived;
|
|
@@ -796,6 +805,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
796
805
|
if (typeof args.conversion_param === 'string') body.conversion_param = args.conversion_param;
|
|
797
806
|
if (typeof args.payout_param === 'string') body.payout_param = args.payout_param;
|
|
798
807
|
if (typeof args.currency_param === 'string') body.currency_param = args.currency_param;
|
|
808
|
+
if (typeof args.txid_param === 'string') body.txid_param = args.txid_param;
|
|
799
809
|
result = await api('/api/affiliate-networks', { method: 'POST', body: JSON.stringify(body) });
|
|
800
810
|
break;
|
|
801
811
|
}
|
|
@@ -805,6 +815,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
805
815
|
if (typeof args.conversion_param === 'string') body.conversion_param = args.conversion_param;
|
|
806
816
|
if (typeof args.payout_param === 'string') body.payout_param = args.payout_param;
|
|
807
817
|
if (typeof args.currency_param === 'string') body.currency_param = args.currency_param;
|
|
818
|
+
if (typeof args.txid_param === 'string') body.txid_param = args.txid_param;
|
|
808
819
|
if (typeof args.archived === 'boolean') body.archived = args.archived;
|
|
809
820
|
result = await api(`/api/affiliate-networks/${Number(args.network_id)}`, { method: 'PATCH', body: JSON.stringify(body) });
|
|
810
821
|
break;
|
|
@@ -972,6 +983,10 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
972
983
|
result = await api(`/api/campaigns/${Number(args.campaign_id)}`, { method: 'DELETE' });
|
|
973
984
|
break;
|
|
974
985
|
}
|
|
986
|
+
case 'duplicate_campaign': {
|
|
987
|
+
result = await api(`/api/campaigns/${Number(args.campaign_id)}/duplicate`, { method: 'POST' });
|
|
988
|
+
break;
|
|
989
|
+
}
|
|
975
990
|
case 'set_campaign_offers': {
|
|
976
991
|
result = await api(`/api/campaigns/${Number(args.campaign_id)}/offers`, {
|
|
977
992
|
method: 'PUT', body: JSON.stringify({ items: args.items }),
|