@ulinkly/mcp-server 0.1.0 → 0.1.2
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 -52
- package/dist/tools/account.js +36 -8
- package/dist/tools/account.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ULink MCP Server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Connect your ULink deep linking projects to Claude Code, Cursor, Windsurf, and other AI assistants.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The [Model Context Protocol](https://modelcontextprotocol.io/introduction) (MCP) standardizes how Large Language Models (LLMs) talk to external services like ULink. It connects AI assistants directly with your ULink account and allows them to perform tasks like managing projects, creating smart links, configuring domains, and more. See the [full list of tools](#tools).
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Setup
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
### 1. Install the MCP server
|
|
10
|
+
|
|
11
|
+
Choose your MCP client and run the corresponding command:
|
|
12
|
+
|
|
13
|
+
**Claude Code:**
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
claude mcp add ulink -- npx -y @ulinkly/mcp-server
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Cursor:**
|
|
20
|
+
|
|
21
|
+
Open **Settings > MCP > Add new MCP server**, or add to `.cursor/mcp.json`:
|
|
10
22
|
|
|
11
23
|
```json
|
|
12
24
|
{
|
|
@@ -19,7 +31,9 @@ Add the following to your MCP client configuration:
|
|
|
19
31
|
}
|
|
20
32
|
```
|
|
21
33
|
|
|
22
|
-
**
|
|
34
|
+
**Windsurf:**
|
|
35
|
+
|
|
36
|
+
Open **Settings > MCP > Add new MCP server**, or add to `~/.windsurf/mcp.json`:
|
|
23
37
|
|
|
24
38
|
```json
|
|
25
39
|
{
|
|
@@ -32,17 +46,27 @@ Add the following to your MCP client configuration:
|
|
|
32
46
|
}
|
|
33
47
|
```
|
|
34
48
|
|
|
35
|
-
|
|
49
|
+
If you don't see your MCP client listed above, check your client's MCP documentation and use the following server command:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
npx -y @ulinkly/mcp-server
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 2. Authenticate
|
|
36
56
|
|
|
37
|
-
|
|
57
|
+
Your MCP client will automatically open a browser window for authentication on first use. Log in with your ULink account and authorize the MCP server. The session persists and tokens refresh automatically.
|
|
38
58
|
|
|
39
|
-
|
|
59
|
+
#### API Key (alternative)
|
|
40
60
|
|
|
41
|
-
|
|
61
|
+
For CI environments or headless servers, set the `ULINK_API_KEY` environment variable to skip the browser flow:
|
|
42
62
|
|
|
43
|
-
|
|
63
|
+
**Claude Code:**
|
|
44
64
|
|
|
45
|
-
|
|
65
|
+
```bash
|
|
66
|
+
claude mcp add ulink -e ULINK_API_KEY=your-api-key -- npx -y @ulinkly/mcp-server
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Manual config:**
|
|
46
70
|
|
|
47
71
|
```json
|
|
48
72
|
{
|
|
@@ -51,7 +75,7 @@ Set the `ULINK_API_KEY` environment variable to skip the browser flow entirely.
|
|
|
51
75
|
"command": "npx",
|
|
52
76
|
"args": ["-y", "@ulinkly/mcp-server"],
|
|
53
77
|
"env": {
|
|
54
|
-
"ULINK_API_KEY": "your-api-key
|
|
78
|
+
"ULINK_API_KEY": "your-api-key"
|
|
55
79
|
}
|
|
56
80
|
}
|
|
57
81
|
}
|
|
@@ -60,69 +84,73 @@ Set the `ULINK_API_KEY` environment variable to skip the browser flow entirely.
|
|
|
60
84
|
|
|
61
85
|
You can generate an API key from the ULink dashboard under **Project Settings > API Keys**, or by using the `create_api_key` tool.
|
|
62
86
|
|
|
87
|
+
### 3. Start building
|
|
88
|
+
|
|
89
|
+
Once connected, your AI assistant can manage your ULink projects directly. Try asking it to:
|
|
90
|
+
|
|
91
|
+
- "List my ULink projects"
|
|
92
|
+
- "Create a new smart link for my app"
|
|
93
|
+
- "Show click analytics for my latest link"
|
|
94
|
+
- "Add a custom domain to my project"
|
|
95
|
+
|
|
63
96
|
## Tools
|
|
64
97
|
|
|
65
|
-
The
|
|
98
|
+
The following ULink tools are available to the LLM, organized by category.
|
|
66
99
|
|
|
67
|
-
|
|
100
|
+
#### Project Management
|
|
68
101
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
| `update_project` | Update the name or default URL of an existing project |
|
|
75
|
-
| `configure_project` | Set platform-specific config (iOS bundle ID, Android package, deeplink schemas, SHA-256 fingerprints) |
|
|
102
|
+
- `list_projects`: Lists all ULink projects owned by or shared with the authenticated user.
|
|
103
|
+
- `get_project`: Gets detailed information about a specific project, including configuration and membership.
|
|
104
|
+
- `create_project`: Creates a new project with a name and default fallback URL.
|
|
105
|
+
- `update_project`: Updates the name or default URL of an existing project.
|
|
106
|
+
- `configure_project`: Sets platform-specific configuration (iOS bundle ID, Android package name, deeplink schemas, SHA-256 fingerprints).
|
|
76
107
|
|
|
77
|
-
|
|
108
|
+
#### Link Management
|
|
78
109
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
| `delete_link` | Permanently delete a link |
|
|
86
|
-
| `get_link_analytics` | Get click analytics for a link (total clicks, platform/country/referrer breakdowns) |
|
|
110
|
+
- `create_link`: Creates a unified or dynamic smart link with platform-specific URLs, parameters, and metadata.
|
|
111
|
+
- `list_links`: Lists all links in a project with pagination.
|
|
112
|
+
- `get_link`: Gets detailed information about a specific link.
|
|
113
|
+
- `update_link`: Updates a link's URLs, parameters, or metadata.
|
|
114
|
+
- `delete_link`: Permanently deletes a link. This is irreversible.
|
|
115
|
+
- `get_link_analytics`: Gets click analytics for a link, including total clicks and breakdowns by platform, country, and referrer.
|
|
87
116
|
|
|
88
|
-
|
|
117
|
+
#### Domain Management
|
|
89
118
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
| `verify_domain` | Trigger DNS verification for a custom domain |
|
|
95
|
-
| `delete_domain` | Remove a custom domain from a project |
|
|
119
|
+
- `list_domains`: Lists all domains (shared and custom) associated with a project.
|
|
120
|
+
- `add_domain`: Adds a custom domain to a project. Requires DNS configuration and verification.
|
|
121
|
+
- `verify_domain`: Triggers DNS verification for a custom domain.
|
|
122
|
+
- `delete_domain`: Removes a custom domain from a project. Links using this domain will stop working.
|
|
96
123
|
|
|
97
|
-
|
|
124
|
+
#### API Keys
|
|
98
125
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
| `create_api_key` | Create a new API key (the full key is only shown once) |
|
|
103
|
-
| `revoke_api_key` | Permanently revoke an API key |
|
|
126
|
+
- `list_api_keys`: Lists all API keys for a project (metadata only, not the key value).
|
|
127
|
+
- `create_api_key`: Creates a new API key. The full key is only returned once — store it securely.
|
|
128
|
+
- `revoke_api_key`: Permanently revokes an API key. Applications using this key will immediately lose access.
|
|
104
129
|
|
|
105
|
-
|
|
130
|
+
#### Account & Billing
|
|
106
131
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
| `list_plans` | List all available subscription plans with pricing and limits |
|
|
111
|
-
| `get_usage` | Get usage statistics for the current billing period (clicks, links, API calls) |
|
|
132
|
+
- `get_subscription`: Gets a project's subscription plan, status, and renewal date. Accepts an optional `projectId`.
|
|
133
|
+
- `list_plans`: Lists all available subscription plans with pricing and limits. Accepts an optional `billingPeriod` (monthly/yearly).
|
|
134
|
+
- `get_usage`: Gets a project's usage statistics for the current billing period (clicks, links, API calls). Accepts an optional `projectId`.
|
|
112
135
|
|
|
113
136
|
## Environment Variables
|
|
114
137
|
|
|
115
138
|
| Variable | Default | Description |
|
|
116
139
|
|----------|---------|-------------|
|
|
117
|
-
| `ULINK_API_KEY` |
|
|
140
|
+
| `ULINK_API_KEY` | — | API key for authentication (skips browser OAuth flow) |
|
|
118
141
|
| `ULINK_API_URL` | `https://api.ulink.ly` | Base URL for the ULink REST API |
|
|
119
142
|
| `ULINK_FRONTEND_URL` | `https://ulink.ly` | Frontend URL used for the OAuth login flow |
|
|
120
|
-
| `ULINK_SUPABASE_ANON_KEY` |
|
|
143
|
+
| `ULINK_SUPABASE_ANON_KEY` | — | Supabase anon key for silent token refresh |
|
|
121
144
|
|
|
122
145
|
## Requirements
|
|
123
146
|
|
|
124
147
|
- Node.js 18 or later
|
|
125
148
|
|
|
149
|
+
## Resources
|
|
150
|
+
|
|
151
|
+
- [**ULink Documentation**](https://docs.ulink.ly): Learn more about ULink's deep linking platform.
|
|
152
|
+
- [**Model Context Protocol**](https://modelcontextprotocol.io/introduction): Learn more about MCP and its capabilities.
|
|
153
|
+
|
|
126
154
|
## License
|
|
127
155
|
|
|
128
156
|
MIT
|
package/dist/tools/account.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
1
2
|
import { apiRequest } from "../client/ulink-api.js";
|
|
2
3
|
export function registerAccountTools(server) {
|
|
3
4
|
// -----------------------------------------------------------------------
|
|
@@ -5,11 +6,20 @@ export function registerAccountTools(server) {
|
|
|
5
6
|
// -----------------------------------------------------------------------
|
|
6
7
|
server.registerTool("get_subscription", {
|
|
7
8
|
title: "Get Subscription",
|
|
8
|
-
description: "Retrieve the
|
|
9
|
+
description: "Retrieve the active subscription for a specific project, including plan name, billing period, status, and renewal date. Subscriptions are per-project.",
|
|
9
10
|
annotations: { readOnlyHint: true },
|
|
10
|
-
|
|
11
|
+
inputSchema: {
|
|
12
|
+
projectId: z
|
|
13
|
+
.string()
|
|
14
|
+
.describe("The project ID to get the subscription for. If omitted, the API returns the subscription for the user's first project.")
|
|
15
|
+
.optional(),
|
|
16
|
+
},
|
|
17
|
+
}, async ({ projectId }) => {
|
|
11
18
|
try {
|
|
12
|
-
const
|
|
19
|
+
const qs = projectId
|
|
20
|
+
? `?projectId=${encodeURIComponent(projectId)}`
|
|
21
|
+
: "";
|
|
22
|
+
const data = await apiRequest("GET", `/subscriptions/current${qs}`);
|
|
13
23
|
return {
|
|
14
24
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
15
25
|
};
|
|
@@ -28,9 +38,18 @@ export function registerAccountTools(server) {
|
|
|
28
38
|
title: "List Plans",
|
|
29
39
|
description: "List all available ULink subscription plans with their features, limits, and pricing. Useful for comparing plans or determining upgrade options.",
|
|
30
40
|
annotations: { readOnlyHint: true },
|
|
31
|
-
|
|
41
|
+
inputSchema: {
|
|
42
|
+
billingPeriod: z
|
|
43
|
+
.enum(["monthly", "yearly"])
|
|
44
|
+
.optional()
|
|
45
|
+
.describe("Billing period to show pricing for (default: monthly)."),
|
|
46
|
+
},
|
|
47
|
+
}, async ({ billingPeriod }) => {
|
|
32
48
|
try {
|
|
33
|
-
const
|
|
49
|
+
const qs = billingPeriod
|
|
50
|
+
? `?billingPeriod=${encodeURIComponent(billingPeriod)}`
|
|
51
|
+
: "";
|
|
52
|
+
const data = await apiRequest("GET", `/subscriptions/plans${qs}`);
|
|
34
53
|
return {
|
|
35
54
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
36
55
|
};
|
|
@@ -47,11 +66,20 @@ export function registerAccountTools(server) {
|
|
|
47
66
|
// -----------------------------------------------------------------------
|
|
48
67
|
server.registerTool("get_usage", {
|
|
49
68
|
title: "Get Usage",
|
|
50
|
-
description: "Retrieve
|
|
69
|
+
description: "Retrieve usage statistics for a specific project's active billing period, including link clicks, links created, and API calls against plan limits. Usage is per-project.",
|
|
51
70
|
annotations: { readOnlyHint: true },
|
|
52
|
-
|
|
71
|
+
inputSchema: {
|
|
72
|
+
projectId: z
|
|
73
|
+
.string()
|
|
74
|
+
.describe("The project ID to get usage for. If omitted, the API returns usage for the user's first project.")
|
|
75
|
+
.optional(),
|
|
76
|
+
},
|
|
77
|
+
}, async ({ projectId }) => {
|
|
53
78
|
try {
|
|
54
|
-
const
|
|
79
|
+
const qs = projectId
|
|
80
|
+
? `?projectId=${encodeURIComponent(projectId)}`
|
|
81
|
+
: "";
|
|
82
|
+
const data = await apiRequest("GET", `/subscriptions/me/usage${qs}`);
|
|
55
83
|
return {
|
|
56
84
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
57
85
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account.js","sourceRoot":"","sources":["../../src/tools/account.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"account.js","sourceRoot":"","sources":["../../src/tools/account.ts"],"names":[],"mappings":"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"}
|