@selfhost.dev/mcp-server 0.3.0 → 0.4.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # SelfHost MCP Server
2
2
 
3
- A full-featured [Model Context Protocol](https://modelcontextprotocol.io/) server that brings [SelfHost's](https://selfhost.dev) database management capabilities directly into AI coding assistants. Provision, monitor, scale, and manage production database infrastructure — all through natural language, without leaving your editor.
3
+ A full-featured [Model Context Protocol](https://modelcontextprotocol.io/) server that brings the [SelfHost](https://selfhost.dev) cloud platform directly into AI coding assistants. Provision, monitor, scale, and manage production database infrastructure **and** deploy apps from GitHub - projects, builds, env vars, custom domains, and more - all through natural language, without leaving your editor.
4
4
 
5
5
  Works with **Claude Code**, **Cursor**, **Windsurf**, **Cline**, and any MCP-compatible client.
6
6
 
@@ -57,7 +57,7 @@ That's it. The server handles authentication, token refresh, and everything else
57
57
 
58
58
  ### First Run
59
59
 
60
- On first use, the MCP server opens your browser to sign in via SelfHost's console. After you authorize, credentials are saved locally (`~/.selfhost/credentials.json`) and auto-refreshed — you won't need to sign in again.
60
+ On first use, the MCP server opens your browser to sign in via SelfHost's console. After you authorize, credentials are saved locally (`~/.selfhost/credentials.json`) and auto-refreshed - you won't need to sign in again.
61
61
 
62
62
  ```
63
63
  You: "Show me my databases"
@@ -89,16 +89,22 @@ Claude: Authenticates → fetches your orgs → selects org → lists instances
89
89
  | *"Upgrade my org to the Pro plan"* | Confirms billing state, creates or changes the subscription |
90
90
  | *"Spin up a Postgres instance on Hetzner in Helsinki"* | Confirms provider, walks through Hetzner location + server type, provisions on Hetzner Cloud |
91
91
  | *"What cloud providers can I use?"* | Lists AWS and Hetzner with their capabilities so you can pick |
92
+ | *"Create a project and deploy my GitHub repo into it"* | Provisions a project, waits for it to be ready, detects the build config, and deploys the repo |
93
+ | *"Deploy the main branch of my-org/api"* | Creates a deployment, triggers the build, and streams build logs until it's live |
94
+ | *"Set DATABASE_URL on my app and redeploy"* | Updates the env var (without wiping the others) and rolls out the change |
95
+ | *"Add a Postgres database to my project"* | Provisions a Postgres database inside the project with the credentials you choose |
96
+ | *"Point app.example.com at my deployment"* | Attaches the custom domain and returns the exact DNS records to add, then verifies them |
97
+ | *"Roll back my app to the last working deploy"* | Re-deploys the commit from the previous successful run |
92
98
 
93
99
  ### Safety Built In
94
100
 
95
- Destructive operations (delete, stop, reboot) require explicit confirmation. The server will always ask before proceeding — you'll never accidentally delete a production database.
101
+ Destructive operations (delete, stop, reboot) require explicit confirmation. The server will always ask before proceeding - you'll never accidentally delete a production database.
96
102
 
97
103
  ---
98
104
 
99
105
  ## Features
100
106
 
101
- ### 111 tools across 14 modules
107
+ ### 151 tools across 22 modules
102
108
 
103
109
  Every tool maps to a real API endpoint. No mock data, no shortcuts.
104
110
 
@@ -117,7 +123,7 @@ Automatic browser-based sign-in with Firebase. Tokens refresh transparently.
117
123
  | `reauthenticate` | Sign out and sign in again (switch accounts) |
118
124
 
119
125
  #### Organizations & Team Management
120
- Multi-tenant — everything is scoped to your org.
126
+ Multi-tenant - everything is scoped to your org.
121
127
 
122
128
  | Tool | Description |
123
129
  |------|-------------|
@@ -147,7 +153,7 @@ Bring your own AWS account (BYOC) or use SelfHost's managed infrastructure.
147
153
  | `get_aws_account_info` | AWS account ID and free tier status |
148
154
 
149
155
  #### Networking
150
- VPCs, subnets, and security groups. Optional — auto-created during provisioning if not specified.
156
+ VPCs, subnets, and security groups. Optional - auto-created during provisioning if not specified.
151
157
 
152
158
  | Tool | Description |
153
159
  |------|-------------|
@@ -237,29 +243,29 @@ PostgreSQL-only. Reduces connection overhead for high-concurrency workloads. Cli
237
243
  | `disable_pgbouncer` | Drain pool and disable (with confirmation) |
238
244
 
239
245
  #### Database Users
240
- DBMS-level credentials — distinct from the SelfHost platform login. Use for apps and people that need their own DB user.
246
+ DBMS-level credentials - distinct from the SelfHost platform login. Use for apps and people that need their own DB user.
241
247
 
242
248
  | Tool | Description |
243
249
  |------|-------------|
244
250
  | `list_database_users` | List users with role, status, target DB, expiry metadata |
245
251
  | `create_database_user` | Create user with role (read_only / read_write / admin) and optional connection limit + password expiry |
246
252
  | `update_database_user` | Change role, connection limit, or password expiry |
247
- | `delete_database_user` | Soft-delete user (with confirmation) — drops active connections |
248
- | `rotate_database_user_password` | Rotate password (with confirmation) — new value shown once |
253
+ | `delete_database_user` | Soft-delete user (with confirmation) - drops active connections |
254
+ | `rotate_database_user_password` | Rotate password (with confirmation) - new value shown once |
249
255
 
250
256
  #### Scaling
251
257
  Manual one-off resize plus auto-scaling policies (reactive metric-based, scheduled cron, and auto start/stop).
252
258
 
253
259
  | Tool | Description |
254
260
  |------|-------------|
255
- | `scale_instance` | Manual resize — change instance type, volume type, size, IOPS, throughput |
261
+ | `scale_instance` | Manual resize - change instance type, volume type, size, IOPS, throughput |
256
262
  | `list_scaling_policies` | List policies, optionally filtered to one instance |
257
- | `create_scaling_policy` | Create policy — reactive metric breach, scheduled cron, or auto start/stop schedule |
263
+ | `create_scaling_policy` | Create policy - reactive metric breach, scheduled cron, or auto start/stop schedule |
258
264
  | `update_scaling_policy` | Modify thresholds, schedule, or action details |
259
265
  | `delete_scaling_policy` | Remove a policy (with confirmation) |
260
266
 
261
267
  #### Point-in-Time Recovery (PITR)
262
- PostgreSQL-only, Pro+. Continuous WAL archiving to S3 + restore to any second within the retention window. Restore creates a brand-new instance — the source is untouched.
268
+ PostgreSQL-only, Pro+. Continuous WAL archiving to S3 + restore to any second within the retention window. Restore creates a brand-new instance - the source is untouched.
263
269
 
264
270
  | Tool | Description |
265
271
  |------|-------------|
@@ -279,18 +285,18 @@ Subscription lifecycle and payment-method linking. All endpoints scoped to the a
279
285
  | `get_subscription` | Get current subscription (404 = no subscription, on Free) |
280
286
  | `create_subscription` | Start a paid subscription (plan goes `pending` → `active` via Razorpay webhook) |
281
287
  | `change_subscription` | Upgrade or downgrade plan (downgrades scheduled at cycle end) |
282
- | `cancel_subscription` | Cancel — keeps access until cycle end (with confirmation) |
283
- | `link_billing_payment_method` | Initiate Razorpay link — returns short URL to open in browser |
288
+ | `cancel_subscription` | Cancel - keeps access until cycle end (with confirmation) |
289
+ | `link_billing_payment_method` | Initiate Razorpay link - returns short URL to open in browser |
284
290
  | `update_billing_contact` | Update billing phone / tax ID / country / state for invoices |
285
291
 
286
292
  #### Hetzner Cloud (Postgres-only)
287
- Provisioning on Hetzner Cloud as an alternative to AWS. Currently provision / get / status / delete only — no start / stop / reboot / update / scaling / PITR / pooling yet. Call `list_cloud_providers` at the start of any create-database intent to surface both options to the user.
293
+ Provisioning on Hetzner Cloud as an alternative to AWS. Currently provision / get / status / delete only - no start / stop / reboot / update / scaling / PITR / pooling yet. Call `list_cloud_providers` at the start of any create-database intent to surface both options to the user.
288
294
 
289
295
  | Tool | Description |
290
296
  |------|-------------|
291
297
  | `list_cloud_providers` | List available cloud providers (AWS, Hetzner) with capabilities + the create tool to use for each |
292
298
  | `list_hetzner_locations` | Hetzner datacenter locations (fsn1, nbg1, hel1, ash, sin) with country + continent |
293
- | `list_hetzner_server_types` | Hetzner server types (cpx11–cpx51) with vCPU / RAM / local disk |
299
+ | `list_hetzner_server_types` | Hetzner server types (cpx11-cpx51) with vCPU / RAM / local disk |
294
300
  | `create_hetzner_instance` | Provision a Postgres instance on Hetzner Cloud (region, server type, storage size, HA toggle, CIDR allowlist) |
295
301
  | `get_hetzner_instance` | Fetch a Hetzner instance's full details by PID |
296
302
  | `get_hetzner_instance_status` | Poll provisioning progress (per-step status: network → firewall → ssh_key → server → volume → load_balancer → ansible → finalize) |
@@ -298,6 +304,86 @@ Provisioning on Hetzner Cloud as an alternative to AWS. Currently provision / ge
298
304
 
299
305
  ---
300
306
 
307
+ ### PaaS - Projects (app containers)
308
+ A **project** is a per-app container: a provisioned server + Coolify install + wildcard DNS that deployments, databases, and services attach to. Creation is async (~2-5 min) - poll `get_project` until status is `active` before deploying into it.
309
+
310
+ | Tool | Description |
311
+ |------|-------------|
312
+ | `list_projects` | List projects in the org (pid, name, status, public_ip, domain) |
313
+ | `get_project` | Get one project; poll this for provisioning progress (active / failed) |
314
+ | `create_project` | Create a project and start async provisioning (returns status `pending`) |
315
+ | `update_project` | Rename / re-describe a project |
316
+ | `delete_project` | Tear down the server and everything in the project (with confirmation; blocked while provisioning or with running deployments) |
317
+ | `get_project_metrics` | Time-series server + database + deployment metrics from the monitoring agent (start_date/end_date) |
318
+
319
+ ### PaaS - Deployments (GitHub apps)
320
+ A **deployment** is an app built from a GitHub repo, living inside an `active` project. Build/run history is returned inline on the deployment.
321
+
322
+ | Tool | Description |
323
+ |------|-------------|
324
+ | `list_deployments` | List apps in the org, each with inline build runs (newest 50) |
325
+ | `get_deployment` | Get one app + runs; poll this for deploy/run progress |
326
+ | `create_deployment` | Deploy a GitHub repo into a project (repo_url, branch, build_pack, port, env_vars, …) |
327
+ | `update_deployment` | Pause/resume, toggle auto-deploy, set ignore_paths / max preview deployments |
328
+ | `update_deployment_build_config` | Change build_pack / base_directory / port / dockerfile / env_vars |
329
+ | `delete_deployment` | Remove the app and its Coolify resources (with confirmation) |
330
+ | `trigger_deploy` | Manually deploy the current branch (new run) |
331
+ | `get_deployment_logs` | Current application/container logs |
332
+ | `get_deployment_health` | Reachability of the deploy URL + attached domains |
333
+ | `get_run_logs` | Full build + container logs for one run (poll until terminal) |
334
+ | `redeploy_run` | Re-run a build from the same commit |
335
+ | `rollback_run` | Re-deploy the commit from a prior successful run |
336
+
337
+ ### PaaS - Custom Domains
338
+ | Tool | Description |
339
+ |------|-------------|
340
+ | `add_deployment_domain` | Attach a custom domain to a deployment (returns DNS records to add) |
341
+ | `sync_deployment_domains` | Set the full domain list for a deployment (set primary / remove several) |
342
+ | `remove_deployment_domain` | Remove one domain from a deployment |
343
+ | `verify_custom_domain` | Check DNS (TXT + CNAME) and advance verification → live HTTPS |
344
+ | `list_custom_domains` | List the org's custom-domain verification states |
345
+
346
+ ### PaaS - Environment Variables
347
+ | Tool | Description |
348
+ |------|-------------|
349
+ | `list_env_vars` | List a deployment's env vars (values returned in cleartext) |
350
+ | `set_env_vars` | **Replace** the entire env-var set (omitted keys are deleted) |
351
+ | `merge_env_vars` | Add/update env vars without deleting others (safe upsert) |
352
+ | `delete_env_var` | Remove one variable by key |
353
+
354
+ ### PaaS - GitHub
355
+ | Tool | Description |
356
+ |------|-------------|
357
+ | `list_github_installations` | Connected GitHub App installations + their accessible repos |
358
+ | `list_repo_branches` | Branches for a repo via an installation |
359
+ | `detect_repo_config` | Auto-detect build_pack / port / monorepo dirs / env-var hints for a repo |
360
+ | `get_github_connect_url` | Get a browser URL to connect GitHub (interactive; then re-list installations) |
361
+
362
+ ### PaaS - Project Databases
363
+ Postgres/Redis/MySQL/MongoDB provisioned inside a project (distinct from AWS/Hetzner managed instances).
364
+
365
+ | Tool | Description |
366
+ |------|-------------|
367
+ | `list_project_databases` | List databases attached to a project |
368
+ | `create_project_database` | Provision a Postgres/Redis/MySQL/MongoDB in a project (type-specific credentials) |
369
+ | `delete_project_database` | Delete a project database (exact name match + confirmation) |
370
+
371
+ ### PaaS - Project Services (templates)
372
+ | Tool | Description |
373
+ |------|-------------|
374
+ | `list_project_services` | List service-template instances (e.g. Supabase) in a project |
375
+ | `create_project_service` | Deploy a service template (currently `supabase`) into a project |
376
+ | `delete_project_service` | Delete a project service (exact name match + confirmation) |
377
+
378
+ ### PaaS - Deployment Notifications
379
+ | Tool | Description |
380
+ |------|-------------|
381
+ | `list_deployment_notification_bindings` | Channels notified on a deployment's deploy outcomes |
382
+ | `bind_deployment_notification_channel` | Notify an org channel (nchan_…) on deploy success/failure |
383
+ | `unbind_deployment_notification_channel` | Stop notifying a channel for a deployment |
384
+
385
+ ---
386
+
301
387
  ## Common Workflows
302
388
 
303
389
  ### Switch AWS Account (BYOC vs Platform-Managed)
@@ -370,12 +456,12 @@ Reference data lookups (regions, instance types, storage types) are unlimited.
370
456
  | `API_URL` | `https://api.selfhost.dev` | SelfHost API endpoint |
371
457
  | `CONSOLE_URL` | `https://console.selfhost.dev` | SelfHost Console URL (for browser auth) |
372
458
  | `TIER` | Auto-detected | Override rate limit tier (`FREE`, `STARTER`, `PRO`, `ENTERPRISE`, `ADMIN`) |
373
- | `FIREBASE_API_KEY` | — | Skip browser auth (CI/headless) |
374
- | `FIREBASE_REFRESH_TOKEN` | — | Skip browser auth (CI/headless) |
459
+ | `FIREBASE_API_KEY` | - | Skip browser auth (CI/headless) |
460
+ | `FIREBASE_REFRESH_TOKEN` | - | Skip browser auth (CI/headless) |
375
461
 
376
462
  ### Local Development
377
463
 
378
- Both `API_URL` and `CONSOLE_URL` are optional overrides — they default to the production endpoints when not set.
464
+ Both `API_URL` and `CONSOLE_URL` are optional overrides - they default to the production endpoints when not set.
379
465
 
380
466
  **1. Local Rails API + Local Console**
381
467
 
@@ -452,7 +538,7 @@ Set `FIREBASE_API_KEY` and `FIREBASE_REFRESH_TOKEN` environment variables to ski
452
538
  ## Security
453
539
 
454
540
  - **Credentials stored locally** at `~/.selfhost/credentials.json` with `chmod 0600` (owner-only read/write)
455
- - **JWT auto-refresh** — tokens refresh 5 minutes before expiry, refresh tokens are rotated
456
- - **Sensitive fields stripped** — passwords, AWS keys, tokens, and secrets are redacted from API responses
457
- - **Destructive operations gated** — delete, stop, and reboot require explicit `confirm: true`
458
- - **No console.log** — all logging goes to stderr to avoid corrupting the MCP JSON-RPC stream on stdout
541
+ - **JWT auto-refresh** - tokens refresh 5 minutes before expiry, refresh tokens are rotated
542
+ - **Sensitive fields stripped** - passwords, AWS keys, tokens, and secrets are redacted from API responses
543
+ - **Destructive operations gated** - delete, stop, and reboot require explicit `confirm: true`
544
+ - **No console.log** - all logging goes to stderr to avoid corrupting the MCP JSON-RPC stream on stdout
package/dist/index.js CHANGED
@@ -18,6 +18,14 @@ import { registerScalingTools } from "./tools/scaling.js";
18
18
  import { registerPitrTools } from "./tools/pitr.js";
19
19
  import { registerBillingTools } from "./tools/billing.js";
20
20
  import { registerHetznerTools } from "./tools/hetzner.js";
21
+ import { registerProjectTools } from "./tools/projects.js";
22
+ import { registerDeploymentTools } from "./tools/deployments.js";
23
+ import { registerDeploymentDomainTools } from "./tools/deployment-domains.js";
24
+ import { registerEnvVarTools } from "./tools/env-vars.js";
25
+ import { registerGithubTools } from "./tools/github.js";
26
+ import { registerProjectDatabaseTools } from "./tools/project-databases.js";
27
+ import { registerProjectServiceTools } from "./tools/project-services.js";
28
+ import { registerDeploymentNotificationTools } from "./tools/deployment-notifications.js";
21
29
  const server = new McpServer({
22
30
  name: "selfhost",
23
31
  version: "0.1.0",
@@ -42,14 +50,31 @@ registerAlertTools(server);
42
50
  registerPgBouncerTools(server);
43
51
  // Module 10: Database users (DBMS-level credentials)
44
52
  registerDatabaseUserTools(server);
45
- // Module 11: Scaling — manual + auto-scaling policies + auto start/stop
53
+ // Module 11: Scaling - manual + auto-scaling policies + auto start/stop
46
54
  registerScalingTools(server);
47
55
  // Module 12: Point-in-Time Recovery (Postgres, Pro+)
48
56
  registerPitrTools(server);
49
- // Module 13: Billing — subscriptions + payment-method linking
57
+ // Module 13: Billing - subscriptions + payment-method linking
50
58
  registerBillingTools(server);
51
- // Module 14: Hetzner Cloud — Postgres-only provision/get/status/delete + provider discovery
59
+ // Module 14: Hetzner Cloud - Postgres-only provision/get/status/delete + provider discovery
52
60
  registerHetznerTools(server);
61
+ // ─── PaaS / Apps surface (/api/v1/platform/...) ──────────────────────────────
62
+ // Module 15: Projects - CoolifyProject app-container lifecycle + metrics
63
+ registerProjectTools(server);
64
+ // Module 16: Deployments - GitHub-repo apps, build runs, deploy/redeploy/rollback, logs, health
65
+ registerDeploymentTools(server);
66
+ // Module 17: Custom domains - deployment-scoped add/sync/remove + org DNS verification
67
+ registerDeploymentDomainTools(server);
68
+ // Module 18: Environment variables - list / set (replace) / merge / delete
69
+ registerEnvVarTools(server);
70
+ // Module 19: GitHub - installations (+repos), branches, repo config detection, connect URL
71
+ registerGithubTools(server);
72
+ // Module 20: Project databases - Postgres/Redis/MySQL/MongoDB inside a project
73
+ registerProjectDatabaseTools(server);
74
+ // Module 21: Project services - service templates (Supabase) inside a project
75
+ registerProjectServiceTools(server);
76
+ // Module 22: Deployment notifications - bind/unbind org channels to deploy outcomes
77
+ registerDeploymentNotificationTools(server);
53
78
  // Server utility tools
54
79
  server.tool("reauthenticate", "Clear stored credentials and sign in again (use to switch accounts or fix auth issues)", {}, async () => {
55
80
  try {
@@ -78,7 +103,7 @@ async function main() {
78
103
  if (!(await hasCredentials()) && !(await wasAuthPrompted())) {
79
104
  markAuthPrompted().catch(() => { });
80
105
  getValidToken().catch(() => {
81
- // Timeout or error — user can retry via any tool call
106
+ // Timeout or error - user can retry via any tool call
82
107
  });
83
108
  }
84
109
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerDeploymentDomainTools(server: McpServer): void;
@@ -0,0 +1,128 @@
1
+ import { z } from "zod";
2
+ import { apiRequest } from "../client.js";
3
+ import { session } from "../session.js";
4
+ /**
5
+ * Custom domains for deployments. Two layers:
6
+ * - Deployment-scoped DeploymentDomain (rides on the deployment payload)
7
+ * - Org-scoped CustomDomainVerification (DNS ownership state, shared across deployments)
8
+ *
9
+ * Endpoints:
10
+ * - PATCH /api/v1/platform/github_repo_deployments/:pid/domains full-replace the domain set
11
+ * - POST /api/v1/platform/github_repo_deployments/:pid/domains append one domain
12
+ * - DELETE /api/v1/platform/github_repo_deployments/:pid/domains/:domain remove one
13
+ * - GET /api/v1/platform/custom_domains list org domain verifications
14
+ * - POST /api/v1/platform/custom_domains/:domain/verify check DNS records live
15
+ *
16
+ * Adding a domain auto-creates the org verification record and returns the DNS
17
+ * records (a TXT for ownership + a CNAME for routing) the user must add. A
18
+ * domain only goes live (and gets a cert) once `verify_custom_domain` confirms
19
+ * BOTH records.
20
+ */
21
+ const DEPLOYMENTS_BASE = "/api/v1/platform/github_repo_deployments";
22
+ const CUSTOM_DOMAINS_BASE = "/api/v1/platform/custom_domains";
23
+ const NO_ORG = "No active organization. Call `list_organizations` then `select_organization` first.";
24
+ function hasOrg() {
25
+ return session.getActiveOrgId() !== null;
26
+ }
27
+ function normalizeDomain(domain) {
28
+ return domain.trim().toLowerCase().replace(/^https?:\/\//, "").replace(/\/.*$/, "");
29
+ }
30
+ export function registerDeploymentDomainTools(server) {
31
+ server.tool("sync_deployment_domains", "Set the FULL list of custom domains on a deployment (replaces any existing set - domains not included are removed). Use this to set/change the primary domain or remove several at once. For just adding one domain, prefer `add_deployment_domain`. Each domain that's new auto-creates an org verification record; the response/`get_deployment` then carries the DNS records to add. The deployment must be provisioned (422 otherwise).", {
32
+ deployment_pid: z.string().min(1),
33
+ domains: z.array(z.object({
34
+ domain: z.string().min(1),
35
+ is_primary: z.boolean().optional().describe("Mark this as the primary domain (at most one)"),
36
+ })).describe("The complete desired domain set; replaces the current set atomically"),
37
+ }, async ({ deployment_pid, domains }) => {
38
+ if (!hasOrg())
39
+ return { content: [{ type: "text", text: NO_ORG }] };
40
+ const normalized = domains.map((d) => ({ domain: normalizeDomain(d.domain), is_primary: d.is_primary ?? false }));
41
+ const result = await apiRequest(`${DEPLOYMENTS_BASE}/${deployment_pid}/domains`, {
42
+ method: "PATCH",
43
+ body: { domains: normalized },
44
+ toolName: "sync_deployment_domains",
45
+ });
46
+ if (!result.success) {
47
+ return { content: [{ type: "text", text: `Failed to sync domains (${result.statusCode}): ${result.message}` }] };
48
+ }
49
+ return {
50
+ content: [
51
+ { type: "text", text: "Domains updated. Add the DNS records shown, then call `verify_custom_domain` for each domain. `get_deployment` shows current domain status." },
52
+ { type: "text", text: JSON.stringify(result.data, null, 2) },
53
+ ],
54
+ };
55
+ });
56
+ server.tool("add_deployment_domain", "Add (append) one custom domain to a deployment as its primary domain, keeping any existing domains. Auto-creates the org verification record and returns the DNS records (TXT + CNAME) to configure. After adding the records at your DNS provider, call `verify_custom_domain`. The deployment must be provisioned (422 otherwise).", {
57
+ deployment_pid: z.string().min(1),
58
+ domain: z.string().min(1).describe("e.g. app.example.com (scheme/path are stripped)"),
59
+ }, async ({ deployment_pid, domain }) => {
60
+ if (!hasOrg())
61
+ return { content: [{ type: "text", text: NO_ORG }] };
62
+ const result = await apiRequest(`${DEPLOYMENTS_BASE}/${deployment_pid}/domains`, {
63
+ method: "POST",
64
+ body: { domain: normalizeDomain(domain) },
65
+ toolName: "add_deployment_domain",
66
+ });
67
+ if (!result.success) {
68
+ return { content: [{ type: "text", text: `Failed to add domain (${result.statusCode}): ${result.message}` }] };
69
+ }
70
+ return {
71
+ content: [
72
+ { type: "text", text: "Domain added. Configure the DNS records returned below, then call `verify_custom_domain`." },
73
+ { type: "text", text: JSON.stringify(result.data, null, 2) },
74
+ ],
75
+ };
76
+ });
77
+ server.tool("remove_deployment_domain", "Remove one custom domain from a deployment. The remaining domains are re-synced and primary metadata updated.", {
78
+ deployment_pid: z.string().min(1),
79
+ domain: z.string().min(1),
80
+ }, async ({ deployment_pid, domain }) => {
81
+ if (!hasOrg())
82
+ return { content: [{ type: "text", text: NO_ORG }] };
83
+ const result = await apiRequest(`${DEPLOYMENTS_BASE}/${deployment_pid}/domains/${encodeURIComponent(normalizeDomain(domain))}`, {
84
+ method: "DELETE",
85
+ toolName: "remove_deployment_domain",
86
+ });
87
+ if (!result.success) {
88
+ return { content: [{ type: "text", text: `Failed to remove domain (${result.statusCode}): ${result.message}` }] };
89
+ }
90
+ return {
91
+ content: [
92
+ { type: "text", text: "Domain removed." },
93
+ { type: "text", text: JSON.stringify(result.data, null, 2) },
94
+ ],
95
+ };
96
+ });
97
+ server.tool("verify_custom_domain", "Check a custom domain's DNS records live and advance its verification. The domain must have been added to a deployment first. Outcomes: `verified` (both TXT + CNAME present → domain goes live with HTTPS); `ownership_verified` (TXT only - add the CNAME); `routing_configured` (CNAME only - add the TXT); or 422 `pending_verification` (neither found yet - DNS can take up to 48h). The `checks` object reports each record's status and expected value.", {
98
+ domain: z.string().min(1),
99
+ }, async ({ domain }) => {
100
+ if (!hasOrg())
101
+ return { content: [{ type: "text", text: NO_ORG }] };
102
+ const result = await apiRequest(`${CUSTOM_DOMAINS_BASE}/${encodeURIComponent(normalizeDomain(domain))}/verify`, {
103
+ method: "POST",
104
+ toolName: "verify_custom_domain",
105
+ });
106
+ if (!result.success) {
107
+ const parts = [
108
+ { type: "text", text: `Domain not fully verified yet (${result.statusCode}): ${result.message}` },
109
+ ];
110
+ if (result.data)
111
+ parts.push({ type: "text", text: JSON.stringify(result.data, null, 2) });
112
+ return { content: parts };
113
+ }
114
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
115
+ });
116
+ server.tool("list_custom_domains", "List all custom-domain verifications for the active organization, with each domain's status (pending_verification | ownership_verified | routing_configured | verified) and when it was verified.", {}, async () => {
117
+ if (!hasOrg())
118
+ return { content: [{ type: "text", text: NO_ORG }] };
119
+ const result = await apiRequest(CUSTOM_DOMAINS_BASE, {
120
+ toolName: "list_custom_domains",
121
+ });
122
+ if (!result.success) {
123
+ return { content: [{ type: "text", text: `Failed to list custom domains (${result.statusCode}): ${result.message}` }] };
124
+ }
125
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
126
+ });
127
+ }
128
+ //# sourceMappingURL=deployment-domains.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-domains.js","sourceRoot":"","sources":["../../src/tools/deployment-domains.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerDeploymentNotificationTools(server: McpServer): void;
@@ -0,0 +1,74 @@
1
+ import { z } from "zod";
2
+ import { apiRequest } from "../client.js";
3
+ import { session } from "../session.js";
4
+ /**
5
+ * Deployment notification bindings - link an existing org notification channel
6
+ * (the `nchan_...` channels from `list_notification_channels`) to a deployment,
7
+ * so it's notified on terminal deploy-run outcomes (succeeded / failed / aborted).
8
+ * Binding covers all terminal events; there is no per-event selection.
9
+ *
10
+ * Endpoints (base /api/v1/platform/github_repo_deployments/:pid/notifications):
11
+ * - GET /notifications list enabled bindings
12
+ * - POST /notifications bind a channel (body {notification_channel_pid})
13
+ * - DELETE /notifications/:channel_pid unbind a channel
14
+ *
15
+ * Note: only org OWNERS may manage these bindings. Create the channel itself via
16
+ * `create_notification_channel` first.
17
+ */
18
+ const DEPLOYMENTS_BASE = "/api/v1/platform/github_repo_deployments";
19
+ const NO_ORG = "No active organization. Call `list_organizations` then `select_organization` first.";
20
+ function hasOrg() {
21
+ return session.getActiveOrgId() !== null;
22
+ }
23
+ export function registerDeploymentNotificationTools(server) {
24
+ server.tool("list_deployment_notification_bindings", "List the notification channels bound to a deployment (which channels get notified when a deploy succeeds/fails/aborts). Returns binding_pid, notification_channel_pid, channel_type, name, and bound_at.", {
25
+ deployment_pid: z.string().min(1),
26
+ }, async ({ deployment_pid }) => {
27
+ if (!hasOrg())
28
+ return { content: [{ type: "text", text: NO_ORG }] };
29
+ const result = await apiRequest(`${DEPLOYMENTS_BASE}/${deployment_pid}/notifications`, {
30
+ toolName: "list_deployment_notification_bindings",
31
+ });
32
+ if (!result.success) {
33
+ return { content: [{ type: "text", text: `Failed to list notification bindings (${result.statusCode}): ${result.message}` }] };
34
+ }
35
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
36
+ });
37
+ server.tool("bind_deployment_notification_channel", "Bind an existing org notification channel to a deployment so it's notified on deploy outcomes. The channel pid (nchan_...) comes from `list_notification_channels` (create one with `create_notification_channel` if needed). Returns 422 if already bound, 404 if the channel doesn't exist. Org owner only.", {
38
+ deployment_pid: z.string().min(1),
39
+ notification_channel_pid: z.string().min(1).describe("Org notification channel pid, e.g. nchan_..."),
40
+ }, async ({ deployment_pid, notification_channel_pid }) => {
41
+ if (!hasOrg())
42
+ return { content: [{ type: "text", text: NO_ORG }] };
43
+ const result = await apiRequest(`${DEPLOYMENTS_BASE}/${deployment_pid}/notifications`, {
44
+ method: "POST",
45
+ body: { notification_channel_pid },
46
+ toolName: "bind_deployment_notification_channel",
47
+ });
48
+ if (!result.success) {
49
+ return { content: [{ type: "text", text: `Failed to bind notification channel (${result.statusCode}): ${result.message}` }] };
50
+ }
51
+ return {
52
+ content: [
53
+ { type: "text", text: "Notification channel bound to deployment." },
54
+ { type: "text", text: JSON.stringify(result.data, null, 2) },
55
+ ],
56
+ };
57
+ });
58
+ server.tool("unbind_deployment_notification_channel", "Unbind a notification channel from a deployment (it will no longer be notified on deploy outcomes). Pass the notification_channel_pid (NOT the binding pid). Org owner only.", {
59
+ deployment_pid: z.string().min(1),
60
+ notification_channel_pid: z.string().min(1).describe("The notification channel pid (nchan_...) to unbind"),
61
+ }, async ({ deployment_pid, notification_channel_pid }) => {
62
+ if (!hasOrg())
63
+ return { content: [{ type: "text", text: NO_ORG }] };
64
+ const result = await apiRequest(`${DEPLOYMENTS_BASE}/${deployment_pid}/notifications/${notification_channel_pid}`, {
65
+ method: "DELETE",
66
+ toolName: "unbind_deployment_notification_channel",
67
+ });
68
+ if (!result.success) {
69
+ return { content: [{ type: "text", text: `Failed to unbind notification channel (${result.statusCode}): ${result.message}` }] };
70
+ }
71
+ return { content: [{ type: "text", text: "Notification channel unbound from deployment." }] };
72
+ });
73
+ }
74
+ //# sourceMappingURL=deployment-notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-notifications.js","sourceRoot":"","sources":["../../src/tools/deployment-notifications.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerDeploymentTools(server: McpServer): void;