@openai/codex-shell-tool-mcp 0.63.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.
Files changed (26) hide show
  1. package/README.md +31 -0
  2. package/bin/mcp-server.js +259 -0
  3. package/package.json +40 -0
  4. package/vendor/aarch64-apple-darwin/bash/macos-14/bash +0 -0
  5. package/vendor/aarch64-apple-darwin/bash/macos-15/bash +0 -0
  6. package/vendor/aarch64-apple-darwin/codex-exec-mcp-server +0 -0
  7. package/vendor/aarch64-apple-darwin/codex-execve-wrapper +0 -0
  8. package/vendor/aarch64-unknown-linux-musl/bash/centos-9/bash +0 -0
  9. package/vendor/aarch64-unknown-linux-musl/bash/debian-11/bash +0 -0
  10. package/vendor/aarch64-unknown-linux-musl/bash/debian-12/bash +0 -0
  11. package/vendor/aarch64-unknown-linux-musl/bash/ubuntu-20.04/bash +0 -0
  12. package/vendor/aarch64-unknown-linux-musl/bash/ubuntu-22.04/bash +0 -0
  13. package/vendor/aarch64-unknown-linux-musl/bash/ubuntu-24.04/bash +0 -0
  14. package/vendor/aarch64-unknown-linux-musl/codex-exec-mcp-server +0 -0
  15. package/vendor/aarch64-unknown-linux-musl/codex-execve-wrapper +0 -0
  16. package/vendor/x86_64-apple-darwin/bash/macos-13/bash +0 -0
  17. package/vendor/x86_64-apple-darwin/codex-exec-mcp-server +0 -0
  18. package/vendor/x86_64-apple-darwin/codex-execve-wrapper +0 -0
  19. package/vendor/x86_64-unknown-linux-musl/bash/centos-9/bash +0 -0
  20. package/vendor/x86_64-unknown-linux-musl/bash/debian-11/bash +0 -0
  21. package/vendor/x86_64-unknown-linux-musl/bash/debian-12/bash +0 -0
  22. package/vendor/x86_64-unknown-linux-musl/bash/ubuntu-20.04/bash +0 -0
  23. package/vendor/x86_64-unknown-linux-musl/bash/ubuntu-22.04/bash +0 -0
  24. package/vendor/x86_64-unknown-linux-musl/bash/ubuntu-24.04/bash +0 -0
  25. package/vendor/x86_64-unknown-linux-musl/codex-exec-mcp-server +0 -0
  26. package/vendor/x86_64-unknown-linux-musl/codex-execve-wrapper +0 -0
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # @openai/codex-shell-tool-mcp
2
+
3
+ This package wraps the `codex-exec-mcp-server` binary and its helpers so that the shell MCP can be invoked via `npx @openai/codex-shell-tool-mcp`. It bundles:
4
+
5
+ - `codex-exec-mcp-server` and `codex-execve-wrapper` built for macOS (arm64, x64) and Linux (musl arm64, musl x64).
6
+ - A patched Bash that honors `BASH_EXEC_WRAPPER`, built for multiple glibc baselines (Ubuntu 24.04/22.04/20.04, Debian 12/11, CentOS-like 9) and macOS (15/14/13).
7
+ - A launcher (`bin/mcp-server.js`) that picks the correct binaries for the current `process.platform` / `process.arch`, specifying `--execve` and `--bash` for the MCP, as appropriate.
8
+
9
+ ## Usage
10
+
11
+ ```bash
12
+ npx @openai/codex-shell-tool-mcp --help
13
+ ```
14
+
15
+ The launcher selects a Rust target triple based on the host and chooses the closest Bash variant by inspecting `/etc/os-release` on Linux or the Darwin major version on macOS.
16
+
17
+ ## Patched Bash
18
+
19
+ We carry a small patch to `execute_cmd.c` (see `patches/bash-exec-wrapper.patch`) that adds support for `BASH_EXEC_WRAPPER`. The original commit message is “add support for BASH_EXEC_WRAPPER” and the patch applies cleanly to `a8a1c2fac029404d3f42cd39f5a20f24b6e4fe4b` from https://github.com/bminor/bash. To rebuild manually:
20
+
21
+ ```bash
22
+ git clone https://github.com/bminor/bash
23
+ git checkout a8a1c2fac029404d3f42cd39f5a20f24b6e4fe4b
24
+ git apply /path/to/patches/bash-exec-wrapper.patch
25
+ ./configure --without-bash-malloc
26
+ make -j"$(nproc)"
27
+ ```
28
+
29
+ ## Release workflow
30
+
31
+ `.github/workflows/shell-tool-mcp.yml` builds the Rust binaries, compiles the patched Bash variants, assembles the `vendor/` tree, and creates `codex-shell-tool-mcp-npm-<version>.tgz` for inclusion in the Rust GitHub Release. When the version is a stable or alpha tag, the workflow also publishes the tarball to npm using OIDC. The workflow is invoked from `rust-release.yml` so the package ships alongside other Codex artifacts.
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/index.ts
27
+ var import_node_child_process = require("child_process");
28
+ var import_node_fs2 = require("fs");
29
+ var import_node_os2 = __toESM(require("os"));
30
+ var import_node_path2 = __toESM(require("path"));
31
+
32
+ // src/bashSelection.ts
33
+ var import_node_path = __toESM(require("path"));
34
+ var import_node_os = __toESM(require("os"));
35
+
36
+ // src/constants.ts
37
+ var LINUX_BASH_VARIANTS = [
38
+ { name: "ubuntu-24.04", ids: ["ubuntu"], versions: ["24.04"] },
39
+ { name: "ubuntu-22.04", ids: ["ubuntu"], versions: ["22.04"] },
40
+ { name: "ubuntu-20.04", ids: ["ubuntu"], versions: ["20.04"] },
41
+ { name: "debian-12", ids: ["debian"], versions: ["12"] },
42
+ { name: "debian-11", ids: ["debian"], versions: ["11"] },
43
+ {
44
+ name: "centos-9",
45
+ ids: ["centos", "rhel", "rocky", "almalinux"],
46
+ versions: ["9"]
47
+ }
48
+ ];
49
+ var DARWIN_BASH_VARIANTS = [
50
+ { name: "macos-15", minDarwin: 24 },
51
+ { name: "macos-14", minDarwin: 23 },
52
+ { name: "macos-13", minDarwin: 22 }
53
+ ];
54
+
55
+ // src/bashSelection.ts
56
+ function supportedDetail(variants) {
57
+ return `Supported variants: ${variants.map((variant) => variant.name).join(", ")}`;
58
+ }
59
+ function selectLinuxBash(bashRoot, info) {
60
+ const versionId = info.versionId;
61
+ const candidates = [];
62
+ for (const variant of LINUX_BASH_VARIANTS) {
63
+ const matchesId = variant.ids.includes(info.id) || variant.ids.some((id) => info.idLike.includes(id));
64
+ if (!matchesId) {
65
+ continue;
66
+ }
67
+ const matchesVersion = Boolean(
68
+ versionId && variant.versions.some((prefix) => versionId.startsWith(prefix))
69
+ );
70
+ candidates.push({ variant, matchesVersion });
71
+ }
72
+ const pickVariant = (list) => list.find((item) => item.variant)?.variant;
73
+ const preferred = pickVariant(
74
+ candidates.filter((item) => item.matchesVersion)
75
+ );
76
+ if (preferred) {
77
+ return {
78
+ path: import_node_path.default.join(bashRoot, preferred.name, "bash"),
79
+ variant: preferred.name
80
+ };
81
+ }
82
+ const fallbackMatch = pickVariant(candidates);
83
+ if (fallbackMatch) {
84
+ return {
85
+ path: import_node_path.default.join(bashRoot, fallbackMatch.name, "bash"),
86
+ variant: fallbackMatch.name
87
+ };
88
+ }
89
+ const fallback = LINUX_BASH_VARIANTS[0];
90
+ if (fallback) {
91
+ return {
92
+ path: import_node_path.default.join(bashRoot, fallback.name, "bash"),
93
+ variant: fallback.name
94
+ };
95
+ }
96
+ const detail = supportedDetail(LINUX_BASH_VARIANTS);
97
+ throw new Error(
98
+ `Unable to select a Bash variant for ${info.id || "unknown"} ${versionId || ""}. ${detail}`
99
+ );
100
+ }
101
+ function selectDarwinBash(bashRoot, darwinRelease) {
102
+ const darwinMajor = Number.parseInt(darwinRelease.split(".")[0] || "0", 10);
103
+ const preferred = DARWIN_BASH_VARIANTS.find(
104
+ (variant) => darwinMajor >= variant.minDarwin
105
+ );
106
+ if (preferred) {
107
+ return {
108
+ path: import_node_path.default.join(bashRoot, preferred.name, "bash"),
109
+ variant: preferred.name
110
+ };
111
+ }
112
+ const fallback = DARWIN_BASH_VARIANTS[0];
113
+ if (fallback) {
114
+ return {
115
+ path: import_node_path.default.join(bashRoot, fallback.name, "bash"),
116
+ variant: fallback.name
117
+ };
118
+ }
119
+ const detail = supportedDetail(DARWIN_BASH_VARIANTS);
120
+ throw new Error(
121
+ `Unable to select a macOS Bash build (darwin ${darwinMajor}). ${detail}`
122
+ );
123
+ }
124
+ function resolveBashPath(targetRoot, platform, darwinRelease = import_node_os.default.release(), osInfo = null) {
125
+ const bashRoot = import_node_path.default.join(targetRoot, "bash");
126
+ if (platform === "linux") {
127
+ if (!osInfo) {
128
+ throw new Error("Linux OS info is required to select a Bash variant.");
129
+ }
130
+ return selectLinuxBash(bashRoot, osInfo);
131
+ }
132
+ if (platform === "darwin") {
133
+ return selectDarwinBash(bashRoot, darwinRelease);
134
+ }
135
+ throw new Error(`Unsupported platform for Bash selection: ${platform}`);
136
+ }
137
+
138
+ // src/osRelease.ts
139
+ var import_node_fs = require("fs");
140
+ function parseOsRelease(contents) {
141
+ const lines = contents.split("\n").filter(Boolean);
142
+ const info = {};
143
+ for (const line of lines) {
144
+ const [rawKey, rawValue] = line.split("=", 2);
145
+ if (!rawKey || rawValue === void 0) {
146
+ continue;
147
+ }
148
+ const key = rawKey.toLowerCase();
149
+ const value = rawValue.replace(/^"/, "").replace(/"$/, "");
150
+ info[key] = value;
151
+ }
152
+ const idLike = (info.id_like || "").split(/\s+/).map((item) => item.trim().toLowerCase()).filter(Boolean);
153
+ return {
154
+ id: (info.id || "").toLowerCase(),
155
+ idLike,
156
+ versionId: info.version_id || ""
157
+ };
158
+ }
159
+ function readOsRelease(pathname = "/etc/os-release") {
160
+ try {
161
+ const contents = (0, import_node_fs.readFileSync)(pathname, "utf8");
162
+ return parseOsRelease(contents);
163
+ } catch {
164
+ return { id: "", idLike: [], versionId: "" };
165
+ }
166
+ }
167
+
168
+ // src/platform.ts
169
+ function resolveTargetTriple(platform, arch) {
170
+ if (platform === "linux") {
171
+ if (arch === "x64") {
172
+ return "x86_64-unknown-linux-musl";
173
+ }
174
+ if (arch === "arm64") {
175
+ return "aarch64-unknown-linux-musl";
176
+ }
177
+ } else if (platform === "darwin") {
178
+ if (arch === "x64") {
179
+ return "x86_64-apple-darwin";
180
+ }
181
+ if (arch === "arm64") {
182
+ return "aarch64-apple-darwin";
183
+ }
184
+ }
185
+ throw new Error(`Unsupported platform: ${platform} (${arch})`);
186
+ }
187
+
188
+ // src/index.ts
189
+ var scriptPath = process.argv[1] ? import_node_path2.default.resolve(process.argv[1]) : process.cwd();
190
+ var __dirname = import_node_path2.default.dirname(scriptPath);
191
+ async function main() {
192
+ const targetTriple = resolveTargetTriple(process.platform, process.arch);
193
+ const vendorRoot = import_node_path2.default.join(__dirname, "..", "vendor");
194
+ const targetRoot = import_node_path2.default.join(vendorRoot, targetTriple);
195
+ const execveWrapperPath = import_node_path2.default.join(targetRoot, "codex-execve-wrapper");
196
+ const serverPath = import_node_path2.default.join(targetRoot, "codex-exec-mcp-server");
197
+ const osInfo = process.platform === "linux" ? readOsRelease() : null;
198
+ const { path: bashPath } = resolveBashPath(
199
+ targetRoot,
200
+ process.platform,
201
+ import_node_os2.default.release(),
202
+ osInfo
203
+ );
204
+ [execveWrapperPath, serverPath, bashPath].forEach((checkPath) => {
205
+ try {
206
+ (0, import_node_fs2.accessSync)(checkPath, import_node_fs2.constants.F_OK);
207
+ } catch {
208
+ throw new Error(`Required binary missing: ${checkPath}`);
209
+ }
210
+ });
211
+ const args = [
212
+ "--execve",
213
+ execveWrapperPath,
214
+ "--bash",
215
+ bashPath,
216
+ ...process.argv.slice(2)
217
+ ];
218
+ const child = (0, import_node_child_process.spawn)(serverPath, args, {
219
+ stdio: "inherit"
220
+ });
221
+ const forwardSignal = (signal) => {
222
+ if (child.killed) {
223
+ return;
224
+ }
225
+ try {
226
+ child.kill(signal);
227
+ } catch {
228
+ }
229
+ };
230
+ ["SIGINT", "SIGTERM", "SIGHUP"].forEach((sig) => {
231
+ process.on(sig, () => forwardSignal(sig));
232
+ });
233
+ child.on("error", (err) => {
234
+ console.error(err);
235
+ process.exit(1);
236
+ });
237
+ const childResult = await new Promise((resolve) => {
238
+ child.on("exit", (code, signal) => {
239
+ if (signal) {
240
+ resolve({ type: "signal", signal });
241
+ } else {
242
+ resolve({ type: "code", exitCode: code ?? 1 });
243
+ }
244
+ });
245
+ });
246
+ if (childResult.type === "signal") {
247
+ try {
248
+ process.kill(process.pid, childResult.signal);
249
+ } catch {
250
+ process.exit(1);
251
+ }
252
+ } else {
253
+ process.exit(childResult.exitCode);
254
+ }
255
+ }
256
+ void main().catch((err) => {
257
+ console.error(err);
258
+ process.exit(1);
259
+ });
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@openai/codex-shell-tool-mcp",
3
+ "version": "0.63.0",
4
+ "description": "Codex MCP server for the shell tool with patched Bash and exec wrappers.",
5
+ "license": "Apache-2.0",
6
+ "bin": {
7
+ "codex-shell-tool-mcp": "bin/mcp-server.js"
8
+ },
9
+ "engines": {
10
+ "node": ">=18"
11
+ },
12
+ "files": [
13
+ "bin",
14
+ "vendor",
15
+ "README.md"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/openai/codex.git",
20
+ "directory": "shell-tool-mcp"
21
+ },
22
+ "scripts": {
23
+ "clean": "rm -rf bin",
24
+ "build": "tsup",
25
+ "build:watch": "tsup --watch",
26
+ "test": "jest",
27
+ "test:watch": "jest --watch",
28
+ "format": "prettier --check .",
29
+ "format:fix": "prettier --write ."
30
+ },
31
+ "devDependencies": {
32
+ "@types/jest": "^29.5.14",
33
+ "@types/node": "^20.19.18",
34
+ "jest": "^29.7.0",
35
+ "prettier": "^3.6.2",
36
+ "ts-jest": "^29.3.4",
37
+ "tsup": "^8.5.0",
38
+ "typescript": "^5.9.2"
39
+ }
40
+ }