@shorten-dev/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/dist/index.js ADDED
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+
6
+ // src/server.ts
7
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+
9
+ // src/api/client.ts
10
+ var BASE_URL = "https://shorten.dev/api/v1";
11
+ var ShortenApiError = class extends Error {
12
+ constructor(status, body) {
13
+ super(body.message);
14
+ this.status = status;
15
+ this.body = body;
16
+ this.name = "ShortenApiError";
17
+ }
18
+ };
19
+ var ApiClient = class {
20
+ apiKey;
21
+ constructor(apiKey2) {
22
+ this.apiKey = apiKey2;
23
+ }
24
+ async get(path, params) {
25
+ const url = new URL(`${BASE_URL}${path}`);
26
+ if (params) {
27
+ for (const [k, v] of Object.entries(params)) {
28
+ if (v !== void 0 && v !== "") url.searchParams.set(k, v);
29
+ }
30
+ }
31
+ return this.request(url, { method: "GET" });
32
+ }
33
+ async post(path, body) {
34
+ return this.request(new URL(`${BASE_URL}${path}`), {
35
+ method: "POST",
36
+ headers: { "Content-Type": "application/json" },
37
+ body: body ? JSON.stringify(body) : void 0
38
+ });
39
+ }
40
+ async patch(path, body) {
41
+ return this.request(new URL(`${BASE_URL}${path}`), {
42
+ method: "PATCH",
43
+ headers: { "Content-Type": "application/json" },
44
+ body: JSON.stringify(body)
45
+ });
46
+ }
47
+ async del(path) {
48
+ const res = await fetch(new URL(`${BASE_URL}${path}`), {
49
+ method: "DELETE",
50
+ headers: { Authorization: `Bearer ${this.apiKey}` }
51
+ });
52
+ if (!res.ok) {
53
+ const body = await res.json();
54
+ throw new ShortenApiError(res.status, body);
55
+ }
56
+ }
57
+ async request(url, init) {
58
+ const res = await fetch(url, {
59
+ ...init,
60
+ headers: {
61
+ ...init.headers ?? {},
62
+ Authorization: `Bearer ${this.apiKey}`
63
+ }
64
+ });
65
+ if (!res.ok) {
66
+ const body = await res.json();
67
+ throw new ShortenApiError(res.status, body);
68
+ }
69
+ return await res.json();
70
+ }
71
+ };
72
+
73
+ // src/tools/create-link.ts
74
+ import { z } from "zod";
75
+
76
+ // ../shared/src/constants.ts
77
+ var MAX_TAGS_PER_LINK = 3;
78
+ var MAX_TAG_LENGTH = 50;
79
+ var LINK_STATUSES = ["active", "flagged"];
80
+ var ANALYTICS_PERIODS = ["7d", "30d", "90d", "all"];
81
+
82
+ // src/tools/shared.ts
83
+ function handleApiError(err) {
84
+ if (err instanceof ShortenApiError) {
85
+ return {
86
+ content: [
87
+ {
88
+ type: "text",
89
+ text: `API Error (${err.status}): ${err.message}`
90
+ }
91
+ ],
92
+ isError: true
93
+ };
94
+ }
95
+ const message = err instanceof Error ? err.message : "Unknown error";
96
+ return {
97
+ content: [{ type: "text", text: `Error: ${message}` }],
98
+ isError: true
99
+ };
100
+ }
101
+
102
+ // src/tools/create-link.ts
103
+ var inputSchema = {
104
+ url: z.string().describe("Destination URL to shorten"),
105
+ custom_slug: z.string().optional().describe("Custom slug (auto-generated if omitted)"),
106
+ tags: z.array(z.string().max(MAX_TAG_LENGTH)).max(MAX_TAGS_PER_LINK).optional().describe("Tags for organization (max 3, each \u2264 50 chars)")
107
+ };
108
+ async function handleCreateLink(client, args) {
109
+ try {
110
+ const res = await client.post("/links", {
111
+ destination_url: args.url,
112
+ custom_slug: args.custom_slug,
113
+ tags: args.tags
114
+ });
115
+ return {
116
+ content: [
117
+ {
118
+ type: "text",
119
+ text: JSON.stringify(
120
+ {
121
+ short_url: res.short_url,
122
+ slug: res.link.slug,
123
+ destination_url: res.link.destination_url
124
+ },
125
+ null,
126
+ 2
127
+ )
128
+ }
129
+ ]
130
+ };
131
+ } catch (err) {
132
+ return handleApiError(err);
133
+ }
134
+ }
135
+ function registerCreateLinkTool(server2, client) {
136
+ server2.tool(
137
+ "create_short_link",
138
+ "Create a new shortened link",
139
+ inputSchema,
140
+ async (args) => handleCreateLink(client, args)
141
+ );
142
+ }
143
+
144
+ // src/tools/list-links.ts
145
+ import { z as z2 } from "zod";
146
+ var inputSchema2 = {
147
+ limit: z2.number().int().min(1).max(100).optional().describe("Maximum results (default: 10, max: 100)"),
148
+ status: z2.enum(LINK_STATUSES).optional().describe("Filter by link status"),
149
+ search: z2.string().optional().describe("Search in slug and destination URL")
150
+ };
151
+ async function handleListLinks(client, args) {
152
+ try {
153
+ const params = {};
154
+ if (args.limit !== void 0) params["limit"] = String(args.limit);
155
+ if (args.status) params["status"] = args.status;
156
+ if (args.search) params["search"] = args.search;
157
+ const res = await client.get("/links", params);
158
+ const links = res.data.map((link) => ({
159
+ slug: link.slug,
160
+ destination_url: link.destination_url,
161
+ status: link.status,
162
+ tags: link.tags,
163
+ created_at: link.created_at
164
+ }));
165
+ return {
166
+ content: [
167
+ {
168
+ type: "text",
169
+ text: JSON.stringify({ links, total: res.total }, null, 2)
170
+ }
171
+ ]
172
+ };
173
+ } catch (err) {
174
+ return handleApiError(err);
175
+ }
176
+ }
177
+ function registerListLinksTool(server2, client) {
178
+ server2.tool(
179
+ "list_links",
180
+ "List and search your shortened links",
181
+ inputSchema2,
182
+ async (args) => handleListLinks(client, args)
183
+ );
184
+ }
185
+
186
+ // src/tools/get-analytics.ts
187
+ import { z as z3 } from "zod";
188
+ var inputSchema3 = {
189
+ slug: z3.string().describe("The link slug to get analytics for"),
190
+ period: z3.enum(ANALYTICS_PERIODS).optional().describe("Time period: 7d, 30d, 90d, or all (default: 7d)")
191
+ };
192
+ async function handleGetAnalytics(client, args) {
193
+ try {
194
+ const params = {};
195
+ if (args.period) params["period"] = args.period;
196
+ const res = await client.get(
197
+ `/links/${encodeURIComponent(args.slug)}/analytics`,
198
+ params
199
+ );
200
+ return {
201
+ content: [
202
+ {
203
+ type: "text",
204
+ text: JSON.stringify(
205
+ {
206
+ total_clicks: res.total_clicks,
207
+ unique_visitors: res.unique_visitors,
208
+ top_country: res.top_countries[0]?.country ?? "N/A",
209
+ top_referrer: res.top_referrers[0]?.referrer ?? "N/A",
210
+ period: res.period
211
+ },
212
+ null,
213
+ 2
214
+ )
215
+ }
216
+ ]
217
+ };
218
+ } catch (err) {
219
+ return handleApiError(err);
220
+ }
221
+ }
222
+ function registerGetAnalyticsTool(server2, client) {
223
+ server2.tool(
224
+ "get_analytics",
225
+ "Retrieve click analytics for a specific link",
226
+ inputSchema3,
227
+ async (args) => handleGetAnalytics(client, args)
228
+ );
229
+ }
230
+
231
+ // src/server.ts
232
+ function createServer(apiKey2) {
233
+ const server2 = new McpServer({
234
+ name: "shorten",
235
+ version: "0.1.0"
236
+ });
237
+ const client = new ApiClient(apiKey2);
238
+ registerCreateLinkTool(server2, client);
239
+ registerListLinksTool(server2, client);
240
+ registerGetAnalyticsTool(server2, client);
241
+ return server2;
242
+ }
243
+
244
+ // src/config.ts
245
+ function resolveApiKey() {
246
+ const key = process.env["SHORTEN_API_KEY"];
247
+ if (!key) {
248
+ process.stderr.write(
249
+ "Error: SHORTEN_API_KEY environment variable is required.\nSet it in your MCP client config or export it in your shell.\nGenerate one at https://shorten.dev/api-keys\n"
250
+ );
251
+ process.exit(1);
252
+ }
253
+ return key;
254
+ }
255
+
256
+ // src/index.ts
257
+ var apiKey = resolveApiKey();
258
+ var server = createServer(apiKey);
259
+ var transport = new StdioServerTransport();
260
+ await server.connect(transport);
261
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/server.ts","../src/api/client.ts","../src/tools/create-link.ts","../../shared/src/constants.ts","../src/tools/shared.ts","../src/tools/list-links.ts","../src/tools/get-analytics.ts","../src/config.ts"],"sourcesContent":["import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createServer } from \"./server.js\";\nimport { resolveApiKey } from \"./config.js\";\n\nconst apiKey = resolveApiKey();\nconst server = createServer(apiKey);\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { ApiClient } from \"./api/client.js\";\nimport { registerCreateLinkTool } from \"./tools/create-link.js\";\nimport { registerListLinksTool } from \"./tools/list-links.js\";\nimport { registerGetAnalyticsTool } from \"./tools/get-analytics.js\";\n\nexport function createServer(apiKey: string): McpServer {\n const server = new McpServer({\n name: \"shorten\",\n version: \"0.1.0\",\n });\n\n const client = new ApiClient(apiKey);\n\n registerCreateLinkTool(server, client);\n registerListLinksTool(server, client);\n registerGetAnalyticsTool(server, client);\n\n return server;\n}\n","import type { ApiError } from \"@shorten/shared\";\n\nconst BASE_URL = \"https://shorten.dev/api/v1\";\n\nexport class ShortenApiError extends Error {\n constructor(\n public readonly status: number,\n public readonly body: ApiError,\n ) {\n super(body.message);\n this.name = \"ShortenApiError\";\n }\n}\n\nexport class ApiClient {\n private apiKey: string;\n\n constructor(apiKey: string) {\n this.apiKey = apiKey;\n }\n\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${BASE_URL}${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== \"\") url.searchParams.set(k, v);\n }\n }\n return this.request(url, { method: \"GET\" });\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request(new URL(`${BASE_URL}${path}`), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: body ? JSON.stringify(body) : undefined,\n });\n }\n\n async patch<T>(path: string, body: unknown): Promise<T> {\n return this.request(new URL(`${BASE_URL}${path}`), {\n method: \"PATCH\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n }\n\n async del(path: string): Promise<void> {\n const res = await fetch(new URL(`${BASE_URL}${path}`), {\n method: \"DELETE\",\n headers: { Authorization: `Bearer ${this.apiKey}` },\n });\n if (!res.ok) {\n const body = (await res.json()) as ApiError;\n throw new ShortenApiError(res.status, body);\n }\n }\n\n private async request<T>(url: URL, init: RequestInit): Promise<T> {\n const res = await fetch(url, {\n ...init,\n headers: {\n ...((init.headers as Record<string, string>) ?? {}),\n Authorization: `Bearer ${this.apiKey}`,\n },\n });\n\n if (!res.ok) {\n const body = (await res.json()) as ApiError;\n throw new ShortenApiError(res.status, body);\n }\n\n return (await res.json()) as T;\n }\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { MAX_TAGS_PER_LINK, MAX_TAG_LENGTH } from \"@shorten/shared\";\nimport type { CreateLinkResponse } from \"@shorten/shared\";\nimport type { ApiClient } from \"../api/client.js\";\nimport { handleApiError, type ToolResponse } from \"./shared.js\";\n\nconst inputSchema = {\n url: z.string().describe(\"Destination URL to shorten\"),\n custom_slug: z\n .string()\n .optional()\n .describe(\"Custom slug (auto-generated if omitted)\"),\n tags: z\n .array(z.string().max(MAX_TAG_LENGTH))\n .max(MAX_TAGS_PER_LINK)\n .optional()\n .describe(\"Tags for organization (max 3, each ≤ 50 chars)\"),\n};\n\nexport async function handleCreateLink(\n client: ApiClient,\n args: { url: string; custom_slug?: string; tags?: string[] },\n): Promise<ToolResponse> {\n try {\n const res = await client.post<CreateLinkResponse>(\"/links\", {\n destination_url: args.url,\n custom_slug: args.custom_slug,\n tags: args.tags,\n });\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(\n {\n short_url: res.short_url,\n slug: res.link.slug,\n destination_url: res.link.destination_url,\n },\n null,\n 2,\n ),\n },\n ],\n };\n } catch (err) {\n return handleApiError(err);\n }\n}\n\nexport function registerCreateLinkTool(\n server: McpServer,\n client: ApiClient,\n): void {\n // @ts-expect-error – MCP SDK generics exceed TS recursion limit with complex Zod schemas\n server.tool(\n \"create_short_link\",\n \"Create a new shortened link\",\n inputSchema,\n async (args) => handleCreateLink(client, args),\n );\n}\n","export const SLUG_LENGTH = 7;\nexport const BASE_URL = \"https://shorten.dev\";\n\nexport const MAX_TAGS_PER_LINK = 3;\nexport const MAX_TAG_LENGTH = 50;\n\nexport const RATE_LIMIT = {\n requests_per_hour: 300,\n} as const;\n\nexport const LINK_STATUSES = [\"active\", \"flagged\"] as const;\n\nexport const API_KEY_SCOPES = [\"read\", \"write\", \"admin\"] as const;\n\nexport const ANALYTICS_PERIODS = [\"7d\", \"30d\", \"90d\", \"all\"] as const;\n\n\nexport const TIMEZONES = [\n \"America/New_York\",\n \"America/Chicago\",\n \"America/Denver\",\n \"America/Los_Angeles\",\n \"America/Anchorage\",\n \"Pacific/Honolulu\",\n \"Europe/London\",\n \"Europe/Paris\",\n \"Europe/Berlin\",\n \"Asia/Tokyo\",\n \"Asia/Shanghai\",\n \"Asia/Kolkata\",\n \"Australia/Sydney\",\n \"UTC\",\n] as const;\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { ShortenApiError } from \"../api/client.js\";\n\nexport type ToolResponse = CallToolResult;\n\nexport function handleApiError(err: unknown): ToolResponse {\n if (err instanceof ShortenApiError) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `API Error (${err.status}): ${err.message}`,\n },\n ],\n isError: true,\n };\n }\n\n const message = err instanceof Error ? err.message : \"Unknown error\";\n return {\n content: [{ type: \"text\" as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { LINK_STATUSES } from \"@shorten/shared\";\nimport type { Link, PaginatedResponse } from \"@shorten/shared\";\nimport type { ApiClient } from \"../api/client.js\";\nimport { handleApiError, type ToolResponse } from \"./shared.js\";\n\nconst inputSchema = {\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe(\"Maximum results (default: 10, max: 100)\"),\n status: z\n .enum(LINK_STATUSES)\n .optional()\n .describe(\"Filter by link status\"),\n search: z\n .string()\n .optional()\n .describe(\"Search in slug and destination URL\"),\n};\n\nexport async function handleListLinks(\n client: ApiClient,\n args: { limit?: number; status?: string; search?: string },\n): Promise<ToolResponse> {\n try {\n const params: Record<string, string> = {};\n if (args.limit !== undefined) params[\"limit\"] = String(args.limit);\n if (args.status) params[\"status\"] = args.status;\n if (args.search) params[\"search\"] = args.search;\n\n const res = await client.get<PaginatedResponse<Link>>(\"/links\", params);\n\n const links = res.data.map((link) => ({\n slug: link.slug,\n destination_url: link.destination_url,\n status: link.status,\n tags: link.tags,\n created_at: link.created_at,\n }));\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ links, total: res.total }, null, 2),\n },\n ],\n };\n } catch (err) {\n return handleApiError(err);\n }\n}\n\nexport function registerListLinksTool(\n server: McpServer,\n client: ApiClient,\n): void {\n // @ts-expect-error – MCP SDK generics exceed TS recursion limit with complex Zod schemas\n server.tool(\n \"list_links\",\n \"List and search your shortened links\",\n inputSchema,\n async (args) => handleListLinks(client, args),\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { ANALYTICS_PERIODS } from \"@shorten/shared\";\nimport type { AnalyticsResponse } from \"@shorten/shared\";\nimport type { ApiClient } from \"../api/client.js\";\nimport { handleApiError, type ToolResponse } from \"./shared.js\";\n\nconst inputSchema = {\n slug: z.string().describe(\"The link slug to get analytics for\"),\n period: z\n .enum(ANALYTICS_PERIODS)\n .optional()\n .describe(\"Time period: 7d, 30d, 90d, or all (default: 7d)\"),\n};\n\nexport async function handleGetAnalytics(\n client: ApiClient,\n args: { slug: string; period?: string },\n): Promise<ToolResponse> {\n try {\n const params: Record<string, string> = {};\n if (args.period) params[\"period\"] = args.period;\n\n const res = await client.get<AnalyticsResponse>(\n `/links/${encodeURIComponent(args.slug)}/analytics`,\n params,\n );\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(\n {\n total_clicks: res.total_clicks,\n unique_visitors: res.unique_visitors,\n top_country: res.top_countries[0]?.country ?? \"N/A\",\n top_referrer: res.top_referrers[0]?.referrer ?? \"N/A\",\n period: res.period,\n },\n null,\n 2,\n ),\n },\n ],\n };\n } catch (err) {\n return handleApiError(err);\n }\n}\n\nexport function registerGetAnalyticsTool(\n server: McpServer,\n client: ApiClient,\n): void {\n // @ts-expect-error – MCP SDK generics exceed TS recursion limit with complex Zod schemas\n server.tool(\n \"get_analytics\",\n \"Retrieve click analytics for a specific link\",\n inputSchema,\n async (args) => handleGetAnalytics(client, args),\n );\n}\n","export function resolveApiKey(): string {\n const key = process.env[\"SHORTEN_API_KEY\"];\n\n if (!key) {\n process.stderr.write(\n \"Error: SHORTEN_API_KEY environment variable is required.\\n\" +\n \"Set it in your MCP client config or export it in your shell.\\n\" +\n \"Generate one at https://shorten.dev/api-keys\\n\",\n );\n process.exit(1);\n }\n\n return key;\n}\n"],"mappings":";;;AAAA,SAAS,4BAA4B;;;ACArC,SAAS,iBAAiB;;;ACE1B,IAAM,WAAW;AAEV,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACzC,YACkB,QACA,MAChB;AACA,UAAM,KAAK,OAAO;AAHF;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,YAAN,MAAgB;AAAA,EACb;AAAA,EAER,YAAYA,SAAgB;AAC1B,SAAK,SAASA;AAAA,EAChB;AAAA,EAEA,MAAM,IAAO,MAAc,QAA6C;AACtE,UAAM,MAAM,IAAI,IAAI,GAAG,QAAQ,GAAG,IAAI,EAAE;AACxC,QAAI,QAAQ;AACV,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,YAAI,MAAM,UAAa,MAAM,GAAI,KAAI,aAAa,IAAI,GAAG,CAAC;AAAA,MAC5D;AAAA,IACF;AACA,WAAO,KAAK,QAAQ,KAAK,EAAE,QAAQ,MAAM,CAAC;AAAA,EAC5C;AAAA,EAEA,MAAM,KAAQ,MAAc,MAA4B;AACtD,WAAO,KAAK,QAAQ,IAAI,IAAI,GAAG,QAAQ,GAAG,IAAI,EAAE,GAAG;AAAA,MACjD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,IACtC,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAS,MAAc,MAA2B;AACtD,WAAO,KAAK,QAAQ,IAAI,IAAI,GAAG,QAAQ,GAAG,IAAI,EAAE,GAAG;AAAA,MACjD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,IAAI,MAA6B;AACrC,UAAM,MAAM,MAAM,MAAM,IAAI,IAAI,GAAG,QAAQ,GAAG,IAAI,EAAE,GAAG;AAAA,MACrD,QAAQ;AAAA,MACR,SAAS,EAAE,eAAe,UAAU,KAAK,MAAM,GAAG;AAAA,IACpD,CAAC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,YAAM,IAAI,gBAAgB,IAAI,QAAQ,IAAI;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,MAAc,QAAW,KAAU,MAA+B;AAChE,UAAM,MAAM,MAAM,MAAM,KAAK;AAAA,MAC3B,GAAG;AAAA,MACH,SAAS;AAAA,QACP,GAAK,KAAK,WAAsC,CAAC;AAAA,QACjD,eAAe,UAAU,KAAK,MAAM;AAAA,MACtC;AAAA,IACF,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,YAAM,IAAI,gBAAgB,IAAI,QAAQ,IAAI;AAAA,IAC5C;AAEA,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AACF;;;AC1EA,SAAS,SAAS;;;ACGX,IAAM,oBAAoB;AAC1B,IAAM,iBAAiB;AAMvB,IAAM,gBAAgB,CAAC,UAAU,SAAS;AAI1C,IAAM,oBAAoB,CAAC,MAAM,OAAO,OAAO,KAAK;;;ACTpD,SAAS,eAAe,KAA4B;AACzD,MAAI,eAAe,iBAAiB;AAClC,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,cAAc,IAAI,MAAM,MAAM,IAAI,OAAO;AAAA,QACjD;AAAA,MACF;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,UAAU,OAAO,GAAG,CAAC;AAAA,IAC9D,SAAS;AAAA,EACX;AACF;;;AFhBA,IAAM,cAAc;AAAA,EAClB,KAAK,EAAE,OAAO,EAAE,SAAS,4BAA4B;AAAA,EACrD,aAAa,EACV,OAAO,EACP,SAAS,EACT,SAAS,yCAAyC;AAAA,EACrD,MAAM,EACH,MAAM,EAAE,OAAO,EAAE,IAAI,cAAc,CAAC,EACpC,IAAI,iBAAiB,EACrB,SAAS,EACT,SAAS,qDAAgD;AAC9D;AAEA,eAAsB,iBACpB,QACA,MACuB;AACvB,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,KAAyB,UAAU;AAAA,MAC1D,iBAAiB,KAAK;AAAA,MACtB,aAAa,KAAK;AAAA,MAClB,MAAM,KAAK;AAAA,IACb,CAAC;AAED,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK;AAAA,YACT;AAAA,cACE,WAAW,IAAI;AAAA,cACf,MAAM,IAAI,KAAK;AAAA,cACf,iBAAiB,IAAI,KAAK;AAAA,YAC5B;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,eAAe,GAAG;AAAA,EAC3B;AACF;AAEO,SAAS,uBACdC,SACA,QACM;AAEN,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,SAAS,iBAAiB,QAAQ,IAAI;AAAA,EAC/C;AACF;;;AG/DA,SAAS,KAAAC,UAAS;AAOlB,IAAMC,eAAc;AAAA,EAClB,OAAOC,GACJ,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL,IAAI,GAAG,EACP,SAAS,EACT,SAAS,yCAAyC;AAAA,EACrD,QAAQA,GACL,KAAK,aAAa,EAClB,SAAS,EACT,SAAS,uBAAuB;AAAA,EACnC,QAAQA,GACL,OAAO,EACP,SAAS,EACT,SAAS,oCAAoC;AAClD;AAEA,eAAsB,gBACpB,QACA,MACuB;AACvB,MAAI;AACF,UAAM,SAAiC,CAAC;AACxC,QAAI,KAAK,UAAU,OAAW,QAAO,OAAO,IAAI,OAAO,KAAK,KAAK;AACjE,QAAI,KAAK,OAAQ,QAAO,QAAQ,IAAI,KAAK;AACzC,QAAI,KAAK,OAAQ,QAAO,QAAQ,IAAI,KAAK;AAEzC,UAAM,MAAM,MAAM,OAAO,IAA6B,UAAU,MAAM;AAEtE,UAAM,QAAQ,IAAI,KAAK,IAAI,CAAC,UAAU;AAAA,MACpC,MAAM,KAAK;AAAA,MACX,iBAAiB,KAAK;AAAA,MACtB,QAAQ,KAAK;AAAA,MACb,MAAM,KAAK;AAAA,MACX,YAAY,KAAK;AAAA,IACnB,EAAE;AAEF,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,EAAE,OAAO,OAAO,IAAI,MAAM,GAAG,MAAM,CAAC;AAAA,QAC3D;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,eAAe,GAAG;AAAA,EAC3B;AACF;AAEO,SAAS,sBACdC,SACA,QACM;AAEN,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACAF;AAAA,IACA,OAAO,SAAS,gBAAgB,QAAQ,IAAI;AAAA,EAC9C;AACF;;;ACrEA,SAAS,KAAAG,UAAS;AAOlB,IAAMC,eAAc;AAAA,EAClB,MAAMC,GAAE,OAAO,EAAE,SAAS,oCAAoC;AAAA,EAC9D,QAAQA,GACL,KAAK,iBAAiB,EACtB,SAAS,EACT,SAAS,iDAAiD;AAC/D;AAEA,eAAsB,mBACpB,QACA,MACuB;AACvB,MAAI;AACF,UAAM,SAAiC,CAAC;AACxC,QAAI,KAAK,OAAQ,QAAO,QAAQ,IAAI,KAAK;AAEzC,UAAM,MAAM,MAAM,OAAO;AAAA,MACvB,UAAU,mBAAmB,KAAK,IAAI,CAAC;AAAA,MACvC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK;AAAA,YACT;AAAA,cACE,cAAc,IAAI;AAAA,cAClB,iBAAiB,IAAI;AAAA,cACrB,aAAa,IAAI,cAAc,CAAC,GAAG,WAAW;AAAA,cAC9C,cAAc,IAAI,cAAc,CAAC,GAAG,YAAY;AAAA,cAChD,QAAQ,IAAI;AAAA,YACd;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,eAAe,GAAG;AAAA,EAC3B;AACF;AAEO,SAAS,yBACdC,SACA,QACM;AAEN,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACAF;AAAA,IACA,OAAO,SAAS,mBAAmB,QAAQ,IAAI;AAAA,EACjD;AACF;;;ANxDO,SAAS,aAAaG,SAA2B;AACtD,QAAMC,UAAS,IAAI,UAAU;AAAA,IAC3B,MAAM;AAAA,IACN,SAAS;AAAA,EACX,CAAC;AAED,QAAM,SAAS,IAAI,UAAUD,OAAM;AAEnC,yBAAuBC,SAAQ,MAAM;AACrC,wBAAsBA,SAAQ,MAAM;AACpC,2BAAyBA,SAAQ,MAAM;AAEvC,SAAOA;AACT;;;AOnBO,SAAS,gBAAwB;AACtC,QAAM,MAAM,QAAQ,IAAI,iBAAiB;AAEzC,MAAI,CAAC,KAAK;AACR,YAAQ,OAAO;AAAA,MACb;AAAA,IAGF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO;AACT;;;ARTA,IAAM,SAAS,cAAc;AAC7B,IAAM,SAAS,aAAa,MAAM;AAClC,IAAM,YAAY,IAAI,qBAAqB;AAC3C,MAAM,OAAO,QAAQ,SAAS;","names":["apiKey","server","z","inputSchema","z","server","z","inputSchema","z","server","apiKey","server"]}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@shorten-dev/mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Shorten — manage links from AI agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "shorten-mcp": "./dist/index.js"
8
+ },
9
+ "files": ["dist"],
10
+ "scripts": {
11
+ "build": "tsup",
12
+ "dev": "tsup --watch",
13
+ "typecheck": "tsc --noEmit",
14
+ "lint": "eslint",
15
+ "test": "vitest run",
16
+ "test:watch": "vitest"
17
+ },
18
+ "dependencies": {
19
+ "@modelcontextprotocol/sdk": "^1.27.0",
20
+ "zod": "^3.25.0"
21
+ },
22
+ "devDependencies": {
23
+ "@shorten/shared": "*",
24
+ "tsup": "^8.4.0",
25
+ "typescript": "^5.8.3",
26
+ "vitest": "^2.1.0"
27
+ },
28
+ "engines": {
29
+ "node": ">=18"
30
+ },
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/shorten-dev/shorten.dev",
35
+ "directory": "packages/mcp"
36
+ },
37
+ "keywords": ["url-shortener", "mcp", "model-context-protocol", "shorten"]
38
+ }