@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.
- package/README.md +31 -0
- package/bin/mcp-server.js +259 -0
- package/package.json +40 -0
- package/vendor/aarch64-apple-darwin/bash/macos-14/bash +0 -0
- package/vendor/aarch64-apple-darwin/bash/macos-15/bash +0 -0
- package/vendor/aarch64-apple-darwin/codex-exec-mcp-server +0 -0
- package/vendor/aarch64-apple-darwin/codex-execve-wrapper +0 -0
- package/vendor/aarch64-unknown-linux-musl/bash/centos-9/bash +0 -0
- package/vendor/aarch64-unknown-linux-musl/bash/debian-11/bash +0 -0
- package/vendor/aarch64-unknown-linux-musl/bash/debian-12/bash +0 -0
- package/vendor/aarch64-unknown-linux-musl/bash/ubuntu-20.04/bash +0 -0
- package/vendor/aarch64-unknown-linux-musl/bash/ubuntu-22.04/bash +0 -0
- package/vendor/aarch64-unknown-linux-musl/bash/ubuntu-24.04/bash +0 -0
- package/vendor/aarch64-unknown-linux-musl/codex-exec-mcp-server +0 -0
- package/vendor/aarch64-unknown-linux-musl/codex-execve-wrapper +0 -0
- package/vendor/x86_64-apple-darwin/bash/macos-13/bash +0 -0
- package/vendor/x86_64-apple-darwin/codex-exec-mcp-server +0 -0
- package/vendor/x86_64-apple-darwin/codex-execve-wrapper +0 -0
- package/vendor/x86_64-unknown-linux-musl/bash/centos-9/bash +0 -0
- package/vendor/x86_64-unknown-linux-musl/bash/debian-11/bash +0 -0
- package/vendor/x86_64-unknown-linux-musl/bash/debian-12/bash +0 -0
- package/vendor/x86_64-unknown-linux-musl/bash/ubuntu-20.04/bash +0 -0
- package/vendor/x86_64-unknown-linux-musl/bash/ubuntu-22.04/bash +0 -0
- package/vendor/x86_64-unknown-linux-musl/bash/ubuntu-24.04/bash +0 -0
- package/vendor/x86_64-unknown-linux-musl/codex-exec-mcp-server +0 -0
- 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
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|