linkbreakers-mcp 1.183.3 → 1.185.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 (3) hide show
  1. package/README.md +26 -16
  2. package/lib/proxy.js +7 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,8 +1,29 @@
1
1
  # linkbreakers-mcp
2
2
 
3
- Local stdio bridge to the hosted [Linkbreakers](https://linkbreakers.com) MCP server at `https://mcp.linkbreakers.com`, for MCP clients that can only start local (stdio) servers.
3
+ **An MCP server that lets AI agents create and track QR codes.** Connect Claude, Cursor, VS Code or any MCP client to [Linkbreakers](https://linkbreakers.com/mcp?utm_source=github&utm_content=linkbreakers-mcp) and your agent can create a dynamic QR code and its short link, style the code, put a lead capture form between the scan and the destination and read back every scan: device, country, city and time, visitors and analytics.
4
4
 
5
- If your client supports remote MCP servers, connect it to `https://mcp.linkbreakers.com` directly instead. See the [setup guide](https://linkbreakers.com/help/article/mcp-server-setup).
5
+ ```bash
6
+ npx -y linkbreakers-mcp
7
+ ```
8
+
9
+ Sign in with OAuth on the first request, nothing to paste. Works on every Linkbreakers plan, Free included.
10
+
11
+ What an agent can ask for, and the tools it uses:
12
+
13
+ | Ask | Tools |
14
+ | --- | --- |
15
+ | "Make a QR code for our spring poster that opens example.com/spring" | `links_create` |
16
+ | "Make one code per store from this list" | `links_create_bulk` |
17
+ | "Make the code navy with rounded dots" | `qrcodedesigns_update` |
18
+ | "Ask for an email before the redirect" | `workflow_steps_create` |
19
+ | "Who scanned the poster this week, and from where?" | `events_list`, `visitors_list` |
20
+ | "How many scans did the workspace get?" | `metrics_workspace` |
21
+
22
+ In clients that render MCP Apps (Claude, ChatGPT), `links_create`, `links_get`, `visitors_list` and `metrics_workspace` answer with an interactive card.
23
+
24
+ ## How it works
25
+
26
+ This package is a local stdio bridge to the hosted server at `https://mcp.linkbreakers.com`, for MCP clients that can only start local (stdio) servers. If your client supports remote MCP servers, connect it to `https://mcp.linkbreakers.com` directly instead. See the [setup guide](https://linkbreakers.com/help/article/mcp-server-setup?utm_source=github&utm_content=linkbreakers-mcp).
6
27
 
7
28
  Tools, resources and their schemas come from the hosted server: this package forwards every request unchanged, so it always matches what `https://mcp.linkbreakers.com` serves.
8
29
 
@@ -21,24 +42,13 @@ Tools, resources and their schemas come from the hosted server: this package for
21
42
 
22
43
  ### Authentication
23
44
 
24
- - **OAuth (default):** on the first request, your browser opens the Linkbreakers sign-in. Once you approve, the tools appear. Tokens are stored in `~/.config/linkbreakers/mcp-oauth.json` and refreshed automatically.
25
- - **API token:** set `LINKBREAKERS_API_TOKEN` to a workspace API token from the [dashboard](https://app.linkbreakers.com) to skip the browser.
45
+ On the first request, your browser opens the Linkbreakers sign-in. Once you approve, the tools appear. Tokens are stored in `~/.config/linkbreakers/mcp-oauth.json` and refreshed automatically.
26
46
 
27
- ```json
28
- {
29
- "mcpServers": {
30
- "linkbreakers": {
31
- "command": "npx",
32
- "args": ["-y", "linkbreakers-mcp"],
33
- "env": { "LINKBREAKERS_API_TOKEN": "your-workspace-token" }
34
- }
35
- }
36
- }
37
- ```
47
+ The MCP server accepts OAuth only: dashboard API tokens are refused, so there
48
+ is nothing to paste. API tokens are for the REST API, the SDKs and the CLI.
38
49
 
39
50
  | Variable | Default | Purpose |
40
51
  | --- | --- | --- |
41
- | `LINKBREAKERS_API_TOKEN` | unset | Workspace API token, sent as a bearer token |
42
52
  | `LINKBREAKERS_MCP_URL` | `https://mcp.linkbreakers.com` | Server to forward to |
43
53
  | `LINKBREAKERS_MCP_CALLBACK_PORT` | `47823` | Local port for the OAuth redirect |
44
54
 
package/lib/proxy.js CHANGED
@@ -9,7 +9,6 @@ import { FileOAuthProvider, hasStoredTokens, openBrowser } from './oauth.js';
9
9
 
10
10
  const { version } = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
11
11
  const SERVER_URL = new URL(process.env.LINKBREAKERS_MCP_URL || 'https://mcp.linkbreakers.com');
12
- const TOKEN = process.env.LINKBREAKERS_API_TOKEN?.trim();
13
12
  const REQUEST_TIMEOUT_MS = 5 * 60 * 1000;
14
13
  const AUTH_REQUIRED = -32001;
15
14
  const DEFAULT_CAPABILITIES = { tools: { listChanged: true }, resources: { listChanged: true } };
@@ -17,15 +16,14 @@ const DEFAULT_CAPABILITIES = { tools: { listChanged: true }, resources: { listCh
17
16
  const log = (message) => process.stderr.write(`linkbreakers-mcp: ${message}\n`);
18
17
 
19
18
  export async function main() {
20
- const oauth = TOKEN ? undefined : new FileOAuthProvider(SERVER_URL.href, version);
19
+ // The MCP server accepts OAuth only: dashboard API tokens are refused.
20
+ const oauth = new FileOAuthProvider(SERVER_URL.href, version);
21
21
  let server;
22
22
  let remote;
23
23
  let connecting;
24
24
  let signIn;
25
25
 
26
- const transportOptions = TOKEN
27
- ? { requestInit: { headers: { Authorization: `Bearer ${TOKEN}` } } }
28
- : { authProvider: oauth };
26
+ const transportOptions = { authProvider: oauth };
29
27
 
30
28
  async function connectRemote(transport = new StreamableHTTPClientTransport(SERVER_URL, transportOptions)) {
31
29
  const client = new Client({ name: 'linkbreakers-mcp', version }, { capabilities: {} });
@@ -38,7 +36,7 @@ export async function main() {
38
36
  try {
39
37
  await client.connect(transport);
40
38
  } catch (err) {
41
- if (oauth && err instanceof UnauthorizedError && oauth.authorizationUrl) startSignIn(transport);
39
+ if (err instanceof UnauthorizedError && oauth.authorizationUrl) startSignIn(transport);
42
40
  throw err;
43
41
  }
44
42
  return client;
@@ -66,12 +64,10 @@ export async function main() {
66
64
  }
67
65
 
68
66
  function authError() {
69
- const url = oauth?.authorizationUrl;
67
+ const url = oauth.authorizationUrl;
70
68
  return new McpError(
71
69
  AUTH_REQUIRED,
72
- TOKEN
73
- ? 'Linkbreakers rejected LINKBREAKERS_API_TOKEN. Create a workspace API token at https://app.linkbreakers.com, or unset it to sign in with OAuth.'
74
- : `Linkbreakers sign-in required. Finish the OAuth sign-in opened in your browser${url ? ` (${url})` : ''}, or set LINKBREAKERS_API_TOKEN to a workspace API token. Tools appear once you are signed in.`,
70
+ `Linkbreakers sign-in required. Finish the OAuth sign-in opened in your browser${url ? ` (${url})` : ''}. Tools appear once you are signed in.`,
75
71
  );
76
72
  }
77
73
 
@@ -90,7 +86,7 @@ export async function main() {
90
86
  }
91
87
  }
92
88
 
93
- if (TOKEN || hasStoredTokens(SERVER_URL.href)) {
89
+ if (hasStoredTokens(SERVER_URL.href)) {
94
90
  try {
95
91
  remote = await connectRemote();
96
92
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linkbreakers-mcp",
3
- "version": "1.183.3",
3
+ "version": "1.185.0",
4
4
  "mcpName": "com.linkbreakers/mcp",
5
5
  "description": "Local stdio bridge to the Linkbreakers MCP server (https://mcp.linkbreakers.com) for MCP clients that only run local servers.",
6
6
  "keywords": [