deploy-mcp 0.5.0 → 0.6.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 +59 -29
- package/dist/{chunk-YU5SU5ZI.js → chunk-BFOEFRRT.js} +474 -24
- package/dist/index.js +4 -2
- package/dist/worker.js +39 -18
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ Track deployments across all platforms directly in your AI conversation.
|
|
|
8
8
|
No more context-switching. No more dashboard hunting.
|
|
9
9
|
|
|
10
10
|
[](https://www.npmjs.com/package/deploy-mcp)
|
|
11
|
+
[](https://www.npmjs.com/package/deploy-mcp)
|
|
11
12
|
[](https://github.com/alexpota/deploy-mcp/blob/main/LICENSE)
|
|
12
13
|
[](https://deploy-mcp.io)
|
|
13
14
|
|
|
@@ -16,34 +17,22 @@ No more context-switching. No more dashboard hunting.
|
|
|
16
17
|
---
|
|
17
18
|
|
|
18
19
|
## Demo
|
|
19
|
-
─────────────────────────
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
<div align="center">
|
|
22
|
+
|
|
23
|
+
<kbd>
|
|
24
|
+
<a href="./assets/demo.gif">
|
|
25
|
+
<img src="./assets/demo-preview.png" alt="Click to watch full demo" width="600" />
|
|
26
|
+
</a>
|
|
27
|
+
</kbd>
|
|
28
|
+
|
|
29
|
+
<br /><br />
|
|
30
|
+
|
|
31
|
+
<sub>**[Watch Full Demo](./assets/demo.gif)** · **[Live Badge Demo](https://mcp-netlify-demo.netlify.app/)**</sub>
|
|
32
|
+
|
|
33
|
+
</div>
|
|
25
34
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
> ## Deployment Status
|
|
29
|
-
>
|
|
30
|
-
> ### Current Status
|
|
31
|
-
> **Project:** my-app
|
|
32
|
-
> **Platform:** Vercel
|
|
33
|
-
> **Status:** ✅ Success
|
|
34
|
-
> **URL:** https://my-app.vercel.app
|
|
35
|
-
> **Duration:** 45s
|
|
36
|
-
> **Deployed:** 2 hours ago
|
|
37
|
-
>
|
|
38
|
-
> ### Commit Info
|
|
39
|
-
> **SHA:** `abc123ef`
|
|
40
|
-
> **Message:** Update homepage hero section
|
|
41
|
-
> **Author:** John Doe
|
|
42
|
-
>
|
|
43
|
-
> Everything looks good - your deployment is live and running successfully!
|
|
44
|
-
|
|
45
|
-
**Just ask your AI**: *"What's the status of my latest deployment?"*
|
|
46
|
-
Get instant answers without leaving your conversation.
|
|
35
|
+
---
|
|
47
36
|
|
|
48
37
|
## Quick Start
|
|
49
38
|
─────────────────────────
|
|
@@ -65,8 +54,8 @@ deploy-mcp supports multiple deployment platforms simultaneously. Configure as m
|
|
|
65
54
|
|----------|--------|---------------|----------|
|
|
66
55
|
| **Vercel** | ✅ Ready | `VERCEL_TOKEN` | Status, Logs, History, Real-time Monitoring |
|
|
67
56
|
| **Netlify** | ✅ Ready | `NETLIFY_TOKEN` | Status, Logs, History, Real-time Monitoring |
|
|
68
|
-
| **
|
|
69
|
-
| **
|
|
57
|
+
| **Cloudflare Pages** | ✅ Ready | `CLOUDFLARE_TOKEN` | Status, Logs, History, Real-time Monitoring |
|
|
58
|
+
| **GitHub Pages** | 🚧 Coming Soon | `GITHUB_TOKEN` | - |
|
|
70
59
|
|
|
71
60
|
### Multi-Platform Configuration
|
|
72
61
|
|
|
@@ -80,7 +69,8 @@ You can use **multiple platforms simultaneously** by providing tokens for each p
|
|
|
80
69
|
"args": ["-y", "deploy-mcp"],
|
|
81
70
|
"env": {
|
|
82
71
|
"VERCEL_TOKEN": "your-vercel-token",
|
|
83
|
-
"NETLIFY_TOKEN": "your-netlify-token"
|
|
72
|
+
"NETLIFY_TOKEN": "your-netlify-token",
|
|
73
|
+
"CLOUDFLARE_TOKEN": "accountId:globalApiKey"
|
|
84
74
|
// Add more platform tokens as needed
|
|
85
75
|
}
|
|
86
76
|
}
|
|
@@ -155,6 +145,46 @@ You can use **multiple platforms simultaneously** by providing tokens for each p
|
|
|
155
145
|
|
|
156
146
|
</details>
|
|
157
147
|
|
|
148
|
+
### Cloudflare Pages
|
|
149
|
+
|
|
150
|
+
<details>
|
|
151
|
+
<summary><strong>Setup Instructions</strong></summary>
|
|
152
|
+
|
|
153
|
+
1. **Get your API token:**
|
|
154
|
+
- Go to [dash.cloudflare.com/profile/api-tokens](https://dash.cloudflare.com/profile/api-tokens)
|
|
155
|
+
- Click "Create Token"
|
|
156
|
+
- Use "Custom token" with these permissions:
|
|
157
|
+
- **Zone:Zone:Read**
|
|
158
|
+
- **Zone:Page Rules:Read**
|
|
159
|
+
- **Account:Cloudflare Pages:Edit**
|
|
160
|
+
- Or use your Global API Key (format: `accountId:globalApiKey`)
|
|
161
|
+
- Copy the token
|
|
162
|
+
|
|
163
|
+
2. **Add to your AI assistant configuration:**
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"env": {
|
|
167
|
+
"CLOUDFLARE_TOKEN": "your-cloudflare-token-or-accountId:globalApiKey"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
3. **Available commands:**
|
|
173
|
+
- `"Check my Cloudflare Pages deployment for project-name"`
|
|
174
|
+
- `"What's the status of my latest Cloudflare Pages deployment?"`
|
|
175
|
+
- `"Show me Cloudflare Pages deployment logs"`
|
|
176
|
+
- `"Watch my Cloudflare Pages deployment progress"`
|
|
177
|
+
- `"List all my Cloudflare Pages projects"`
|
|
178
|
+
- `"Show deployment history for project-name"`
|
|
179
|
+
|
|
180
|
+
4. **Token formats supported:**
|
|
181
|
+
- **API Token**: `your-api-token` (requires `CLOUDFLARE_ACCOUNT_ID` env var)
|
|
182
|
+
- **Global API Key**: `accountId:globalApiKey` (all-in-one format)
|
|
183
|
+
|
|
184
|
+
5. **Required permissions:** Account access to Cloudflare Pages
|
|
185
|
+
|
|
186
|
+
</details>
|
|
187
|
+
|
|
158
188
|
## AI Assistant Configuration
|
|
159
189
|
─────────────────────────
|
|
160
190
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/core/tools.ts
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
var SUPPORTED_PLATFORMS = ["vercel", "netlify"];
|
|
3
|
+
var SUPPORTED_PLATFORMS = ["vercel", "netlify", "cloudflare-pages"];
|
|
4
4
|
var checkDeploymentStatusSchema = z.object({
|
|
5
5
|
platform: z.enum(SUPPORTED_PLATFORMS).describe("The deployment platform"),
|
|
6
6
|
project: z.string().describe("The project name or ID"),
|
|
@@ -57,7 +57,7 @@ var tools = [
|
|
|
57
57
|
properties: {
|
|
58
58
|
platform: {
|
|
59
59
|
type: "string",
|
|
60
|
-
enum:
|
|
60
|
+
enum: SUPPORTED_PLATFORMS,
|
|
61
61
|
description: "The deployment platform"
|
|
62
62
|
},
|
|
63
63
|
project: {
|
|
@@ -87,7 +87,7 @@ var tools = [
|
|
|
87
87
|
properties: {
|
|
88
88
|
platform: {
|
|
89
89
|
type: "string",
|
|
90
|
-
enum:
|
|
90
|
+
enum: SUPPORTED_PLATFORMS,
|
|
91
91
|
description: "The deployment platform"
|
|
92
92
|
},
|
|
93
93
|
project: {
|
|
@@ -114,7 +114,7 @@ var tools = [
|
|
|
114
114
|
properties: {
|
|
115
115
|
platform: {
|
|
116
116
|
type: "string",
|
|
117
|
-
enum:
|
|
117
|
+
enum: SUPPORTED_PLATFORMS,
|
|
118
118
|
description: "The deployment platform"
|
|
119
119
|
},
|
|
120
120
|
project: {
|
|
@@ -165,7 +165,7 @@ var tools = [
|
|
|
165
165
|
properties: {
|
|
166
166
|
platform: {
|
|
167
167
|
type: "string",
|
|
168
|
-
enum:
|
|
168
|
+
enum: SUPPORTED_PLATFORMS,
|
|
169
169
|
description: "The deployment platform"
|
|
170
170
|
},
|
|
171
171
|
deploymentId: {
|
|
@@ -198,7 +198,7 @@ var tools = [
|
|
|
198
198
|
properties: {
|
|
199
199
|
platform: {
|
|
200
200
|
type: "string",
|
|
201
|
-
enum:
|
|
201
|
+
enum: SUPPORTED_PLATFORMS,
|
|
202
202
|
description: "The deployment platform"
|
|
203
203
|
},
|
|
204
204
|
limit: {
|
|
@@ -351,6 +351,7 @@ var API_PARAMS = {
|
|
|
351
351
|
};
|
|
352
352
|
var API_CONFIG = {
|
|
353
353
|
VERCEL_BASE_URL: "https://api.vercel.com",
|
|
354
|
+
CLOUDFLARE_BASE_URL: "https://api.cloudflare.com/client/v4",
|
|
354
355
|
DEFAULT_TIMEOUT_MS: 1e4,
|
|
355
356
|
DEFAULT_RETRY_ATTEMPTS: 3,
|
|
356
357
|
DEFAULT_DEPLOYMENT_LIMIT: 10,
|
|
@@ -359,8 +360,8 @@ var API_CONFIG = {
|
|
|
359
360
|
var PLATFORM = {
|
|
360
361
|
VERCEL: "vercel",
|
|
361
362
|
NETLIFY: "netlify",
|
|
362
|
-
|
|
363
|
-
|
|
363
|
+
CLOUDFLARE_PAGES: "cloudflare-pages",
|
|
364
|
+
GITHUB_PAGES: "github-pages"
|
|
364
365
|
};
|
|
365
366
|
var ENVIRONMENT_TYPES = {
|
|
366
367
|
PRODUCTION: "production",
|
|
@@ -392,10 +393,21 @@ var NETLIFY_STATES = {
|
|
|
392
393
|
ERROR: "error",
|
|
393
394
|
RETRYING: "retrying"
|
|
394
395
|
};
|
|
396
|
+
var CLOUDFLARE_PAGES_STATES = {
|
|
397
|
+
ACTIVE: "active",
|
|
398
|
+
SUCCESS: "success",
|
|
399
|
+
FAILED: "failed",
|
|
400
|
+
CANCELED: "canceled",
|
|
401
|
+
SKIPPED: "skipped"
|
|
402
|
+
};
|
|
395
403
|
var ADAPTER_ERRORS = {
|
|
396
|
-
TOKEN_REQUIRED: "
|
|
397
|
-
|
|
398
|
-
|
|
404
|
+
TOKEN_REQUIRED: "API token required. Set appropriate environment variable or pass token parameter.",
|
|
405
|
+
VERCEL_TOKEN_REQUIRED: "Vercel token required. Set VERCEL_TOKEN environment variable or pass token parameter.",
|
|
406
|
+
NETLIFY_TOKEN_REQUIRED: "Netlify token required. Set NETLIFY_TOKEN environment variable or pass token parameter.",
|
|
407
|
+
CLOUDFLARE_TOKEN_REQUIRED: "Cloudflare token required. Set CLOUDFLARE_TOKEN environment variable or pass token parameter.",
|
|
408
|
+
FETCH_DEPLOYMENT_FAILED: "Failed to fetch deployment status",
|
|
409
|
+
UNKNOWN_STATUS: "unknown",
|
|
410
|
+
CLOUDFLARE_ACCOUNT_ID_REQUIRED: "Cloudflare account ID required. Provide as 'accountId:apiToken' or set CLOUDFLARE_ACCOUNT_ID"
|
|
399
411
|
};
|
|
400
412
|
|
|
401
413
|
// src/adapters/base/api-client.ts
|
|
@@ -811,7 +823,7 @@ var VercelAdapter = class extends BaseAdapter {
|
|
|
811
823
|
async getLatestDeployment(project, token) {
|
|
812
824
|
const apiToken = token || process.env.VERCEL_TOKEN;
|
|
813
825
|
if (!apiToken) {
|
|
814
|
-
throw new Error(ADAPTER_ERRORS.
|
|
826
|
+
throw new Error(ADAPTER_ERRORS.VERCEL_TOKEN_REQUIRED);
|
|
815
827
|
}
|
|
816
828
|
try {
|
|
817
829
|
const data = await this.api.getDeployments(
|
|
@@ -1190,6 +1202,404 @@ var NetlifyAdapter = class extends BaseAdapter {
|
|
|
1190
1202
|
}
|
|
1191
1203
|
};
|
|
1192
1204
|
|
|
1205
|
+
// src/adapters/cloudflare-pages/endpoints.ts
|
|
1206
|
+
var CloudflarePagesEndpoints = {
|
|
1207
|
+
// Base URL
|
|
1208
|
+
base: "https://api.cloudflare.com/client/v4",
|
|
1209
|
+
// Projects
|
|
1210
|
+
listProjects: (accountId) => `/accounts/${accountId}/pages/projects`,
|
|
1211
|
+
getProject: (accountId, projectName) => `/accounts/${accountId}/pages/projects/${projectName}`,
|
|
1212
|
+
// Deployments
|
|
1213
|
+
listDeployments: (accountId, projectName) => `/accounts/${accountId}/pages/projects/${projectName}/deployments`,
|
|
1214
|
+
getDeployment: (accountId, projectName, deploymentId) => `/accounts/${accountId}/pages/projects/${projectName}/deployments/${deploymentId}`,
|
|
1215
|
+
createDeployment: (accountId, projectName) => `/accounts/${accountId}/pages/projects/${projectName}/deployments`,
|
|
1216
|
+
deleteDeployment: (accountId, projectName, deploymentId) => `/accounts/${accountId}/pages/projects/${projectName}/deployments/${deploymentId}`,
|
|
1217
|
+
retryDeployment: (accountId, projectName, deploymentId) => `/accounts/${accountId}/pages/projects/${projectName}/deployments/${deploymentId}/retry`,
|
|
1218
|
+
rollbackDeployment: (accountId, projectName, deploymentId) => `/accounts/${accountId}/pages/projects/${projectName}/deployments/${deploymentId}/rollback`,
|
|
1219
|
+
// Logs
|
|
1220
|
+
getDeploymentLogs: (accountId, projectName, deploymentId) => `/accounts/${accountId}/pages/projects/${projectName}/deployments/${deploymentId}/history/logs`,
|
|
1221
|
+
// Documentation URLs
|
|
1222
|
+
docs: {
|
|
1223
|
+
api: "https://developers.cloudflare.com/api/resources/pages/",
|
|
1224
|
+
gettingStarted: "https://developers.cloudflare.com/pages/get-started/",
|
|
1225
|
+
authentication: "https://developers.cloudflare.com/fundamentals/api/get-started/create-token/",
|
|
1226
|
+
deployments: "https://developers.cloudflare.com/pages/configuration/deployments/",
|
|
1227
|
+
buildConfiguration: "https://developers.cloudflare.com/pages/configuration/build-configuration/"
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
|
|
1231
|
+
// src/adapters/cloudflare-pages/api.ts
|
|
1232
|
+
var CloudflarePagesAPI = class extends BaseAPIClient {
|
|
1233
|
+
accountId;
|
|
1234
|
+
apiToken;
|
|
1235
|
+
endpoints = {
|
|
1236
|
+
listProjects: {
|
|
1237
|
+
path: "",
|
|
1238
|
+
// Will be set dynamically
|
|
1239
|
+
method: "GET",
|
|
1240
|
+
docsUrl: CloudflarePagesEndpoints.docs.api,
|
|
1241
|
+
description: "List all Cloudflare Pages projects"
|
|
1242
|
+
},
|
|
1243
|
+
getProject: {
|
|
1244
|
+
path: "pages/projects/{projectName}",
|
|
1245
|
+
method: "GET",
|
|
1246
|
+
docsUrl: CloudflarePagesEndpoints.docs.api,
|
|
1247
|
+
description: "Get details for a specific project"
|
|
1248
|
+
},
|
|
1249
|
+
listDeployments: {
|
|
1250
|
+
path: "pages/projects/{projectName}/deployments",
|
|
1251
|
+
method: "GET",
|
|
1252
|
+
docsUrl: CloudflarePagesEndpoints.docs.deployments,
|
|
1253
|
+
description: "List deployments for a project"
|
|
1254
|
+
},
|
|
1255
|
+
getDeployment: {
|
|
1256
|
+
path: "pages/projects/{projectName}/deployments/{deploymentId}",
|
|
1257
|
+
method: "GET",
|
|
1258
|
+
docsUrl: CloudflarePagesEndpoints.docs.deployments,
|
|
1259
|
+
description: "Get details for a specific deployment"
|
|
1260
|
+
},
|
|
1261
|
+
getDeploymentLogs: {
|
|
1262
|
+
path: "pages/projects/{projectName}/deployments/{deploymentId}/history/logs",
|
|
1263
|
+
method: "GET",
|
|
1264
|
+
docsUrl: CloudflarePagesEndpoints.docs.deployments,
|
|
1265
|
+
description: "Get logs for a deployment"
|
|
1266
|
+
},
|
|
1267
|
+
createDeployment: {
|
|
1268
|
+
path: "pages/projects/{projectName}/deployments",
|
|
1269
|
+
method: "POST",
|
|
1270
|
+
docsUrl: CloudflarePagesEndpoints.docs.deployments,
|
|
1271
|
+
description: "Create a new deployment"
|
|
1272
|
+
},
|
|
1273
|
+
retryDeployment: {
|
|
1274
|
+
path: "pages/projects/{projectName}/deployments/{deploymentId}/retry",
|
|
1275
|
+
method: "POST",
|
|
1276
|
+
docsUrl: CloudflarePagesEndpoints.docs.deployments,
|
|
1277
|
+
description: "Retry a failed deployment"
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
1280
|
+
constructor(accountId, apiToken) {
|
|
1281
|
+
super({
|
|
1282
|
+
baseUrl: CloudflarePagesEndpoints.base,
|
|
1283
|
+
headers: {
|
|
1284
|
+
Authorization: `Bearer ${apiToken}`
|
|
1285
|
+
},
|
|
1286
|
+
timeout: 3e4,
|
|
1287
|
+
retry: 3
|
|
1288
|
+
});
|
|
1289
|
+
this.accountId = accountId;
|
|
1290
|
+
this.apiToken = apiToken;
|
|
1291
|
+
}
|
|
1292
|
+
cleanPath(path) {
|
|
1293
|
+
return path.startsWith("/") ? path.slice(1) : path;
|
|
1294
|
+
}
|
|
1295
|
+
async listProjects(options) {
|
|
1296
|
+
const endpoint = this.endpoints.listProjects;
|
|
1297
|
+
const path = this.cleanPath(
|
|
1298
|
+
CloudflarePagesEndpoints.listProjects(this.accountId)
|
|
1299
|
+
);
|
|
1300
|
+
const response = await this.request(
|
|
1301
|
+
{ ...endpoint, path },
|
|
1302
|
+
{
|
|
1303
|
+
searchParams: options?.page || options?.perPage ? {
|
|
1304
|
+
...options.page && { page: options.page },
|
|
1305
|
+
...options.perPage && { per_page: options.perPage }
|
|
1306
|
+
} : void 0,
|
|
1307
|
+
token: this.apiToken
|
|
1308
|
+
}
|
|
1309
|
+
);
|
|
1310
|
+
if (!response.success) {
|
|
1311
|
+
throw new Error(
|
|
1312
|
+
`Failed to list projects: ${response.errors?.[0]?.message || "Unknown error"}`
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
return response.result;
|
|
1316
|
+
}
|
|
1317
|
+
async getProject(projectName) {
|
|
1318
|
+
const endpoint = this.endpoints.getProject;
|
|
1319
|
+
const path = this.cleanPath(
|
|
1320
|
+
CloudflarePagesEndpoints.getProject(this.accountId, projectName)
|
|
1321
|
+
);
|
|
1322
|
+
const response = await this.request(
|
|
1323
|
+
{ ...endpoint, path },
|
|
1324
|
+
{ token: this.apiToken }
|
|
1325
|
+
);
|
|
1326
|
+
if (!response.success) {
|
|
1327
|
+
throw new Error(
|
|
1328
|
+
`Failed to get project ${projectName}: ${response.errors?.[0]?.message || "Unknown error"}`
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
return response.result;
|
|
1332
|
+
}
|
|
1333
|
+
async listDeployments(projectName, options) {
|
|
1334
|
+
const endpoint = this.endpoints.listDeployments;
|
|
1335
|
+
const path = this.cleanPath(
|
|
1336
|
+
CloudflarePagesEndpoints.listDeployments(this.accountId, projectName)
|
|
1337
|
+
);
|
|
1338
|
+
const searchParams = {};
|
|
1339
|
+
if (options?.page) {
|
|
1340
|
+
searchParams.page = options.page;
|
|
1341
|
+
}
|
|
1342
|
+
if (options?.perPage) {
|
|
1343
|
+
searchParams.per_page = options.perPage;
|
|
1344
|
+
}
|
|
1345
|
+
if (options?.environment) {
|
|
1346
|
+
searchParams.env = options.environment;
|
|
1347
|
+
}
|
|
1348
|
+
const response = await this.request(
|
|
1349
|
+
{ ...endpoint, path },
|
|
1350
|
+
{
|
|
1351
|
+
searchParams,
|
|
1352
|
+
token: this.apiToken
|
|
1353
|
+
}
|
|
1354
|
+
);
|
|
1355
|
+
if (!response.success) {
|
|
1356
|
+
throw new Error(
|
|
1357
|
+
`Failed to list deployments for ${projectName}: ${response.errors?.[0]?.message || "Unknown error"}`
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1360
|
+
return response.result;
|
|
1361
|
+
}
|
|
1362
|
+
async getDeployment(projectName, deploymentId) {
|
|
1363
|
+
const endpoint = this.endpoints.getDeployment;
|
|
1364
|
+
const path = this.cleanPath(
|
|
1365
|
+
CloudflarePagesEndpoints.getDeployment(
|
|
1366
|
+
this.accountId,
|
|
1367
|
+
projectName,
|
|
1368
|
+
deploymentId
|
|
1369
|
+
)
|
|
1370
|
+
);
|
|
1371
|
+
const response = await this.request(
|
|
1372
|
+
{ ...endpoint, path },
|
|
1373
|
+
{ token: this.apiToken }
|
|
1374
|
+
);
|
|
1375
|
+
if (!response.success) {
|
|
1376
|
+
throw new Error(
|
|
1377
|
+
`Failed to get deployment ${deploymentId}: ${response.errors?.[0]?.message || "Unknown error"}`
|
|
1378
|
+
);
|
|
1379
|
+
}
|
|
1380
|
+
return response.result;
|
|
1381
|
+
}
|
|
1382
|
+
async getLatestDeployment(projectName, environment = "production") {
|
|
1383
|
+
const deployments = await this.listDeployments(projectName, {
|
|
1384
|
+
environment
|
|
1385
|
+
});
|
|
1386
|
+
return deployments[0] || null;
|
|
1387
|
+
}
|
|
1388
|
+
async getDeploymentLogs(projectName, deploymentId) {
|
|
1389
|
+
const endpoint = this.endpoints.getDeploymentLogs;
|
|
1390
|
+
const path = this.cleanPath(
|
|
1391
|
+
CloudflarePagesEndpoints.getDeploymentLogs(
|
|
1392
|
+
this.accountId,
|
|
1393
|
+
projectName,
|
|
1394
|
+
deploymentId
|
|
1395
|
+
)
|
|
1396
|
+
);
|
|
1397
|
+
const response = await this.request(
|
|
1398
|
+
{ ...endpoint, path },
|
|
1399
|
+
{ token: this.apiToken }
|
|
1400
|
+
);
|
|
1401
|
+
if (!response.success) {
|
|
1402
|
+
throw new Error(
|
|
1403
|
+
`Failed to get deployment logs: ${response.errors?.[0]?.message || "Unknown error"}`
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1406
|
+
return response;
|
|
1407
|
+
}
|
|
1408
|
+
async createDeployment(projectName, branch) {
|
|
1409
|
+
const endpoint = this.endpoints.createDeployment;
|
|
1410
|
+
const path = this.cleanPath(
|
|
1411
|
+
CloudflarePagesEndpoints.createDeployment(this.accountId, projectName)
|
|
1412
|
+
);
|
|
1413
|
+
const body = branch ? { branch } : {};
|
|
1414
|
+
const response = await this.request(
|
|
1415
|
+
{ ...endpoint, path },
|
|
1416
|
+
{
|
|
1417
|
+
body,
|
|
1418
|
+
token: this.apiToken
|
|
1419
|
+
}
|
|
1420
|
+
);
|
|
1421
|
+
if (!response.success) {
|
|
1422
|
+
throw new Error(
|
|
1423
|
+
`Failed to create deployment: ${response.errors?.[0]?.message || "Unknown error"}`
|
|
1424
|
+
);
|
|
1425
|
+
}
|
|
1426
|
+
return response.result;
|
|
1427
|
+
}
|
|
1428
|
+
async retryDeployment(projectName, deploymentId) {
|
|
1429
|
+
const endpoint = this.endpoints.retryDeployment;
|
|
1430
|
+
const path = this.cleanPath(
|
|
1431
|
+
CloudflarePagesEndpoints.retryDeployment(
|
|
1432
|
+
this.accountId,
|
|
1433
|
+
projectName,
|
|
1434
|
+
deploymentId
|
|
1435
|
+
)
|
|
1436
|
+
);
|
|
1437
|
+
const response = await this.request(
|
|
1438
|
+
{ ...endpoint, path },
|
|
1439
|
+
{ token: this.apiToken }
|
|
1440
|
+
);
|
|
1441
|
+
if (!response.success) {
|
|
1442
|
+
throw new Error(
|
|
1443
|
+
`Failed to retry deployment: ${response.errors?.[0]?.message || "Unknown error"}`
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1446
|
+
return response.result;
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
|
|
1450
|
+
// src/adapters/cloudflare-pages/index.ts
|
|
1451
|
+
var CloudflarePagesAdapter = class extends BaseAdapter {
|
|
1452
|
+
name = "cloudflare-pages";
|
|
1453
|
+
api = null;
|
|
1454
|
+
getAPI(token) {
|
|
1455
|
+
let accountId;
|
|
1456
|
+
let apiToken;
|
|
1457
|
+
if (token.includes(":")) {
|
|
1458
|
+
[accountId, apiToken] = token.split(":", 2);
|
|
1459
|
+
} else {
|
|
1460
|
+
accountId = process.env.CLOUDFLARE_ACCOUNT_ID || "";
|
|
1461
|
+
apiToken = token;
|
|
1462
|
+
}
|
|
1463
|
+
if (!accountId) {
|
|
1464
|
+
throw new Error(
|
|
1465
|
+
"Cloudflare account ID is required. Provide it as 'accountId:apiToken' or set CLOUDFLARE_ACCOUNT_ID environment variable"
|
|
1466
|
+
);
|
|
1467
|
+
}
|
|
1468
|
+
if (!this.api || this.api["accountId"] !== accountId) {
|
|
1469
|
+
this.api = new CloudflarePagesAPI(accountId, apiToken);
|
|
1470
|
+
}
|
|
1471
|
+
return this.api;
|
|
1472
|
+
}
|
|
1473
|
+
async getLatestDeployment(project, token) {
|
|
1474
|
+
const apiToken = token || process.env.CLOUDFLARE_TOKEN || process.env.CLOUDFLARE_API_TOKEN;
|
|
1475
|
+
if (!apiToken) {
|
|
1476
|
+
throw new Error("Cloudflare API token is required");
|
|
1477
|
+
}
|
|
1478
|
+
try {
|
|
1479
|
+
const api = this.getAPI(apiToken);
|
|
1480
|
+
const deployment = await api.getLatestDeployment(project);
|
|
1481
|
+
if (!deployment) {
|
|
1482
|
+
return {
|
|
1483
|
+
status: "unknown",
|
|
1484
|
+
projectName: project,
|
|
1485
|
+
platform: "cloudflare-pages"
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
return this.transformDeployment(deployment);
|
|
1489
|
+
} catch (error) {
|
|
1490
|
+
if (error instanceof Error) {
|
|
1491
|
+
throw error;
|
|
1492
|
+
}
|
|
1493
|
+
throw new Error(`Failed to fetch deployment: ${error}`);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
async authenticate(token) {
|
|
1497
|
+
try {
|
|
1498
|
+
const api = this.getAPI(token);
|
|
1499
|
+
await api.listProjects({ perPage: 1 });
|
|
1500
|
+
return true;
|
|
1501
|
+
} catch {
|
|
1502
|
+
return false;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
async getDeploymentById(deploymentId, token) {
|
|
1506
|
+
if (!deploymentId.includes(":")) {
|
|
1507
|
+
throw new Error(
|
|
1508
|
+
"Deployment ID must be in format 'projectName:deploymentId' for Cloudflare Pages"
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
const [projectName, actualDeploymentId] = deploymentId.split(":", 2);
|
|
1512
|
+
const api = this.getAPI(token);
|
|
1513
|
+
return api.getDeployment(projectName, actualDeploymentId);
|
|
1514
|
+
}
|
|
1515
|
+
async getRecentDeployments(project, token, _limit = 10) {
|
|
1516
|
+
const api = this.getAPI(token);
|
|
1517
|
+
return api.listDeployments(project);
|
|
1518
|
+
}
|
|
1519
|
+
async getDeploymentLogs(deploymentId, token) {
|
|
1520
|
+
if (!deploymentId.includes(":")) {
|
|
1521
|
+
throw new Error(
|
|
1522
|
+
"Deployment ID must be in format 'projectName:deploymentId' for Cloudflare Pages"
|
|
1523
|
+
);
|
|
1524
|
+
}
|
|
1525
|
+
const [projectName, actualDeploymentId] = deploymentId.split(":", 2);
|
|
1526
|
+
const api = this.getAPI(token);
|
|
1527
|
+
const response = await api.getDeploymentLogs(
|
|
1528
|
+
projectName,
|
|
1529
|
+
actualDeploymentId
|
|
1530
|
+
);
|
|
1531
|
+
if (!response.result?.data || response.result.data.length === 0) {
|
|
1532
|
+
return "No logs available";
|
|
1533
|
+
}
|
|
1534
|
+
return response.result.data.map(
|
|
1535
|
+
(log) => `[${log.timestamp}] ${log.level.toUpperCase()}: ${log.message}`
|
|
1536
|
+
).join("\n");
|
|
1537
|
+
}
|
|
1538
|
+
async listProjects(token, _limit = 20) {
|
|
1539
|
+
const api = this.getAPI(token);
|
|
1540
|
+
const projects = await api.listProjects();
|
|
1541
|
+
return projects.map((project) => ({
|
|
1542
|
+
id: project.id,
|
|
1543
|
+
name: project.name,
|
|
1544
|
+
url: project.domains?.[0] ? `https://${project.domains[0]}` : `https://${project.subdomain}.pages.dev`
|
|
1545
|
+
}));
|
|
1546
|
+
}
|
|
1547
|
+
transformDeployment(deployment) {
|
|
1548
|
+
const status = this.mapStageStatus(deployment.latest_stage?.status);
|
|
1549
|
+
return {
|
|
1550
|
+
id: deployment.id,
|
|
1551
|
+
status,
|
|
1552
|
+
url: deployment.url,
|
|
1553
|
+
projectName: deployment.project_name,
|
|
1554
|
+
platform: "cloudflare-pages",
|
|
1555
|
+
timestamp: this.formatTimestamp(deployment.created_on),
|
|
1556
|
+
duration: deployment.latest_stage ? this.calculateDuration(
|
|
1557
|
+
deployment.latest_stage.started_on || deployment.created_on,
|
|
1558
|
+
deployment.latest_stage.ended_on || void 0
|
|
1559
|
+
) : void 0,
|
|
1560
|
+
environment: deployment.environment,
|
|
1561
|
+
commit: deployment.source?.config ? {
|
|
1562
|
+
sha: deployment.source.config.commit_hash,
|
|
1563
|
+
message: deployment.source.config.commit_message,
|
|
1564
|
+
author: void 0
|
|
1565
|
+
// Cloudflare Pages doesn't provide author in API
|
|
1566
|
+
} : void 0
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
1569
|
+
mapStageStatus(status) {
|
|
1570
|
+
if (!status) {
|
|
1571
|
+
return "unknown";
|
|
1572
|
+
}
|
|
1573
|
+
switch (status) {
|
|
1574
|
+
case "success":
|
|
1575
|
+
return "success";
|
|
1576
|
+
case "failed":
|
|
1577
|
+
case "canceled":
|
|
1578
|
+
return "failed";
|
|
1579
|
+
case "active":
|
|
1580
|
+
return "building";
|
|
1581
|
+
case "skipped":
|
|
1582
|
+
return "unknown";
|
|
1583
|
+
default:
|
|
1584
|
+
return "unknown";
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
// Helper method to get deployment status
|
|
1588
|
+
async getDeploymentStatus(project, token) {
|
|
1589
|
+
return this.getLatestDeployment(project, token);
|
|
1590
|
+
}
|
|
1591
|
+
// Helper method to trigger a new deployment
|
|
1592
|
+
async triggerDeployment(project, token, branch) {
|
|
1593
|
+
const api = this.getAPI(token);
|
|
1594
|
+
return api.createDeployment(project, branch);
|
|
1595
|
+
}
|
|
1596
|
+
// Helper method to retry a failed deployment
|
|
1597
|
+
async retryDeployment(projectName, deploymentId, token) {
|
|
1598
|
+
const api = this.getAPI(token);
|
|
1599
|
+
return api.retryDeployment(projectName, deploymentId);
|
|
1600
|
+
}
|
|
1601
|
+
};
|
|
1602
|
+
|
|
1193
1603
|
// src/core/deployment-intelligence.ts
|
|
1194
1604
|
var DeploymentIntelligence = class {
|
|
1195
1605
|
adapter;
|
|
@@ -1204,10 +1614,8 @@ var DeploymentIntelligence = class {
|
|
|
1204
1614
|
return process.env.VERCEL_TOKEN;
|
|
1205
1615
|
case "netlify":
|
|
1206
1616
|
return process.env.NETLIFY_TOKEN;
|
|
1207
|
-
case "
|
|
1208
|
-
return process.env.
|
|
1209
|
-
case "render":
|
|
1210
|
-
return process.env.RENDER_TOKEN;
|
|
1617
|
+
case "cloudflare-pages":
|
|
1618
|
+
return process.env.CLOUDFLARE_TOKEN;
|
|
1211
1619
|
default:
|
|
1212
1620
|
return void 0;
|
|
1213
1621
|
}
|
|
@@ -1248,11 +1656,11 @@ var DeploymentIntelligence = class {
|
|
|
1248
1656
|
return new VercelAdapter();
|
|
1249
1657
|
case "netlify":
|
|
1250
1658
|
return new NetlifyAdapter();
|
|
1659
|
+
case "cloudflare-pages":
|
|
1660
|
+
return new CloudflarePagesAdapter();
|
|
1251
1661
|
// Ready for future platforms
|
|
1252
|
-
// case "
|
|
1253
|
-
// return new
|
|
1254
|
-
// case "render":
|
|
1255
|
-
// return new RenderAdapter();
|
|
1662
|
+
// case "github-pages":
|
|
1663
|
+
// return new GitHubPagesAdapter();
|
|
1256
1664
|
default:
|
|
1257
1665
|
throw new Error(`Unsupported platform: ${platform}`);
|
|
1258
1666
|
}
|
|
@@ -2050,9 +2458,12 @@ var MCPHandler = class {
|
|
|
2050
2458
|
const formattedStatus = this.formatResponse(status, validated.platform);
|
|
2051
2459
|
return ResponseFormatter.formatStatus(formattedStatus);
|
|
2052
2460
|
} else {
|
|
2461
|
+
const tokenEnvKey = `${validated.platform.toUpperCase().replace(/-/g, "_")}_TOKEN`;
|
|
2462
|
+
const generalTokenKey = validated.platform.startsWith("cloudflare-") ? "CLOUDFLARE_TOKEN" : validated.platform.startsWith("github-") ? "GITHUB_TOKEN" : null;
|
|
2463
|
+
const token = validated.token || process.env[tokenEnvKey] || (generalTokenKey ? process.env[generalTokenKey] : null) || "";
|
|
2053
2464
|
const deployments = await adapter.getRecentDeployments(
|
|
2054
2465
|
validated.project,
|
|
2055
|
-
|
|
2466
|
+
token,
|
|
2056
2467
|
validated.limit
|
|
2057
2468
|
);
|
|
2058
2469
|
if (deployments.length === 0) {
|
|
@@ -2108,6 +2519,27 @@ var MCPHandler = class {
|
|
|
2108
2519
|
author: deployment.committer
|
|
2109
2520
|
} : void 0
|
|
2110
2521
|
};
|
|
2522
|
+
} else if (platform === PLATFORM.CLOUDFLARE_PAGES) {
|
|
2523
|
+
return {
|
|
2524
|
+
id: deployment.id,
|
|
2525
|
+
status: this.mapCloudflareState(
|
|
2526
|
+
deployment.latest_stage?.status || "unknown"
|
|
2527
|
+
),
|
|
2528
|
+
url: deployment.url,
|
|
2529
|
+
projectName: deployment.project_name,
|
|
2530
|
+
platform,
|
|
2531
|
+
timestamp: deployment.created_on,
|
|
2532
|
+
duration: deployment.latest_stage?.ended_on && deployment.latest_stage?.started_on ? Math.floor(
|
|
2533
|
+
(new Date(deployment.latest_stage.ended_on).getTime() - new Date(deployment.latest_stage.started_on).getTime()) / 1e3
|
|
2534
|
+
) : void 0,
|
|
2535
|
+
environment: deployment.environment || "production",
|
|
2536
|
+
commit: deployment.source?.config ? {
|
|
2537
|
+
sha: deployment.source.config.commit_hash,
|
|
2538
|
+
message: deployment.source.config.commit_message,
|
|
2539
|
+
author: void 0
|
|
2540
|
+
// Cloudflare doesn't provide author
|
|
2541
|
+
} : void 0
|
|
2542
|
+
};
|
|
2111
2543
|
}
|
|
2112
2544
|
return deployment;
|
|
2113
2545
|
}
|
|
@@ -2138,6 +2570,21 @@ var MCPHandler = class {
|
|
|
2138
2570
|
return "building";
|
|
2139
2571
|
}
|
|
2140
2572
|
}
|
|
2573
|
+
mapCloudflareState(state) {
|
|
2574
|
+
switch (state) {
|
|
2575
|
+
case CLOUDFLARE_PAGES_STATES.SUCCESS:
|
|
2576
|
+
return "success";
|
|
2577
|
+
case CLOUDFLARE_PAGES_STATES.FAILED:
|
|
2578
|
+
case CLOUDFLARE_PAGES_STATES.CANCELED:
|
|
2579
|
+
return "failed";
|
|
2580
|
+
case CLOUDFLARE_PAGES_STATES.ACTIVE:
|
|
2581
|
+
return "building";
|
|
2582
|
+
case CLOUDFLARE_PAGES_STATES.SKIPPED:
|
|
2583
|
+
return "unknown";
|
|
2584
|
+
default:
|
|
2585
|
+
return "unknown";
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2141
2588
|
formatResponse(status, platform) {
|
|
2142
2589
|
return {
|
|
2143
2590
|
...status,
|
|
@@ -2217,11 +2664,13 @@ ${messages.join("\n\n")}
|
|
|
2217
2664
|
if (!adapter) {
|
|
2218
2665
|
throw new Error(`Unsupported platform: ${validated.platform}`);
|
|
2219
2666
|
}
|
|
2220
|
-
const tokenEnvKey = `${validated.platform.toUpperCase()}_TOKEN`;
|
|
2221
|
-
const
|
|
2667
|
+
const tokenEnvKey = `${validated.platform.toUpperCase().replace(/-/g, "_")}_TOKEN`;
|
|
2668
|
+
const generalTokenKey = validated.platform.startsWith("cloudflare-") ? "CLOUDFLARE_TOKEN" : validated.platform.startsWith("github-") ? "GITHUB_TOKEN" : null;
|
|
2669
|
+
const token = validated.token || process.env[tokenEnvKey] || (generalTokenKey ? process.env[generalTokenKey] : null);
|
|
2222
2670
|
if (!token) {
|
|
2671
|
+
const tokenOptions = generalTokenKey ? `${tokenEnvKey} or ${generalTokenKey} environment variable` : `${tokenEnvKey} environment variable`;
|
|
2223
2672
|
throw new Error(
|
|
2224
|
-
`Authentication required. Please provide a token or set ${
|
|
2673
|
+
`Authentication required. Please provide a token or set ${tokenOptions}.`
|
|
2225
2674
|
);
|
|
2226
2675
|
}
|
|
2227
2676
|
try {
|
|
@@ -2280,5 +2729,6 @@ export {
|
|
|
2280
2729
|
tools,
|
|
2281
2730
|
VercelAdapter,
|
|
2282
2731
|
NetlifyAdapter,
|
|
2732
|
+
CloudflarePagesAdapter,
|
|
2283
2733
|
MCPHandler
|
|
2284
2734
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
CloudflarePagesAdapter,
|
|
3
4
|
MCPHandler,
|
|
4
5
|
NetlifyAdapter,
|
|
5
6
|
VercelAdapter,
|
|
6
7
|
tools
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-BFOEFRRT.js";
|
|
8
9
|
|
|
9
10
|
// src/index.ts
|
|
10
11
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -16,7 +17,8 @@ import {
|
|
|
16
17
|
var handler = new MCPHandler(
|
|
17
18
|
/* @__PURE__ */ new Map([
|
|
18
19
|
["vercel", new VercelAdapter()],
|
|
19
|
-
["netlify", new NetlifyAdapter()]
|
|
20
|
+
["netlify", new NetlifyAdapter()],
|
|
21
|
+
["cloudflare-pages", new CloudflarePagesAdapter()]
|
|
20
22
|
])
|
|
21
23
|
);
|
|
22
24
|
var server = new Server(
|
package/dist/worker.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MCPHandler,
|
|
3
3
|
VercelAdapter
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BFOEFRRT.js";
|
|
5
5
|
|
|
6
6
|
// src/utils/github.ts
|
|
7
7
|
async function validateRepository(user, repo) {
|
|
@@ -32,7 +32,7 @@ async function validateRepository(user, repo) {
|
|
|
32
32
|
}
|
|
33
33
|
function validateParams(user, repo, platform) {
|
|
34
34
|
const validName = /^[a-zA-Z0-9._-]+$/;
|
|
35
|
-
const validPlatforms = ["vercel", "netlify", "
|
|
35
|
+
const validPlatforms = ["vercel", "netlify", "cloudflare-pages"];
|
|
36
36
|
return validName.test(user) && validName.test(repo) && validPlatforms.includes(platform);
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -53,9 +53,9 @@ var PLATFORM_CONFIG = {
|
|
|
53
53
|
label: "Netlify",
|
|
54
54
|
logo: "netlify"
|
|
55
55
|
},
|
|
56
|
-
|
|
57
|
-
label: "
|
|
58
|
-
logo: "
|
|
56
|
+
"cloudflare-pages": {
|
|
57
|
+
label: "Cloudflare Pages",
|
|
58
|
+
logo: "cloudflare"
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
61
|
function validateParams2(user, repo, platform) {
|
|
@@ -651,23 +651,23 @@ var landingPageHTML = `<!DOCTYPE html>
|
|
|
651
651
|
</p>
|
|
652
652
|
</div>
|
|
653
653
|
|
|
654
|
-
<div class="platform">
|
|
654
|
+
<div class="platform active">
|
|
655
655
|
<div class="platform-header">
|
|
656
|
-
<span class="platform-name">
|
|
657
|
-
<span class="platform-status
|
|
656
|
+
<span class="platform-name">Cloudflare Pages</span>
|
|
657
|
+
<span class="platform-status">Ready</span>
|
|
658
658
|
</div>
|
|
659
659
|
<p class="platform-desc">
|
|
660
|
-
|
|
660
|
+
Fast edge deployments with free bandwidth and global CDN.
|
|
661
661
|
</p>
|
|
662
662
|
</div>
|
|
663
663
|
|
|
664
664
|
<div class="platform">
|
|
665
665
|
<div class="platform-header">
|
|
666
|
-
<span class="platform-name">
|
|
666
|
+
<span class="platform-name">GitHub Pages</span>
|
|
667
667
|
<span class="platform-status soon">Soon</span>
|
|
668
668
|
</div>
|
|
669
669
|
<p class="platform-desc">
|
|
670
|
-
|
|
670
|
+
Direct GitHub integration with Actions-based deployment tracking.
|
|
671
671
|
</p>
|
|
672
672
|
</div>
|
|
673
673
|
</div>
|
|
@@ -680,7 +680,8 @@ var landingPageHTML = `<!DOCTYPE html>
|
|
|
680
680
|
<pre style="margin: 0;">{
|
|
681
681
|
"env": {
|
|
682
682
|
"VERCEL_TOKEN": "your-vercel-token",
|
|
683
|
-
"NETLIFY_TOKEN": "your-netlify-token"
|
|
683
|
+
"NETLIFY_TOKEN": "your-netlify-token",
|
|
684
|
+
"CLOUDFLARE_TOKEN": "accountId:globalApiKey"
|
|
684
685
|
}
|
|
685
686
|
}</pre>
|
|
686
687
|
</div>
|
|
@@ -767,7 +768,8 @@ var landingPageHTML = `<!DOCTYPE html>
|
|
|
767
768
|
"args": ["-y", "deploy-mcp"],
|
|
768
769
|
"env": {
|
|
769
770
|
"VERCEL_TOKEN": "your-vercel-token",
|
|
770
|
-
"NETLIFY_TOKEN": "your-netlify-token"
|
|
771
|
+
"NETLIFY_TOKEN": "your-netlify-token",
|
|
772
|
+
"CLOUDFLARE_TOKEN": "accountId:globalApiKey"
|
|
771
773
|
}
|
|
772
774
|
}
|
|
773
775
|
}
|
|
@@ -822,7 +824,7 @@ var landingPageHTML = `<!DOCTYPE html>
|
|
|
822
824
|
<div class="badge-examples">
|
|
823
825
|
<img src="https://img.shields.io/badge/vercel-success-22c55e" alt="Vercel Status">
|
|
824
826
|
<img src="https://img.shields.io/badge/netlify-building-FCD34D" alt="Netlify Status">
|
|
825
|
-
<img src="https://img.shields.io/badge/
|
|
827
|
+
<img src="https://img.shields.io/badge/cloudflare%20pages-ready-22c55e" alt="Cloudflare Pages Status">
|
|
826
828
|
</div>
|
|
827
829
|
|
|
828
830
|
<div class="badge-code">
|
|
@@ -875,7 +877,8 @@ var landingPageHTML = `<!DOCTYPE html>
|
|
|
875
877
|
args: ['-y', 'deploy-mcp'],
|
|
876
878
|
env: {
|
|
877
879
|
VERCEL_TOKEN: 'your-vercel-token',
|
|
878
|
-
NETLIFY_TOKEN: 'your-netlify-token'
|
|
880
|
+
NETLIFY_TOKEN: 'your-netlify-token',
|
|
881
|
+
CLOUDFLARE_TOKEN: 'accountId:globalApiKey'
|
|
879
882
|
}
|
|
880
883
|
}
|
|
881
884
|
}
|
|
@@ -887,7 +890,8 @@ var landingPageHTML = `<!DOCTYPE html>
|
|
|
887
890
|
const config = JSON.stringify({
|
|
888
891
|
env: {
|
|
889
892
|
VERCEL_TOKEN: 'your-vercel-token',
|
|
890
|
-
NETLIFY_TOKEN: 'your-netlify-token'
|
|
893
|
+
NETLIFY_TOKEN: 'your-netlify-token',
|
|
894
|
+
CLOUDFLARE_TOKEN: 'accountId:globalApiKey'
|
|
891
895
|
}
|
|
892
896
|
}, null, 2);
|
|
893
897
|
copyToClipboard(config, event);
|
|
@@ -932,6 +936,9 @@ async function validateWebhookSignature(request, platform, env) {
|
|
|
932
936
|
return false;
|
|
933
937
|
}
|
|
934
938
|
}
|
|
939
|
+
if (platform === "cloudflare-pages") {
|
|
940
|
+
return true;
|
|
941
|
+
}
|
|
935
942
|
return true;
|
|
936
943
|
}
|
|
937
944
|
function mapDeploymentStatus(platform, payload) {
|
|
@@ -964,8 +971,22 @@ function mapDeploymentStatus(platform, payload) {
|
|
|
964
971
|
return "unknown";
|
|
965
972
|
}
|
|
966
973
|
}
|
|
967
|
-
case "
|
|
968
|
-
|
|
974
|
+
case "cloudflare-pages": {
|
|
975
|
+
const cloudflarePagesPayload = payload;
|
|
976
|
+
switch (cloudflarePagesPayload.status) {
|
|
977
|
+
case "success":
|
|
978
|
+
return "success";
|
|
979
|
+
case "failed":
|
|
980
|
+
case "canceled":
|
|
981
|
+
return "failed";
|
|
982
|
+
case "active":
|
|
983
|
+
return "building";
|
|
984
|
+
case "skipped":
|
|
985
|
+
return "unknown";
|
|
986
|
+
default:
|
|
987
|
+
return "unknown";
|
|
988
|
+
}
|
|
989
|
+
}
|
|
969
990
|
default:
|
|
970
991
|
return "unknown";
|
|
971
992
|
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deploy-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Universal deployment tracker for AI assistants",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
7
7
|
"deployment",
|
|
8
8
|
"vercel",
|
|
9
9
|
"netlify",
|
|
10
|
+
"cloudflare-pages",
|
|
10
11
|
"ai",
|
|
11
12
|
"claude",
|
|
12
13
|
"deployment-tracking",
|
|
13
14
|
"netlify-deployment",
|
|
14
15
|
"vercel-deployment",
|
|
16
|
+
"cloudflare-deployment",
|
|
15
17
|
"deployment-status",
|
|
16
18
|
"deployment-monitor",
|
|
17
19
|
"ci-cd"
|