wocingflow-mcp-server 0.0.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/README.md +84 -0
- package/bin/wocingflow-mcp-server.js +200 -0
- package/package.json +19 -0
- package/vendor/mcp_server.exe +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# wocingflow-mcp-server
|
|
2
|
+
|
|
3
|
+
WocingFlow MCP launcher package compatible with `install-mcp`.
|
|
4
|
+
|
|
5
|
+
## What this package does
|
|
6
|
+
|
|
7
|
+
- Starts WocingFlow backend `mcp_server` on HTTP (`127.0.0.1:8787` by default)
|
|
8
|
+
- Bridges HTTP MCP to stdio using `mcp-remote@latest`
|
|
9
|
+
- Exposes a bin command: `wocingflow-mcp-server`
|
|
10
|
+
|
|
11
|
+
## Install to Cursor via install-mcp
|
|
12
|
+
|
|
13
|
+
After publishing this package to npm:
|
|
14
|
+
|
|
15
|
+
## Configure Your AI Assistant
|
|
16
|
+
|
|
17
|
+
Use `install-mcp` to add the server to your AI assistant:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx -y install-mcp wocingflow-mcp-server --client claude-code
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Supported clients: `claude-code`, `cursor`, `windsurf`, `vscode`, `cline`, `roo-cline`, `claude`, `zed`, `goose`, `warp`, `codex`
|
|
24
|
+
|
|
25
|
+
### Claude Code
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx -y install-mcp wocingflow-mcp-server --client claude-code
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Cursor
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx -y install-mcp wocingflow-mcp-server --client cursor
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### VS Code / Copilot
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx -y install-mcp wocingflow-mcp-server --client vscode
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Windsurf
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx -y install-mcp wocingflow-mcp-server --client windsurf
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Cline
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx -y install-mcp wocingflow-mcp-server --client cline
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Restart your AI assistant after adding the configuration.
|
|
56
|
+
|
|
57
|
+
## Local .tgz install (Windows example)
|
|
58
|
+
|
|
59
|
+
Use `--package <path-to-tgz> <bin-name>` form instead of calling the `.tgz` directly:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx -y install-mcp "npx --yes --package d:/Project/wocingflow/mcp/wocingflow-mcp-server/wocingflow-mcp-server-0.0.1.tgz wocingflow-mcp-server" --client cursor --name wocingflow-mcp-server --yes
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Local development usage
|
|
66
|
+
|
|
67
|
+
From this folder:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm pack
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Then install the generated tarball target with `install-mcp`:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx -y install-mcp "npx --yes --package d:/Project/wocingflow/mcp/wocingflow-mcp-server/wocingflow-mcp-server-0.0.1.tgz wocingflow-mcp-server" --client cursor --name wocingflow-mcp-server --yes
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Environment variables
|
|
80
|
+
|
|
81
|
+
- `WF_MCP_SERVER_BIN`: absolute path to `mcp_server` binary (optional)
|
|
82
|
+
- `WF_SERVICE_DATA_DIR`: absolute path to `service/data` (optional)
|
|
83
|
+
- `WF_MCP_HTTP_HOST`: default `127.0.0.1`
|
|
84
|
+
- `WF_MCP_HTTP_PORT`: default `8787`
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require("node:fs");
|
|
3
|
+
const path = require("node:path");
|
|
4
|
+
const net = require("node:net");
|
|
5
|
+
const { spawn } = require("node:child_process");
|
|
6
|
+
|
|
7
|
+
function sleep(ms) {
|
|
8
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function isWindows() {
|
|
12
|
+
return process.platform === "win32";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function fileExists(filePath) {
|
|
16
|
+
try {
|
|
17
|
+
return fs.existsSync(filePath);
|
|
18
|
+
} catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function candidateRoots() {
|
|
24
|
+
const cwd = process.cwd();
|
|
25
|
+
return [cwd, path.resolve(cwd, ".."), path.resolve(cwd, "..", "..")];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function resolveServiceDataDir() {
|
|
29
|
+
if (process.env.WF_SERVICE_DATA_DIR && fileExists(process.env.WF_SERVICE_DATA_DIR)) {
|
|
30
|
+
return process.env.WF_SERVICE_DATA_DIR;
|
|
31
|
+
}
|
|
32
|
+
for (const root of candidateRoots()) {
|
|
33
|
+
const candidate = path.join(root, "service", "data");
|
|
34
|
+
if (fileExists(candidate)) {
|
|
35
|
+
return candidate;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function resolveServerLaunch() {
|
|
42
|
+
if (process.env.WF_MCP_SERVER_BIN && fileExists(process.env.WF_MCP_SERVER_BIN)) {
|
|
43
|
+
return { command: process.env.WF_MCP_SERVER_BIN, args: [] };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const exeName = isWindows() ? "mcp_server.exe" : "mcp_server";
|
|
47
|
+
const bundledPath = path.join(__dirname, "..", "vendor", exeName);
|
|
48
|
+
if (fileExists(bundledPath)) {
|
|
49
|
+
return { command: bundledPath, args: [] };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for (const root of candidateRoots()) {
|
|
53
|
+
const debugPath = path.join(root, "service", "target", "debug", exeName);
|
|
54
|
+
const releasePath = path.join(root, "service", "target", "release", exeName);
|
|
55
|
+
if (fileExists(debugPath)) return { command: debugPath, args: [] };
|
|
56
|
+
if (fileExists(releasePath)) return { command: releasePath, args: [] };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
for (const root of candidateRoots()) {
|
|
60
|
+
const manifestPath = path.join(root, "service", "Cargo.toml");
|
|
61
|
+
if (fileExists(manifestPath)) {
|
|
62
|
+
return {
|
|
63
|
+
command: "cargo",
|
|
64
|
+
args: ["run", "--manifest-path", manifestPath, "--bin", "mcp_server", "--"],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
throw new Error(
|
|
70
|
+
"Cannot locate wocingflow mcp_server. Build service/bin/mcp_server or set WF_MCP_SERVER_BIN."
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function resolvePort() {
|
|
75
|
+
if (process.env.WF_MCP_HTTP_PORT) {
|
|
76
|
+
return String(process.env.WF_MCP_HTTP_PORT);
|
|
77
|
+
}
|
|
78
|
+
return String(
|
|
79
|
+
await new Promise((resolve, reject) => {
|
|
80
|
+
const server = net.createServer();
|
|
81
|
+
server.listen(0, "127.0.0.1", () => {
|
|
82
|
+
const address = server.address();
|
|
83
|
+
if (!address || typeof address === "string") {
|
|
84
|
+
server.close();
|
|
85
|
+
reject(new Error("Failed to allocate free TCP port."));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const freePort = address.port;
|
|
89
|
+
server.close(() => resolve(freePort));
|
|
90
|
+
});
|
|
91
|
+
server.on("error", reject);
|
|
92
|
+
})
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function waitHealth(endpoint, timeoutMs) {
|
|
97
|
+
const started = Date.now();
|
|
98
|
+
while (Date.now() - started < timeoutMs) {
|
|
99
|
+
try {
|
|
100
|
+
const response = await fetch(`${endpoint}/health`);
|
|
101
|
+
if (response.ok) return;
|
|
102
|
+
} catch {
|
|
103
|
+
// keep waiting
|
|
104
|
+
}
|
|
105
|
+
await sleep(300);
|
|
106
|
+
}
|
|
107
|
+
throw new Error(`mcp_server health check timeout: ${endpoint}/health`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function spawnBackend(command, args, env) {
|
|
111
|
+
const child = spawn(command, args, {
|
|
112
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
113
|
+
env,
|
|
114
|
+
shell: false,
|
|
115
|
+
windowsHide: true,
|
|
116
|
+
});
|
|
117
|
+
child.stdout.on("data", (chunk) => {
|
|
118
|
+
process.stderr.write(String(chunk));
|
|
119
|
+
});
|
|
120
|
+
child.stderr.on("data", (chunk) => {
|
|
121
|
+
process.stderr.write(String(chunk));
|
|
122
|
+
});
|
|
123
|
+
return child;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function spawnBridge(env, endpoint) {
|
|
127
|
+
let command;
|
|
128
|
+
let args;
|
|
129
|
+
if (isWindows()) {
|
|
130
|
+
command = "cmd.exe";
|
|
131
|
+
args = ["/d", "/s", "/c", `npx -y mcp-remote@latest ${endpoint}`];
|
|
132
|
+
} else {
|
|
133
|
+
command = "npx";
|
|
134
|
+
args = ["-y", "mcp-remote@latest", endpoint];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const child = spawn(command, args, {
|
|
138
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
139
|
+
env,
|
|
140
|
+
shell: false,
|
|
141
|
+
windowsHide: true,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
process.stdin.pipe(child.stdin);
|
|
145
|
+
child.stdout.pipe(process.stdout);
|
|
146
|
+
child.stderr.pipe(process.stderr);
|
|
147
|
+
return child;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function main() {
|
|
151
|
+
const host = process.env.WF_MCP_HTTP_HOST || "127.0.0.1";
|
|
152
|
+
const port = await resolvePort();
|
|
153
|
+
const endpoint = `http://${host}:${port}`;
|
|
154
|
+
const serviceDataDir = resolveServiceDataDir();
|
|
155
|
+
const launch = resolveServerLaunch();
|
|
156
|
+
|
|
157
|
+
const backendEnv = { ...process.env };
|
|
158
|
+
if (serviceDataDir) {
|
|
159
|
+
backendEnv.WF_SERVICE_DATA_DIR = serviceDataDir;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const backend = spawnBackend(
|
|
163
|
+
launch.command,
|
|
164
|
+
[...launch.args, "--host", host, "--port", String(port)],
|
|
165
|
+
backendEnv
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
let shuttingDown = false;
|
|
169
|
+
const shutdown = () => {
|
|
170
|
+
if (shuttingDown) return;
|
|
171
|
+
shuttingDown = true;
|
|
172
|
+
if (!backend.killed) {
|
|
173
|
+
backend.kill();
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
process.on("SIGINT", shutdown);
|
|
178
|
+
process.on("SIGTERM", shutdown);
|
|
179
|
+
process.on("exit", shutdown);
|
|
180
|
+
|
|
181
|
+
backend.on("exit", (code) => {
|
|
182
|
+
if (!shuttingDown && code !== 0) {
|
|
183
|
+
console.error(`[wocingflow-mcp] backend exited early with code ${code}`);
|
|
184
|
+
process.exit(code || 1);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
await waitHealth(endpoint, 20000);
|
|
189
|
+
|
|
190
|
+
const bridge = spawnBridge(process.env, endpoint);
|
|
191
|
+
bridge.on("exit", (code) => {
|
|
192
|
+
shutdown();
|
|
193
|
+
process.exit(code || 0);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
main().catch((error) => {
|
|
198
|
+
console.error(`[wocingflow-mcp] ${error.message}`);
|
|
199
|
+
process.exit(1);
|
|
200
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wocingflow-mcp-server",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "MCP stdio launcher for WocingFlow service mcp_server",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"bin": {
|
|
7
|
+
"wocingflow-mcp-server": "bin/wocingflow-mcp-server.js"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=18"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"prepack": "node scripts/prepack.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"bin",
|
|
17
|
+
"vendor"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
Binary file
|