Skip to content

Commit 7e14472

Browse files
cpoderclaude
andcommitted
Add npx support via npm package with zero-dependency binary downloader
npm package (npm/): - install.js downloads platform-specific binary from GitHub Releases - run.js spawns binary with inherited stdio, auto-downloads if missing - Zero npm dependencies — uses only Node.js built-in https module - Supports: linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64 Usage: npx wm-mcp-server # run directly npm install -g wm-mcp-server # install globally MCP client config: "command": "npx", "args": ["-y", "wm-mcp-server"] Release workflow updated to publish to npm after GitHub Release creation (needs NPM_TOKEN secret). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7ce165e commit 7e14472

10 files changed

Lines changed: 309 additions & 2 deletions

File tree

.github/workflows/release.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,38 @@ jobs:
155155
- run: cargo publish --manifest-path mcp-server-rs/Cargo.toml --allow-dirty
156156
env:
157157
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
158+
159+
publish-npm:
160+
name: Publish to npm
161+
needs: release
162+
runs-on: ubuntu-latest
163+
steps:
164+
- uses: actions/checkout@v6
165+
166+
- uses: actions/setup-node@v4
167+
with:
168+
node-version: '20'
169+
registry-url: 'https://registry.npmjs.org'
170+
171+
- name: Set npm version from tag
172+
run: |
173+
VERSION="${GITHUB_REF#refs/tags/v}"
174+
cd npm
175+
node -e "
176+
const pkg = require('./package.json');
177+
pkg.version = '${VERSION}';
178+
require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
179+
"
180+
echo "Publishing wm-mcp-server@${VERSION}"
181+
182+
- name: Verify download URL works
183+
run: |
184+
VERSION="${GITHUB_REF#refs/tags/v}"
185+
URL="https://github.com/cpoder/wm-mcp-server/releases/download/v${VERSION}/wm-mcp-server-linux-x86_64"
186+
echo "Checking $URL"
187+
curl -sSfL -o /dev/null -w "%{http_code}" "$URL"
188+
189+
- name: Publish to npm
190+
run: cd npm && npm publish
191+
env:
192+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
[![CI](https://github.com/cpoder/wm-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/cpoder/wm-mcp-server/actions/workflows/ci.yml)
44
[![crates.io](https://img.shields.io/crates/v/wm-mcp-server.svg)](https://crates.io/crates/wm-mcp-server)
5+
[![npm](https://img.shields.io/npm/v/wm-mcp-server.svg)](https://www.npmjs.com/package/wm-mcp-server)
56

67
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that gives AI assistants full control over [webMethods Integration Server](https://www.ibm.com/docs/en/webmethods-integration/wm-integration-server/11.1.0) -- replacing webMethods Designer for most development and administration tasks.
78

@@ -78,7 +79,13 @@ The AI can guide you step-by-step through setting up:
7879
### 1. Install
7980

8081
```bash
81-
# From crates.io
82+
# Via npx (no install needed)
83+
npx wm-mcp-server
84+
85+
# Or install globally via npm
86+
npm install -g wm-mcp-server
87+
88+
# Or from crates.io (requires Rust)
8289
cargo install wm-mcp-server
8390

8491
# Or download a pre-built binary from Releases
@@ -91,6 +98,24 @@ Binaries available for: Linux (x86_64, aarch64), macOS (x86_64, Apple Silicon),
9198

9299
Add to `.mcp.json` in your project directory:
93100

101+
```json
102+
{
103+
"mcpServers": {
104+
"webmethods-is": {
105+
"command": "npx",
106+
"args": ["-y", "wm-mcp-server"],
107+
"env": {
108+
"WM_IS_URL": "http://your-is-host:5555",
109+
"WM_IS_USER": "Administrator",
110+
"WM_IS_PASSWORD": "your-password"
111+
}
112+
}
113+
}
114+
}
115+
```
116+
117+
Or if installed globally / via cargo:
118+
94119
```json
95120
{
96121
"mcpServers": {

mcp-server-rs/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
## Installation
44

55
```bash
6-
cargo install wm-mcp-server # from crates.io
6+
npx wm-mcp-server # run via npx (no install needed)
7+
npm install -g wm-mcp-server # install globally via npm
8+
cargo install wm-mcp-server # from crates.io (requires Rust)
79
# or download from https://github.com/cpoder/wm-mcp-server/releases
810
```
911

npm/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
wm-mcp-server
2+
wm-mcp-server.exe
3+
node_modules/

npm/.npmignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
wm-mcp-server
2+
wm-mcp-server.exe
3+
.gitignore

npm/README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# wm-mcp-server
2+
3+
MCP server for [webMethods Integration Server](https://www.ibm.com/docs/en/webmethods-integration/wm-integration-server/11.1.0) — 336 tools replacing Designer for development and administration.
4+
5+
## Quick Start
6+
7+
```bash
8+
npx wm-mcp-server
9+
```
10+
11+
Or install globally:
12+
13+
```bash
14+
npm install -g wm-mcp-server
15+
```
16+
17+
## MCP Client Configuration
18+
19+
Add to `.mcp.json` in your project:
20+
21+
```json
22+
{
23+
"mcpServers": {
24+
"webmethods-is": {
25+
"command": "npx",
26+
"args": ["-y", "wm-mcp-server"],
27+
"env": {
28+
"WM_IS_URL": "http://localhost:5555",
29+
"WM_IS_USER": "Administrator",
30+
"WM_IS_PASSWORD": "manage"
31+
}
32+
}
33+
}
34+
}
35+
```
36+
37+
## Alternative Installation
38+
39+
```bash
40+
# From crates.io (requires Rust)
41+
cargo install wm-mcp-server
42+
43+
# Pre-built binaries
44+
# https://github.com/cpoder/wm-mcp-server/releases
45+
```
46+
47+
## Documentation
48+
49+
See the [full documentation](https://github.com/cpoder/wm-mcp-server) on GitHub.

npm/binary.js

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/usr/bin/env node
2+
"use strict";
3+
4+
const os = require("os");
5+
const path = require("path");
6+
const fs = require("fs");
7+
8+
const VERSION = require("./package.json").version;
9+
const REPO = "cpoder/wm-mcp-server";
10+
11+
/**
12+
* Map Node.js platform/arch to GitHub Release asset names.
13+
*/
14+
function getAssetName() {
15+
const platform = os.platform();
16+
const arch = os.arch();
17+
18+
const map = {
19+
"linux-x64": "wm-mcp-server-linux-x86_64",
20+
"linux-arm64": "wm-mcp-server-linux-aarch64",
21+
"darwin-x64": "wm-mcp-server-macos-x86_64",
22+
"darwin-arm64": "wm-mcp-server-macos-aarch64",
23+
"win32-x64": "wm-mcp-server-windows-x86_64.exe",
24+
};
25+
26+
const key = `${platform}-${arch}`;
27+
const asset = map[key];
28+
if (!asset) {
29+
throw new Error(
30+
`Unsupported platform: ${platform}-${arch}. ` +
31+
`Supported: ${Object.keys(map).join(", ")}`
32+
);
33+
}
34+
return asset;
35+
}
36+
37+
/**
38+
* Returns the URL to download the binary from GitHub Releases.
39+
*/
40+
function getDownloadUrl() {
41+
const asset = getAssetName();
42+
return `https://github.com/${REPO}/releases/download/v${VERSION}/${asset}`;
43+
}
44+
45+
/**
46+
* Returns the local path where the binary is stored.
47+
*/
48+
function getBinaryPath() {
49+
const name = os.platform() === "win32" ? "wm-mcp-server.exe" : "wm-mcp-server";
50+
return path.join(__dirname, name);
51+
}
52+
53+
/**
54+
* Download a URL, following redirects (GitHub releases redirect to S3).
55+
* Returns a Promise<Buffer>.
56+
*/
57+
function download(url, maxRedirects = 5) {
58+
return new Promise((resolve, reject) => {
59+
if (maxRedirects <= 0) {
60+
return reject(new Error("Too many redirects"));
61+
}
62+
63+
const lib = url.startsWith("https") ? require("https") : require("http");
64+
lib.get(url, { headers: { "User-Agent": "wm-mcp-server-npm" } }, (res) => {
65+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
66+
return resolve(download(res.headers.location, maxRedirects - 1));
67+
}
68+
if (res.statusCode !== 200) {
69+
return reject(new Error(`Download failed: HTTP ${res.statusCode} from ${url}`));
70+
}
71+
72+
const chunks = [];
73+
res.on("data", (chunk) => chunks.push(chunk));
74+
res.on("end", () => resolve(Buffer.concat(chunks)));
75+
res.on("error", reject);
76+
}).on("error", reject);
77+
});
78+
}
79+
80+
/**
81+
* Install the binary: download from GitHub Releases and save to disk.
82+
*/
83+
async function install() {
84+
const binPath = getBinaryPath();
85+
86+
if (fs.existsSync(binPath)) {
87+
console.log(`wm-mcp-server binary already exists at ${binPath}`);
88+
return;
89+
}
90+
91+
const url = getDownloadUrl();
92+
console.log(`Downloading wm-mcp-server v${VERSION}...`);
93+
console.log(` ${url}`);
94+
95+
const data = await download(url);
96+
fs.writeFileSync(binPath, data);
97+
98+
if (os.platform() !== "win32") {
99+
fs.chmodSync(binPath, 0o755);
100+
}
101+
102+
console.log(`Installed wm-mcp-server to ${binPath}`);
103+
}
104+
105+
/**
106+
* Run the binary, forwarding all arguments and stdio.
107+
*/
108+
function run() {
109+
const binPath = getBinaryPath();
110+
111+
if (!fs.existsSync(binPath)) {
112+
console.error(
113+
"wm-mcp-server binary not found. Run 'npm install' or 'node install.js' first."
114+
);
115+
process.exit(1);
116+
}
117+
118+
const { spawnSync } = require("child_process");
119+
const result = spawnSync(binPath, process.argv.slice(2), {
120+
stdio: "inherit",
121+
env: process.env,
122+
});
123+
124+
process.exit(result.status ?? 1);
125+
}
126+
127+
module.exports = { install, run, getBinaryPath, getDownloadUrl };

npm/install.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env node
2+
"use strict";
3+
4+
const { install } = require("./binary");
5+
6+
install().catch((err) => {
7+
console.error("Failed to install wm-mcp-server:", err.message);
8+
// Don't fail the npm install -- the binary can be downloaded on first run
9+
process.exit(0);
10+
});

npm/package.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "wm-mcp-server",
3+
"version": "2.6.0",
4+
"description": "MCP server for webMethods Integration Server — 336 tools replacing Designer for development and administration",
5+
"license": "MIT",
6+
"repository": {
7+
"type": "git",
8+
"url": "https://github.com/cpoder/wm-mcp-server"
9+
},
10+
"homepage": "https://github.com/cpoder/wm-mcp-server",
11+
"keywords": [
12+
"webmethods",
13+
"integration-server",
14+
"mcp",
15+
"model-context-protocol",
16+
"ibm",
17+
"flow-services",
18+
"adapter",
19+
"middleware"
20+
],
21+
"bin": {
22+
"wm-mcp-server": "./run.js"
23+
},
24+
"scripts": {
25+
"postinstall": "node ./install.js"
26+
},
27+
"files": [
28+
"install.js",
29+
"run.js",
30+
"binary.js",
31+
"README.md"
32+
],
33+
"engines": {
34+
"node": ">=16"
35+
}
36+
}

npm/run.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env node
2+
"use strict";
3+
4+
const fs = require("fs");
5+
const { run, install, getBinaryPath } = require("./binary");
6+
7+
// If binary is missing (e.g., postinstall was skipped), download on first run
8+
if (!fs.existsSync(getBinaryPath())) {
9+
install()
10+
.then(() => run())
11+
.catch((err) => {
12+
console.error("Failed to download wm-mcp-server:", err.message);
13+
process.exit(1);
14+
});
15+
} else {
16+
run();
17+
}

0 commit comments

Comments
 (0)