@selfhost.dev/mcp-server 0.3.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.
Files changed (44) hide show
  1. package/README.md +147 -24
  2. package/dist/auth.d.ts +1 -1
  3. package/dist/auth.js +3 -3
  4. package/dist/client.js +1 -1
  5. package/dist/config.js +1 -1
  6. package/dist/index.js +29 -4
  7. package/dist/index.js.map +1 -1
  8. package/dist/rate-limiter.js +1 -1
  9. package/dist/tools/billing.js +14 -14
  10. package/dist/tools/credentials.js +1 -1
  11. package/dist/tools/database-users.js +9 -9
  12. package/dist/tools/deployment-domains.d.ts +2 -0
  13. package/dist/tools/deployment-domains.js +128 -0
  14. package/dist/tools/deployment-domains.js.map +1 -0
  15. package/dist/tools/deployment-notifications.d.ts +2 -0
  16. package/dist/tools/deployment-notifications.js +74 -0
  17. package/dist/tools/deployment-notifications.js.map +1 -0
  18. package/dist/tools/deployments.d.ts +2 -0
  19. package/dist/tools/deployments.js +302 -0
  20. package/dist/tools/deployments.js.map +1 -0
  21. package/dist/tools/env-vars.d.ts +2 -0
  22. package/dist/tools/env-vars.js +121 -0
  23. package/dist/tools/env-vars.js.map +1 -0
  24. package/dist/tools/github.d.ts +2 -0
  25. package/dist/tools/github.js +106 -0
  26. package/dist/tools/github.js.map +1 -0
  27. package/dist/tools/hetzner.js +13 -13
  28. package/dist/tools/instances.js +11 -11
  29. package/dist/tools/pgbouncer.js +4 -4
  30. package/dist/tools/pitr.js +16 -16
  31. package/dist/tools/project-databases.d.ts +2 -0
  32. package/dist/tools/project-databases.js +169 -0
  33. package/dist/tools/project-databases.js.map +1 -0
  34. package/dist/tools/project-services.d.ts +2 -0
  35. package/dist/tools/project-services.js +93 -0
  36. package/dist/tools/project-services.js.map +1 -0
  37. package/dist/tools/projects.d.ts +2 -0
  38. package/dist/tools/projects.js +141 -0
  39. package/dist/tools/projects.js.map +1 -0
  40. package/dist/tools/scaling.js +13 -13
  41. package/dist/types/models.js +1 -1
  42. package/dist/types/tiers.js +31 -1
  43. package/dist/types/tiers.js.map +1 -1
  44. package/package.json +10 -3
@@ -0,0 +1,169 @@
1
+ import { z } from "zod";
2
+ import { apiRequest } from "../client.js";
3
+ import { session } from "../session.js";
4
+ /**
5
+ * Project databases (CoolifyDatabase) - Postgres/Redis/MySQL/MongoDB instances
6
+ * attached to a project, provisioned via Coolify. Distinct from the AWS/Hetzner
7
+ * *managed instances* (`list_instances`/`create_instance`) - these live inside a
8
+ * PaaS project and share its server.
9
+ *
10
+ * Endpoints:
11
+ * - GET /api/v1/platform/projects/:pid/databases
12
+ * - POST /api/v1/platform/projects/:pid/databases/:db_type (202 - async provisioning)
13
+ * - DELETE /api/v1/platform/projects/:pid/databases/:database_pid (202; body {name} must match)
14
+ *
15
+ * The project must be `active` before creating a database (409 otherwise).
16
+ */
17
+ const PROJECTS_BASE = "/api/v1/platform/projects";
18
+ const DB_TYPES = ["postgres", "redis", "mysql", "mongodb"];
19
+ // Coolify password rule: 8+ chars, no spaces or shell-dangerous chars.
20
+ const PASSWORD_RE = /^[A-Za-z0-9!@#%^*()_+\-=\[\]{}:,.?/~]+$/;
21
+ const DEFAULT_PORTS = { postgres: 5432, redis: 6379, mysql: 3306, mongodb: 27017 };
22
+ const NO_ORG = "No active organization. Call `list_organizations` then `select_organization` first.";
23
+ function hasOrg() {
24
+ return session.getActiveOrgId() !== null;
25
+ }
26
+ function dbTypePath(t) {
27
+ return t === "postgres" ? "postgresql" : t;
28
+ }
29
+ function checkPassword(label, v) {
30
+ if (!v)
31
+ return `${label} is required for this database type.`;
32
+ if (v.length < 8)
33
+ return `${label} must be at least 8 characters.`;
34
+ if (!PASSWORD_RE.test(v))
35
+ return `${label} contains invalid characters (no spaces or \` $ ; | & < > \\ ' ").`;
36
+ return null;
37
+ }
38
+ export function registerProjectDatabaseTools(server) {
39
+ server.tool("list_project_databases", "List the databases attached to a project (Postgres/Redis/MySQL/MongoDB provisioned via Coolify, NOT AWS managed instances). Returns pid, name, db_type, status (active | inactive | creating | failed | unknown), is_public, and public_port. Passwords are never returned here.", {
40
+ project_pid: z.string().min(1),
41
+ }, async ({ project_pid }) => {
42
+ if (!hasOrg())
43
+ return { content: [{ type: "text", text: NO_ORG }] };
44
+ const result = await apiRequest(`${PROJECTS_BASE}/${project_pid}/databases`, {
45
+ toolName: "list_project_databases",
46
+ });
47
+ if (!result.success) {
48
+ return { content: [{ type: "text", text: `Failed to list project databases (${result.statusCode}): ${result.message}` }] };
49
+ }
50
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
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. `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
+ project_pid: z.string().min(1),
54
+ db_type: z.enum(DB_TYPES).describe("postgres | redis | mysql | mongodb"),
55
+ name: z.string().min(1).max(255),
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
+ 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
+ // postgres
59
+ postgres_user: z.string().max(255).optional(),
60
+ postgres_password: z.string().optional(),
61
+ postgres_db: z.string().max(255).optional(),
62
+ // redis
63
+ redis_password: z.string().optional(),
64
+ // mysql
65
+ mysql_user: z.string().max(255).optional(),
66
+ mysql_password: z.string().optional(),
67
+ mysql_database: z.string().max(255).optional(),
68
+ mysql_root_password: z.string().optional(),
69
+ // mongodb
70
+ mongo_initdb_root_username: z.string().max(255).optional(),
71
+ mongo_initdb_root_password: z.string().optional(),
72
+ mongo_initdb_database: z.string().max(255).optional(),
73
+ }, async (args) => {
74
+ if (!hasOrg())
75
+ return { content: [{ type: "text", text: NO_ORG }] };
76
+ const dbType = args.db_type;
77
+ const isPublic = args.is_public;
78
+ const body = { name: args.name, is_public: isPublic };
79
+ if (isPublic)
80
+ body.public_port = args.public_port ?? DEFAULT_PORTS[dbType];
81
+ let err = null;
82
+ switch (dbType) {
83
+ case "postgres":
84
+ err = checkPassword("postgres_password", args.postgres_password);
85
+ if (!err && !args.postgres_user)
86
+ err = "postgres_user is required.";
87
+ if (!err && !args.postgres_db)
88
+ err = "postgres_db is required.";
89
+ if (!err) {
90
+ body.postgres_user = args.postgres_user;
91
+ body.postgres_password = args.postgres_password;
92
+ body.postgres_db = args.postgres_db;
93
+ body.instant_deploy = true;
94
+ }
95
+ break;
96
+ case "redis":
97
+ err = checkPassword("redis_password", args.redis_password);
98
+ if (!err) {
99
+ body.redis_password = args.redis_password;
100
+ body.instant_deploy = true;
101
+ }
102
+ break;
103
+ case "mysql":
104
+ err = checkPassword("mysql_password", args.mysql_password) || checkPassword("mysql_root_password", args.mysql_root_password);
105
+ if (!err && !args.mysql_user)
106
+ err = "mysql_user is required.";
107
+ if (!err && !args.mysql_database)
108
+ err = "mysql_database is required.";
109
+ if (!err) {
110
+ body.mysql_user = args.mysql_user;
111
+ body.mysql_password = args.mysql_password;
112
+ body.mysql_database = args.mysql_database;
113
+ body.mysql_root_password = args.mysql_root_password;
114
+ body.instant_deploy = true;
115
+ }
116
+ break;
117
+ case "mongodb":
118
+ err = checkPassword("mongo_initdb_root_password", args.mongo_initdb_root_password);
119
+ if (!err && !args.mongo_initdb_root_username)
120
+ err = "mongo_initdb_root_username is required.";
121
+ if (!err && !args.mongo_initdb_database)
122
+ err = "mongo_initdb_database is required.";
123
+ if (!err) {
124
+ body.mongo_initdb_root_username = args.mongo_initdb_root_username;
125
+ body.mongo_initdb_root_password = args.mongo_initdb_root_password;
126
+ body.mongo_initdb_database = args.mongo_initdb_database;
127
+ }
128
+ break;
129
+ }
130
+ if (err)
131
+ return { content: [{ type: "text", text: err }] };
132
+ const result = await apiRequest(`${PROJECTS_BASE}/${args.project_pid}/databases/${dbTypePath(dbType)}`, {
133
+ method: "POST",
134
+ body,
135
+ toolName: "create_project_database",
136
+ });
137
+ if (!result.success) {
138
+ return { content: [{ type: "text", text: `Failed to create database (${result.statusCode}): ${result.message}` }] };
139
+ }
140
+ return {
141
+ content: [
142
+ { type: "text", text: `Database \`${args.name}\` (${dbType}) provisioning started. Poll \`list_project_databases\` until status is \`active\`.` },
143
+ { type: "text", text: JSON.stringify(result.data, null, 2) },
144
+ ],
145
+ };
146
+ });
147
+ server.tool("delete_project_database", "Delete a project database. The exact current `name` must be supplied and match (a safety check, 422 otherwise). Returns 202 (async tear-down). Irreversible.", {
148
+ project_pid: z.string().min(1),
149
+ database_pid: z.string().min(1),
150
+ name: z.string().min(1).describe("Exact current database name - must match"),
151
+ confirm: z.boolean().describe("Must be true. Permanently destroys the database and its data."),
152
+ }, async ({ project_pid, database_pid, name, confirm }) => {
153
+ if (!hasOrg())
154
+ return { content: [{ type: "text", text: NO_ORG }] };
155
+ if (!confirm) {
156
+ return { content: [{ type: "text", text: `⚠️ About to DELETE database \`${name}\` (${database_pid}) - all its data is destroyed. No undo.\n\nCall again with confirm=true to proceed.` }] };
157
+ }
158
+ const result = await apiRequest(`${PROJECTS_BASE}/${project_pid}/databases/${database_pid}`, {
159
+ method: "DELETE",
160
+ body: { name },
161
+ toolName: "delete_project_database",
162
+ });
163
+ if (!result.success) {
164
+ return { content: [{ type: "text", text: `Failed to delete database (${result.statusCode}): ${result.message}` }] };
165
+ }
166
+ return { content: [{ type: "text", text: "Database deletion queued." }] };
167
+ });
168
+ }
169
+ //# sourceMappingURL=project-databases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-databases.js","sourceRoot":"","sources":["../../src/tools/project-databases.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 registerProjectServiceTools(server: McpServer): void;
@@ -0,0 +1,93 @@
1
+ import { z } from "zod";
2
+ import { apiRequest } from "../client.js";
3
+ import { session } from "../session.js";
4
+ /**
5
+ * Project services (CoolifyService) - pre-packaged service templates deployed
6
+ * into a project. Today the only supported template is `supabase`. There is no
7
+ * catalog endpoint; the supported set is fixed server-side.
8
+ *
9
+ * Endpoints:
10
+ * - GET /api/v1/platform/projects/:pid/services
11
+ * - POST /api/v1/platform/projects/:pid/services/:template_type (202 - async provisioning)
12
+ * - DELETE /api/v1/platform/projects/:pid/services/:service_pid (202; body {name} must match)
13
+ *
14
+ * The project must be `active` before creating a service (409 otherwise).
15
+ */
16
+ const PROJECTS_BASE = "/api/v1/platform/projects";
17
+ const TEMPLATE_TYPES = ["supabase"];
18
+ const NO_ORG = "No active organization. Call `list_organizations` then `select_organization` first.";
19
+ function hasOrg() {
20
+ return session.getActiveOrgId() !== null;
21
+ }
22
+ export function registerProjectServiceTools(server) {
23
+ server.tool("list_project_services", "List the service-template instances deployed in a project (e.g. Supabase). Returns pid, name, template_type, status (active | inactive | creating | failed | unknown), is_public, public_port, and external_url. Credentials are not returned in the list.", {
24
+ project_pid: z.string().min(1),
25
+ }, async ({ project_pid }) => {
26
+ if (!hasOrg())
27
+ return { content: [{ type: "text", text: NO_ORG }] };
28
+ const result = await apiRequest(`${PROJECTS_BASE}/${project_pid}/services`, {
29
+ toolName: "list_project_services",
30
+ });
31
+ if (!result.success) {
32
+ return { content: [{ type: "text", text: `Failed to list project services (${result.statusCode}): ${result.message}` }] };
33
+ }
34
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
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. `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
+ project_pid: z.string().min(1),
38
+ template_type: z.enum(TEMPLATE_TYPES).describe("Service template (only `supabase` is supported today)"),
39
+ name: z.string().min(1).max(255),
40
+ dashboard_username: z.string().min(1).max(255).describe("Supabase Studio dashboard username"),
41
+ dashboard_password: z.string().min(8).max(255).describe("Supabase Studio dashboard password (8+ chars)"),
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
+ public_port: z.number().int().min(1024).max(65535).optional(),
44
+ }, async ({ project_pid, template_type, name, dashboard_username, dashboard_password, is_public, public_port }) => {
45
+ if (!hasOrg())
46
+ return { content: [{ type: "text", text: NO_ORG }] };
47
+ const body = {
48
+ name,
49
+ dashboard_username,
50
+ dashboard_password,
51
+ instant_deploy: true,
52
+ is_public,
53
+ };
54
+ if (public_port !== undefined)
55
+ body.public_port = public_port;
56
+ const result = await apiRequest(`${PROJECTS_BASE}/${project_pid}/services/${template_type}`, {
57
+ method: "POST",
58
+ body,
59
+ toolName: "create_project_service",
60
+ });
61
+ if (!result.success) {
62
+ return { content: [{ type: "text", text: `Failed to create service (${result.statusCode}): ${result.message}` }] };
63
+ }
64
+ return {
65
+ content: [
66
+ { type: "text", text: `Service \`${name}\` (${template_type}) provisioning started. Poll \`list_project_services\` until status is \`active\`.` },
67
+ { type: "text", text: JSON.stringify(result.data, null, 2) },
68
+ ],
69
+ };
70
+ });
71
+ server.tool("delete_project_service", "Delete a project service. The exact current `name` must be supplied and match (a safety check, 422 otherwise). Returns 202 (async tear-down). Irreversible.", {
72
+ project_pid: z.string().min(1),
73
+ service_pid: z.string().min(1),
74
+ name: z.string().min(1).describe("Exact current service name - must match"),
75
+ confirm: z.boolean().describe("Must be true. Permanently destroys the service and its data."),
76
+ }, async ({ project_pid, service_pid, name, confirm }) => {
77
+ if (!hasOrg())
78
+ return { content: [{ type: "text", text: NO_ORG }] };
79
+ if (!confirm) {
80
+ return { content: [{ type: "text", text: `⚠️ About to DELETE service \`${name}\` (${service_pid}) - all its data is destroyed. No undo.\n\nCall again with confirm=true to proceed.` }] };
81
+ }
82
+ const result = await apiRequest(`${PROJECTS_BASE}/${project_pid}/services/${service_pid}`, {
83
+ method: "DELETE",
84
+ body: { name },
85
+ toolName: "delete_project_service",
86
+ });
87
+ if (!result.success) {
88
+ return { content: [{ type: "text", text: `Failed to delete service (${result.statusCode}): ${result.message}` }] };
89
+ }
90
+ return { content: [{ type: "text", text: "Service deletion queued." }] };
91
+ });
92
+ }
93
+ //# sourceMappingURL=project-services.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-services.js","sourceRoot":"","sources":["../../src/tools/project-services.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 registerProjectTools(server: McpServer): void;
@@ -0,0 +1,141 @@
1
+ import { z } from "zod";
2
+ import { apiRequest } from "../client.js";
3
+ import { session } from "../session.js";
4
+ /**
5
+ * Projects (CoolifyProject) - the per-app container: a provisioned server +
6
+ * Coolify install + wildcard DNS that deployments and project databases attach
7
+ * to. Mounted on Rails as `resources :projects, controller: "coolify_projects"`
8
+ * so the URL path is `/projects` (NOT `/coolify_projects`).
9
+ *
10
+ * Endpoints:
11
+ * - GET /api/v1/platform/projects
12
+ * - GET /api/v1/platform/projects/:pid
13
+ * - POST /api/v1/platform/projects (202 - async provisioning)
14
+ * - PATCH /api/v1/platform/projects/:pid
15
+ * - DELETE /api/v1/platform/projects/:pid (202 - async tear-down)
16
+ * - GET /api/v1/platform/projects/:pid/metrics
17
+ *
18
+ * `organization_id` is required on every call and is auto-injected from the
19
+ * active org by the HTTP client (query for GET, body for POST/PATCH/DELETE).
20
+ */
21
+ const PROJECTS_BASE = "/api/v1/platform/projects";
22
+ const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
23
+ function requireOrg() {
24
+ return session.getActiveOrgId();
25
+ }
26
+ const NO_ORG = "No active organization. Call `list_organizations` then `select_organization` first.";
27
+ export function registerProjectTools(server) {
28
+ server.tool("list_projects", "List PaaS projects (app containers) in the active organization. Each project is a provisioned server + Coolify install that deployments and project databases attach to. Returns pid, name, status (pending | provisioning | active | failed - note `deleting`/`terminated` are filtered out server-side), public_ip, instance_domain, and timestamps. A project must reach status `active` before you can create a deployment in it.", {}, async () => {
29
+ if (!requireOrg())
30
+ return { content: [{ type: "text", text: NO_ORG }] };
31
+ const result = await apiRequest(PROJECTS_BASE, {
32
+ toolName: "list_projects",
33
+ });
34
+ if (!result.success) {
35
+ return { content: [{ type: "text", text: `Failed to list projects (${result.statusCode}): ${result.message}` }] };
36
+ }
37
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
38
+ });
39
+ server.tool("get_project", "Get one project by pid. Use this to POLL provisioning progress after `create_project`: re-call every ~5-10s until `status` becomes `active` (ready for deployments) or `failed` (provisioning errored). `status` of `deleting` or a 404 means it has been/ is being torn down. `public_ip` and `instance_domain` populate during provisioning.", {
40
+ project_pid: z.string().min(1).describe("Project pid, e.g. prj_01h..."),
41
+ }, async ({ project_pid }) => {
42
+ if (!requireOrg())
43
+ return { content: [{ type: "text", text: NO_ORG }] };
44
+ const result = await apiRequest(`${PROJECTS_BASE}/${project_pid}`, {
45
+ toolName: "get_project",
46
+ });
47
+ if (!result.success) {
48
+ return { content: [{ type: "text", text: `Failed to get project (${result.statusCode}): ${result.message}` }] };
49
+ }
50
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
51
+ });
52
+ server.tool("create_project", "Create a new PaaS project and start async server provisioning. Returns immediately (HTTP 202) with the project in status `pending` - actual provisioning (server → Coolify → DNS) takes ~2-5 minutes. Poll `get_project` until status is `active` before creating a deployment in it. Name must be unique within the org (excluding failed/terminated projects). May return 422 if the platform is at capacity for new servers - retry later.", {
53
+ name: z.string().min(1).max(255).describe("Project name; unique per org, <=255 chars"),
54
+ description: z.string().optional().describe("Optional free-text description"),
55
+ }, async ({ name, description }) => {
56
+ if (!requireOrg())
57
+ return { content: [{ type: "text", text: NO_ORG }] };
58
+ const project = { name };
59
+ if (description !== undefined && description !== "")
60
+ project.description = description;
61
+ const result = await apiRequest(PROJECTS_BASE, {
62
+ method: "POST",
63
+ body: { project },
64
+ toolName: "create_project",
65
+ });
66
+ if (!result.success) {
67
+ return { content: [{ type: "text", text: `Failed to create project (${result.statusCode}): ${result.message}` }] };
68
+ }
69
+ return {
70
+ content: [
71
+ { type: "text", text: `Project \`${name}\` created and provisioning started (status: pending). This takes ~2-5 min - poll \`get_project\` until status is \`active\` before deploying.` },
72
+ { type: "text", text: JSON.stringify(result.data, null, 2) },
73
+ ],
74
+ };
75
+ });
76
+ server.tool("update_project", "Update a project's name and/or description. Only these two fields are editable - status, IPs, and domain are server-managed. Name must remain unique within the org.", {
77
+ project_pid: z.string().min(1),
78
+ name: z.string().min(1).max(255).describe("New name (required by the backend even if unchanged)"),
79
+ description: z.string().nullable().optional().describe("New description; pass null to clear"),
80
+ }, async ({ project_pid, name, description }) => {
81
+ if (!requireOrg())
82
+ return { content: [{ type: "text", text: NO_ORG }] };
83
+ const project = { name };
84
+ if (description !== undefined)
85
+ project.description = description;
86
+ const result = await apiRequest(`${PROJECTS_BASE}/${project_pid}`, {
87
+ method: "PATCH",
88
+ body: { project },
89
+ toolName: "update_project",
90
+ });
91
+ if (!result.success) {
92
+ return { content: [{ type: "text", text: `Failed to update project (${result.statusCode}): ${result.message}` }] };
93
+ }
94
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
95
+ });
96
+ server.tool("delete_project", "Delete a project - tears down its provisioned server, Coolify install, DNS, and all attached deployments/databases/services. This is irreversible. Returns 202 (async tear-down; status moves to `deleting` then `terminated`). Blocked with 409 if the project is still `pending`/`provisioning`/`deleting`, or if it has an active deployment with a running container - pause active deployments first.", {
97
+ project_pid: z.string().min(1),
98
+ name: z.string().optional().describe("Project name for the confirmation message (cosmetic)"),
99
+ confirm: z.boolean().describe("Must be true. Permanently destroys the server and everything in the project."),
100
+ }, async ({ project_pid, name, confirm }) => {
101
+ if (!requireOrg())
102
+ return { content: [{ type: "text", text: NO_ORG }] };
103
+ if (!confirm) {
104
+ const label = name ? `\`${name}\` (${project_pid})` : project_pid;
105
+ return {
106
+ content: [{
107
+ type: "text",
108
+ text: `⚠️ About to DELETE project ${label}. This destroys the provisioned server and ALL deployments, databases, and services inside it. There is no undo.\n\nPause any active deployments first, then call again with confirm=true.`,
109
+ }],
110
+ };
111
+ }
112
+ const result = await apiRequest(`${PROJECTS_BASE}/${project_pid}`, {
113
+ method: "DELETE",
114
+ toolName: "delete_project",
115
+ });
116
+ if (!result.success) {
117
+ return { content: [{ type: "text", text: `Failed to delete project (${result.statusCode}): ${result.message}` }] };
118
+ }
119
+ return { content: [{ type: "text", text: "Project deletion started - status will move to `deleting` then disappear once tear-down completes." }] };
120
+ });
121
+ server.tool("get_project_metrics", "Get time-series infrastructure metrics for a project (server CPU/memory/disk/network, plus per-database and per-deployment container metrics) sourced from the project's monitoring agent heartbeats. Returns `agent_status`, `last_seen_at`, and a `batches` array. Each batch has `timestamp_ms` and `metric_sets`; a metric set with no `resource` belongs to the server, otherwise `resource.pid` identifies the database/service/deployment it describes. For a 'current' snapshot use a narrow window and read the newest batch. Heartbeats land ~every 25s, so poll no faster than ~30s.", {
122
+ project_pid: z.string().min(1),
123
+ start_date: z.string().regex(DATE_RE, "YYYY-MM-DD").optional().describe("Inclusive start date YYYY-MM-DD (default: 24h ago)"),
124
+ end_date: z.string().regex(DATE_RE, "YYYY-MM-DD").optional().describe("Inclusive end date YYYY-MM-DD (default: today)"),
125
+ }, async ({ project_pid, start_date, end_date }) => {
126
+ if (!requireOrg())
127
+ return { content: [{ type: "text", text: NO_ORG }] };
128
+ if (start_date && end_date && start_date > end_date) {
129
+ return { content: [{ type: "text", text: "Invalid date range: start_date must be on or before end_date." }] };
130
+ }
131
+ const result = await apiRequest(`${PROJECTS_BASE}/${project_pid}/metrics`, {
132
+ query: { start_date, end_date },
133
+ toolName: "get_project_metrics",
134
+ });
135
+ if (!result.success) {
136
+ return { content: [{ type: "text", text: `Failed to get project metrics (${result.statusCode}): ${result.message}` }] };
137
+ }
138
+ return { content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }] };
139
+ });
140
+ }
141
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/tools/projects.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;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,aAAa,GAAG,2BAA2B,CAAC;AAClD,MAAM,OAAO,GAAG,qBAAqB,CAAC;AAEtC,SAAS,UAAU;IACjB,OAAO,OAAO,CAAC,cAAc,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,MAAM,GACV,qFAAqF,CAAC;AAExF,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,eAAe,EACf,uaAAua,EACva,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC,UAAU,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACxE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAU,aAAa,EAAE;YACtD,QAAQ,EAAE,eAAe;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,MAAM,CAAC,UAAU,MAAM,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;QACpH,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,aAAa,EACb,gVAAgV,EAChV;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,8BAA8B,CAAC;KACxE,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,IAAI,CAAC,UAAU,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACxE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAU,GAAG,aAAa,IAAI,WAAW,EAAE,EAAE;YAC1E,QAAQ,EAAE,aAAa;SACxB,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,0BAA0B,MAAM,CAAC,UAAU,MAAM,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;QAClH,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,gBAAgB,EAChB,+aAA+a,EAC/a;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,2CAA2C,CAAC;QACtF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;KAC9E,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE;QAC9B,IAAI,CAAC,UAAU,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACxE,MAAM,OAAO,GAA4B,EAAE,IAAI,EAAE,CAAC;QAClD,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,EAAE;YAAE,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;QAEvF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAU,aAAa,EAAE;YACtD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,EAAE,OAAO,EAAE;YACjB,QAAQ,EAAE,gBAAgB;SAC3B,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,6BAA6B,MAAM,CAAC,UAAU,MAAM,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;QACrH,CAAC;QACD,OAAO;YACL,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,IAAI,gJAAgJ,EAAE;gBACzL,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;aAC7D;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,sKAAsK,EACtK;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,sDAAsD,CAAC;QACjG,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;KAC9F,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE;QAC3C,IAAI,CAAC,UAAU,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACxE,MAAM,OAAO,GAA4B,EAAE,IAAI,EAAE,CAAC;QAClD,IAAI,WAAW,KAAK,SAAS;YAAE,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;QAEjE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAU,GAAG,aAAa,IAAI,WAAW,EAAE,EAAE;YAC1E,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,EAAE,OAAO,EAAE;YACjB,QAAQ,EAAE,gBAAgB;SAC3B,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,6BAA6B,MAAM,CAAC,UAAU,MAAM,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;QACrH,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,gBAAgB,EAChB,4YAA4Y,EAC5Y;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;QAC5F,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,8EAA8E,CAAC;KAC9G,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;QACvC,IAAI,CAAC,UAAU,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACxE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,OAAO,WAAW,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;YAClE,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,+BAA+B,KAAK,4LAA4L;qBACvO,CAAC;aACH,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAU,GAAG,aAAa,IAAI,WAAW,EAAE,EAAE;YAC1E,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,gBAAgB;SAC3B,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,6BAA6B,MAAM,CAAC,UAAU,MAAM,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;QACrH,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,oGAAoG,EAAE,CAAC,EAAE,CAAC;IACrJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,ikBAAikB,EACjkB;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oDAAoD,CAAC;QAC7H,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC;KACxH,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC9C,IAAI,CAAC,UAAU,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACxE,IAAI,UAAU,IAAI,QAAQ,IAAI,UAAU,GAAG,QAAQ,EAAE,CAAC;YACpD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,+DAA+D,EAAE,CAAC,EAAE,CAAC;QAChH,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAU,GAAG,aAAa,IAAI,WAAW,UAAU,EAAE;YAClF,KAAK,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE;YAC/B,QAAQ,EAAE,qBAAqB;SAChC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kCAAkC,MAAM,CAAC,UAAU,MAAM,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;QAC1H,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;AACJ,CAAC"}
@@ -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 — manual one-off resize + auto-scaling policies.
5
+ * Scaling - manual one-off resize + auto-scaling policies.
6
6
  *
7
7
  * Endpoints:
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
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 — 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.", {
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 — pass at least one of target_instance_type / new_size_gb / new_iops / new_throughput / new_volume_type.",
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–100 for percentage metrics"),
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 — only for action=start_instance"),
149
+ .describe("HH:MM UTC - only for action=start_instance"),
150
150
  scheduled_stop_time: z.string().optional()
151
- .describe("HH:MM UTC — only for action=stop_instance"),
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 — pass at least one field to update.",
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 — only the schedule / rule is removed.", {
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 }) => {
@@ -1,3 +1,3 @@
1
- // Domain model types — expanded per module
1
+ // Domain model types - expanded per module
2
2
  export {};
3
3
  //# sourceMappingURL=models.js.map
@@ -24,7 +24,7 @@ export const EXEMPT_TOOLS = new Set([
24
24
  "list_regions",
25
25
  "get_instance_types_for_region",
26
26
  "list_storage_types",
27
- // Provider / Hetzner reference data — static, no BE call
27
+ // Provider / Hetzner reference data - static, no BE call
28
28
  "list_cloud_providers",
29
29
  "list_hetzner_locations",
30
30
  "list_hetzner_server_types",
@@ -107,6 +107,36 @@ export const WRITE_TOOLS = new Set([
107
107
  "delete_agent_token",
108
108
  "admin_revoke_invitation",
109
109
  "admin_grant_credits",
110
+ // PaaS - Projects (Module 15)
111
+ "create_project",
112
+ "update_project",
113
+ "delete_project",
114
+ // PaaS - Deployments (Module 16)
115
+ "create_deployment",
116
+ "update_deployment",
117
+ "update_deployment_build_config",
118
+ "delete_deployment",
119
+ "trigger_deploy",
120
+ "redeploy_run",
121
+ "rollback_run",
122
+ // PaaS - Custom domains (Module 17)
123
+ "sync_deployment_domains",
124
+ "add_deployment_domain",
125
+ "remove_deployment_domain",
126
+ "verify_custom_domain",
127
+ // PaaS - Environment variables (Module 18)
128
+ "set_env_vars",
129
+ "merge_env_vars",
130
+ "delete_env_var",
131
+ // PaaS - Project databases (Module 20)
132
+ "create_project_database",
133
+ "delete_project_database",
134
+ // PaaS - Project services (Module 21)
135
+ "create_project_service",
136
+ "delete_project_service",
137
+ // PaaS - Deployment notifications (Module 22)
138
+ "bind_deployment_notification_channel",
139
+ "unbind_deployment_notification_channel",
110
140
  ]);
111
141
  export function categorizeOperation(toolName) {
112
142
  if (EXEMPT_TOOLS.has(toolName))
@@ -1 +1 @@
1
- {"version":3,"file":"tiers.js","sourceRoot":"","sources":["../../src/types/tiers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tiers.js","sourceRoot":"","sources":["../../src/types/tiers.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@selfhost.dev/mcp-server",
3
- "version": "0.3.0",
4
- "description": "MCP server for SelfHost.dev — Manage Database Infrastructure via Natural Language",
3
+ "version": "0.4.1",
4
+ "description": "MCP server for SelfHost.dev - provision managed databases and deploy apps (PaaS) via natural language",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
@@ -24,7 +24,14 @@
24
24
  "cheap managed databases",
25
25
  "cost efficient managed databases",
26
26
  "SelfHost",
27
- "cloudSql"
27
+ "cloudSql",
28
+ "paas",
29
+ "deploy",
30
+ "deployment",
31
+ "github",
32
+ "app hosting",
33
+ "deploy app",
34
+ "coolify"
28
35
  ],
29
36
  "license": "MIT",
30
37
  "engines": {