@selfhost.dev/mcp-server 0.4.0 → 0.4.1
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 +45 -8
- package/dist/auth.d.ts +1 -1
- package/dist/auth.js +3 -3
- package/dist/client.js +1 -1
- package/dist/config.js +1 -1
- package/dist/rate-limiter.js +1 -1
- package/dist/tools/billing.js +14 -14
- package/dist/tools/credentials.js +1 -1
- package/dist/tools/database-users.js +9 -9
- package/dist/tools/hetzner.js +13 -13
- package/dist/tools/instances.js +11 -11
- package/dist/tools/pgbouncer.js +4 -4
- package/dist/tools/pitr.js +16 -16
- package/dist/tools/project-databases.js +3 -3
- package/dist/tools/project-databases.js.map +1 -1
- package/dist/tools/project-services.js +3 -4
- package/dist/tools/project-services.js.map +1 -1
- package/dist/tools/scaling.js +13 -13
- package/dist/types/models.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# SelfHost MCP Server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The [SelfHost](https://selfhost.dev) cloud platform, one sentence away inside your AI coding assistant. Spin up production databases, ship apps straight from GitHub, wire up domains and environment variables, and watch builds stream live, all in plain English without ever leaving your editor.
|
|
4
|
+
|
|
5
|
+
SelfHost pairs the power of production-grade managed databases with the effortless, deploy-from-GitHub simplicity of a modern app platform. This [Model Context Protocol](https://modelcontextprotocol.io/) server puts the whole thing at your fingertips.
|
|
6
|
+
|
|
7
|
+
**Two products, one server:**
|
|
8
|
+
|
|
9
|
+
- **Projects** - your apps, shipped. Connect a GitHub repo, click deploy, and it's live: auto-detected builds (Nixpacks, Dockerfile, Docker Compose, or static), auto-deploy on every push, live streaming build logs, environment variables, custom domains, pause and resume to scale to zero, and databases right inside the project. The ease of Railway, Render, and Vercel, with nothing to manage.
|
|
10
|
+
- **Managed Databases** - production-grade database hosting, your way. PostgreSQL, MySQL, and MongoDB on AWS, or Postgres on Hetzner, in our cloud or your own account (BYOC), with backups, point-in-time recovery, autoscaling, alerting, and connection pooling.
|
|
4
11
|
|
|
5
12
|
Works with **Claude Code**, **Cursor**, **Windsurf**, **Cline**, and any MCP-compatible client.
|
|
6
13
|
|
|
@@ -70,7 +77,29 @@ Claude: Authenticates → fetches your orgs → selects org → lists instances
|
|
|
70
77
|
|
|
71
78
|
## What Can You Do?
|
|
72
79
|
|
|
73
|
-
|
|
80
|
+
Talk to both products in plain English.
|
|
81
|
+
|
|
82
|
+
### Ship and run apps with Projects
|
|
83
|
+
|
|
84
|
+
Connect a repo, deploy, and it's live - SelfHost takes your code from GitHub to a running app.
|
|
85
|
+
|
|
86
|
+
| You say | What happens |
|
|
87
|
+
|---------|-------------|
|
|
88
|
+
| *"Create a project and deploy my GitHub repo into it"* | Provisions the project, waits until it's ready, auto-detects the build, and deploys the repo |
|
|
89
|
+
| *"Deploy the main branch of my-org/api"* | Creates the deployment, triggers the build, and streams live logs until it's running |
|
|
90
|
+
| *"Turn on auto-deploy so every push ships"* | Enables auto-deploy; future pushes to the branch redeploy automatically |
|
|
91
|
+
| *"Add a private Postgres database to my project"* | Provisions a Postgres database inside the project, with the credentials and visibility you choose |
|
|
92
|
+
| *"Spin up Supabase in this project"* | Deploys the Supabase template alongside your app |
|
|
93
|
+
| *"Set DATABASE_URL on my app and redeploy"* | Updates the env var (without wiping the others) and rolls out the change |
|
|
94
|
+
| *"Point app.example.com at my deployment"* | Attaches the custom domain and returns the exact DNS records to add, then verifies them |
|
|
95
|
+
| *"Show me the build logs for the last deploy"* | Streams the build and container logs for that run |
|
|
96
|
+
| *"Pause my staging app so I stop paying for it"* | Pauses the deployment (scales to zero); resume instantly when you need it |
|
|
97
|
+
| *"Roll back to the last working deploy"* | Re-deploys the commit from the previous successful run |
|
|
98
|
+
| *"Notify my team channel when a deploy fails"* | Binds a notification channel to the app's deploy outcomes |
|
|
99
|
+
|
|
100
|
+
### Manage database infrastructure with Managed Databases
|
|
101
|
+
|
|
102
|
+
Production-grade, standalone database hosting.
|
|
74
103
|
|
|
75
104
|
| You say | What happens |
|
|
76
105
|
|---------|-------------|
|
|
@@ -89,12 +118,6 @@ Claude: Authenticates → fetches your orgs → selects org → lists instances
|
|
|
89
118
|
| *"Upgrade my org to the Pro plan"* | Confirms billing state, creates or changes the subscription |
|
|
90
119
|
| *"Spin up a Postgres instance on Hetzner in Helsinki"* | Confirms provider, walks through Hetzner location + server type, provisions on Hetzner Cloud |
|
|
91
120
|
| *"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 |
|
|
98
121
|
|
|
99
122
|
### Safety Built In
|
|
100
123
|
|
|
@@ -386,6 +409,20 @@ Postgres/Redis/MySQL/MongoDB provisioned inside a project (distinct from AWS/Het
|
|
|
386
409
|
|
|
387
410
|
## Common Workflows
|
|
388
411
|
|
|
412
|
+
### Deploy an app from GitHub (Projects)
|
|
413
|
+
|
|
414
|
+
```
|
|
415
|
+
You: "Deploy my-org/web to a new project"
|
|
416
|
+
|
|
417
|
+
Claude: Creates a project → polls until it's provisioned and active
|
|
418
|
+
→ detects the build config from the repo (build pack, port)
|
|
419
|
+
→ creates the deployment and triggers the first build
|
|
420
|
+
→ streams the build logs until the app is live
|
|
421
|
+
→ hands you the deploy URL
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
Then: *"add a private Postgres to it"*, *"set my env vars"*, *"point app.example.com at it"*, or *"turn on auto-deploy"* to round out the app.
|
|
425
|
+
|
|
389
426
|
### Switch AWS Account (BYOC vs Platform-Managed)
|
|
390
427
|
|
|
391
428
|
```
|
package/dist/auth.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export declare function wasAuthPrompted(): Promise<boolean>;
|
|
|
2
2
|
export declare function markAuthPrompted(): Promise<void>;
|
|
3
3
|
/**
|
|
4
4
|
* Returns true if credentials are available (env vars or stored file).
|
|
5
|
-
* No network calls
|
|
5
|
+
* No network calls - just a fast file existence check.
|
|
6
6
|
*/
|
|
7
7
|
export declare function hasCredentials(): Promise<boolean>;
|
|
8
8
|
/**
|
package/dist/auth.js
CHANGED
|
@@ -130,7 +130,7 @@ async function resolveCredentials() {
|
|
|
130
130
|
}
|
|
131
131
|
/**
|
|
132
132
|
* Returns true if credentials are available (env vars or stored file).
|
|
133
|
-
* No network calls
|
|
133
|
+
* No network calls - just a fast file existence check.
|
|
134
134
|
*/
|
|
135
135
|
export async function hasCredentials() {
|
|
136
136
|
if (config.firebaseApiKey && config.firebaseRefreshToken)
|
|
@@ -169,7 +169,7 @@ async function _getValidTokenImpl() {
|
|
|
169
169
|
return jwt;
|
|
170
170
|
}
|
|
171
171
|
catch {
|
|
172
|
-
// Refresh token expired
|
|
172
|
+
// Refresh token expired - re-authenticate via browser
|
|
173
173
|
cachedJwt = null;
|
|
174
174
|
jwtExpiresAt = 0;
|
|
175
175
|
const newCreds = await browserLogin();
|
|
@@ -192,7 +192,7 @@ export async function forceReauth() {
|
|
|
192
192
|
await unlink(config.credentialsPath);
|
|
193
193
|
}
|
|
194
194
|
catch {
|
|
195
|
-
// File may not exist
|
|
195
|
+
// File may not exist - that's fine
|
|
196
196
|
}
|
|
197
197
|
const creds = await browserLogin();
|
|
198
198
|
await saveCredentials(creds.apiKey, creds.refreshToken);
|
package/dist/client.js
CHANGED
|
@@ -63,7 +63,7 @@ export async function apiRequest(path, options = {}) {
|
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
catch (error) {
|
|
66
|
-
// Rate limit errors are thrown before fetch
|
|
66
|
+
// Rate limit errors are thrown before fetch - re-throw as-is
|
|
67
67
|
if (error instanceof Error && error.message.includes("Rate limit")) {
|
|
68
68
|
throw error;
|
|
69
69
|
}
|
package/dist/config.js
CHANGED
|
@@ -5,7 +5,7 @@ function log(message) {
|
|
|
5
5
|
const API_URL = process.env.API_URL || "https://api.selfhost.dev";
|
|
6
6
|
const CONSOLE_URL = process.env.CONSOLE_URL || "https://console.selfhost.dev";
|
|
7
7
|
const TIER_OVERRIDE = process.env.TIER;
|
|
8
|
-
// Headless/CI fallback
|
|
8
|
+
// Headless/CI fallback - skip browser login if these are set
|
|
9
9
|
const FIREBASE_API_KEY = process.env.FIREBASE_API_KEY;
|
|
10
10
|
const FIREBASE_REFRESH_TOKEN = process.env.FIREBASE_REFRESH_TOKEN;
|
|
11
11
|
export const config = {
|
package/dist/rate-limiter.js
CHANGED
|
@@ -43,7 +43,7 @@ class RateLimiter {
|
|
|
43
43
|
this.tier = tier;
|
|
44
44
|
this.isAdmin = tier === "ADMIN";
|
|
45
45
|
if (this.isAdmin) {
|
|
46
|
-
config.log("Admin tier set
|
|
46
|
+
config.log("Admin tier set - rate limits disabled.");
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
49
|
const tierConfig = TIER_CONFIGS[tier];
|
package/dist/tools/billing.js
CHANGED
|
@@ -2,15 +2,15 @@ import { z } from "zod";
|
|
|
2
2
|
import { apiRequest } from "../client.js";
|
|
3
3
|
import { session } from "../session.js";
|
|
4
4
|
/**
|
|
5
|
-
* Billing
|
|
5
|
+
* Billing - subscription lifecycle + payment method linking.
|
|
6
6
|
*
|
|
7
7
|
* Endpoints:
|
|
8
|
-
* - GET /organizations/:pid/billing/subscription
|
|
9
|
-
* - POST /organizations/:pid/billing/subscriptions
|
|
10
|
-
* - PATCH /organizations/:pid/billing/subscriptions
|
|
11
|
-
* - DELETE /organizations/:pid/billing/subscriptions
|
|
12
|
-
* - POST /organizations/:pid/billing/link
|
|
13
|
-
* - PATCH /organizations/:pid/billing/contact
|
|
8
|
+
* - GET /organizations/:pid/billing/subscription - current subscription
|
|
9
|
+
* - POST /organizations/:pid/billing/subscriptions - create (first time)
|
|
10
|
+
* - PATCH /organizations/:pid/billing/subscriptions - change plan (up/downgrade)
|
|
11
|
+
* - DELETE /organizations/:pid/billing/subscriptions - cancel
|
|
12
|
+
* - POST /organizations/:pid/billing/link - initiate Razorpay link
|
|
13
|
+
* - PATCH /organizations/:pid/billing/contact - update contact / tax info
|
|
14
14
|
*
|
|
15
15
|
* All endpoints are org-scoped via the path. The org PID is taken from the
|
|
16
16
|
* MCP session by default; pass `organization_id` to target a different org.
|
|
@@ -55,7 +55,7 @@ export function registerBillingTools(server) {
|
|
|
55
55
|
return {
|
|
56
56
|
content: [{
|
|
57
57
|
type: "text",
|
|
58
|
-
text: "Free is the default
|
|
58
|
+
text: "Free is the default - no subscription needed. Use `change_subscription` with billing_plan=free to downgrade an existing paid subscription.",
|
|
59
59
|
}],
|
|
60
60
|
};
|
|
61
61
|
}
|
|
@@ -79,12 +79,12 @@ export function registerBillingTools(server) {
|
|
|
79
79
|
}
|
|
80
80
|
return {
|
|
81
81
|
content: [
|
|
82
|
-
{ type: "text", text: `Subscription create requested for plan \`${billing_plan}\`. The lifecycle state will move from \`pending\` to \`active\` once Razorpay confirms
|
|
82
|
+
{ type: "text", text: `Subscription create requested for plan \`${billing_plan}\`. The lifecycle state will move from \`pending\` to \`active\` once Razorpay confirms - poll \`get_subscription\`.` },
|
|
83
83
|
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
84
84
|
],
|
|
85
85
|
};
|
|
86
86
|
});
|
|
87
|
-
server.tool("change_subscription", "Change an existing subscription's plan (upgrade or downgrade). Upgrades apply immediately and prorate; downgrades are scheduled at the end of the current billing cycle. A downgrade may return 422 DOWNGRADE_BLOCKED if the org has resources above the target plan's caps (e.g. >3 instances on Starter)
|
|
87
|
+
server.tool("change_subscription", "Change an existing subscription's plan (upgrade or downgrade). Upgrades apply immediately and prorate; downgrades are scheduled at the end of the current billing cycle. A downgrade may return 422 DOWNGRADE_BLOCKED if the org has resources above the target plan's caps (e.g. >3 instances on Starter) - surface the BE error message to the user.", {
|
|
88
88
|
organization_id: z.string().optional(),
|
|
89
89
|
billing_plan: z.enum(PLANS).describe("Target plan"),
|
|
90
90
|
}, async ({ organization_id, billing_plan }) => {
|
|
@@ -144,7 +144,7 @@ export function registerBillingTools(server) {
|
|
|
144
144
|
}
|
|
145
145
|
return {
|
|
146
146
|
content: [
|
|
147
|
-
{ type: "text", text: "Subscription cancellation scheduled
|
|
147
|
+
{ type: "text", text: "Subscription cancellation scheduled - org will move to `cancelling` until cycle end, then `cancelled`." },
|
|
148
148
|
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
149
149
|
],
|
|
150
150
|
};
|
|
@@ -193,12 +193,12 @@ export function registerBillingTools(server) {
|
|
|
193
193
|
}
|
|
194
194
|
return {
|
|
195
195
|
content: [
|
|
196
|
-
{ type: "text", text: "Razorpay link initiated. Open the `short_url` in a browser to add a card / UPI. The MCP can't complete the checkout
|
|
196
|
+
{ type: "text", text: "Razorpay link initiated. Open the `short_url` in a browser to add a card / UPI. The MCP can't complete the checkout - it's a browser-only flow." },
|
|
197
197
|
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
198
198
|
],
|
|
199
199
|
};
|
|
200
200
|
});
|
|
201
|
-
server.tool("update_billing_contact", "Update billing contact info on an already-linked org. Doesn't re-run Razorpay
|
|
201
|
+
server.tool("update_billing_contact", "Update billing contact info on an already-linked org. Doesn't re-run Razorpay - only persists DB overrides for invoices.", {
|
|
202
202
|
organization_id: z.string().optional(),
|
|
203
203
|
billing_contact_phone: z.string().optional(),
|
|
204
204
|
tax_id: z.string().optional()
|
|
@@ -224,7 +224,7 @@ export function registerBillingTools(server) {
|
|
|
224
224
|
return {
|
|
225
225
|
content: [{
|
|
226
226
|
type: "text",
|
|
227
|
-
text: "No changes to apply
|
|
227
|
+
text: "No changes to apply - pass at least one of billing_contact_phone / tax_id / country_code / state_code.",
|
|
228
228
|
}],
|
|
229
229
|
};
|
|
230
230
|
}
|
|
@@ -15,7 +15,7 @@ When selecting credentials for instance creation:
|
|
|
15
15
|
- Filter by cloud_provider matching the user's chosen provider (e.g. "aws")
|
|
16
16
|
- Only use credentials with status "active"
|
|
17
17
|
- is_platform_managed=true → SelfHost's cloud account (no VPC needed)
|
|
18
|
-
- is_platform_managed=false → user's own cloud account (BYOC
|
|
18
|
+
- is_platform_managed=false → user's own cloud account (BYOC - VPC required, use list_vpcs)
|
|
19
19
|
- Present the user with a choice between platform-managed and their own credentials`, {
|
|
20
20
|
organization_id: z.string().optional().describe("Organization PID (defaults to active org)"),
|
|
21
21
|
}, async ({ organization_id }) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { apiRequest } from "../client.js";
|
|
3
3
|
/**
|
|
4
|
-
* Database users
|
|
4
|
+
* Database users - DBMS-level credentials (distinct from the platform login).
|
|
5
5
|
*
|
|
6
6
|
* Endpoints:
|
|
7
7
|
* - GET /aws/v1/instances/:id/database_users
|
|
@@ -70,12 +70,12 @@ export function registerDatabaseUserTools(server) {
|
|
|
70
70
|
}
|
|
71
71
|
return {
|
|
72
72
|
content: [
|
|
73
|
-
{ type: "text", text: `Database user \`${username}\` create requested. Status will transition from \`pending\` to \`active\` once applied
|
|
73
|
+
{ type: "text", text: `Database user \`${username}\` create requested. Status will transition from \`pending\` to \`active\` once applied - poll \`list_database_users\`.` },
|
|
74
74
|
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
75
75
|
],
|
|
76
76
|
};
|
|
77
77
|
});
|
|
78
|
-
server.tool("update_database_user", "Update a database user
|
|
78
|
+
server.tool("update_database_user", "Update a database user - change role, connection limit, or password expiry. Username and target database are immutable (delete + recreate to change them).", {
|
|
79
79
|
instance_id: z.string().min(1),
|
|
80
80
|
user_id: z.string().min(1).describe("Database user PID (from list_database_users)"),
|
|
81
81
|
role: z.enum(ROLES).optional(),
|
|
@@ -94,7 +94,7 @@ export function registerDatabaseUserTools(server) {
|
|
|
94
94
|
return {
|
|
95
95
|
content: [{
|
|
96
96
|
type: "text",
|
|
97
|
-
text: "No changes to apply
|
|
97
|
+
text: "No changes to apply - pass at least one of role / connection_limit / password_expiry_days.",
|
|
98
98
|
}],
|
|
99
99
|
};
|
|
100
100
|
}
|
|
@@ -114,7 +114,7 @@ export function registerDatabaseUserTools(server) {
|
|
|
114
114
|
}
|
|
115
115
|
return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
|
|
116
116
|
});
|
|
117
|
-
server.tool("delete_database_user", "Soft-delete a database user. Existing connections opened by this user are terminated. The record is preserved for audit
|
|
117
|
+
server.tool("delete_database_user", "Soft-delete a database user. Existing connections opened by this user are terminated. The record is preserved for audit - contact support to recover.", {
|
|
118
118
|
instance_id: z.string().min(1),
|
|
119
119
|
user_id: z.string().min(1),
|
|
120
120
|
username: z.string().optional().describe("Username for the confirmation message (cosmetic)"),
|
|
@@ -142,9 +142,9 @@ export function registerDatabaseUserTools(server) {
|
|
|
142
142
|
}],
|
|
143
143
|
};
|
|
144
144
|
}
|
|
145
|
-
return { content: [{ type: "text", text: "Database user delete requested
|
|
145
|
+
return { content: [{ type: "text", text: "Database user delete requested - status will move to `deleting` and then disappear from the list." }] };
|
|
146
146
|
});
|
|
147
|
-
server.tool("rotate_database_user_password", "Rotate the password for a database user. The new password is generated server-side and returned ONCE in the response. SECURITY: save it immediately
|
|
147
|
+
server.tool("rotate_database_user_password", "Rotate the password for a database user. The new password is generated server-side and returned ONCE in the response. SECURITY: save it immediately - there is no way to retrieve it later. Existing connections using the old password are terminated.", {
|
|
148
148
|
instance_id: z.string().min(1),
|
|
149
149
|
user_id: z.string().min(1),
|
|
150
150
|
confirm: z.boolean().describe("Must be true. Old password is invalidated immediately; apps and scripts must pick up the new value."),
|
|
@@ -153,7 +153,7 @@ export function registerDatabaseUserTools(server) {
|
|
|
153
153
|
return {
|
|
154
154
|
content: [{
|
|
155
155
|
type: "text",
|
|
156
|
-
text: `⚠️ About to ROTATE the password for database user ${user_id} on instance ${instance_id}.\n\nThe new password is shown ONCE in the response
|
|
156
|
+
text: `⚠️ About to ROTATE the password for database user ${user_id} on instance ${instance_id}.\n\nThe new password is shown ONCE in the response - save it before doing anything else.\nApps and scripts using the old password will lose connections immediately.\n\nCall again with confirm=true to proceed.`,
|
|
157
157
|
}],
|
|
158
158
|
};
|
|
159
159
|
}
|
|
@@ -172,7 +172,7 @@ export function registerDatabaseUserTools(server) {
|
|
|
172
172
|
}
|
|
173
173
|
return {
|
|
174
174
|
content: [
|
|
175
|
-
{ type: "text", text: "🔑 New password generated. Copy it now
|
|
175
|
+
{ type: "text", text: "🔑 New password generated. Copy it now - it will not be shown again." },
|
|
176
176
|
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
177
177
|
],
|
|
178
178
|
};
|
package/dist/tools/hetzner.js
CHANGED
|
@@ -2,17 +2,17 @@ import { z } from "zod";
|
|
|
2
2
|
import { apiRequest } from "../client.js";
|
|
3
3
|
import { session } from "../session.js";
|
|
4
4
|
/**
|
|
5
|
-
* Hetzner Cloud
|
|
5
|
+
* Hetzner Cloud - Postgres-only provisioning.
|
|
6
6
|
*
|
|
7
7
|
* Backend endpoints (added in selfhost-dev/selfhost PR #983):
|
|
8
|
-
* - POST /hetzner/v1/instances
|
|
9
|
-
* - GET /hetzner/v1/instances/:pid
|
|
10
|
-
* - GET /hetzner/v1/instances/:pid/status
|
|
11
|
-
* - DELETE /hetzner/v1/instances/:pid
|
|
8
|
+
* - POST /hetzner/v1/instances - provision
|
|
9
|
+
* - GET /hetzner/v1/instances/:pid - read
|
|
10
|
+
* - GET /hetzner/v1/instances/:pid/status - provisioning progress
|
|
11
|
+
* - DELETE /hetzner/v1/instances/:pid - destroy
|
|
12
12
|
*
|
|
13
13
|
* Limitations vs AWS today:
|
|
14
14
|
* - Postgres only (no MySQL, no MongoDB)
|
|
15
|
-
* - No list endpoint
|
|
15
|
+
* - No list endpoint - callers must keep track of `pid` after create
|
|
16
16
|
* - No start / stop / reboot / update / fork
|
|
17
17
|
* - No scaling, no PITR, no PgBouncer, no database-user management
|
|
18
18
|
*
|
|
@@ -70,7 +70,7 @@ const SERVER_TYPE_CODES = HETZNER_SERVER_TYPES.map((s) => s.code);
|
|
|
70
70
|
// --- Registration ------------------------------------------------------------
|
|
71
71
|
export function registerHetznerTools(server) {
|
|
72
72
|
// ----- Provider discovery -------------------------------------------------
|
|
73
|
-
server.tool("list_cloud_providers", "List the cloud providers SelfHost can provision Postgres on. Call this whenever the user expresses an intent to create a database
|
|
73
|
+
server.tool("list_cloud_providers", "List the cloud providers SelfHost can provision Postgres on. Call this whenever the user expresses an intent to create a database - present the options and ask which one they want before choosing the create tool. The response includes capabilities and the specific create tool for each provider.", {}, async () => {
|
|
74
74
|
return {
|
|
75
75
|
content: [
|
|
76
76
|
{ type: "text", text: JSON.stringify(CLOUD_PROVIDERS, null, 2) },
|
|
@@ -102,7 +102,7 @@ RECOMMENDED FLOW:
|
|
|
102
102
|
5. Then call this tool.
|
|
103
103
|
|
|
104
104
|
IMPORTANT:
|
|
105
|
-
- The password returned in the response is shown ONCE. Save it immediately
|
|
105
|
+
- The password returned in the response is shown ONCE. Save it immediately - there's no way to retrieve it.
|
|
106
106
|
- Hetzner integration is currently provision/delete only. After creation, use \`get_hetzner_instance_status\` to poll provisioning progress, and \`get_hetzner_instance\` to read details. To remove it, use \`delete_hetzner_instance\`.
|
|
107
107
|
- Provisioning takes ~5-10 minutes (network + firewall + SSH key + server + volume + load balancer + Ansible/autobase playbook + Cloudflare DNS).`, {
|
|
108
108
|
organization_id: z.string().optional()
|
|
@@ -110,9 +110,9 @@ IMPORTANT:
|
|
|
110
110
|
name: z.string().min(1).max(63)
|
|
111
111
|
.describe("Instance name (used for DNS host)"),
|
|
112
112
|
region: z.enum(LOCATION_CODES)
|
|
113
|
-
.describe("Hetzner location code
|
|
113
|
+
.describe("Hetzner location code - call list_hetzner_locations to see options"),
|
|
114
114
|
server_type: z.enum(SERVER_TYPE_CODES)
|
|
115
|
-
.describe("Hetzner server type
|
|
115
|
+
.describe("Hetzner server type - call list_hetzner_server_types to see options"),
|
|
116
116
|
storage_size: z.number().int().min(10).max(10240)
|
|
117
117
|
.describe("Database storage size in GB (Hetzner Volume, separate from server local disk)"),
|
|
118
118
|
db_version: z.string().optional()
|
|
@@ -182,10 +182,10 @@ IMPORTANT:
|
|
|
182
182
|
if (data.password) {
|
|
183
183
|
lines.push(`Password: ${data.password}`);
|
|
184
184
|
lines.push("");
|
|
185
|
-
lines.push("⚠️ SAVE THIS PASSWORD NOW
|
|
185
|
+
lines.push("⚠️ SAVE THIS PASSWORD NOW - it cannot be retrieved again.");
|
|
186
186
|
}
|
|
187
187
|
lines.push("");
|
|
188
|
-
lines.push(`Poll provisioning progress with \`get_hetzner_instance_status\` (pid: ${data.pid}). Provisioning typically takes 5
|
|
188
|
+
lines.push(`Poll provisioning progress with \`get_hetzner_instance_status\` (pid: ${data.pid}). Provisioning typically takes 5-10 minutes.`);
|
|
189
189
|
return {
|
|
190
190
|
content: [
|
|
191
191
|
{ type: "text", text: lines.join("\n") },
|
|
@@ -227,7 +227,7 @@ IMPORTANT:
|
|
|
227
227
|
}
|
|
228
228
|
return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
|
|
229
229
|
});
|
|
230
|
-
server.tool("delete_hetzner_instance", "Delete a Hetzner instance and all associated resources (server, volume, firewall, network, load balancer if HA, DNS record). IRREVERSIBLE
|
|
230
|
+
server.tool("delete_hetzner_instance", "Delete a Hetzner instance and all associated resources (server, volume, firewall, network, load balancer if HA, DNS record). IRREVERSIBLE - there's no `start` / `stop` on Hetzner; deletion is the only way to remove an instance.", {
|
|
231
231
|
pid: z.string().min(1),
|
|
232
232
|
confirm: z.boolean().describe("Must be true to proceed. ALL DATA on this instance will be permanently lost."),
|
|
233
233
|
}, async ({ pid, confirm }) => {
|
package/dist/tools/instances.js
CHANGED
|
@@ -179,14 +179,14 @@ Returns an itemized cost breakdown including compute, storage, markup, and add-o
|
|
|
179
179
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
180
180
|
});
|
|
181
181
|
// --- Instance lifecycle tools ---
|
|
182
|
-
server.tool("create_instance", `Create a new database instance on AWS. This is the core AWS provisioning tool. For Hetzner Cloud, use \`create_hetzner_instance\` instead
|
|
182
|
+
server.tool("create_instance", `Create a new database instance on AWS. This is the core AWS provisioning tool. For Hetzner Cloud, use \`create_hetzner_instance\` instead - call \`list_cloud_providers\` first to confirm which provider the user wants.
|
|
183
183
|
|
|
184
184
|
RECOMMENDED FLOW (follow this before calling create_instance):
|
|
185
185
|
1. Ask the user: host on SelfHost's cloud (platform-managed) or their own AWS account (BYOC)?
|
|
186
|
-
2. Call list_credentials
|
|
186
|
+
2. Call list_credentials - filter results by cloud_provider matching chosen provider AND status "active".
|
|
187
187
|
- Platform-managed: pick credential where is_platform_managed=true
|
|
188
188
|
- BYOC: pick credential where is_platform_managed=false. If none exist, user must add_credential first.
|
|
189
|
-
3. If BYOC: call list_vpcs with the credential's id and chosen region
|
|
189
|
+
3. If BYOC: call list_vpcs with the credential's id and chosen region - only present VPCs from the "public" group. vpc_id is REQUIRED for BYOC.
|
|
190
190
|
4. If platform-managed: vpc_id is NOT needed (skip VPC selection entirely).
|
|
191
191
|
5. Call estimate_instance_cost to show the user the estimated monthly cost before deploying.
|
|
192
192
|
6. Only call create_instance after the user confirms the cost is acceptable.
|
|
@@ -209,7 +209,7 @@ IMPORTANT:
|
|
|
209
209
|
custom_password: z.string().min(8).max(128).optional().describe("Database password (8-128 printable ASCII chars). Auto-generated if omitted."),
|
|
210
210
|
description: z.string().optional(),
|
|
211
211
|
cloud_credential_id: z.string().optional().describe("Credential PID from list_credentials. Use is_platform_managed=true credential for SelfHost's cloud, or is_platform_managed=false for BYOC. Always ask the user which they prefer."),
|
|
212
|
-
vpc_id: z.string().optional().describe("VPC ID
|
|
212
|
+
vpc_id: z.string().optional().describe("VPC ID - REQUIRED when using BYOC credentials (is_platform_managed=false). Use list_vpcs and only pick from the 'public' group. Not needed for platform-managed."),
|
|
213
213
|
multi_az: z.boolean().optional().describe("Enable multi-AZ replication (default: false)"),
|
|
214
214
|
replica_count: z.number().int().min(1).max(2).optional().describe("Number of replicas if multi_az (1 or 2)"),
|
|
215
215
|
delete_protection: z.boolean().optional().describe("Prevent accidental deletion (default: true recommended)"),
|
|
@@ -235,7 +235,7 @@ IMPORTANT:
|
|
|
235
235
|
if (params.storage.size < spec.minSize) {
|
|
236
236
|
return { content: [{ type: "text", text: `For ${params.storage.type}, storage size must be at least ${spec.minSize} GiB` }] };
|
|
237
237
|
}
|
|
238
|
-
// Build request body
|
|
238
|
+
// Build request body - only include defined fields
|
|
239
239
|
const body = {
|
|
240
240
|
organization_id: orgId,
|
|
241
241
|
identifier: params.identifier,
|
|
@@ -247,7 +247,7 @@ IMPORTANT:
|
|
|
247
247
|
iops: params.storage.iops ?? 0,
|
|
248
248
|
throughput: params.storage.throughput ?? 0,
|
|
249
249
|
},
|
|
250
|
-
public_access: true, // Always true
|
|
250
|
+
public_access: true, // Always true - private access not yet supported
|
|
251
251
|
};
|
|
252
252
|
if (params.db_version)
|
|
253
253
|
body.db_version = params.db_version;
|
|
@@ -306,7 +306,7 @@ IMPORTANT:
|
|
|
306
306
|
`Username: ${data.username}`,
|
|
307
307
|
`Password: ${data.password}`,
|
|
308
308
|
"",
|
|
309
|
-
"⚠️ SAVE THIS PASSWORD NOW
|
|
309
|
+
"⚠️ SAVE THIS PASSWORD NOW - it cannot be retrieved again.",
|
|
310
310
|
"",
|
|
311
311
|
`Group ID: ${data.group_id}`,
|
|
312
312
|
`Organization: ${data.organization_id}`,
|
|
@@ -357,7 +357,7 @@ IMPORTANT:
|
|
|
357
357
|
}
|
|
358
358
|
return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
|
|
359
359
|
});
|
|
360
|
-
server.tool("update_instance", "Update an instance's configuration. Some changes are synchronous (db_port, backup, CIDR ranges), others are async (instance_type, multi_az, storage). Cannot update replicas
|
|
360
|
+
server.tool("update_instance", "Update an instance's configuration. Some changes are synchronous (db_port, backup, CIDR ranges), others are async (instance_type, multi_az, storage). Cannot update replicas - update the master instead.", {
|
|
361
361
|
instance_id: z.string().min(1, "Instance PID is required"),
|
|
362
362
|
identifier: z.string().optional().describe("New instance name"),
|
|
363
363
|
delete_protection: z.boolean().optional(),
|
|
@@ -400,7 +400,7 @@ IMPORTANT:
|
|
|
400
400
|
],
|
|
401
401
|
};
|
|
402
402
|
});
|
|
403
|
-
server.tool("stop_instance", "DESTRUCTIVE: Stop one or more running database instances. Databases will become unavailable. Cannot stop replicas independently
|
|
403
|
+
server.tool("stop_instance", "DESTRUCTIVE: Stop one or more running database instances. Databases will become unavailable. Cannot stop replicas independently - stop the master to stop all. You MUST set confirm=true to proceed.", {
|
|
404
404
|
pids: z.array(z.string().min(1)).min(1, "At least one instance PID is required"),
|
|
405
405
|
confirm: z.boolean().describe("Must be true to proceed. Ask the user for explicit confirmation before setting this."),
|
|
406
406
|
}, async ({ pids, confirm }) => {
|
|
@@ -489,7 +489,7 @@ You MUST set confirm=true to proceed. Before calling this tool, always ask the u
|
|
|
489
489
|
}
|
|
490
490
|
return { content: [{ type: "text", text: `Instance(s) ${pids.join(", ")} deletion initiated.` }] };
|
|
491
491
|
});
|
|
492
|
-
server.tool("fork_instance", "Fork (clone) an existing database instance into a new independent instance. Cannot fork replicas or deleted instances. Returns a new password
|
|
492
|
+
server.tool("fork_instance", "Fork (clone) an existing database instance into a new independent instance. Cannot fork replicas or deleted instances. Returns a new password - save it immediately.", {
|
|
493
493
|
instance_id: z.string().min(1, "Source instance PID is required"),
|
|
494
494
|
instance_name: z.string().min(1, "Name for the forked instance"),
|
|
495
495
|
cloud_credential_id: z.string().optional().describe("Credential PID (defaults to source instance's credential)"),
|
|
@@ -518,7 +518,7 @@ You MUST set confirm=true to proceed. Before calling this tool, always ask the u
|
|
|
518
518
|
`Username: ${data.username}`,
|
|
519
519
|
`Password: ${data.password}`,
|
|
520
520
|
"",
|
|
521
|
-
"⚠️ SAVE THIS PASSWORD NOW
|
|
521
|
+
"⚠️ SAVE THIS PASSWORD NOW - it cannot be retrieved again.",
|
|
522
522
|
"",
|
|
523
523
|
`Group ID: ${data.group_id}`,
|
|
524
524
|
`Organization: ${data.organization_id}`,
|
package/dist/tools/pgbouncer.js
CHANGED
|
@@ -71,7 +71,7 @@ export function registerPgBouncerTools(server) {
|
|
|
71
71
|
}
|
|
72
72
|
return {
|
|
73
73
|
content: [
|
|
74
|
-
{ type: "text", text: "PgBouncer enable requested
|
|
74
|
+
{ type: "text", text: "PgBouncer enable requested - status will transition to `enabled` once the configuration is applied. Poll `get_pgbouncer` to track progress." },
|
|
75
75
|
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
76
76
|
],
|
|
77
77
|
};
|
|
@@ -99,7 +99,7 @@ export function registerPgBouncerTools(server) {
|
|
|
99
99
|
return {
|
|
100
100
|
content: [{
|
|
101
101
|
type: "text",
|
|
102
|
-
text: "No changes to apply
|
|
102
|
+
text: "No changes to apply - pass at least one of pool_mode / max_client_conn / default_pool_size / min_pool_size / reserve_pool_size.",
|
|
103
103
|
}],
|
|
104
104
|
};
|
|
105
105
|
}
|
|
@@ -119,7 +119,7 @@ export function registerPgBouncerTools(server) {
|
|
|
119
119
|
}
|
|
120
120
|
return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
|
|
121
121
|
});
|
|
122
|
-
server.tool("disable_pgbouncer", "Disable PgBouncer on an instance. Existing connections drain gracefully. The config row is preserved so you can re-enable later with `enable_pgbouncer`. Valid from `enabled` or `error` state
|
|
122
|
+
server.tool("disable_pgbouncer", "Disable PgBouncer on an instance. Existing connections drain gracefully. The config row is preserved so you can re-enable later with `enable_pgbouncer`. Valid from `enabled` or `error` state - use this to recover from `error`.", {
|
|
123
123
|
instance_id: z.string().min(1),
|
|
124
124
|
confirm: z.boolean().describe("Must be true to proceed. Disabling will drop pool warmth and force clients back to port 5432."),
|
|
125
125
|
}, async ({ instance_id, confirm }) => {
|
|
@@ -146,7 +146,7 @@ export function registerPgBouncerTools(server) {
|
|
|
146
146
|
}
|
|
147
147
|
return {
|
|
148
148
|
content: [
|
|
149
|
-
{ type: "text", text: "PgBouncer disable requested
|
|
149
|
+
{ type: "text", text: "PgBouncer disable requested - clients should switch to port 5432." },
|
|
150
150
|
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
151
151
|
],
|
|
152
152
|
};
|
package/dist/tools/pitr.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { apiRequest } from "../client.js";
|
|
3
3
|
/**
|
|
4
|
-
* Point-in-Time Recovery (PITR)
|
|
4
|
+
* Point-in-Time Recovery (PITR) - continuous WAL archiving to S3 + restore
|
|
5
5
|
* to any second within the retention window.
|
|
6
6
|
*
|
|
7
7
|
* Endpoints:
|
|
8
|
-
* - GET /aws/v1/instances/:id/pitr
|
|
9
|
-
* - POST /aws/v1/instances/:id/pitr
|
|
10
|
-
* - PUT /aws/v1/instances/:id/pitr/configure
|
|
11
|
-
* - POST /aws/v1/instances/:id/pitr/retry
|
|
12
|
-
* - POST /aws/v1/instances/:id/pitr/base_backup
|
|
13
|
-
* - GET /aws/v1/instances/:id/pitr/base_backups
|
|
14
|
-
* - POST /aws/v1/instances/:id/pitr/restore
|
|
8
|
+
* - GET /aws/v1/instances/:id/pitr - current config + restore window
|
|
9
|
+
* - POST /aws/v1/instances/:id/pitr - enable
|
|
10
|
+
* - PUT /aws/v1/instances/:id/pitr/configure - toggle enabled/disabled
|
|
11
|
+
* - POST /aws/v1/instances/:id/pitr/retry - recover from error
|
|
12
|
+
* - POST /aws/v1/instances/:id/pitr/base_backup - trigger one-off backup
|
|
13
|
+
* - GET /aws/v1/instances/:id/pitr/base_backups - list base backups
|
|
14
|
+
* - POST /aws/v1/instances/:id/pitr/restore - restore to point-in-time
|
|
15
15
|
*
|
|
16
16
|
* Postgres-only, Pro+ plan only. Status: configuring | enabled | disabled |
|
|
17
|
-
* error. Restore creates a NEW instance
|
|
17
|
+
* error. Restore creates a NEW instance - the source stays untouched.
|
|
18
18
|
*/
|
|
19
19
|
const PITR_TOGGLE = ["enabled", "disabled"];
|
|
20
20
|
export function registerPitrTools(server) {
|
|
@@ -35,7 +35,7 @@ export function registerPitrTools(server) {
|
|
|
35
35
|
}
|
|
36
36
|
return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
|
|
37
37
|
});
|
|
38
|
-
server.tool("enable_pitr", "Enable PITR on a Postgres instance
|
|
38
|
+
server.tool("enable_pitr", "Enable PITR on a Postgres instance - streams WAL to S3 continuously and takes nightly base backups. The S3 bucket must exist in the same region; the instance role needs s3:PutObject / GetObject / ListBucket. Status transitions: configuring → enabled (or error).", {
|
|
39
39
|
instance_id: z.string().min(1),
|
|
40
40
|
s3_bucket: z.string().min(3).max(63).regex(/^[a-z0-9.-]+$/, "lowercase letters, digits, dots, hyphens only")
|
|
41
41
|
.describe("S3 bucket name (must exist in same region)"),
|
|
@@ -65,7 +65,7 @@ export function registerPitrTools(server) {
|
|
|
65
65
|
});
|
|
66
66
|
server.tool("configure_pitr", "Toggle an existing PITR config between `enabled` (resume WAL archiving) and `disabled` (pause). The bucket and retention are preserved either way. Use `enable_pitr` for first-time setup, not this.", {
|
|
67
67
|
instance_id: z.string().min(1),
|
|
68
|
-
status: z.enum(PITR_TOGGLE).describe("Target state
|
|
68
|
+
status: z.enum(PITR_TOGGLE).describe("Target state - enabled resumes WAL, disabled pauses it"),
|
|
69
69
|
}, async ({ instance_id, status }) => {
|
|
70
70
|
const result = await apiRequest(`/aws/v1/instances/${instance_id}/pitr/configure`, {
|
|
71
71
|
method: "PUT",
|
|
@@ -86,8 +86,8 @@ export function registerPitrTools(server) {
|
|
|
86
86
|
{
|
|
87
87
|
type: "text",
|
|
88
88
|
text: status === "enabled"
|
|
89
|
-
? "PITR resumed
|
|
90
|
-
: "PITR paused
|
|
89
|
+
? "PITR resumed - WAL archiving is back on."
|
|
90
|
+
: "PITR paused - no new WAL or base backups. Existing backups are preserved.",
|
|
91
91
|
},
|
|
92
92
|
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
93
93
|
],
|
|
@@ -116,7 +116,7 @@ export function registerPitrTools(server) {
|
|
|
116
116
|
],
|
|
117
117
|
};
|
|
118
118
|
});
|
|
119
|
-
server.tool("trigger_pitr_base_backup", "Trigger a one-off base backup now. The backup runs `wal-g backup-push` in the background
|
|
119
|
+
server.tool("trigger_pitr_base_backup", "Trigger a one-off base backup now. The backup runs `wal-g backup-push` in the background - your instance keeps serving traffic. Useful before risky migrations or to seed the restore window after a fresh enable.", {
|
|
120
120
|
instance_id: z.string().min(1),
|
|
121
121
|
}, async ({ instance_id }) => {
|
|
122
122
|
const result = await apiRequest(`/aws/v1/instances/${instance_id}/pitr/base_backup`, {
|
|
@@ -134,7 +134,7 @@ export function registerPitrTools(server) {
|
|
|
134
134
|
}
|
|
135
135
|
return {
|
|
136
136
|
content: [
|
|
137
|
-
{ type: "text", text: "Base backup triggered. Track it via `list_pitr_base_backups`
|
|
137
|
+
{ type: "text", text: "Base backup triggered. Track it via `list_pitr_base_backups` - status moves pending → running → completed (or failed)." },
|
|
138
138
|
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
139
139
|
],
|
|
140
140
|
};
|
|
@@ -156,7 +156,7 @@ export function registerPitrTools(server) {
|
|
|
156
156
|
}
|
|
157
157
|
return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
|
|
158
158
|
});
|
|
159
|
-
server.tool("restore_pitr", "Restore an instance to a point in time. Creates a NEW Postgres instance recovered to `target_time`
|
|
159
|
+
server.tool("restore_pitr", "Restore an instance to a point in time. Creates a NEW Postgres instance recovered to `target_time` - the source instance is untouched. `target_time` must fall within the source instance's [oldest_restore_point, latest_restore_point] window (see `get_pitr`). `name` is the new instance name; must start with a letter and use letters/digits/hyphens only.", {
|
|
160
160
|
instance_id: z.string().min(1).describe("Source instance to restore FROM"),
|
|
161
161
|
target_time: z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?$/, "ISO 8601 timestamp, ideally with Z suffix (UTC)").describe("Target moment, e.g. 2026-05-12T14:30:00Z"),
|
|
162
162
|
name: z.string().regex(/^[a-zA-Z][a-zA-Z0-9-]{0,62}$/, "1-63 chars, must start with a letter")
|
|
@@ -49,11 +49,11 @@ export function registerProjectDatabaseTools(server) {
|
|
|
49
49
|
}
|
|
50
50
|
return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
|
|
51
51
|
});
|
|
52
|
-
server.tool("create_project_database", "Create a database inside a project (provisioned via Coolify; returns 202, status starts `creating` - poll `list_project_databases`). The project must be `active`. Provide the type-specific credentials (see fields). Passwords must be 8+ chars with no spaces or shell-dangerous chars.
|
|
52
|
+
server.tool("create_project_database", "Create a database inside a project (provisioned via Coolify; returns 202, status starts `creating` - poll `list_project_databases`). The project must be `active`. Provide the type-specific credentials (see fields). Passwords must be 8+ chars with no spaces or shell-dangerous chars. `is_public` is REQUIRED and has no default: ASK THE USER whether the database should be publicly reachable on a port (convenient for external clients but exposes it to the internet) or kept private to the project (safer). Do not assume.", {
|
|
53
53
|
project_pid: z.string().min(1),
|
|
54
54
|
db_type: z.enum(DB_TYPES).describe("postgres | redis | mysql | mongodb"),
|
|
55
55
|
name: z.string().min(1).max(255),
|
|
56
|
-
is_public: z.boolean().
|
|
56
|
+
is_public: z.boolean().describe("Required choice (ask the user, do not assume): true = expose on a public port (internet-reachable); false = private to the project."),
|
|
57
57
|
public_port: z.number().int().min(1024).max(65535).optional().describe("Public port when is_public (defaults: pg 5432, redis 6379, mysql 3306, mongo 27017)"),
|
|
58
58
|
// postgres
|
|
59
59
|
postgres_user: z.string().max(255).optional(),
|
|
@@ -74,7 +74,7 @@ export function registerProjectDatabaseTools(server) {
|
|
|
74
74
|
if (!hasOrg())
|
|
75
75
|
return { content: [{ type: "text", text: NO_ORG }] };
|
|
76
76
|
const dbType = args.db_type;
|
|
77
|
-
const isPublic = args.is_public
|
|
77
|
+
const isPublic = args.is_public;
|
|
78
78
|
const body = { name: args.name, is_public: isPublic };
|
|
79
79
|
if (isPublic)
|
|
80
80
|
body.public_port = args.public_port ?? DEFAULT_PORTS[dbType];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-databases.js","sourceRoot":"","sources":["../../src/tools/project-databases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC;;;;;;;;;;;;GAYG;AAEH,MAAM,aAAa,GAAG,2BAA2B,CAAC;AAClD,MAAM,QAAQ,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAU,CAAC;AAGpE,uEAAuE;AACvE,MAAM,WAAW,GAAG,yCAAyC,CAAC;AAC9D,MAAM,aAAa,GAA2B,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAE3G,MAAM,MAAM,GACV,qFAAqF,CAAC;AAExF,SAAS,MAAM;IACb,OAAO,OAAO,CAAC,cAAc,EAAE,KAAK,IAAI,CAAC;AAC3C,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,aAAa,CAAC,KAAa,EAAE,CAAqB;IACzD,IAAI,CAAC,CAAC;QAAE,OAAO,GAAG,KAAK,sCAAsC,CAAC;IAC9D,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,GAAG,KAAK,iCAAiC,CAAC;IACnE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,GAAG,KAAK,oEAAoE,CAAC;IAC9G,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,MAAiB;IAC5D,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,kRAAkR,EAClR;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;KAC/B,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,IAAI,CAAC,MAAM,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACpE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAU,GAAG,aAAa,IAAI,WAAW,YAAY,EAAE;YACpF,QAAQ,EAAE,wBAAwB;SACnC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qCAAqC,MAAM,CAAC,UAAU,MAAM,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;QAC7H,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACrF,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,yBAAyB,EACzB,
|
|
1
|
+
{"version":3,"file":"project-databases.js","sourceRoot":"","sources":["../../src/tools/project-databases.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,13 +33,13 @@ export function registerProjectServiceTools(server) {
|
|
|
33
33
|
}
|
|
34
34
|
return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
|
|
35
35
|
});
|
|
36
|
-
server.tool("create_project_service", "Deploy a service template into a project (currently only `supabase`). Returns 202, status starts `creating` - poll `list_project_services`. The project must be `active`. The dashboard password must be 8+ characters.", {
|
|
36
|
+
server.tool("create_project_service", "Deploy a service template into a project (currently only `supabase`). Returns 202, status starts `creating` - poll `list_project_services`. The project must be `active`. The dashboard password must be 8+ characters. `is_public` is REQUIRED and has no default: ASK THE USER whether the service should be publicly reachable (internet-exposed) or private to the project. Do not assume.", {
|
|
37
37
|
project_pid: z.string().min(1),
|
|
38
38
|
template_type: z.enum(TEMPLATE_TYPES).describe("Service template (only `supabase` is supported today)"),
|
|
39
39
|
name: z.string().min(1).max(255),
|
|
40
40
|
dashboard_username: z.string().min(1).max(255).describe("Supabase Studio dashboard username"),
|
|
41
41
|
dashboard_password: z.string().min(8).max(255).describe("Supabase Studio dashboard password (8+ chars)"),
|
|
42
|
-
is_public: z.boolean().
|
|
42
|
+
is_public: z.boolean().describe("Required choice (ask the user, do not assume): true = expose publicly (internet-reachable); false = private to the project."),
|
|
43
43
|
public_port: z.number().int().min(1024).max(65535).optional(),
|
|
44
44
|
}, async ({ project_pid, template_type, name, dashboard_username, dashboard_password, is_public, public_port }) => {
|
|
45
45
|
if (!hasOrg())
|
|
@@ -49,9 +49,8 @@ export function registerProjectServiceTools(server) {
|
|
|
49
49
|
dashboard_username,
|
|
50
50
|
dashboard_password,
|
|
51
51
|
instant_deploy: true,
|
|
52
|
+
is_public,
|
|
52
53
|
};
|
|
53
|
-
if (is_public !== undefined)
|
|
54
|
-
body.is_public = is_public;
|
|
55
54
|
if (public_port !== undefined)
|
|
56
55
|
body.public_port = public_port;
|
|
57
56
|
const result = await apiRequest(`${PROJECTS_BASE}/${project_pid}/services/${template_type}`, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-services.js","sourceRoot":"","sources":["../../src/tools/project-services.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC;;;;;;;;;;;GAWG;AAEH,MAAM,aAAa,GAAG,2BAA2B,CAAC;AAClD,MAAM,cAAc,GAAG,CAAC,UAAU,CAAU,CAAC;AAE7C,MAAM,MAAM,GACV,qFAAqF,CAAC;AAExF,SAAS,MAAM;IACb,OAAO,OAAO,CAAC,cAAc,EAAE,KAAK,IAAI,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,MAAiB;IAC3D,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,4PAA4P,EAC5P;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;KAC/B,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,IAAI,CAAC,MAAM,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACpE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAU,GAAG,aAAa,IAAI,WAAW,WAAW,EAAE;YACnF,QAAQ,EAAE,uBAAuB;SAClC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,oCAAoC,MAAM,CAAC,UAAU,MAAM,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;QAC5H,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACrF,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,
|
|
1
|
+
{"version":3,"file":"project-services.js","sourceRoot":"","sources":["../../src/tools/project-services.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/scaling.js
CHANGED
|
@@ -2,14 +2,14 @@ import { z } from "zod";
|
|
|
2
2
|
import { apiRequest } from "../client.js";
|
|
3
3
|
import { session } from "../session.js";
|
|
4
4
|
/**
|
|
5
|
-
* Scaling
|
|
5
|
+
* Scaling - manual one-off resize + auto-scaling policies.
|
|
6
6
|
*
|
|
7
7
|
* Endpoints:
|
|
8
|
-
* - PUT /aws/v1/instances/:id/scale
|
|
9
|
-
* - GET /scaling_policies
|
|
10
|
-
* - POST /scaling_policies
|
|
11
|
-
* - PATCH /scaling_policies/:id
|
|
12
|
-
* - DELETE /scaling_policies/:id
|
|
8
|
+
* - PUT /aws/v1/instances/:id/scale - manual scale
|
|
9
|
+
* - GET /scaling_policies - list (filterable by instance)
|
|
10
|
+
* - POST /scaling_policies - create
|
|
11
|
+
* - PATCH /scaling_policies/:id - update
|
|
12
|
+
* - DELETE /scaling_policies/:id - delete
|
|
13
13
|
*
|
|
14
14
|
* Scaling-policy actions: start_instance | stop_instance | resize_instance |
|
|
15
15
|
* expand_storage | add_replica | manual_scale.
|
|
@@ -41,7 +41,7 @@ const METRIC_NAMES = [
|
|
|
41
41
|
];
|
|
42
42
|
const COMPARISON_OPERATORS = [">", "<", ">=", "<="];
|
|
43
43
|
export function registerScalingTools(server) {
|
|
44
|
-
server.tool("scale_instance", "Manual one-off resize of an instance
|
|
44
|
+
server.tool("scale_instance", "Manual one-off resize of an instance - change instance type, volume type, size, IOPS, throughput. Only fields you pass are sent (PATCH-style). Response includes `scaling_event_id` you can poll on the instance status (`resizing` / `modifying_storage` → terminal state). Storage must grow, not shrink.", {
|
|
45
45
|
instance_id: z.string().min(1),
|
|
46
46
|
target_instance_type: z.string().optional()
|
|
47
47
|
.describe("e.g. t3.medium, m6i.xlarge, r7g.4xlarge"),
|
|
@@ -68,7 +68,7 @@ export function registerScalingTools(server) {
|
|
|
68
68
|
return {
|
|
69
69
|
content: [{
|
|
70
70
|
type: "text",
|
|
71
|
-
text: "Nothing to scale
|
|
71
|
+
text: "Nothing to scale - pass at least one of target_instance_type / new_size_gb / new_iops / new_throughput / new_volume_type.",
|
|
72
72
|
}],
|
|
73
73
|
};
|
|
74
74
|
}
|
|
@@ -135,7 +135,7 @@ export function registerScalingTools(server) {
|
|
|
135
135
|
metric_name: z.enum(METRIC_NAMES).optional(),
|
|
136
136
|
comparison_operator: z.enum(COMPARISON_OPERATORS).optional(),
|
|
137
137
|
threshold: z.number().optional()
|
|
138
|
-
.describe("0
|
|
138
|
+
.describe("0-100 for percentage metrics"),
|
|
139
139
|
duration_minutes: z.number().int().min(1).optional(),
|
|
140
140
|
cooldown_minutes: z.number().int().min(0).optional(),
|
|
141
141
|
// Scheduled / start-stop trigger
|
|
@@ -146,9 +146,9 @@ export function registerScalingTools(server) {
|
|
|
146
146
|
end_time: z.string().optional()
|
|
147
147
|
.describe("ISO 8601 window end"),
|
|
148
148
|
scheduled_start_time: z.string().optional()
|
|
149
|
-
.describe("HH:MM UTC
|
|
149
|
+
.describe("HH:MM UTC - only for action=start_instance"),
|
|
150
150
|
scheduled_stop_time: z.string().optional()
|
|
151
|
-
.describe("HH:MM UTC
|
|
151
|
+
.describe("HH:MM UTC - only for action=stop_instance"),
|
|
152
152
|
days_of_week: z.array(z.enum(["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"])).optional(),
|
|
153
153
|
timezone: z.string().optional().describe("Default UTC; BE supports UTC | EST | PST | GMT | CET"),
|
|
154
154
|
// Action-specific details
|
|
@@ -239,7 +239,7 @@ export function registerScalingTools(server) {
|
|
|
239
239
|
return {
|
|
240
240
|
content: [{
|
|
241
241
|
type: "text",
|
|
242
|
-
text: "No changes to apply
|
|
242
|
+
text: "No changes to apply - pass at least one field to update.",
|
|
243
243
|
}],
|
|
244
244
|
};
|
|
245
245
|
}
|
|
@@ -259,7 +259,7 @@ export function registerScalingTools(server) {
|
|
|
259
259
|
}
|
|
260
260
|
return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
|
|
261
261
|
});
|
|
262
|
-
server.tool("delete_scaling_policy", "Delete a scaling policy. The associated instance is unaffected
|
|
262
|
+
server.tool("delete_scaling_policy", "Delete a scaling policy. The associated instance is unaffected - only the schedule / rule is removed.", {
|
|
263
263
|
policy_id: z.string().min(1),
|
|
264
264
|
confirm: z.boolean().describe("Must be true to proceed."),
|
|
265
265
|
}, async ({ policy_id, confirm }) => {
|
package/dist/types/models.js
CHANGED
package/package.json
CHANGED