@awesomate/hosting-mcp 0.5.0 → 0.6.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
@@ -21106,6 +21106,12 @@ var StdioServerTransport = class {
21106
21106
  }
21107
21107
  };
21108
21108
 
21109
+ // src/index.ts
21110
+ import { readFileSync as readFileSync2 } from "node:fs";
21111
+ import { homedir as homedir2 } from "node:os";
21112
+ import { join as join2, dirname } from "node:path";
21113
+ import { fileURLToPath } from "node:url";
21114
+
21109
21115
  // src/config.ts
21110
21116
  import { readFileSync } from "node:fs";
21111
21117
  import { homedir } from "node:os";
@@ -21214,9 +21220,34 @@ function hubDelete(config3, path) {
21214
21220
 
21215
21221
  // src/index.ts
21216
21222
  var config2;
21223
+ var SERVER_VERSION = (() => {
21224
+ try {
21225
+ const pkg = JSON.parse(
21226
+ readFileSync2(join2(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf8")
21227
+ );
21228
+ return pkg.version ?? "0.0.0";
21229
+ } catch {
21230
+ return "0.0.0";
21231
+ }
21232
+ })();
21233
+ function skillUpdateInfo() {
21234
+ let installedSkillVersion = null;
21235
+ try {
21236
+ installedSkillVersion = readFileSync2(
21237
+ join2(homedir2(), ".claude", "skills", "awesomate-hosting", ".installed-version"),
21238
+ "utf8"
21239
+ ).trim() || null;
21240
+ } catch {
21241
+ }
21242
+ return {
21243
+ serverVersion: SERVER_VERSION,
21244
+ installedSkillVersion,
21245
+ updateAvailable: installedSkillVersion !== SERVER_VERSION
21246
+ };
21247
+ }
21217
21248
  var server = new McpServer({
21218
21249
  name: "awesomate-hosting",
21219
- version: "0.1.0"
21250
+ version: SERVER_VERSION
21220
21251
  });
21221
21252
  function textResult(data) {
21222
21253
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
@@ -21234,10 +21265,20 @@ function readTool(name, description, path) {
21234
21265
  }
21235
21266
  });
21236
21267
  }
21237
- readTool(
21268
+ server.registerTool(
21238
21269
  "awesomate_get_context",
21239
- "Call this FIRST each session. Returns the connected Awesomate account: plan, capabilities (shell access), plan limits, scopes this token can exercise, token expiry (warn the user if within 7 days), and cPanel routing when provisioned.",
21240
- "/api/hosting-access/context"
21270
+ {
21271
+ description: "Call this FIRST each session. Returns the connected Awesomate account: plan, capabilities (shell access), plan limits, scopes this token can exercise, token expiry (warn the user if within 7 days), cPanel routing when provisioned, and skill.updateAvailable \u2014 if true, the local awesomate-hosting skill files are older than this server; tell the user to re-run Connect Claude Code from hub.awesomate.ai/sites to refresh them (this also renews the token).",
21272
+ inputSchema: {}
21273
+ },
21274
+ async () => {
21275
+ try {
21276
+ const ctx = await hubGet(config2, "/api/hosting-access/context");
21277
+ return textResult({ ...ctx, skill: skillUpdateInfo() });
21278
+ } catch (err) {
21279
+ return errorResult(err);
21280
+ }
21281
+ }
21241
21282
  );
21242
21283
  readTool(
21243
21284
  "awesomate_n8n_context",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awesomate/hosting-mcp",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "Awesomate MCP server — lets Claude manage your Awesomate WordPress hosting, plan, limits, and n8n automations",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -32,11 +32,35 @@ context note three things and cache them for the session:
32
32
  - **`patExpiresAt`** — if it's within ~7 days, tell the user to open
33
33
  **hub.awesomate.ai/sites → Connect Claude Code** and re-run the setup prompt to
34
34
  refresh the token. If any tool returns a 401, do the same.
35
+ - **`skill.updateAvailable`** — if true, this skill's local files are older than
36
+ the MCP server. Mention it once (don't nag): re-running Connect Claude Code
37
+ from **hub.awesomate.ai/sites** refreshes the skill and renews the token in
38
+ one go. Not urgent — finish the user's actual request first.
35
39
  - **`cpanel`** routing (host/user), present once hosting is provisioned.
36
40
 
37
41
  If `awesomate_get_context` fails with a connectivity error, it's the user's
38
42
  network or the API base — not an auth problem; say so.
39
43
 
44
+ If this skill is loaded but **no `awesomate_*` tools exist in the session at
45
+ all**, the MCP server was registered after Claude Code started (the bootstrap
46
+ just ran). Don't investigate settings files or reinstall anything — and don't
47
+ make a restart the precondition for showing the user their own data. The
48
+ skill works right now over REST: read `apiBase` and `pat` from
49
+ `~/.awesomate/credentials.json` (never echo the pat into the conversation)
50
+ and GET with `Authorization: Bearer <pat>`:
51
+
52
+ | MCP tool | REST equivalent |
53
+ |---|---|
54
+ | `awesomate_get_context` | `GET {apiBase}/api/hosting-access/context` |
55
+ | `awesomate_get_hosting_status` | `GET {apiBase}/api/client-hosting/status` |
56
+ | `awesomate_get_hosting_account` | `GET {apiBase}/api/client-hosting/account` |
57
+ | `awesomate_list_sites` | `GET {apiBase}/api/client-hosting/sites` |
58
+ | `awesomate_list_domains` | `GET {apiBase}/api/client-hosting/domains` |
59
+ | `awesomate_get_limits` | `GET {apiBase}/api/client-hosting/limits` |
60
+
61
+ Serve the request with these now, then suggest restarting Claude Code at a
62
+ natural break so the richer MCP integration loads.
63
+
40
64
  ## 1. The plan model (so your nudges are accurate)
41
65
 
42
66
  | Plan | WP sites | Custom domains | Shell / Claude Code | Notes |
@@ -82,6 +82,15 @@ function installSkill() {
82
82
  const bundled = skillRoot.endsWith('/skill')
83
83
  ? readdirSync(skillRoot)
84
84
  : [hostingSkill.split('/').pop()];
85
+ // Package version, stamped into each installed skill as .installed-version.
86
+ // The MCP server (always latest via unpinned npx) compares it against its own
87
+ // version and reports skill.updateAvailable in awesomate_get_context.
88
+ let pkgVersion = null;
89
+ if (skillRoot.endsWith('/skill')) {
90
+ try {
91
+ pkgVersion = JSON.parse(readFileSync(join(dirname(skillRoot), 'package.json'), 'utf8')).version ?? null;
92
+ } catch { /* non-fatal — marker just won't be written */ }
93
+ }
85
94
  let installed = 0;
86
95
  for (const name of bundled) {
87
96
  const src = join(skillRoot, name);
@@ -97,6 +106,9 @@ function installSkill() {
97
106
  if (/\.(sh|mjs)$/.test(f)) { try { chmodSync(join(scriptsDir, f), 0o755); } catch { /* non-fatal */ } }
98
107
  }
99
108
  }
109
+ if (pkgVersion) {
110
+ try { writeFileSync(join(dest, '.installed-version'), `${pkgVersion}\n`); } catch { /* non-fatal */ }
111
+ }
100
112
  console.log(`✓ Installed the "${name}" skill to ${dest}.`);
101
113
  installed += 1;
102
114
  }
@@ -174,7 +186,7 @@ async function main() {
174
186
  }
175
187
 
176
188
  console.log('\nSetup complete. Next: ask me to read your plan, list your sites, and tell you what we can do.');
177
- if (!registered) console.log('(Restart Claude Code first so it picks up the new MCP server.)');
189
+ if (!registered) console.log('(The skill works in your current Claude session right away via its REST fallback — restart Claude Code when convenient to load the MCP tools.)');
178
190
  }
179
191
 
180
192
  main().catch((err) => {