@hoststack.dev/mcp 0.10.2 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hoststack-mcp.js +124 -2
- package/dist/hoststack-mcp.js.map +1 -1
- package/dist/index.js +124 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -751,6 +751,36 @@ defineTool({
|
|
|
751
751
|
});
|
|
752
752
|
}
|
|
753
753
|
});
|
|
754
|
+
defineTool({
|
|
755
|
+
name: "upgrade_database_version",
|
|
756
|
+
category: "databases",
|
|
757
|
+
description: [
|
|
758
|
+
"Upgrade a standalone managed database (postgres or redis) to a newer engine version in place. The agent dumps the live data, recreates the container at the target version under the same DNS name, and restores \u2014 so connection URLs stay valid and services do NOT need a redeploy. The database is briefly unavailable (seconds) during the cut-over; on any failure the original container is rolled back automatically.",
|
|
759
|
+
"",
|
|
760
|
+
"`version` must be a supported, strictly-newer version for the engine (postgres: 18/17/16/15, redis: 8/7/6). Downgrades are rejected. Returns 400 for unsupported engines (mysql/mariadb/mongodb upgrades are not implemented yet), for HA (Patroni) clusters, or if the database is not currently `available`.",
|
|
761
|
+
"",
|
|
762
|
+
"When to use: a customer wants to move to a newer Postgres/Redis major version. Check get_database first \u2014 the `version` field shows the current version; compare against the engine latest.",
|
|
763
|
+
"",
|
|
764
|
+
"Inputs:",
|
|
765
|
+
" - database_id: publicId of the postgres/redis database to upgrade.",
|
|
766
|
+
' - version: target engine version (e.g. "18" for postgres, "8" for redis).',
|
|
767
|
+
"",
|
|
768
|
+
'Returns: 202 Accepted. The upgrade is async \u2014 poll get_database until `version` matches the target and `status === "available"` to confirm.',
|
|
769
|
+
"",
|
|
770
|
+
'Example: upgrade_database_version({ database_id: "db_abc", version: "18" }) \u2192 { ok: true }'
|
|
771
|
+
].join("\n"),
|
|
772
|
+
input: {
|
|
773
|
+
database_id: z5.string().describe("Database publicId (e.g. db_abc) to upgrade."),
|
|
774
|
+
version: z5.string().describe('Target engine version, e.g. "18" for postgres or "8" for redis.')
|
|
775
|
+
},
|
|
776
|
+
handler: async (args, ctx) => {
|
|
777
|
+
const teamId = await ctx.resolveTeamId();
|
|
778
|
+
await ctx.hoststack.databases.upgradeVersion(teamId, args.database_id, args.version);
|
|
779
|
+
return respond({
|
|
780
|
+
summary: `Version upgrade to v${args.version} started for ${args.database_id}. Poll get_database until version=${args.version} and status=available to confirm.`
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
});
|
|
754
784
|
defineTool({
|
|
755
785
|
name: "get_database_cluster",
|
|
756
786
|
category: "databases",
|
|
@@ -2068,7 +2098,7 @@ defineTool({
|
|
|
2068
2098
|
|
|
2069
2099
|
// src/tools/services.ts
|
|
2070
2100
|
import { z as z13 } from "zod";
|
|
2071
|
-
var DEV_ENV_IMAGE = "hoststack/dev-env:
|
|
2101
|
+
var DEV_ENV_IMAGE = "hoststack/dev-env:latest";
|
|
2072
2102
|
var DEV_ENV_VOLUME = { name: "workspace", mountPath: "/workspace", sizeGb: 10 };
|
|
2073
2103
|
var SERVICE_TYPES = [
|
|
2074
2104
|
"web_service",
|
|
@@ -2237,6 +2267,7 @@ defineTool({
|
|
|
2237
2267
|
" - disk_gb (optional): /workspace volume size in GB (default 10, 1\u2013100).",
|
|
2238
2268
|
" - hoststack_api_key (optional): sets HOSTSTACK_API_KEY so the hoststack MCP works inside the container.",
|
|
2239
2269
|
" - poststack_api_key (optional): sets POSTSTACK_API_KEY so the poststack MCP works inside the container.",
|
|
2270
|
+
" - repo_url (optional): clone this git URL into /workspace on first boot (with optional branch).",
|
|
2240
2271
|
"",
|
|
2241
2272
|
"Returns: { service: Service, volumeAttached: boolean, deployId: number | null }. Open the Terminal tab on the service (dashboard or phone) once it is running; log in once with `claude /login` inside the container.",
|
|
2242
2273
|
"",
|
|
@@ -2248,7 +2279,11 @@ defineTool({
|
|
|
2248
2279
|
plan: z13.enum(SERVICE_PLANS).optional().describe('Service size (default "micro").'),
|
|
2249
2280
|
disk_gb: z13.number().int().min(1).max(100).optional().describe("/workspace volume size in GB (default 10)."),
|
|
2250
2281
|
hoststack_api_key: z13.string().optional().describe("Value for HOSTSTACK_API_KEY (enables the hoststack MCP in-container)."),
|
|
2251
|
-
poststack_api_key: z13.string().optional().describe("Value for POSTSTACK_API_KEY (enables the poststack MCP in-container).")
|
|
2282
|
+
poststack_api_key: z13.string().optional().describe("Value for POSTSTACK_API_KEY (enables the poststack MCP in-container)."),
|
|
2283
|
+
repo_url: z13.string().max(500).optional().describe(
|
|
2284
|
+
"Clone this git URL into /workspace on first boot (HTTPS, or SSH once a key is set)."
|
|
2285
|
+
),
|
|
2286
|
+
branch: z13.string().max(200).optional().describe("Branch to clone (with repo_url).")
|
|
2252
2287
|
},
|
|
2253
2288
|
handler: async (args, ctx) => {
|
|
2254
2289
|
const teamId = await ctx.resolveTeamId();
|
|
@@ -2281,6 +2316,19 @@ defineTool({
|
|
|
2281
2316
|
value: args.poststack_api_key,
|
|
2282
2317
|
isSecret: true
|
|
2283
2318
|
});
|
|
2319
|
+
if (args.repo_url) {
|
|
2320
|
+
envVars.push({
|
|
2321
|
+
key: "HOSTSTACK_DEVENV_REPO_URL",
|
|
2322
|
+
value: args.repo_url,
|
|
2323
|
+
isSecret: false
|
|
2324
|
+
});
|
|
2325
|
+
if (args.branch)
|
|
2326
|
+
envVars.push({
|
|
2327
|
+
key: "HOSTSTACK_DEVENV_BRANCH",
|
|
2328
|
+
value: args.branch,
|
|
2329
|
+
isSecret: false
|
|
2330
|
+
});
|
|
2331
|
+
}
|
|
2284
2332
|
if (envVars.length > 0) {
|
|
2285
2333
|
await ctx.hoststack.envVars.bulkSet(teamId, service.id, { vars: envVars });
|
|
2286
2334
|
}
|
|
@@ -2302,6 +2350,80 @@ defineTool({
|
|
|
2302
2350
|
});
|
|
2303
2351
|
}
|
|
2304
2352
|
});
|
|
2353
|
+
defineTool({
|
|
2354
|
+
name: "spin_up_dev_environment",
|
|
2355
|
+
category: "services",
|
|
2356
|
+
description: [
|
|
2357
|
+
"Spin up an agentic dev environment FROM an existing service so you can reproduce a bug, fix it, view it, and ship it. Creates a dev box (Claude/Codex/OpenCode + MCPs) that RUNS a clone of the app: the repo is auto-cloned into /workspace, the service env-vars are copied, and its linked database is cloned (so the box never touches the prod DB). The box gets an unguessable public dev URL and seamless `git push`.",
|
|
2358
|
+
"",
|
|
2359
|
+
'When to use: "spin up a dev environment for <service>", "I found a bug on <service>, give me a box to fix it". Distinct from create_dev_environment, which makes a BARE box not tied to any app.',
|
|
2360
|
+
"",
|
|
2361
|
+
"Inputs:",
|
|
2362
|
+
' - service_id: the source service to debug \u2014 numeric id or publicId ("svc_\u2026").',
|
|
2363
|
+
" - include_database_clone (optional): clone the linked database so the app runs on a copy of real data (default true).",
|
|
2364
|
+
' - name (optional): dev box name (default "<source>-dev").',
|
|
2365
|
+
"",
|
|
2366
|
+
"Returns: { service, devUrl, deployId }. Once it is live: open the Terminal tab, run `claude`, start the dev server (it must bind $PORT), and view the app at https://<devUrl>. Tear it all down later with delete_dev_environment.",
|
|
2367
|
+
"",
|
|
2368
|
+
'Example: spin_up_dev_environment({ service_id: "svc_api" }) \u2192 a dev box running a clone of the api service (repo + env-vars + cloned DB) with a public dev URL.'
|
|
2369
|
+
].join("\n"),
|
|
2370
|
+
input: {
|
|
2371
|
+
service_id: z13.union([z13.number().int().positive(), z13.string()]).describe("Source service to debug \u2014 numeric id or publicId."),
|
|
2372
|
+
include_database_clone: z13.boolean().optional().describe("Clone the linked database so the app runs on copied data (default true)."),
|
|
2373
|
+
name: z13.string().min(1).max(100).optional().describe('Dev box name (default "<source>-dev").')
|
|
2374
|
+
},
|
|
2375
|
+
handler: async (args, ctx) => {
|
|
2376
|
+
const teamId = await ctx.resolveTeamId();
|
|
2377
|
+
const serviceId = await ctx.hoststack.resolveId(args.service_id, {
|
|
2378
|
+
kind: "service",
|
|
2379
|
+
teamId
|
|
2380
|
+
});
|
|
2381
|
+
const opts = {};
|
|
2382
|
+
if (args.include_database_clone !== void 0)
|
|
2383
|
+
opts.includeDatabaseClone = args.include_database_clone;
|
|
2384
|
+
if (args.name !== void 0) opts.name = args.name;
|
|
2385
|
+
const result = await ctx.hoststack.services.spinUpDevEnvironment(teamId, serviceId, opts);
|
|
2386
|
+
return respond({
|
|
2387
|
+
summary: `Spun up dev environment "${result.service.name}" (${result.service.publicId}) \u2014 deploying. Once live: open the Terminal tab, run \`claude\`, start the dev server on $PORT, and view it at https://${result.devUrl}. \`git push\` works from inside.`,
|
|
2388
|
+
data: {
|
|
2389
|
+
service: shapeService(result.service),
|
|
2390
|
+
devUrl: result.devUrl,
|
|
2391
|
+
deployId: result.deployId
|
|
2392
|
+
}
|
|
2393
|
+
});
|
|
2394
|
+
}
|
|
2395
|
+
});
|
|
2396
|
+
defineTool({
|
|
2397
|
+
name: "delete_dev_environment",
|
|
2398
|
+
category: "services",
|
|
2399
|
+
description: [
|
|
2400
|
+
"Tear down an agentic dev environment in one call: removes the dev box AND cascade-deletes its cloned database, its /workspace volume, and the auto-created `development` environment if it is now empty.",
|
|
2401
|
+
"",
|
|
2402
|
+
'When to use: "delete / tear down the dev environment", once you have shipped the fix and no longer need the box.',
|
|
2403
|
+
"",
|
|
2404
|
+
"Inputs:",
|
|
2405
|
+
" - service_id: the dev box to tear down \u2014 numeric id or publicId.",
|
|
2406
|
+
"",
|
|
2407
|
+
"Returns: { ok: true }. Irreversible \u2014 the cloned database and workspace volume are deleted.",
|
|
2408
|
+
"",
|
|
2409
|
+
'Example: delete_dev_environment({ service_id: "svc_api_dev" }) \u2192 removes the dev box, its cloned database, and the /workspace volume.'
|
|
2410
|
+
].join("\n"),
|
|
2411
|
+
input: {
|
|
2412
|
+
service_id: z13.union([z13.number().int().positive(), z13.string()]).describe("The dev box to tear down \u2014 numeric id or publicId.")
|
|
2413
|
+
},
|
|
2414
|
+
handler: async (args, ctx) => {
|
|
2415
|
+
const teamId = await ctx.resolveTeamId();
|
|
2416
|
+
const serviceId = await ctx.hoststack.resolveId(args.service_id, {
|
|
2417
|
+
kind: "service",
|
|
2418
|
+
teamId
|
|
2419
|
+
});
|
|
2420
|
+
await ctx.hoststack.services.tearDownDevEnvironment(teamId, serviceId);
|
|
2421
|
+
return respond({
|
|
2422
|
+
summary: "Dev environment torn down \u2014 box, cloned database, /workspace volume, and empty development environment removed.",
|
|
2423
|
+
data: { ok: true }
|
|
2424
|
+
});
|
|
2425
|
+
}
|
|
2426
|
+
});
|
|
2305
2427
|
defineTool({
|
|
2306
2428
|
name: "get_service",
|
|
2307
2429
|
category: "services",
|