@open-qr/mcp 1.0.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 +54 -0
- package/index.js +63 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @open-qr/mcp
|
|
2
|
+
|
|
3
|
+
MCP server for [OpenQR](https://openqr.uk): generate QR codes and create, edit
|
|
4
|
+
and track dynamic (editable) QR codes with scan analytics.
|
|
5
|
+
|
|
6
|
+
A thin stdio-to-HTTP bridge: it forwards MCP traffic between your client and the
|
|
7
|
+
hosted endpoint at `https://openqr.uk/mcp`. No tools are implemented here, so
|
|
8
|
+
the tool list always matches what the server exposes (currently 17 tools, 4
|
|
9
|
+
prompts, 5 resources).
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
1. Get a free API key at [openqr.uk/api](https://openqr.uk/api).
|
|
14
|
+
2. Point your MCP client at the command below with the key in the environment.
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"mcpServers": {
|
|
19
|
+
"openqr": {
|
|
20
|
+
"command": "npx",
|
|
21
|
+
"args": ["-y", "@open-qr/mcp"],
|
|
22
|
+
"env": { "OPENQR_API_KEY": "oqr_..." }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Prefer the hosted endpoint directly? Most remote-capable clients (Claude Web,
|
|
29
|
+
Claude Desktop, Cursor, Cline) can connect to `https://openqr.uk/mcp` over
|
|
30
|
+
streamable HTTP with a `Bearer` Authorization header, no bridge needed.
|
|
31
|
+
|
|
32
|
+
## Environment
|
|
33
|
+
|
|
34
|
+
| Variable | Required | Purpose |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| `OPENQR_API_KEY` | yes | Bearer key from [openqr.uk/api](https://openqr.uk/api) |
|
|
37
|
+
| `OPENQR_MCP_URL` | no | Override the endpoint (default `https://openqr.uk/mcp`) |
|
|
38
|
+
|
|
39
|
+
## Verify
|
|
40
|
+
|
|
41
|
+
With a real key in the environment:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install
|
|
45
|
+
OPENQR_API_KEY=oqr_... node verify.mjs
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
That runs the full round-trip a client would: initialize, list tools, list
|
|
49
|
+
prompts and resources, generate a QR, and make an authenticated dynamic-code
|
|
50
|
+
call.
|
|
51
|
+
|
|
52
|
+
## Licence
|
|
53
|
+
|
|
54
|
+
AGPL-3.0-only, same as the repository.
|
package/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Bridge a local stdio MCP client to the hosted OpenQR MCP endpoint
|
|
3
|
+
// (https://openqr.uk/mcp, streamable HTTP, Bearer API key).
|
|
4
|
+
//
|
|
5
|
+
// The bridge is transparent: every JSON-RPC message the client writes to
|
|
6
|
+
// stdio is forwarded to the remote session verbatim, and every message the
|
|
7
|
+
// remote sends back is written to stdio. Nothing is buffered, filtered or
|
|
8
|
+
// re-implemented, so the tool list stays exactly what the server exposes.
|
|
9
|
+
//
|
|
10
|
+
// Usage: OPENQR_API_KEY=oqr_... npx -y @open-qr/mcp
|
|
11
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
13
|
+
|
|
14
|
+
const url = process.env.OPENQR_MCP_URL ?? "https://openqr.uk/mcp";
|
|
15
|
+
const key = process.env.OPENQR_API_KEY;
|
|
16
|
+
|
|
17
|
+
if (!key) {
|
|
18
|
+
console.error(
|
|
19
|
+
"OPENQR_API_KEY is required. Get a free key at https://openqr.uk/api"
|
|
20
|
+
);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const remote = new StreamableHTTPClientTransport(new URL(url), {
|
|
25
|
+
requestInit: { headers: { Authorization: `Bearer ${key}` } },
|
|
26
|
+
});
|
|
27
|
+
const stdio = new StdioServerTransport();
|
|
28
|
+
|
|
29
|
+
let warned = false;
|
|
30
|
+
remote.onerror = (error) => {
|
|
31
|
+
// A 401 from the remote surfaces here as a generic stream error; say the
|
|
32
|
+
// useful thing once instead of the SDK's raw message.
|
|
33
|
+
if (!warned && /401|unauthorized|forbidden/i.test(String(error))) {
|
|
34
|
+
warned = true;
|
|
35
|
+
console.error(
|
|
36
|
+
"OpenQR rejected the API key. Check OPENQR_API_KEY (free key: https://openqr.uk/api)."
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
console.error(String(error));
|
|
40
|
+
};
|
|
41
|
+
stdio.onerror = (error) => console.error(String(error));
|
|
42
|
+
|
|
43
|
+
remote.onmessage = (message) => stdio.send(message);
|
|
44
|
+
stdio.onmessage = (message) => remote.send(message);
|
|
45
|
+
|
|
46
|
+
let closing = false;
|
|
47
|
+
const close = async () => {
|
|
48
|
+
if (closing) return;
|
|
49
|
+
closing = true;
|
|
50
|
+
for (const transport of [stdio, remote]) {
|
|
51
|
+
try {
|
|
52
|
+
await transport.close();
|
|
53
|
+
} catch {
|
|
54
|
+
// already closed or never opened; nothing to do
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
process.exit(0);
|
|
58
|
+
};
|
|
59
|
+
process.on("SIGINT", close);
|
|
60
|
+
process.on("SIGTERM", close);
|
|
61
|
+
|
|
62
|
+
await remote.start();
|
|
63
|
+
await stdio.start();
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@open-qr/mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for OpenQR (https://openqr.uk): generate QR codes and create, edit and track dynamic (editable) QR codes with scan analytics. Bridges stdio MCP clients to the hosted endpoint.",
|
|
5
|
+
"license": "AGPL-3.0-only",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"openqr-mcp": "index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"index.js",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/open-qr/openqr.git",
|
|
20
|
+
"directory": "mcp"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"mcp",
|
|
24
|
+
"model-context-protocol",
|
|
25
|
+
"qr-code",
|
|
26
|
+
"qr",
|
|
27
|
+
"dynamic-qr",
|
|
28
|
+
"openqr"
|
|
29
|
+
],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@modelcontextprotocol/sdk": "^1.30.0"
|
|
32
|
+
}
|
|
33
|
+
}
|