@hoststack.dev/mcp 0.9.0 → 0.9.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 CHANGED
@@ -52,7 +52,13 @@ Add to `~/.cursor/mcp.json` (or via Settings → MCP):
52
52
  #### Claude Code
53
53
 
54
54
  ```bash
55
- claude mcp add hoststack -- npx -y @hoststack.dev/mcp -e HOSTSTACK_API_KEY=hs_live_...
55
+ claude mcp add hoststack --env HOSTSTACK_API_KEY=hs_live_... -- npx -y @hoststack.dev/mcp
56
+ ```
57
+
58
+ Or — equivalently — use the hosted HTTP transport so credentials live only in your Claude Code config, not on disk:
59
+
60
+ ```bash
61
+ claude mcp add --transport http hoststack https://hoststack.dev/api/mcp --header "Authorization: Bearer hs_live_..."
56
62
  ```
57
63
 
58
64
  #### Any other client (hosted)
@@ -79,7 +85,7 @@ If `HOSTSTACK_API_KEY` is set in your shell, it gets baked into the snippet; oth
79
85
 
80
86
  ## Tool inventory
81
87
 
82
- 55 tools, grouped by resource:
88
+ 58 tools, grouped by resource:
83
89
 
84
90
  | Category | Read | Write |
85
91
  | ----------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
@@ -87,7 +93,7 @@ If `HOSTSTACK_API_KEY` is set in your shell, it gets baked into the snippet; oth
87
93
  | **services** | `list_services`, `get_service`, `get_service_metrics`, `get_service_metrics_history`, `get_service_logs`, `get_service_logs_bulk` | `update_service`, `update_service_config`, `suspend_service`, `resume_service` |
88
94
  | **deploys** | `list_deploys`, `get_deploy`, `get_deploy_logs`, `diagnose_deploy` | `trigger_deploy`, `cancel_deploy` |
89
95
  | **environments** | `list_environments` | `create_environment`, `delete_environment`, `promote_deploy` |
90
- | **databases** | `list_databases`, `get_database` | `update_database` (use the dashboard for create/delete/credentials) |
96
+ | **databases** | `list_databases`, `get_database`, `get_database_cluster`, `query_database` | `update_database`, `upgrade_database_to_ha` (use the dashboard for create/delete/credentials) |
91
97
  | **volumes** | `list_volumes` | `create_volume`, `update_volume`, `delete_volume` |
92
98
  | **domains** | `list_domains` | `add_domain`, `verify_domain`, `remove_domain` |
93
99
  | **dns** | `list_dns_zones`, `list_dns_records`, `get_dns_record` | `create_dns_record`, `update_dns_record`, `delete_dns_record` |
@@ -834,13 +834,14 @@ defineTool({
834
834
  name: "trigger_deploy",
835
835
  category: "deploys",
836
836
  description: [
837
- "Kick off a new deploy from the latest commit on the service branch. Optionally clear the build cache for a clean rebuild.",
837
+ "Kick off a new deploy. Defaults to the latest commit on the service branch; pass commit_hash or branch to deploy something else.",
838
838
  "",
839
- 'When to use: the user explicitly asks to deploy ("ship it", "redeploy", "kick off a new build"). For services with auto-deploy enabled, a fresh git push already triggers a deploy automatically \u2014 only call this for manual triggers, cache-clearing, or after a config change.',
839
+ 'When to use: the user explicitly asks to deploy ("ship it", "redeploy", "kick off a new build"). For services with auto-deploy enabled, a fresh git push already triggers a deploy automatically \u2014 only call this for manual triggers or after a config change.',
840
840
  "",
841
841
  "Inputs:",
842
842
  " - service_id: publicId of the service.",
843
- " - clear_cache (optional): boolean \u2014 discard the cached build layers. Default false.",
843
+ " - commit_hash (optional): build a specific commit instead of HEAD on the configured branch.",
844
+ " - branch (optional): build the tip of a non-default branch.",
844
845
  "",
845
846
  'Returns: { deploy: Deploy } \u2014 the new deploy record. Status will start as "pending" then transition through "building" \u2192 "deploying" \u2192 "live" or "failed".',
846
847
  "",
@@ -848,12 +849,14 @@ defineTool({
848
849
  ].join("\n"),
849
850
  input: {
850
851
  service_id: z6.string().describe("Service publicId."),
851
- clear_cache: z6.boolean().optional().describe("Clear the build cache (default false).")
852
+ commit_hash: z6.string().max(40).optional().describe("Specific commit to build (default: branch HEAD)."),
853
+ branch: z6.string().max(200).optional().describe("Branch to build (default: service configured branch).")
852
854
  },
853
855
  handler: async (args2, ctx) => {
854
856
  const teamId = await ctx.resolveTeamId();
855
857
  const input = {};
856
- if (args2.clear_cache !== void 0) input.clearCache = args2.clear_cache;
858
+ if (args2.commit_hash !== void 0) input.commitHash = args2.commit_hash;
859
+ if (args2.branch !== void 0) input.branch = args2.branch;
857
860
  const response = await ctx.hoststack.deploys.trigger(teamId, args2.service_id, input);
858
861
  const data = { deploy: shapeDeploy(response.deploy) };
859
862
  const publicId = data.deploy && "publicId" in data.deploy ? data.deploy.publicId : "unknown";
@@ -896,7 +899,7 @@ defineTool({
896
899
  name: "get_deploy_logs",
897
900
  category: "deploys",
898
901
  description: [
899
- "Fetch the build/deploy logs for a single deploy. Returns the entire log buffer the agent can the search for errors.",
902
+ "Fetch the build/deploy logs for a single deploy. Returns the entire log buffer the agent can then search for errors.",
900
903
  "",
901
904
  "When to use: a deploy failed and you need to read the build output to diagnose. Pair with get_deploy to find a failed deploy_id, then call this. For runtime (post-deploy) logs of the running container, use get_service_logs instead.",
902
905
  "",
@@ -1337,7 +1340,8 @@ defineTool({
1337
1340
  "",
1338
1341
  "Inputs:",
1339
1342
  ' - hostname: the domain to add (e.g. "api.example.com").',
1340
- " - service_id (optional): publicId of the service to bind to. If omitted, the domain is added unbound and you can attach it later with update_domain.",
1343
+ " - service_id: publicId of the service to bind the domain to.",
1344
+ " - path_prefix (optional): when set, only requests under this URL prefix route to this service. Use for path-based fan-out (e.g. `/api` to an api service, `/` to a web service on the same hostname).",
1341
1345
  "",
1342
1346
  "Returns: { domain: Domain } \u2014 includes dnsTargets you must configure (CNAME / A records).",
1343
1347
  "",
@@ -1345,12 +1349,16 @@ defineTool({
1345
1349
  ].join("\n"),
1346
1350
  input: {
1347
1351
  hostname: z8.string().min(3).max(253).describe("Fully-qualified hostname (e.g. api.example.com)."),
1348
- service_id: z8.string().optional().describe("Optional service publicId to bind to.")
1352
+ service_id: z8.string().describe("Service publicId to bind to."),
1353
+ path_prefix: z8.string().optional().describe('Optional URL prefix for path-based routing (e.g. "/api").')
1349
1354
  },
1350
1355
  handler: async (args2, ctx) => {
1351
1356
  const teamId = await ctx.resolveTeamId();
1352
- const input = { domain: args2.hostname };
1353
- if (args2.service_id !== void 0) input.serviceId = args2.service_id;
1357
+ const input = {
1358
+ domain: args2.hostname,
1359
+ serviceId: args2.service_id
1360
+ };
1361
+ if (args2.path_prefix !== void 0) input.pathPrefix = args2.path_prefix;
1354
1362
  const response = await ctx.hoststack.domains.add(teamId, input);
1355
1363
  const data = { domain: shapeDomain(response.domain) };
1356
1364
  return respond({
@@ -1451,7 +1459,7 @@ defineTool({
1451
1459
  " - service_id: publicId of the service.",
1452
1460
  ' - key: env-var name (e.g. "DATABASE_URL").',
1453
1461
  " - value: new value (will be encrypted at rest if is_secret=true).",
1454
- " - is_secret (optional): true marks the value as secret (masked on read). Default true for safety; pass false for boring config like PORT or NODE_ENV.",
1462
+ " - is_secret (optional): true marks the value as secret (masked on read). On create, defaults to true for safety. On update, omitting it leaves the existing flag untouched \u2014 pass it explicitly only when you want to change classification.",
1455
1463
  "",
1456
1464
  'Returns: { envVar: EnvVar, action: "created" | "updated" }.',
1457
1465
  "",
@@ -1465,18 +1473,16 @@ defineTool({
1465
1473
  },
1466
1474
  handler: async (args2, ctx) => {
1467
1475
  const teamId = await ctx.resolveTeamId();
1468
- const isSecret = args2.is_secret ?? true;
1469
1476
  const existing = await ctx.hoststack.envVars.list(teamId, args2.service_id);
1470
1477
  const match = existing.envVars.find((v) => v.key === args2.key);
1471
1478
  if (match) {
1479
+ const updatePayload = { value: args2.value };
1480
+ if (args2.is_secret !== void 0) updatePayload.isSecret = args2.is_secret;
1472
1481
  const response2 = await ctx.hoststack.envVars.update(
1473
1482
  teamId,
1474
1483
  args2.service_id,
1475
1484
  String(match.id),
1476
- {
1477
- value: args2.value,
1478
- isSecret
1479
- }
1485
+ updatePayload
1480
1486
  );
1481
1487
  const data2 = {
1482
1488
  envVar: shapeEnvVar(response2.envVar),
@@ -1487,7 +1493,7 @@ defineTool({
1487
1493
  const response = await ctx.hoststack.envVars.create(teamId, args2.service_id, {
1488
1494
  key: args2.key,
1489
1495
  value: args2.value,
1490
- isSecret
1496
+ isSecret: args2.is_secret ?? true
1491
1497
  });
1492
1498
  const data = {
1493
1499
  envVar: shapeEnvVar(response.envVar),
@@ -1623,7 +1629,7 @@ defineTool({
1623
1629
  "",
1624
1630
  "Returns: { environment: Environment }.",
1625
1631
  "",
1626
- 'Example: create_environment({ project_id: "prj_abc", name: "Staging", type: "staging" }) \u2192 { environment: { id: 7, publicId: "environment_\u2026", name: "Staging", type: "staging" } }'
1632
+ 'Example: create_environment({ project_id: "prj_abc", name: "Staging", type: "staging" }) \u2192 { environment: { id: 7, publicId: "env_\u2026", name: "Staging", type: "staging" } }'
1627
1633
  ].join("\n"),
1628
1634
  input: {
1629
1635
  project_id: z10.string().describe("Project publicId."),
@@ -1660,7 +1666,7 @@ defineTool({
1660
1666
  "",
1661
1667
  "Returns: { success: true } on success.",
1662
1668
  "",
1663
- 'Example: delete_environment({ project_id: "prj_abc", environment_id: "environment_xyz" }) \u2192 { success: true }'
1669
+ 'Example: delete_environment({ project_id: "prj_abc", environment_id: "env_xyz" }) \u2192 { success: true }'
1664
1670
  ].join("\n"),
1665
1671
  input: {
1666
1672
  project_id: z10.string().describe("Project publicId."),
@@ -1692,7 +1698,7 @@ defineTool({
1692
1698
  "",
1693
1699
  "Returns: { deploy: Deploy } \u2014 the new deploy on the target service.",
1694
1700
  "",
1695
- 'Example: promote_deploy({ service_id: "svc_staging", deploy_id: "dpl_built", target_environment_id: "environment_prod" }) \u2192 { deploy: { id: 99, status: "pending", trigger: "rollback", dockerImageId: "sha256:\u2026" } }'
1701
+ 'Example: promote_deploy({ service_id: "svc_staging", deploy_id: "dpl_built", target_environment_id: "env_prod" }) \u2192 { deploy: { id: 99, status: "pending", trigger: "rollback", dockerImageId: "sha256:\u2026" } }'
1696
1702
  ].join("\n"),
1697
1703
  input: {
1698
1704
  service_id: z10.string().describe("Source service publicId."),
@@ -2714,7 +2720,7 @@ defineTool({
2714
2720
 
2715
2721
  // src/server-factory.ts
2716
2722
  var PACKAGE_NAME = "hoststack";
2717
- var PACKAGE_VERSION = "0.6.0";
2723
+ var PACKAGE_VERSION = "0.9.1";
2718
2724
  function createMcpServer(options) {
2719
2725
  const baseUrl2 = (options.baseUrl ?? "https://hoststack.dev").replace(/\/$/, "");
2720
2726
  const hoststack = new HostStack({ apiKey: options.apiKey, baseUrl: baseUrl2 });
@@ -2779,7 +2785,7 @@ if (printIdx !== -1) {
2779
2785
  }
2780
2786
  if (target === "claude-code") {
2781
2787
  process.stdout.write(
2782
- `claude mcp add hoststack -- npx -y @hoststack.dev/mcp -e HOSTSTACK_API_KEY=${apiKeyPlaceholder}
2788
+ `claude mcp add hoststack --env HOSTSTACK_API_KEY=${apiKeyPlaceholder} -- npx -y @hoststack.dev/mcp
2783
2789
  `
2784
2790
  );
2785
2791
  process.exit(0);