mcp-server-wework 0.1.0 → 0.3.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/index.js CHANGED
@@ -3,9 +3,11 @@ const fs = require("fs");
3
3
  const path = require("path");
4
4
  const { spawn } = require("child_process");
5
5
 
6
+ const { installBinary } = require("./postinstall");
6
7
  const { startUpdateCheck } = require("./update_check");
7
8
 
8
- const exe = process.platform === "win32" ? "mcp-server-wework.exe" : "mcp-server-wework";
9
+ const exe =
10
+ process.platform === "win32" ? "mcp-server-wework.exe" : "mcp-server-wework";
9
11
  const binPath = path.join(__dirname, exe);
10
12
 
11
13
  const PKG = (() => {
@@ -16,34 +18,48 @@ const PKG = (() => {
16
18
  }
17
19
  })();
18
20
 
19
- if (!fs.existsSync(binPath)) {
20
- console.error(`Binary not found: ${binPath}`);
21
- process.exit(1);
22
- }
21
+ async function main() {
22
+ if (!fs.existsSync(binPath)) {
23
+ await installBinary();
24
+ }
23
25
 
24
- if (process.platform !== "win32") {
25
- try {
26
- fs.chmodSync(binPath, 0o755);
27
- } catch {}
28
- }
26
+ if (!fs.existsSync(binPath)) {
27
+ console.error(`Binary not found: ${binPath}`);
28
+ process.exit(1);
29
+ }
29
30
 
30
- const child = spawn(binPath, process.argv.slice(2), {
31
- stdio: "inherit",
32
- windowsHide: true,
33
- });
31
+ if (process.platform !== "win32") {
32
+ try {
33
+ fs.chmodSync(binPath, 0o755);
34
+ } catch {}
35
+ }
34
36
 
35
- // Best-effort update notice (cached + short timeout).
36
- // Aborts on command exit so it never delays shutdown.
37
- const updateAbort = new AbortController();
38
- startUpdateCheck({ installedVersion: PKG && PKG.version, signal: updateAbort.signal });
37
+ const child = spawn(binPath, process.argv.slice(2), {
38
+ stdio: "inherit",
39
+ windowsHide: true,
40
+ });
39
41
 
40
- child.on("exit", (code) => {
41
- try {
42
- updateAbort.abort();
43
- } catch {}
44
- process.exitCode = code == null ? 1 : code;
45
- });
46
- child.on("error", (err) => {
47
- console.error(err.message);
48
- process.exitCode = 1;
42
+ // Best-effort update notice (cached + short timeout).
43
+ // Aborts on command exit so it never delays shutdown.
44
+ const updateAbort = new AbortController();
45
+ startUpdateCheck({
46
+ installedVersion: PKG && PKG.version,
47
+ signal: updateAbort.signal,
48
+ });
49
+
50
+ child.on("exit", (code) => {
51
+ try {
52
+ updateAbort.abort();
53
+ } catch {}
54
+ process.exitCode = code == null ? 1 : code;
55
+ });
56
+ child.on("error", (err) => {
57
+ console.error(err.message);
58
+ process.exitCode = 1;
59
+ });
60
+ }
61
+
62
+ main().catch((err) => {
63
+ console.error(`mcp-server-wework: failed to install binary: ${err.message}`);
64
+ process.exit(1);
49
65
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-server-wework",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "MCP server for WeWork bookings and space search",
5
5
  "scripts": {
6
6
  "postinstall": "node postinstall.js"
package/postinstall.js CHANGED
@@ -17,7 +17,12 @@ const PLATFORM_ENV = "MCP_SERVER_WEWORK_PLATFORM";
17
17
  function httpGet(url, { headers } = {}) {
18
18
  return new Promise((resolve, reject) => {
19
19
  const req = https.get(url, { headers }, (res) => {
20
- if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
20
+ if (
21
+ res.statusCode &&
22
+ res.statusCode >= 300 &&
23
+ res.statusCode < 400 &&
24
+ res.headers.location
25
+ ) {
21
26
  resolve(httpGet(res.headers.location, { headers }));
22
27
  return;
23
28
  }
@@ -65,108 +70,113 @@ function parseChecksums(text) {
65
70
  return map;
66
71
  }
67
72
 
68
- (async function main() {
69
- try {
70
- const platformRaw = process.env[PLATFORM_ENV] || process.platform;
71
- const platform = platformRaw === "win32" ? "windows" : platformRaw;
72
- if (!["darwin", "linux", "windows"].includes(platform)) {
73
- console.error("mcp-server-wework: npm install supports macOS (darwin), Linux, and Windows only");
74
- process.exit(1);
75
- }
73
+ async function installBinary() {
74
+ const platformRaw = process.env[PLATFORM_ENV] || process.platform;
75
+ const platform = platformRaw === "win32" ? "windows" : platformRaw;
76
+ if (!["darwin", "linux", "windows"].includes(platform)) {
77
+ throw new Error(
78
+ "mcp-server-wework: npm install supports macOS (darwin), Linux, and Windows only",
79
+ );
80
+ }
76
81
 
77
- const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8"));
78
- const version = process.env[VERSION_ENV] || pkg.version || "";
79
- if (!version) {
80
- console.error("postinstall: could not determine version");
81
- process.exit(1);
82
- }
82
+ const pkg = JSON.parse(
83
+ fs.readFileSync(path.join(__dirname, "package.json"), "utf8"),
84
+ );
85
+ const version = process.env[VERSION_ENV] || pkg.version || "";
86
+ if (!version) {
87
+ throw new Error("postinstall: could not determine version");
88
+ }
83
89
 
84
- const detectedArch =
85
- process.arch === "x64"
86
- ? "amd64"
87
- : process.arch === "arm64"
88
- ? "arm64"
89
- : process.arch === "arm"
90
- ? "armv7"
91
- : process.arch;
92
- const arch = process.env[ARCH_ENV] || detectedArch;
93
- if (!["amd64", "arm64", "armv7"].includes(arch)) {
94
- console.error(`Unsupported arch: ${arch}`);
95
- process.exit(1);
96
- }
97
- if (platform === "windows" && arch === "armv7") {
98
- console.error(`Unsupported Windows arch: ${arch}`);
99
- process.exit(1);
100
- }
90
+ const detectedArch =
91
+ process.arch === "x64"
92
+ ? "amd64"
93
+ : process.arch === "arm64"
94
+ ? "arm64"
95
+ : process.arch === "arm"
96
+ ? "armv7"
97
+ : process.arch;
98
+ const arch = process.env[ARCH_ENV] || detectedArch;
99
+ if (!["amd64", "arm64", "armv7"].includes(arch)) {
100
+ throw new Error(`Unsupported arch: ${arch}`);
101
+ }
102
+ if (platform === "windows" && arch === "armv7") {
103
+ throw new Error(`Unsupported Windows arch: ${arch}`);
104
+ }
101
105
 
102
- const assetName = `${BIN}_${version}_${platform}_${arch}.tar.gz`;
103
- const baseOverride = process.env[BASE_URL_ENV];
104
- const bases = baseOverride
105
- ? [baseOverride]
106
- : [
107
- `https://github.com/${OWNER}/${REPO}/releases/download/${version}`,
108
- `https://github.com/${OWNER}/${REPO}/releases/download/v${version}`,
109
- ];
110
- const headers = { "User-Agent": `${REPO}-postinstall` };
111
- const outDir = __dirname;
112
- const exe = platform === "windows" ? `${BIN}.exe` : BIN;
113
- const binPath = path.join(outDir, exe);
106
+ const assetName = `${BIN}_${version}_${platform}_${arch}.tar.gz`;
107
+ const baseOverride = process.env[BASE_URL_ENV];
108
+ const bases = baseOverride
109
+ ? [baseOverride]
110
+ : [
111
+ `https://github.com/${OWNER}/${REPO}/releases/download/${version}`,
112
+ `https://github.com/${OWNER}/${REPO}/releases/download/v${version}`,
113
+ ];
114
+ const headers = { "User-Agent": `${REPO}-postinstall` };
115
+ const outDir = __dirname;
116
+ const exe = platform === "windows" ? `${BIN}.exe` : BIN;
117
+ const binPath = path.join(outDir, exe);
114
118
 
115
- if (fs.existsSync(binPath)) {
116
- try {
117
- fs.chmodSync(binPath, 0o755);
118
- } catch {}
119
- process.exit(0);
120
- }
121
-
122
- let tarGz = null;
123
- let baseUsed = "";
124
- let lastErr = null;
125
- for (const base of bases) {
126
- const url = `${base}/${assetName}`;
127
- console.log(`postinstall: downloading ${assetName} from ${url}`);
128
- try {
129
- tarGz = await httpGet(url, { headers });
130
- baseUsed = base;
131
- break;
132
- } catch (e) {
133
- lastErr = e;
134
- }
135
- }
136
- if (!tarGz) throw lastErr || new Error("failed to download binary");
119
+ if (fs.existsSync(binPath)) {
120
+ try {
121
+ fs.chmodSync(binPath, 0o755);
122
+ } catch {}
123
+ return;
124
+ }
137
125
 
138
- // checksum (best effort)
126
+ let tarGz = null;
127
+ let baseUsed = "";
128
+ let lastErr = null;
129
+ for (const base of bases) {
130
+ const url = `${base}/${assetName}`;
131
+ console.log(`postinstall: downloading ${assetName} from ${url}`);
139
132
  try {
140
- const checksumsUrl = `${baseUsed}/checksums.txt`;
141
- const checksumsBuf = await httpGet(checksumsUrl, { headers });
142
- const checksums = parseChecksums(checksumsBuf.toString("utf8"));
143
- const sumExpected = checksums.get(assetName);
144
- if (!sumExpected) throw new Error("asset not in checksums.txt");
145
- const sumActual = sha256(tarGz);
146
- if (sumActual.toLowerCase() !== sumExpected.toLowerCase()) throw new Error("checksum mismatch");
147
- console.log("postinstall: checksum OK");
133
+ tarGz = await httpGet(url, { headers });
134
+ baseUsed = base;
135
+ break;
148
136
  } catch (e) {
149
- console.warn(`postinstall: checksum skipped/failed: ${e.message}`);
137
+ lastErr = e;
150
138
  }
139
+ }
140
+ if (!tarGz) throw lastErr || new Error("failed to download binary");
151
141
 
152
- // extract only the binary into npm directory (archive contains binary at root)
153
- const tmpFile = path.join(os.tmpdir(), `${REPO}-${Date.now()}.tar.gz`);
154
- fs.writeFileSync(tmpFile, tarGz);
155
- const tarRes = spawnSync("tar", ["-xzf", tmpFile, "-C", outDir, exe], { stdio: "inherit" });
156
- if (tarRes.status !== 0) {
157
- console.error("postinstall: failed to extract binary");
158
- process.exit(1);
159
- }
160
- try {
161
- fs.chmodSync(binPath, 0o755);
162
- } catch {}
163
- try {
164
- fs.unlinkSync(tmpFile);
165
- } catch {}
166
- console.log(`postinstall: installed ${exe} to ${outDir}`);
167
- process.exit(0);
168
- } catch (err) {
142
+ // checksum (best effort)
143
+ try {
144
+ const checksumsUrl = `${baseUsed}/checksums.txt`;
145
+ const checksumsBuf = await httpGet(checksumsUrl, { headers });
146
+ const checksums = parseChecksums(checksumsBuf.toString("utf8"));
147
+ const sumExpected = checksums.get(assetName);
148
+ if (!sumExpected) throw new Error("asset not in checksums.txt");
149
+ const sumActual = sha256(tarGz);
150
+ if (sumActual.toLowerCase() !== sumExpected.toLowerCase())
151
+ throw new Error("checksum mismatch");
152
+ console.log("postinstall: checksum OK");
153
+ } catch (e) {
154
+ console.warn(`postinstall: checksum skipped/failed: ${e.message}`);
155
+ }
156
+
157
+ // extract only the binary into npm directory (archive contains binary at root)
158
+ const tmpFile = path.join(os.tmpdir(), `${REPO}-${Date.now()}.tar.gz`);
159
+ fs.writeFileSync(tmpFile, tarGz);
160
+ const tarRes = spawnSync("tar", ["-xzf", tmpFile, "-C", outDir, exe], {
161
+ stdio: "inherit",
162
+ });
163
+ if (tarRes.status !== 0) {
164
+ throw new Error("postinstall: failed to extract binary");
165
+ }
166
+ try {
167
+ fs.chmodSync(binPath, 0o755);
168
+ } catch {}
169
+ try {
170
+ fs.unlinkSync(tmpFile);
171
+ } catch {}
172
+ console.log(`postinstall: installed ${exe} to ${outDir}`);
173
+ }
174
+
175
+ if (require.main === module) {
176
+ installBinary().catch((err) => {
169
177
  console.error(`postinstall error: ${err.message}`);
170
178
  process.exit(1);
171
- }
172
- })();
179
+ });
180
+ }
181
+
182
+ module.exports = { installBinary };
package/update_check.js CHANGED
@@ -29,7 +29,8 @@ function getCacheFile() {
29
29
 
30
30
  if (process.platform === "win32") {
31
31
  const base = process.env.LOCALAPPDATA || process.env.APPDATA;
32
- if (!base) return path.join(home, "AppData", "Local", CACHE_DIR_NAME, "update.json");
32
+ if (!base)
33
+ return path.join(home, "AppData", "Local", CACHE_DIR_NAME, "update.json");
33
34
  return path.join(base, CACHE_DIR_NAME, "update.json");
34
35
  }
35
36
 
@@ -64,24 +65,28 @@ function fetchLatestVersion(packageName, timeoutMs, signal) {
64
65
  const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`;
65
66
 
66
67
  return new Promise((resolve, reject) => {
67
- const req = https.get(url, { headers: { "User-Agent": `${DEFAULT_PACKAGE_NAME}-update-check` } }, (res) => {
68
- if (res.statusCode !== 200) {
69
- reject(new Error(`GET ${url} -> ${res.statusCode}`));
70
- res.resume();
71
- return;
72
- }
73
-
74
- const chunks = [];
75
- res.on("data", (c) => chunks.push(c));
76
- res.on("end", () => {
77
- try {
78
- const json = JSON.parse(Buffer.concat(chunks).toString("utf8"));
79
- resolve(typeof json.version === "string" ? json.version : "");
80
- } catch (e) {
81
- reject(e);
68
+ const req = https.get(
69
+ url,
70
+ { headers: { "User-Agent": `${DEFAULT_PACKAGE_NAME}-update-check` } },
71
+ (res) => {
72
+ if (res.statusCode !== 200) {
73
+ reject(new Error(`GET ${url} -> ${res.statusCode}`));
74
+ res.resume();
75
+ return;
82
76
  }
83
- });
84
- });
77
+
78
+ const chunks = [];
79
+ res.on("data", (c) => chunks.push(c));
80
+ res.on("end", () => {
81
+ try {
82
+ const json = JSON.parse(Buffer.concat(chunks).toString("utf8"));
83
+ resolve(typeof json.version === "string" ? json.version : "");
84
+ } catch (e) {
85
+ reject(e);
86
+ }
87
+ });
88
+ },
89
+ );
85
90
 
86
91
  req.on("error", reject);
87
92
  req.setTimeout(timeoutMs, () => req.destroy(new Error("timeout")));
@@ -91,7 +96,11 @@ function fetchLatestVersion(packageName, timeoutMs, signal) {
91
96
  req.destroy(new Error("aborted"));
92
97
  return;
93
98
  }
94
- signal.addEventListener("abort", () => req.destroy(new Error("aborted")), { once: true });
99
+ signal.addEventListener(
100
+ "abort",
101
+ () => req.destroy(new Error("aborted")),
102
+ { once: true },
103
+ );
95
104
  }
96
105
  });
97
106
  }
@@ -107,13 +116,22 @@ function normalizeVersion(version) {
107
116
  function printNotice({ packageName, installed, latest, updateCommand }) {
108
117
  const prefix = `${packageName}:`;
109
118
  if (installed && latest) {
110
- console.error(`${prefix} an update is available (installed ${installed}, latest ${latest}). Update with: ${updateCommand}`);
119
+ console.error(
120
+ `${prefix} an update is available (installed ${installed}, latest ${latest}). Update with: ${updateCommand}`,
121
+ );
111
122
  return;
112
123
  }
113
- console.error(`${prefix} an update is available. Update with: ${updateCommand}`);
124
+ console.error(
125
+ `${prefix} an update is available. Update with: ${updateCommand}`,
126
+ );
114
127
  }
115
128
 
116
- async function runUpdateCheck({ packageName, installedVersion, updateCommand, signal }) {
129
+ async function runUpdateCheck({
130
+ packageName,
131
+ installedVersion,
132
+ updateCommand,
133
+ signal,
134
+ }) {
117
135
  if (isDisabled()) return;
118
136
  if (!process.stderr.isTTY) return;
119
137
 
@@ -121,8 +139,12 @@ async function runUpdateCheck({ packageName, installedVersion, updateCommand, si
121
139
  if (!installed) return;
122
140
 
123
141
  const cache = readCache() || {};
124
- const lastChecked = Number.isFinite(cache.lastChecked) ? cache.lastChecked : 0;
125
- const lastNotified = Number.isFinite(cache.lastNotified) ? cache.lastNotified : 0;
142
+ const lastChecked = Number.isFinite(cache.lastChecked)
143
+ ? cache.lastChecked
144
+ : 0;
145
+ const lastNotified = Number.isFinite(cache.lastNotified)
146
+ ? cache.lastNotified
147
+ : 0;
126
148
  const cachedLatest = typeof cache.latest === "string" ? cache.latest : "";
127
149
 
128
150
  const now = Date.now();
@@ -131,14 +153,23 @@ async function runUpdateCheck({ packageName, installedVersion, updateCommand, si
131
153
  const latestCached = normalizeVersion(cachedLatest);
132
154
  if (latestCached && semver.gt(latestCached, installed)) {
133
155
  if (!lastNotified || now - lastNotified >= UPDATE_CHECK_INTERVAL_MS) {
134
- printNotice({ packageName, installed, latest: latestCached, updateCommand });
156
+ printNotice({
157
+ packageName,
158
+ installed,
159
+ latest: latestCached,
160
+ updateCommand,
161
+ });
135
162
  writeCache({ ...cache, lastNotified: now });
136
163
  }
137
164
  }
138
165
  return;
139
166
  }
140
167
 
141
- const latestRaw = await fetchLatestVersion(packageName, UPDATE_CHECK_TIMEOUT_MS, signal);
168
+ const latestRaw = await fetchLatestVersion(
169
+ packageName,
170
+ UPDATE_CHECK_TIMEOUT_MS,
171
+ signal,
172
+ );
142
173
  const latest = normalizeVersion(latestRaw);
143
174
 
144
175
  writeCache({ lastChecked: now, lastNotified, latest: latest || latestRaw });
@@ -158,7 +189,12 @@ function startUpdateCheck({
158
189
  signal,
159
190
  } = {}) {
160
191
  // Fire-and-forget; never block MCP server startup.
161
- runUpdateCheck({ packageName, installedVersion, updateCommand, signal }).catch(() => {});
192
+ runUpdateCheck({
193
+ packageName,
194
+ installedVersion,
195
+ updateCommand,
196
+ signal,
197
+ }).catch(() => {});
162
198
  }
163
199
 
164
200
  module.exports = {