@hoststack.dev/mcp 0.12.0 → 0.13.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/dist/index.js CHANGED
@@ -1974,7 +1974,7 @@ defineTool({
1974
1974
 
1975
1975
  // src/tools/projects.ts
1976
1976
  import { z as z12 } from "zod";
1977
- var REGION_IDS = ["eu-central-1", "eu-central-2", "eu-west-1", "us-east-1"];
1977
+ var AVAILABLE_REGION_IDS = ["eu-central-1"];
1978
1978
  defineTool({
1979
1979
  name: "list_projects",
1980
1980
  category: "projects",
@@ -2007,7 +2007,7 @@ defineTool({
2007
2007
  "Inputs:",
2008
2008
  " - name: human-readable project name (1\u201360 chars).",
2009
2009
  " - description (optional): short blurb shown in the dashboard.",
2010
- ' - region (optional): "eu-central-1" (Falkenstein) | "eu-central-2" (Nuremberg) | "eu-west-1" (Helsinki) | "us-east-1" (Ashburn). Defaults to eu-central-2.',
2010
+ ' - region (optional): "eu-central-1" (Falkenstein). Currently the only region with available capacity; defaults to eu-central-1.',
2011
2011
  "",
2012
2012
  "Returns: { project: Project } \u2014 includes the new id and publicId.",
2013
2013
  "",
@@ -2016,7 +2016,7 @@ defineTool({
2016
2016
  input: {
2017
2017
  name: z12.string().min(1).max(60).describe("Project name (1\u201360 chars)."),
2018
2018
  description: z12.string().max(500).optional().describe("Short description (\u2264500 chars)."),
2019
- region: z12.enum(REGION_IDS).optional().describe("Region: eu-central-1 | eu-central-2 | eu-west-1 | us-east-1.")
2019
+ region: z12.enum(AVAILABLE_REGION_IDS).optional().describe("Region: eu-central-1 (Falkenstein) \u2014 currently the only available region.")
2020
2020
  },
2021
2021
  handler: async (args, ctx) => {
2022
2022
  const teamId = await ctx.resolveTeamId();
@@ -2263,7 +2263,7 @@ defineTool({
2263
2263
  "Inputs:",
2264
2264
  ' - project_id: numeric id or publicId ("prj_\u2026") of the target project.',
2265
2265
  ' - name (optional): service name (default "dev-environment").',
2266
- ' - plan (optional): service size (default "micro").',
2266
+ ' - plan (optional): service size (default "standard" \u2014 2 GB, the smallest that fits a coding agent + build).',
2267
2267
  " - disk_gb (optional): /workspace volume size in GB (default 10, 1\u2013100).",
2268
2268
  " - hoststack_api_key (optional): sets HOSTSTACK_API_KEY so the hoststack MCP works inside the container.",
2269
2269
  " - poststack_api_key (optional): sets POSTSTACK_API_KEY so the poststack MCP works inside the container.",
@@ -2276,7 +2276,9 @@ defineTool({
2276
2276
  input: {
2277
2277
  project_id: z13.union([z13.number().int().positive(), z13.string()]).describe("Target project \u2014 numeric id or publicId."),
2278
2278
  name: z13.string().min(1).max(100).optional().describe('Service name (default "dev-environment").'),
2279
- plan: z13.enum(SERVICE_PLANS).optional().describe('Service size (default "micro").'),
2279
+ plan: z13.enum(SERVICE_PLANS).optional().describe(
2280
+ 'Service size (default "standard" \u2014 2 GB; smallest that fits a coding agent).'
2281
+ ),
2280
2282
  disk_gb: z13.number().int().min(1).max(100).optional().describe("/workspace volume size in GB (default 10)."),
2281
2283
  hoststack_api_key: z13.string().optional().describe("Value for HOSTSTACK_API_KEY (enables the hoststack MCP in-container)."),
2282
2284
  poststack_api_key: z13.string().optional().describe("Value for POSTSTACK_API_KEY (enables the poststack MCP in-container)."),
@@ -2424,6 +2426,164 @@ defineTool({
2424
2426
  });
2425
2427
  }
2426
2428
  });
2429
+ defineTool({
2430
+ name: "resize_dev_environment",
2431
+ category: "services",
2432
+ description: [
2433
+ "Resize a dev box (or any service) to a different size tier \u2014 the supported way to give it more memory/CPU/disk headroom (e.g. when ESLint/tsc OOMs).",
2434
+ "",
2435
+ "When to use: a dev box OOM-killed (see exitReason/recommendedSize from list_dev_environments), or you just want more headroom. This changes the SIZE TIER \u2014 unlike per-config memory/CPU overrides, which are clamped to the current tier and so cannot grow a box past it.",
2436
+ "",
2437
+ "How it applies: the new tier's memory + CPU take effect LIVE on the running container (no recreate, no dropped shell sessions); a larger disk takes effect on the next recreate (suspend\u2192resume). Dev boxes are floored to the OOM-safe minimum size server-side.",
2438
+ "",
2439
+ "Inputs:",
2440
+ " - service_id: the box to resize \u2014 numeric id or publicId.",
2441
+ ' - size: target tier (e.g. "standard", "large", "xlarge").',
2442
+ "",
2443
+ "Returns: { service } with the new plan.",
2444
+ "",
2445
+ 'Example: resize_dev_environment({ service_id: "svc_skyskraber_dev", size: "large" }) \u2192 bumps the box to the large tier, applied live.'
2446
+ ].join("\n"),
2447
+ input: {
2448
+ service_id: z13.union([z13.number().int().positive(), z13.string()]).describe("The box to resize \u2014 numeric id or publicId."),
2449
+ size: z13.string().min(1).describe('Target size tier, e.g. "standard", "large", "xlarge".')
2450
+ },
2451
+ handler: async (args, ctx) => {
2452
+ const teamId = await ctx.resolveTeamId();
2453
+ const serviceId = await ctx.hoststack.resolveId(args.service_id, {
2454
+ kind: "service",
2455
+ teamId
2456
+ });
2457
+ const { service } = await ctx.hoststack.services.resize(teamId, serviceId, args.size);
2458
+ return respond({
2459
+ summary: `Resized to ${service.plan} \u2014 memory/CPU applied live; disk grows on next recreate.`,
2460
+ data: { service: shapeService(service) }
2461
+ });
2462
+ }
2463
+ });
2464
+ defineTool({
2465
+ name: "list_dev_environments",
2466
+ category: "services",
2467
+ description: [
2468
+ `List the team's dev environments (the dashboard "Development" section), each annotated with the companion services attached to it.`,
2469
+ "",
2470
+ `When to use: "show my dev environments", before opening/tearing one down, to find a box's id.`,
2471
+ "",
2472
+ 'Returns: { items: [{ ...service, devUrl, databases, exitReason, recommendedSize }] } where `databases` lists the companion engines wired into the box (e.g. ["postgres","redis"]). `exitReason` is "oom_killed" / "crashed" / null for the box\'s last container exit; when it is "oom_killed", `recommendedSize` is the next tier up to rescale to (use resize_dev_environment).',
2473
+ "",
2474
+ "Example: list_dev_environments() \u2192 every dev box for the active team."
2475
+ ].join("\n"),
2476
+ input: {},
2477
+ handler: async (_args, ctx) => {
2478
+ const teamId = await ctx.resolveTeamId();
2479
+ const { environments } = await ctx.hoststack.services.listDevEnvironments(teamId);
2480
+ const oomCount = environments.filter((e) => e.exitReason === "oom_killed").length;
2481
+ return respond({
2482
+ summary: `${environments.length} dev environment${environments.length === 1 ? "" : "s"}.` + (oomCount > 0 ? ` ${oomCount} recently OOM-killed \u2014 consider resize_dev_environment.` : ""),
2483
+ data: {
2484
+ items: environments.map((env) => ({
2485
+ ...shapeService(env),
2486
+ devUrl: env.devUrl ?? null,
2487
+ databases: env.databases ?? [],
2488
+ exitReason: env.exitReason ?? null,
2489
+ recommendedSize: env.recommendedSize ?? null
2490
+ }))
2491
+ }
2492
+ });
2493
+ }
2494
+ });
2495
+ defineTool({
2496
+ name: "create_standalone_dev_environment",
2497
+ category: "services",
2498
+ description: [
2499
+ "Create a STANDALONE dev environment in one call: a cloud box (Claude Code + Codex + OpenCode + MCPs) on a persistent /workspace, from a connected GitHub repo, an arbitrary clone URL, or blank \u2014 with optional companion Postgres / Redis / Meilisearch wired into its env (mirrors a local `make db-up`). The box lives in the team's hidden Development home, NOT under a project.",
2500
+ "",
2501
+ 'When to use: "create a dev environment for <repo>", "spin me up a cloud dev box with a Postgres". Distinct from spin_up_dev_environment (which clones an EXISTING service) and create_dev_environment (a bare box in a chosen project).',
2502
+ "",
2503
+ "Inputs:",
2504
+ " - name: the dev box name.",
2505
+ ' - source_kind: "github_repo" (clone a connected repo \u2014 needs github_repo_id), "url" (clone any http(s) git URL \u2014 needs clone_url), or "blank" (empty box).',
2506
+ " - github_repo_id (for github_repo): numeric id of a connected GitHub repo.",
2507
+ " - clone_url (for url): an http(s) git clone URL.",
2508
+ " - branch (optional): branch to clone.",
2509
+ ' - databases (optional): companion services to attach \u2014 any of "postgres", "redis", "meilisearch".',
2510
+ ' - plan (optional): box size (default "micro").',
2511
+ " - agent_accounts (optional): bind specific saved agent logins by account id per provider. OMIT to auto-inherit the box owner's default logins (claude/codex/opencode), so `claude` is already authenticated on first boot \u2014 no manual login.",
2512
+ "",
2513
+ "Returns: { service, devUrl, deployId } \u2014 deploying. Once live: open the Terminal tab, run `claude`, start the dev server on $PORT, view at https://<devUrl>. Tear down with delete_dev_environment.",
2514
+ "",
2515
+ 'Example: create_standalone_dev_environment({ name: "app-dev", source_kind: "github_repo", github_repo_id: 42, databases: ["postgres","redis"] })'
2516
+ ].join("\n"),
2517
+ input: {
2518
+ name: z13.string().min(1).max(100).describe("Dev box name."),
2519
+ source_kind: z13.enum(["github_repo", "url", "blank"]).describe("Where the code comes from."),
2520
+ github_repo_id: z13.number().int().positive().optional().describe('Connected GitHub repo id (required when source_kind="github_repo").'),
2521
+ clone_url: z13.string().url().optional().describe('http(s) git clone URL (required when source_kind="url").'),
2522
+ branch: z13.string().min(1).max(255).optional().describe("Branch to clone."),
2523
+ databases: z13.array(z13.enum(["postgres", "redis", "meilisearch"])).optional().describe("Companion services to attach (fresh + empty)."),
2524
+ plan: z13.enum(SERVICE_PLANS).optional().describe('Box size (default "micro").'),
2525
+ agent_accounts: z13.array(
2526
+ z13.object({
2527
+ provider: z13.enum(["claude", "codex", "opencode"]),
2528
+ account_id: z13.number().int().positive()
2529
+ })
2530
+ ).max(3).optional().describe(
2531
+ "Bind saved agent logins by account id per provider. Omit to inherit the box owner's default logins automatically."
2532
+ )
2533
+ },
2534
+ handler: async (args, ctx) => {
2535
+ const teamId = await ctx.resolveTeamId();
2536
+ let source;
2537
+ if (args.source_kind === "github_repo") {
2538
+ if (!args.github_repo_id) {
2539
+ return respond({
2540
+ summary: 'github_repo_id is required when source_kind is "github_repo".',
2541
+ data: { ok: false }
2542
+ });
2543
+ }
2544
+ source = {
2545
+ kind: "github_repo",
2546
+ githubRepoId: args.github_repo_id,
2547
+ ...args.branch ? { branch: args.branch } : {}
2548
+ };
2549
+ } else if (args.source_kind === "url") {
2550
+ if (!args.clone_url) {
2551
+ return respond({
2552
+ summary: 'clone_url is required when source_kind is "url".',
2553
+ data: { ok: false }
2554
+ });
2555
+ }
2556
+ source = {
2557
+ kind: "url",
2558
+ cloneUrl: args.clone_url,
2559
+ ...args.branch ? { branch: args.branch } : {}
2560
+ };
2561
+ } else {
2562
+ source = { kind: "blank" };
2563
+ }
2564
+ const input = {
2565
+ name: args.name,
2566
+ source,
2567
+ ...args.databases ? { databases: args.databases } : {},
2568
+ ...args.plan ? { plan: args.plan } : {},
2569
+ ...args.agent_accounts && args.agent_accounts.length > 0 ? {
2570
+ agentAccounts: args.agent_accounts.map((a) => ({
2571
+ provider: a.provider,
2572
+ accountId: a.account_id
2573
+ }))
2574
+ } : {}
2575
+ };
2576
+ const result = await ctx.hoststack.services.createDevEnvironment(teamId, input);
2577
+ return respond({
2578
+ summary: `Created 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}.`,
2579
+ data: {
2580
+ service: shapeService(result.service),
2581
+ devUrl: result.devUrl,
2582
+ deployId: result.deployId
2583
+ }
2584
+ });
2585
+ }
2586
+ });
2427
2587
  defineTool({
2428
2588
  name: "get_service",
2429
2589
  category: "services",