@buygolinks/mcp 0.1.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 +80 -0
- package/package.json +34 -0
- package/src/index.js +174 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @buygolinks/mcp
|
|
2
|
+
|
|
3
|
+
Model Context Protocol (MCP) server for [buygolinks.com](https://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, and others.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
No install needed — use `npx`:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx @buygolinks/mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Get an API key
|
|
14
|
+
|
|
15
|
+
1. Sign in at [app.buygolinks.com](https://app.buygolinks.com)
|
|
16
|
+
2. Go to **Settings** → **API Keys** → **New Key**
|
|
17
|
+
3. Copy the `bgl_…` token (shown once)
|
|
18
|
+
|
|
19
|
+
## Configure your client
|
|
20
|
+
|
|
21
|
+
### Claude Desktop
|
|
22
|
+
|
|
23
|
+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"buygolinks": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["-y", "@buygolinks/mcp"],
|
|
31
|
+
"env": {
|
|
32
|
+
"BUYGOLINKS_API_KEY": "bgl_your_key_here"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Restart Claude Desktop. You'll see a 🔌 icon — buygolinks tools are now available.
|
|
40
|
+
|
|
41
|
+
### Cursor
|
|
42
|
+
|
|
43
|
+
`.cursor/mcp.json` in your project, or `~/.cursor/mcp.json` globally:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"mcpServers": {
|
|
48
|
+
"buygolinks": {
|
|
49
|
+
"command": "npx",
|
|
50
|
+
"args": ["-y", "@buygolinks/mcp"],
|
|
51
|
+
"env": { "BUYGOLINKS_API_KEY": "bgl_your_key_here" }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Cline / Continue / Hermes / others
|
|
58
|
+
|
|
59
|
+
Most MCP clients use the same shape. Point them at the `npx -y @buygolinks/mcp` command with `BUYGOLINKS_API_KEY` in the env.
|
|
60
|
+
|
|
61
|
+
## Tools
|
|
62
|
+
|
|
63
|
+
| Tool | Description |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `create_link` | Create a short link. Amazon URLs auto-detect ASIN and trigger geo-routing. |
|
|
66
|
+
| `list_links` | List your links with click counts. |
|
|
67
|
+
| `get_link_stats` | Per-link analytics (by day, country, device, browser, hour, weekday). |
|
|
68
|
+
| `get_overview_stats` | Account-wide analytics. |
|
|
69
|
+
|
|
70
|
+
## Example prompts
|
|
71
|
+
|
|
72
|
+
> "Create a short link for `https://www.amazon.com/dp/B0CFG6RB6T` with the title 'Anker GaN charger'."
|
|
73
|
+
|
|
74
|
+
> "How many clicks did I get last week? Which country drove the most?"
|
|
75
|
+
|
|
76
|
+
> "Show me the top 5 most-clicked links and their countries."
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@buygolinks/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
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
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"buygolinks-mcp": "src/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=18"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@modelcontextprotocol/sdk": "^1.0.4"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"model-context-protocol",
|
|
22
|
+
"buygolinks",
|
|
23
|
+
"short-links",
|
|
24
|
+
"amazon-affiliate",
|
|
25
|
+
"claude",
|
|
26
|
+
"cursor"
|
|
27
|
+
],
|
|
28
|
+
"homepage": "https://buygolinks.com",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/buygolinks/mcp.git"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT"
|
|
34
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* buygolinks MCP server (stdio).
|
|
4
|
+
*
|
|
5
|
+
* Exposes the buygolinks.com API as MCP tools so any MCP-compatible agent
|
|
6
|
+
* (Claude Desktop, Cursor, Cline, Continue, Hermes, etc.) can create and
|
|
7
|
+
* manage branded short links on the user's behalf.
|
|
8
|
+
*
|
|
9
|
+
* Auth: BUYGOLINKS_API_KEY env var (personal access token, format bgl_…).
|
|
10
|
+
* Create one at https://app.buygolinks.com/settings/account.
|
|
11
|
+
*/
|
|
12
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
13
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
14
|
+
import {
|
|
15
|
+
CallToolRequestSchema,
|
|
16
|
+
ListToolsRequestSchema,
|
|
17
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
18
|
+
|
|
19
|
+
const API_BASE = process.env.BUYGOLINKS_API_BASE || 'https://app.buygolinks.com';
|
|
20
|
+
const API_KEY = process.env.BUYGOLINKS_API_KEY;
|
|
21
|
+
|
|
22
|
+
if (!API_KEY) {
|
|
23
|
+
console.error('[buygolinks-mcp] BUYGOLINKS_API_KEY env var is required.');
|
|
24
|
+
console.error(' Create one at https://app.buygolinks.com/settings/account');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function api(path, init = {}) {
|
|
29
|
+
const r = await fetch(`${API_BASE}${path}`, {
|
|
30
|
+
...init,
|
|
31
|
+
headers: {
|
|
32
|
+
'Authorization': `Bearer ${API_KEY}`,
|
|
33
|
+
'Content-Type': 'application/json',
|
|
34
|
+
...(init.headers || {}),
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
const text = await r.text();
|
|
38
|
+
let body;
|
|
39
|
+
try { body = text ? JSON.parse(text) : null; } catch { body = text; }
|
|
40
|
+
if (!r.ok) {
|
|
41
|
+
const code = body?.error || r.statusText || `http_${r.status}`;
|
|
42
|
+
throw new Error(`buygolinks API ${r.status}: ${code}`);
|
|
43
|
+
}
|
|
44
|
+
return body;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const TOOLS = [
|
|
48
|
+
{
|
|
49
|
+
name: 'create_link',
|
|
50
|
+
description:
|
|
51
|
+
'Create a new branded short link on buygolinks.com. If the destination is an Amazon product URL (contains /dp/ASIN), the ASIN is auto-extracted and the link will geo-route to the visitor\'s local Amazon storefront with the owner\'s affiliate tag applied. Returns the short URL and link metadata.',
|
|
52
|
+
inputSchema: {
|
|
53
|
+
type: 'object',
|
|
54
|
+
properties: {
|
|
55
|
+
destination_url: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'The full URL the short link should redirect to. Must be http(s).',
|
|
58
|
+
},
|
|
59
|
+
title: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
description: 'Optional human-readable title for the link. If omitted on an Amazon URL, the product title is scraped.',
|
|
62
|
+
},
|
|
63
|
+
source_label: {
|
|
64
|
+
type: 'string',
|
|
65
|
+
description: 'Optional source label (campaign tag) — appears in ascsubtag on Amazon redirects for attribution.',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
required: ['destination_url'],
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'list_links',
|
|
73
|
+
description:
|
|
74
|
+
'List all short links owned by the authenticated user, including per-link click counts. Returns links in newest-first order. Use include_archived=true to also include archived links.',
|
|
75
|
+
inputSchema: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
include_archived: {
|
|
79
|
+
type: 'boolean',
|
|
80
|
+
description: 'If true, include archived links. Defaults to false.',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'get_link_stats',
|
|
87
|
+
description:
|
|
88
|
+
'Get aggregated click analytics for a single short link: clicks by day, country, device, browser, referrer, hour-of-day, and weekday. Use the link id returned from list_links or create_link.',
|
|
89
|
+
inputSchema: {
|
|
90
|
+
type: 'object',
|
|
91
|
+
properties: {
|
|
92
|
+
link_id: {
|
|
93
|
+
type: 'number',
|
|
94
|
+
description: 'The numeric id of the link (from list_links / create_link).',
|
|
95
|
+
},
|
|
96
|
+
days: {
|
|
97
|
+
type: 'number',
|
|
98
|
+
description: 'Window size in days (1–90). Defaults to 14.',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
required: ['link_id'],
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'get_overview_stats',
|
|
106
|
+
description:
|
|
107
|
+
'Get account-wide click analytics across all of the user\'s links: total clicks, clicks by day, top countries, devices, browsers, referrers, peak hour and weekday. Use this for "how is my account doing" type questions.',
|
|
108
|
+
inputSchema: {
|
|
109
|
+
type: 'object',
|
|
110
|
+
properties: {
|
|
111
|
+
days: {
|
|
112
|
+
type: 'number',
|
|
113
|
+
description: 'Window size in days (1–90). Defaults to 14.',
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
const server = new Server(
|
|
121
|
+
{ name: 'buygolinks', version: '0.1.0' },
|
|
122
|
+
{ capabilities: { tools: {} } },
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
126
|
+
|
|
127
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
128
|
+
const { name, arguments: args } = req.params;
|
|
129
|
+
try {
|
|
130
|
+
let result;
|
|
131
|
+
switch (name) {
|
|
132
|
+
case 'create_link': {
|
|
133
|
+
result = await api('/api/links', {
|
|
134
|
+
method: 'POST',
|
|
135
|
+
body: JSON.stringify({
|
|
136
|
+
destination_url: args.destination_url,
|
|
137
|
+
title: args.title,
|
|
138
|
+
source_label: args.source_label,
|
|
139
|
+
}),
|
|
140
|
+
});
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
case 'list_links': {
|
|
144
|
+
const qs = args?.include_archived ? '?include_archived=1' : '';
|
|
145
|
+
result = await api(`/api/links${qs}`);
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case 'get_link_stats': {
|
|
149
|
+
const days = args?.days ? `?days=${Number(args.days)}` : '';
|
|
150
|
+
result = await api(`/api/stats/link/${Number(args.link_id)}${days}`);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case 'get_overview_stats': {
|
|
154
|
+
const days = args?.days ? `?days=${Number(args.days)}` : '';
|
|
155
|
+
result = await api(`/api/stats/overview${days}`);
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
default:
|
|
159
|
+
throw new Error(`unknown tool: ${name}`);
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
163
|
+
};
|
|
164
|
+
} catch (err) {
|
|
165
|
+
return {
|
|
166
|
+
isError: true,
|
|
167
|
+
content: [{ type: 'text', text: String(err.message || err) }],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const transport = new StdioServerTransport();
|
|
173
|
+
await server.connect(transport);
|
|
174
|
+
console.error('[buygolinks-mcp] ready');
|