xs-shlink-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/CHANGELOG.md +11 -0
- package/LICENSE +17 -0
- package/README.md +159 -0
- package/SECURITY.md +17 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +22 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +281 -0
- package/dist/server.js.map +1 -0
- package/dist/shlink/client.d.ts +21 -0
- package/dist/shlink/client.js +82 -0
- package/dist/shlink/client.js.map +1 -0
- package/package.json +57 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# XS Shlink MCP Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented here.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 - Unreleased
|
|
6
|
+
|
|
7
|
+
- Add a local `stdio` MCP server for Shlink.
|
|
8
|
+
- Add 23 tools covering short URLs, analytics, visits, tags, domains, redirect
|
|
9
|
+
rules, QR-code URLs, health, and Mercure information.
|
|
10
|
+
- Guard destructive tools with server opt-in and per-call confirmation.
|
|
11
|
+
- Add mocked API tests and an end-to-end MCP discovery test.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
package/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# XS Shlink MCP
|
|
2
|
+
|
|
3
|
+
An MCP server for managing and analyzing a
|
|
4
|
+
[Shlink](https://shlink.io/) URL-shortener instance.
|
|
5
|
+
|
|
6
|
+
It runs locally over `stdio`, keeps the Shlink API key on the machine running
|
|
7
|
+
the MCP client, and does not require Docker.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- 23 tools for short URLs, visits, tags, domains, redirect rules, QR codes, and
|
|
12
|
+
Mercure integration information
|
|
13
|
+
- Typed and validated tool inputs
|
|
14
|
+
- Structured Shlink API errors with request IDs
|
|
15
|
+
- Bounded pagination and request timeouts
|
|
16
|
+
- Destructive operations disabled by default
|
|
17
|
+
- Windows, macOS, and Linux support through Node.js
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- Node.js 20 or newer
|
|
22
|
+
- A reachable Shlink instance
|
|
23
|
+
- A Shlink API key
|
|
24
|
+
|
|
25
|
+
## Run from a local checkout
|
|
26
|
+
|
|
27
|
+
```shell
|
|
28
|
+
npm install
|
|
29
|
+
npm run build
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Add the server to an MCP client:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"shlink": {
|
|
38
|
+
"command": "node",
|
|
39
|
+
"args": ["/absolute/path/to/shlink-mcp/dist/index.js"],
|
|
40
|
+
"env": {
|
|
41
|
+
"SHLINK_BASE_URL": "https://s.example.com",
|
|
42
|
+
"SHLINK_API_KEY": "replace-me",
|
|
43
|
+
"SHLINK_API_VERSION": "3",
|
|
44
|
+
"SHLINK_ALLOW_DESTRUCTIVE": "false"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
On Windows, use a fully escaped absolute path:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
"args": ["C:\\path\\to\\shlink-mcp\\dist\\index.js"]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Run the published package
|
|
58
|
+
|
|
59
|
+
After the package is published to npm, an MCP client can launch it with:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"shlink": {
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["-y", "xs-shlink-mcp"],
|
|
67
|
+
"env": {
|
|
68
|
+
"SHLINK_BASE_URL": "https://s.example.com",
|
|
69
|
+
"SHLINK_API_KEY": "replace-me"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Configuration
|
|
77
|
+
|
|
78
|
+
| Variable | Required | Default | Description |
|
|
79
|
+
|---|---:|---:|---|
|
|
80
|
+
| `SHLINK_BASE_URL` | Yes | — | Shlink origin without `/rest`, such as `https://s.example.com` |
|
|
81
|
+
| `SHLINK_API_KEY` | Yes | — | Shlink API key |
|
|
82
|
+
| `SHLINK_API_VERSION` | No | `3` | REST API major version |
|
|
83
|
+
| `SHLINK_TIMEOUT_MS` | No | `10000` | Per-request timeout in milliseconds |
|
|
84
|
+
| `SHLINK_ALLOW_DESTRUCTIVE` | No | `false` | Enables deletion tools when set to `true` |
|
|
85
|
+
|
|
86
|
+
Never commit an API key. Tool results and errors do not include it.
|
|
87
|
+
|
|
88
|
+
## Tools
|
|
89
|
+
|
|
90
|
+
### Short URLs
|
|
91
|
+
|
|
92
|
+
- `list_short_urls`
|
|
93
|
+
- `get_short_url`
|
|
94
|
+
- `create_short_url`
|
|
95
|
+
- `edit_short_url`
|
|
96
|
+
- `delete_short_url`
|
|
97
|
+
- `get_qr_code_url`
|
|
98
|
+
|
|
99
|
+
### Analytics and visits
|
|
100
|
+
|
|
101
|
+
- `get_visit_stats`
|
|
102
|
+
- `get_short_url_visits`
|
|
103
|
+
- `get_tag_visits`
|
|
104
|
+
- `get_domain_visits`
|
|
105
|
+
- `list_orphan_visits`
|
|
106
|
+
- `list_non_orphan_visits`
|
|
107
|
+
- `delete_short_url_visits`
|
|
108
|
+
- `delete_orphan_visits`
|
|
109
|
+
|
|
110
|
+
### Redirect rules, tags, and domains
|
|
111
|
+
|
|
112
|
+
- `get_redirect_rules`
|
|
113
|
+
- `set_redirect_rules`
|
|
114
|
+
- `list_tags`
|
|
115
|
+
- `rename_tag`
|
|
116
|
+
- `delete_tags`
|
|
117
|
+
- `list_domains`
|
|
118
|
+
- `set_domain_redirects`
|
|
119
|
+
|
|
120
|
+
### Monitoring and integrations
|
|
121
|
+
|
|
122
|
+
- `shlink_health`
|
|
123
|
+
- `get_mercure_info`
|
|
124
|
+
|
|
125
|
+
All deletion tools require both `SHLINK_ALLOW_DESTRUCTIVE=true` and an explicit
|
|
126
|
+
`confirm: true` tool argument.
|
|
127
|
+
|
|
128
|
+
## Test with MCP Inspector
|
|
129
|
+
|
|
130
|
+
Build first, then pass the server environment explicitly:
|
|
131
|
+
|
|
132
|
+
```shell
|
|
133
|
+
npx -y @modelcontextprotocol/inspector \
|
|
134
|
+
-e SHLINK_BASE_URL=https://s.example.com \
|
|
135
|
+
-e SHLINK_API_KEY=replace-me \
|
|
136
|
+
-- node /absolute/path/to/shlink-mcp/dist/index.js
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Start with `shlink_health`, followed by `list_short_urls`.
|
|
140
|
+
|
|
141
|
+
## Development
|
|
142
|
+
|
|
143
|
+
```shell
|
|
144
|
+
npm run check
|
|
145
|
+
npm test
|
|
146
|
+
npm run validate
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The automated tests use mocked Shlink responses. They do not require or modify
|
|
150
|
+
a live Shlink instance.
|
|
151
|
+
|
|
152
|
+
## Security
|
|
153
|
+
|
|
154
|
+
See [SECURITY.md](SECURITY.md) for reporting security issues and guidance for
|
|
155
|
+
deploying API keys safely.
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Do not open a public issue containing exploit details, API keys, or private
|
|
6
|
+
Shlink data. Contact the repository owner privately through the security
|
|
7
|
+
reporting channel configured on the GitHub repository.
|
|
8
|
+
|
|
9
|
+
## Deployment guidance
|
|
10
|
+
|
|
11
|
+
- Store `SHLINK_API_KEY` in the MCP client's environment or secret store.
|
|
12
|
+
- Use the narrowest Shlink API-key roles that satisfy the intended workflows.
|
|
13
|
+
- Leave `SHLINK_ALLOW_DESTRUCTIVE` set to `false` unless deletion is required.
|
|
14
|
+
- Do not expose a local MCP Inspector proxy to untrusted networks.
|
|
15
|
+
- Use HTTPS for the Shlink base URL.
|
|
16
|
+
- Rotate an API key immediately if it appears in logs, screenshots, commits, or
|
|
17
|
+
shell history.
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const envSchema = z.object({
|
|
3
|
+
SHLINK_BASE_URL: z.string().url(),
|
|
4
|
+
SHLINK_API_KEY: z.string().min(1),
|
|
5
|
+
SHLINK_API_VERSION: z.coerce.number().int().positive().default(3),
|
|
6
|
+
SHLINK_TIMEOUT_MS: z.coerce.number().int().positive().default(10_000),
|
|
7
|
+
SHLINK_ALLOW_DESTRUCTIVE: z
|
|
8
|
+
.enum(["true", "false"])
|
|
9
|
+
.default("false")
|
|
10
|
+
.transform((value) => value === "true"),
|
|
11
|
+
});
|
|
12
|
+
export function loadConfig(env = process.env) {
|
|
13
|
+
const parsed = envSchema.parse(env);
|
|
14
|
+
return {
|
|
15
|
+
baseUrl: parsed.SHLINK_BASE_URL.replace(/\/+$/, ""),
|
|
16
|
+
apiKey: parsed.SHLINK_API_KEY,
|
|
17
|
+
apiVersion: parsed.SHLINK_API_VERSION,
|
|
18
|
+
timeoutMs: parsed.SHLINK_TIMEOUT_MS,
|
|
19
|
+
allowDestructive: parsed.SHLINK_ALLOW_DESTRUCTIVE,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACjC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,kBAAkB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACjE,iBAAiB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IACrE,wBAAwB,EAAE,CAAC;SACxB,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACvB,OAAO,CAAC,OAAO,CAAC;SAChB,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,MAAM,CAAC;CAC1C,CAAC,CAAC;AAUH,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACnD,MAAM,EAAE,MAAM,CAAC,cAAc;QAC7B,UAAU,EAAE,MAAM,CAAC,kBAAkB;QACrC,SAAS,EAAE,MAAM,CAAC,iBAAiB;QACnC,gBAAgB,EAAE,MAAM,CAAC,wBAAwB;KAClD,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { ZodError } from "zod";
|
|
4
|
+
import { loadConfig } from "./config.js";
|
|
5
|
+
import { createServer } from "./server.js";
|
|
6
|
+
async function main() {
|
|
7
|
+
const config = loadConfig();
|
|
8
|
+
const server = createServer(config);
|
|
9
|
+
const transport = new StdioServerTransport();
|
|
10
|
+
const shutdown = async () => {
|
|
11
|
+
await server.close();
|
|
12
|
+
process.exit(0);
|
|
13
|
+
};
|
|
14
|
+
process.once("SIGINT", shutdown);
|
|
15
|
+
process.once("SIGTERM", shutdown);
|
|
16
|
+
await server.connect(transport);
|
|
17
|
+
}
|
|
18
|
+
main().catch((error) => {
|
|
19
|
+
if (error instanceof ZodError) {
|
|
20
|
+
console.error("Invalid configuration:", error.issues.map((issue) => issue.message).join("; "));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
24
|
+
}
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAElC,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACjG,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { ShlinkClient, ShlinkError } from "./shlink/client.js";
|
|
4
|
+
const shortCodeIdentity = {
|
|
5
|
+
shortCode: z.string().min(1).describe("The Shlink short code"),
|
|
6
|
+
domain: z.string().min(1).optional().describe("Domain when the short code is not on the default domain"),
|
|
7
|
+
};
|
|
8
|
+
const isoDate = z.string().datetime({ offset: true });
|
|
9
|
+
const pagination = {
|
|
10
|
+
page: z.number().int().positive().optional(),
|
|
11
|
+
itemsPerPage: z.number().int().min(1).max(100).optional(),
|
|
12
|
+
};
|
|
13
|
+
const shortUrlBody = {
|
|
14
|
+
longUrl: z.string().url().optional(),
|
|
15
|
+
customSlug: z.string().min(1).optional(),
|
|
16
|
+
title: z.string().nullable().optional(),
|
|
17
|
+
tags: z.array(z.string()).optional(),
|
|
18
|
+
domain: z.string().optional(),
|
|
19
|
+
validSince: isoDate.nullable().optional(),
|
|
20
|
+
validUntil: isoDate.nullable().optional(),
|
|
21
|
+
maxVisits: z.number().int().positive().nullable().optional(),
|
|
22
|
+
crawlable: z.boolean().optional(),
|
|
23
|
+
forwardQuery: z.boolean().optional(),
|
|
24
|
+
};
|
|
25
|
+
const visitFilters = {
|
|
26
|
+
...pagination,
|
|
27
|
+
startDate: isoDate.optional(),
|
|
28
|
+
endDate: isoDate.optional(),
|
|
29
|
+
excludeBots: z.boolean().optional(),
|
|
30
|
+
};
|
|
31
|
+
function result(data) {
|
|
32
|
+
return {
|
|
33
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function errorResult(error) {
|
|
37
|
+
if (error instanceof ShlinkError) {
|
|
38
|
+
return {
|
|
39
|
+
isError: true,
|
|
40
|
+
content: [{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: JSON.stringify({
|
|
43
|
+
error: error.message,
|
|
44
|
+
status: error.status,
|
|
45
|
+
requestId: error.requestId,
|
|
46
|
+
type: error.problemType,
|
|
47
|
+
}),
|
|
48
|
+
}],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
isError: true,
|
|
53
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function queryOf(values) {
|
|
57
|
+
return values;
|
|
58
|
+
}
|
|
59
|
+
export function createServer(config, client = new ShlinkClient(config)) {
|
|
60
|
+
const server = new McpServer({ name: "shlink-mcp", version: "0.1.0" }, {
|
|
61
|
+
instructions: "Use read-only tools freely. Create and edit tools change Shlink. Deletion requires explicit confirmation and server-side opt-in.",
|
|
62
|
+
});
|
|
63
|
+
const register = (name,
|
|
64
|
+
// The SDK's registerTool overload is generic over each individual schema.
|
|
65
|
+
// This small wrapper centralizes result/error formatting, so preserve the
|
|
66
|
+
// SDK's runtime validation while allowing each call to infer independently.
|
|
67
|
+
definition, handler) => {
|
|
68
|
+
server.registerTool(name, definition, async (args) => {
|
|
69
|
+
try {
|
|
70
|
+
return result(await handler(args));
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
return errorResult(error);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
register("shlink_health", {
|
|
78
|
+
description: "Check whether the configured Shlink instance is healthy.",
|
|
79
|
+
inputSchema: {},
|
|
80
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
81
|
+
}, () => client.health());
|
|
82
|
+
register("list_short_urls", {
|
|
83
|
+
description: "List and search short URLs, with bounded pagination.",
|
|
84
|
+
inputSchema: {
|
|
85
|
+
...pagination,
|
|
86
|
+
searchTerm: z.string().optional(),
|
|
87
|
+
tags: z.array(z.string()).optional(),
|
|
88
|
+
orderBy: z.string().optional(),
|
|
89
|
+
startDate: isoDate.optional(),
|
|
90
|
+
endDate: isoDate.optional(),
|
|
91
|
+
},
|
|
92
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
93
|
+
}, (args) => client.api("/short-urls", { query: queryOf(args) }));
|
|
94
|
+
register("get_short_url", {
|
|
95
|
+
description: "Get details for one Shlink short code.",
|
|
96
|
+
inputSchema: shortCodeIdentity,
|
|
97
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
98
|
+
}, ({ shortCode, domain }) => client.api(`/short-urls/${encodeURIComponent(shortCode)}`, { query: { domain } }));
|
|
99
|
+
register("create_short_url", {
|
|
100
|
+
description: "Create a new Shlink short URL.",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
...shortUrlBody,
|
|
103
|
+
longUrl: z.string().url(),
|
|
104
|
+
findIfExists: z.boolean().optional(),
|
|
105
|
+
},
|
|
106
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
|
|
107
|
+
}, (args) => client.api("/short-urls", { method: "POST", body: args }));
|
|
108
|
+
register("edit_short_url", {
|
|
109
|
+
description: "Edit an existing Shlink short URL.",
|
|
110
|
+
inputSchema: { ...shortCodeIdentity, ...shortUrlBody },
|
|
111
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
|
|
112
|
+
}, ({ shortCode, domain, ...body }) => client.api(`/short-urls/${encodeURIComponent(shortCode)}`, {
|
|
113
|
+
method: "PATCH",
|
|
114
|
+
query: { domain },
|
|
115
|
+
body,
|
|
116
|
+
}));
|
|
117
|
+
register("delete_short_url", {
|
|
118
|
+
description: "Permanently delete a short URL. Requires SHLINK_ALLOW_DESTRUCTIVE=true and confirm=true.",
|
|
119
|
+
inputSchema: { ...shortCodeIdentity, confirm: z.literal(true) },
|
|
120
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true },
|
|
121
|
+
}, async ({ shortCode, domain }) => {
|
|
122
|
+
if (!config.allowDestructive) {
|
|
123
|
+
throw new Error("Deletion is disabled. Set SHLINK_ALLOW_DESTRUCTIVE=true to enable it.");
|
|
124
|
+
}
|
|
125
|
+
await client.api(`/short-urls/${encodeURIComponent(shortCode)}`, {
|
|
126
|
+
method: "DELETE",
|
|
127
|
+
query: { domain },
|
|
128
|
+
});
|
|
129
|
+
return { deleted: true, shortCode, domain: domain ?? null };
|
|
130
|
+
});
|
|
131
|
+
register("get_short_url_visits", {
|
|
132
|
+
description: "List visits for one short URL.",
|
|
133
|
+
inputSchema: {
|
|
134
|
+
...shortCodeIdentity,
|
|
135
|
+
...pagination,
|
|
136
|
+
startDate: isoDate.optional(),
|
|
137
|
+
endDate: isoDate.optional(),
|
|
138
|
+
excludeBots: z.boolean().optional(),
|
|
139
|
+
},
|
|
140
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
141
|
+
}, ({ shortCode, ...query }) => client.api(`/short-urls/${encodeURIComponent(shortCode)}/visits`, {
|
|
142
|
+
query: queryOf(query),
|
|
143
|
+
}));
|
|
144
|
+
register("list_tags", {
|
|
145
|
+
description: "List Shlink tags, optionally including usage and visit statistics.",
|
|
146
|
+
inputSchema: { withStats: z.boolean().optional() },
|
|
147
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
148
|
+
}, ({ withStats }) => client.api(withStats ? "/tags/stats" : "/tags"));
|
|
149
|
+
register("list_domains", {
|
|
150
|
+
description: "List domains configured or used by Shlink.",
|
|
151
|
+
inputSchema: {},
|
|
152
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
153
|
+
}, () => client.api("/domains"));
|
|
154
|
+
register("get_visit_stats", {
|
|
155
|
+
description: "Get general visit statistics from Shlink.",
|
|
156
|
+
inputSchema: {
|
|
157
|
+
startDate: isoDate.optional(),
|
|
158
|
+
endDate: isoDate.optional(),
|
|
159
|
+
groupBy: z.enum(["date", "country", "city", "browser", "os", "referer"]).optional(),
|
|
160
|
+
excludeBots: z.boolean().optional(),
|
|
161
|
+
},
|
|
162
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
163
|
+
}, (args) => client.api("/visits", { query: queryOf(args) }));
|
|
164
|
+
register("get_redirect_rules", {
|
|
165
|
+
description: "List dynamic redirect rules configured for a short URL.",
|
|
166
|
+
inputSchema: shortCodeIdentity,
|
|
167
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
168
|
+
}, ({ shortCode, domain }) => client.api(`/short-urls/${encodeURIComponent(shortCode)}/redirect-rules`, {
|
|
169
|
+
query: { domain },
|
|
170
|
+
}));
|
|
171
|
+
register("set_redirect_rules", {
|
|
172
|
+
description: "Replace the dynamic redirect rules for a short URL. Rules are evaluated by Shlink in their provided order.",
|
|
173
|
+
inputSchema: {
|
|
174
|
+
...shortCodeIdentity,
|
|
175
|
+
redirectRules: z.array(z.record(z.unknown())).describe("Shlink redirect-rule objects"),
|
|
176
|
+
},
|
|
177
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
|
|
178
|
+
}, ({ shortCode, domain, redirectRules }) => client.api(`/short-urls/${encodeURIComponent(shortCode)}/redirect-rules`, {
|
|
179
|
+
method: "POST",
|
|
180
|
+
query: { domain },
|
|
181
|
+
body: { redirectRules },
|
|
182
|
+
}));
|
|
183
|
+
register("get_tag_visits", {
|
|
184
|
+
description: "List visits associated with short URLs carrying a specific tag.",
|
|
185
|
+
inputSchema: { tag: z.string().min(1), ...visitFilters },
|
|
186
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
187
|
+
}, ({ tag, ...query }) => client.api(`/tags/${encodeURIComponent(tag)}/visits`, { query: queryOf(query) }));
|
|
188
|
+
register("get_domain_visits", {
|
|
189
|
+
description: "List visits for short URLs under a specific domain.",
|
|
190
|
+
inputSchema: { domain: z.string().min(1), ...visitFilters },
|
|
191
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
192
|
+
}, ({ domain, ...query }) => client.api(`/domains/${encodeURIComponent(domain)}/visits`, { query: queryOf(query) }));
|
|
193
|
+
register("list_orphan_visits", {
|
|
194
|
+
description: "List visits that did not resolve to a valid short URL.",
|
|
195
|
+
inputSchema: visitFilters,
|
|
196
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
197
|
+
}, (args) => client.api("/visits/orphan", { query: queryOf(args) }));
|
|
198
|
+
register("list_non_orphan_visits", {
|
|
199
|
+
description: "List visits that belong to valid short URLs.",
|
|
200
|
+
inputSchema: visitFilters,
|
|
201
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
202
|
+
}, (args) => client.api("/visits/non-orphan", { query: queryOf(args) }));
|
|
203
|
+
register("rename_tag", {
|
|
204
|
+
description: "Rename a tag everywhere it is used.",
|
|
205
|
+
inputSchema: {
|
|
206
|
+
oldName: z.string().min(1),
|
|
207
|
+
newName: z.string().min(1),
|
|
208
|
+
},
|
|
209
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
|
|
210
|
+
}, (body) => client.api("/tags", { method: "PUT", body }));
|
|
211
|
+
register("delete_tags", {
|
|
212
|
+
description: "Delete one or more tags. Requires SHLINK_ALLOW_DESTRUCTIVE=true and confirm=true.",
|
|
213
|
+
inputSchema: {
|
|
214
|
+
tags: z.array(z.string().min(1)).min(1),
|
|
215
|
+
confirm: z.literal(true),
|
|
216
|
+
},
|
|
217
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true },
|
|
218
|
+
}, async ({ tags }) => {
|
|
219
|
+
if (!config.allowDestructive) {
|
|
220
|
+
throw new Error("Tag deletion is disabled. Set SHLINK_ALLOW_DESTRUCTIVE=true to enable it.");
|
|
221
|
+
}
|
|
222
|
+
await client.api("/tags", { method: "DELETE", query: { tags } });
|
|
223
|
+
return { deleted: true, tags };
|
|
224
|
+
});
|
|
225
|
+
register("set_domain_redirects", {
|
|
226
|
+
description: "Configure optional fallback redirects for the base URL, invalid short URLs, and regular 404 paths.",
|
|
227
|
+
inputSchema: {
|
|
228
|
+
baseUrlRedirect: z.string().url().nullable().optional(),
|
|
229
|
+
invalidShortUrlRedirect: z.string().url().nullable().optional(),
|
|
230
|
+
regular404Redirect: z.string().url().nullable().optional(),
|
|
231
|
+
},
|
|
232
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
|
|
233
|
+
}, (body) => client.api("/domains/redirects", { method: "PATCH", body }));
|
|
234
|
+
register("delete_short_url_visits", {
|
|
235
|
+
description: "Permanently erase visit history for one short URL. Requires SHLINK_ALLOW_DESTRUCTIVE=true and confirm=true.",
|
|
236
|
+
inputSchema: { ...shortCodeIdentity, confirm: z.literal(true) },
|
|
237
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true },
|
|
238
|
+
}, async ({ shortCode, domain }) => {
|
|
239
|
+
if (!config.allowDestructive) {
|
|
240
|
+
throw new Error("Visit deletion is disabled. Set SHLINK_ALLOW_DESTRUCTIVE=true to enable it.");
|
|
241
|
+
}
|
|
242
|
+
const response = await client.api(`/short-urls/${encodeURIComponent(shortCode)}/visits`, {
|
|
243
|
+
method: "DELETE",
|
|
244
|
+
query: { domain },
|
|
245
|
+
});
|
|
246
|
+
return { deleted: true, shortCode, domain: domain ?? null, response };
|
|
247
|
+
});
|
|
248
|
+
register("delete_orphan_visits", {
|
|
249
|
+
description: "Permanently erase all orphan visits. Requires SHLINK_ALLOW_DESTRUCTIVE=true and confirm=true.",
|
|
250
|
+
inputSchema: { confirm: z.literal(true) },
|
|
251
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true },
|
|
252
|
+
}, async () => {
|
|
253
|
+
if (!config.allowDestructive) {
|
|
254
|
+
throw new Error("Visit deletion is disabled. Set SHLINK_ALLOW_DESTRUCTIVE=true to enable it.");
|
|
255
|
+
}
|
|
256
|
+
const response = await client.api("/visits/orphan", { method: "DELETE" });
|
|
257
|
+
return { deleted: true, response };
|
|
258
|
+
});
|
|
259
|
+
register("get_mercure_info", {
|
|
260
|
+
description: "Get Shlink's Mercure real-time integration information when configured.",
|
|
261
|
+
inputSchema: {},
|
|
262
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
263
|
+
}, () => client.api("/mercure-info"));
|
|
264
|
+
register("get_qr_code_url", {
|
|
265
|
+
description: "Build the public Shlink QR-code image URL for a short code. This returns a URL rather than downloading binary image data.",
|
|
266
|
+
inputSchema: {
|
|
267
|
+
...shortCodeIdentity,
|
|
268
|
+
size: z.number().int().min(50).max(1000).optional(),
|
|
269
|
+
},
|
|
270
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
271
|
+
}, ({ shortCode, domain, size }) => {
|
|
272
|
+
const origin = domain ? new URL(config.baseUrl) : null;
|
|
273
|
+
if (origin && domain)
|
|
274
|
+
origin.hostname = domain;
|
|
275
|
+
const base = (origin?.toString() ?? config.baseUrl).replace(/\/+$/, "");
|
|
276
|
+
const suffix = size ? `/qr-code/${size}` : "/qr-code";
|
|
277
|
+
return { qrCodeUrl: `${base}/${encodeURIComponent(shortCode)}${suffix}` };
|
|
278
|
+
});
|
|
279
|
+
return server;
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Config } from "../config.js";
|
|
2
|
+
export declare class ShlinkError extends Error {
|
|
3
|
+
readonly status?: number | undefined;
|
|
4
|
+
readonly requestId?: string | undefined;
|
|
5
|
+
readonly problemType?: string | undefined;
|
|
6
|
+
constructor(message: string, status?: number | undefined, requestId?: string | undefined, problemType?: string | undefined);
|
|
7
|
+
}
|
|
8
|
+
export type QueryValue = string | number | boolean | undefined | null | string[];
|
|
9
|
+
export type FetchLike = typeof fetch;
|
|
10
|
+
export declare class ShlinkClient {
|
|
11
|
+
private readonly config;
|
|
12
|
+
private readonly fetchImpl;
|
|
13
|
+
constructor(config: Config, fetchImpl?: FetchLike);
|
|
14
|
+
health(): Promise<unknown>;
|
|
15
|
+
api(path: string, options?: {
|
|
16
|
+
method?: string;
|
|
17
|
+
query?: Record<string, QueryValue>;
|
|
18
|
+
body?: unknown;
|
|
19
|
+
}): Promise<unknown>;
|
|
20
|
+
private request;
|
|
21
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export class ShlinkError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
requestId;
|
|
4
|
+
problemType;
|
|
5
|
+
constructor(message, status, requestId, problemType) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.requestId = requestId;
|
|
9
|
+
this.problemType = problemType;
|
|
10
|
+
this.name = "ShlinkError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class ShlinkClient {
|
|
14
|
+
config;
|
|
15
|
+
fetchImpl;
|
|
16
|
+
constructor(config, fetchImpl = fetch) {
|
|
17
|
+
this.config = config;
|
|
18
|
+
this.fetchImpl = fetchImpl;
|
|
19
|
+
}
|
|
20
|
+
health() {
|
|
21
|
+
return this.request("/rest/health", { authenticated: false });
|
|
22
|
+
}
|
|
23
|
+
api(path, options = {}) {
|
|
24
|
+
return this.request(`/rest/v${this.config.apiVersion}${path}`, options);
|
|
25
|
+
}
|
|
26
|
+
async request(path, options = {}) {
|
|
27
|
+
const url = new URL(`${this.config.baseUrl}${path}`);
|
|
28
|
+
for (const [key, value] of Object.entries(options.query ?? {})) {
|
|
29
|
+
if (value === undefined || value === null)
|
|
30
|
+
continue;
|
|
31
|
+
if (Array.isArray(value)) {
|
|
32
|
+
for (const item of value)
|
|
33
|
+
url.searchParams.append(key, item);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
url.searchParams.set(key, String(value));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const headers = { Accept: "application/json" };
|
|
40
|
+
if (options.authenticated !== false)
|
|
41
|
+
headers["X-Api-Key"] = this.config.apiKey;
|
|
42
|
+
if (options.body !== undefined)
|
|
43
|
+
headers["Content-Type"] = "application/json";
|
|
44
|
+
let response;
|
|
45
|
+
try {
|
|
46
|
+
response = await this.fetchImpl(url, {
|
|
47
|
+
method: options.method ?? "GET",
|
|
48
|
+
headers,
|
|
49
|
+
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
|
50
|
+
signal: AbortSignal.timeout(this.config.timeoutMs),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new ShlinkError(error instanceof Error ? `Could not reach Shlink: ${error.message}` : "Could not reach Shlink");
|
|
55
|
+
}
|
|
56
|
+
const requestId = response.headers.get("x-request-id") ?? undefined;
|
|
57
|
+
const text = await response.text();
|
|
58
|
+
let data = null;
|
|
59
|
+
if (text) {
|
|
60
|
+
try {
|
|
61
|
+
data = JSON.parse(text);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
throw new ShlinkError(`Shlink returned HTTP ${response.status}`, response.status, requestId);
|
|
66
|
+
}
|
|
67
|
+
data = text;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
const problem = data && typeof data === "object" ? data : {};
|
|
72
|
+
const detail = typeof problem.detail === "string"
|
|
73
|
+
? problem.detail
|
|
74
|
+
: typeof problem.title === "string"
|
|
75
|
+
? problem.title
|
|
76
|
+
: `Shlink returned HTTP ${response.status}`;
|
|
77
|
+
throw new ShlinkError(detail, response.status, requestId, typeof problem.type === "string" ? problem.type : undefined);
|
|
78
|
+
}
|
|
79
|
+
return data;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/shlink/client.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "xs-shlink-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A Model Context Protocol server for Shlink",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"xs-shlink-mcp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md",
|
|
12
|
+
"CHANGELOG.md",
|
|
13
|
+
"SECURITY.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p tsconfig.build.json",
|
|
18
|
+
"clean": "node scripts/clean.mjs",
|
|
19
|
+
"dev": "tsx src/index.ts",
|
|
20
|
+
"start": "node dist/index.js",
|
|
21
|
+
"test": "npm run build && tsx --test tests/*.test.ts",
|
|
22
|
+
"check": "tsc -p tsconfig.json",
|
|
23
|
+
"validate": "npm run check && npm test",
|
|
24
|
+
"prepack": "npm run clean && npm run build"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"mcp",
|
|
31
|
+
"model-context-protocol",
|
|
32
|
+
"shlink",
|
|
33
|
+
"url-shortener"
|
|
34
|
+
],
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"author": "AlexGreenUK",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/AlexGreenUK/XS-Shlink-MCP.git"
|
|
42
|
+
},
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/AlexGreenUK/XS-Shlink-MCP/issues"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://github.com/AlexGreenUK/XS-Shlink-MCP#readme",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@modelcontextprotocol/sdk": "^1.17.0",
|
|
50
|
+
"zod": "^3.25.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/node": "^24.0.0",
|
|
54
|
+
"tsx": "^4.20.0",
|
|
55
|
+
"typescript": "^5.9.0"
|
|
56
|
+
}
|
|
57
|
+
}
|