mcp-for-i 0.1.0 → 0.1.2
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 +76 -11
- package/dist/controlplane/autostart.js +35 -48
- package/dist/controlplane/runtimeService.js +110 -14
- package/dist/controlplane/server.js +12 -1
- package/dist/controlplane/ui.js +6 -4
- package/dist/index.js +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
# MCP-for-i
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`mcp-for-i` is a local MCP server + control plane for IBM i workflows. It provides secure connection onboarding, keychain-backed credentials, runtime update controls, and IBM i tools for agent-driven operations.
|
|
4
4
|
|
|
5
|
-
## Install
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
|
-
Install globally:
|
|
7
|
+
Install globally from npm:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
npm i -g mcp-for-i
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Verify commands:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
mcp-for-i --help
|
|
17
|
+
mcp-for-i-control help
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
1. Start the local control plane:
|
|
14
23
|
|
|
15
24
|
```bash
|
|
16
25
|
mcp-for-i-control serve
|
|
17
26
|
```
|
|
18
27
|
|
|
19
|
-
|
|
28
|
+
2. Open the UI at:
|
|
20
29
|
|
|
21
30
|
```text
|
|
22
31
|
http://127.0.0.1:3980
|
|
23
32
|
```
|
|
24
33
|
|
|
25
|
-
|
|
34
|
+
3. Add IBM i connection profiles in the UI. Passwords are stored in the OS keychain, not plain config.
|
|
35
|
+
|
|
36
|
+
## Background Startup (Windows)
|
|
26
37
|
|
|
27
|
-
|
|
38
|
+
Enable startup at login:
|
|
28
39
|
|
|
29
40
|
```bash
|
|
30
41
|
mcp-for-i-control setup
|
|
@@ -36,18 +47,72 @@ Check status:
|
|
|
36
47
|
mcp-for-i-control status
|
|
37
48
|
```
|
|
38
49
|
|
|
39
|
-
Disable
|
|
50
|
+
Disable startup:
|
|
40
51
|
|
|
41
52
|
```bash
|
|
42
53
|
mcp-for-i-control remove
|
|
43
54
|
```
|
|
44
55
|
|
|
45
|
-
##
|
|
56
|
+
## Update and Version Management
|
|
46
57
|
|
|
47
|
-
|
|
58
|
+
Update to latest globally:
|
|
48
59
|
|
|
49
60
|
```bash
|
|
61
|
+
npm i -g mcp-for-i@latest
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Install a specific version:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm i -g mcp-for-i@0.1.1
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Rollback example:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm i -g mcp-for-i@0.1.0
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Check current installed version:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
mcp-for-i --version
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Control Plane Runtime Actions
|
|
83
|
+
|
|
84
|
+
In the UI, runtime buttons behave as follows:
|
|
85
|
+
|
|
86
|
+
- `Install/Repair MCP`
|
|
87
|
+
- If running from a git checkout: runs local dependency repair/build.
|
|
88
|
+
- If running as npm-installed package: runs global npm install/repair for latest package.
|
|
89
|
+
- `Update MCP`
|
|
90
|
+
- If running from a git checkout: pulls latest changes from `origin/<current-branch>`, then installs/builds.
|
|
91
|
+
- If running as npm-installed package: upgrades global npm package to latest.
|
|
92
|
+
- On Windows global installs, update runs in a detached updater and briefly restarts control plane to avoid file-lock (`EBUSY`) errors.
|
|
93
|
+
- `Update Skills`
|
|
94
|
+
- Pulls/clones the configured skills repository and branch into the local `skills` directory.
|
|
95
|
+
|
|
96
|
+
## Development (Git Checkout)
|
|
97
|
+
|
|
98
|
+
For contributors working from source:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm install
|
|
102
|
+
npm run build
|
|
103
|
+
npm test
|
|
50
104
|
npm run start:controlplane
|
|
51
105
|
```
|
|
52
106
|
|
|
53
|
-
|
|
107
|
+
## Security Model
|
|
108
|
+
|
|
109
|
+
- Credential-bearing direct tool arguments are blocked for connection creation/update flows.
|
|
110
|
+
- Passwords are stored in keychain when available.
|
|
111
|
+
- Control plane is local-first (`127.0.0.1` by default).
|
|
112
|
+
- Guarded policy profile is the default for operational safety.
|
|
113
|
+
|
|
114
|
+
## Links
|
|
115
|
+
|
|
116
|
+
- Main repo: [ashishthomas2202/mcp-for-i](https://github.com/ashishthomas2202/mcp-for-i)
|
|
117
|
+
- Skills repo: [ashishthomas2202/mcp-for-i-skills](https://github.com/ashishthomas2202/mcp-for-i-skills)
|
|
118
|
+
- Docs: `docs/`
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
|
+
import fs from "fs/promises";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
2
5
|
export const AUTOSTART_TASK_NAME = "mcp-for-i-controlplane";
|
|
3
6
|
export function getControlPlaneUrl() {
|
|
4
7
|
const host = process.env.MCP_FOR_I_CONTROL_HOST || "127.0.0.1";
|
|
@@ -20,74 +23,58 @@ export async function isControlPlaneRunning(baseUrl = getControlPlaneUrl()) {
|
|
|
20
23
|
}
|
|
21
24
|
export async function configureWindowsAutostart(scriptPath, nodePath = process.execPath) {
|
|
22
25
|
assertWindowsPlatform();
|
|
23
|
-
const
|
|
24
|
-
await
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"/
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
const startupScriptPath = getWindowsStartupScriptPath();
|
|
27
|
+
await fs.mkdir(path.dirname(startupScriptPath), { recursive: true });
|
|
28
|
+
const command = `${quoteForWindowsCommand(nodePath)} ${quoteForWindowsCommand(scriptPath)} serve`;
|
|
29
|
+
const startupScript = [
|
|
30
|
+
"@echo off",
|
|
31
|
+
"setlocal",
|
|
32
|
+
`start \"\" /MIN ${command}`,
|
|
33
|
+
"exit /b 0"
|
|
34
|
+
].join("\r\n");
|
|
35
|
+
await fs.writeFile(startupScriptPath, startupScript, "utf8");
|
|
36
|
+
spawn(nodePath, [scriptPath, "serve"], {
|
|
37
|
+
detached: true,
|
|
38
|
+
stdio: "ignore",
|
|
39
|
+
windowsHide: true
|
|
40
|
+
}).unref();
|
|
37
41
|
}
|
|
38
42
|
export async function removeWindowsAutostart() {
|
|
39
43
|
assertWindowsPlatform();
|
|
40
|
-
|
|
44
|
+
const startupScriptPath = getWindowsStartupScriptPath();
|
|
45
|
+
await fs.rm(startupScriptPath, { force: true });
|
|
41
46
|
}
|
|
42
47
|
export async function getWindowsAutostartStatus() {
|
|
43
48
|
assertWindowsPlatform();
|
|
49
|
+
const startupScriptPath = getWindowsStartupScriptPath();
|
|
44
50
|
try {
|
|
45
|
-
const
|
|
46
|
-
const lower = output.toLowerCase();
|
|
47
|
-
const hasTask = lower.includes("taskname:");
|
|
48
|
-
const stateLine = output
|
|
49
|
-
.split(/\r?\n/)
|
|
50
|
-
.find(line => line.trim().toLowerCase().startsWith("status:"));
|
|
51
|
+
const stat = await fs.stat(startupScriptPath);
|
|
51
52
|
return {
|
|
52
|
-
installed:
|
|
53
|
-
state:
|
|
54
|
-
raw:
|
|
53
|
+
installed: true,
|
|
54
|
+
state: "startup-script",
|
|
55
|
+
raw: startupScriptPath,
|
|
56
|
+
updatedAt: stat.mtime.toISOString()
|
|
55
57
|
};
|
|
56
58
|
}
|
|
57
59
|
catch {
|
|
58
60
|
return {
|
|
59
61
|
installed: false,
|
|
60
62
|
state: undefined,
|
|
61
|
-
raw:
|
|
63
|
+
raw: startupScriptPath,
|
|
64
|
+
updatedAt: undefined
|
|
62
65
|
};
|
|
63
66
|
}
|
|
64
67
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
export async function runCommandCapture(command, args) {
|
|
69
|
-
return await new Promise((resolve, reject) => {
|
|
70
|
-
const child = spawn(command, args, { shell: process.platform === "win32" });
|
|
71
|
-
let output = "";
|
|
72
|
-
child.stdout.on("data", chunk => {
|
|
73
|
-
output += String(chunk);
|
|
74
|
-
});
|
|
75
|
-
child.stderr.on("data", chunk => {
|
|
76
|
-
output += String(chunk);
|
|
77
|
-
});
|
|
78
|
-
child.on("error", reject);
|
|
79
|
-
child.on("exit", code => {
|
|
80
|
-
if (code === 0) {
|
|
81
|
-
resolve(output.trim());
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
reject(new Error(output.trim() || `Command failed (${code}): ${command} ${args.join(" ")}`));
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
});
|
|
68
|
+
function getWindowsStartupScriptPath() {
|
|
69
|
+
const appData = process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming");
|
|
70
|
+
return path.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Startup", `${AUTOSTART_TASK_NAME}.cmd`);
|
|
88
71
|
}
|
|
89
72
|
function assertWindowsPlatform() {
|
|
90
73
|
if (process.platform !== "win32") {
|
|
91
74
|
throw new Error("This autostart operation is currently supported on Windows only.");
|
|
92
75
|
}
|
|
93
76
|
}
|
|
77
|
+
function quoteForWindowsCommand(value) {
|
|
78
|
+
const escaped = value.replaceAll(`"`, `""`);
|
|
79
|
+
return `"${escaped}"`;
|
|
80
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
2
|
import fs from "fs/promises";
|
|
3
|
+
import os from "os";
|
|
3
4
|
import path from "path";
|
|
4
5
|
import { fileURLToPath } from "url";
|
|
5
6
|
import { AUTOSTART_TASK_NAME, configureWindowsAutostart, getControlPlaneUrl, getWindowsAutostartStatus, isControlPlaneRunning, removeWindowsAutostart } from "./autostart.js";
|
|
@@ -20,15 +21,33 @@ export class RuntimeService {
|
|
|
20
21
|
}
|
|
21
22
|
async installOrRepair() {
|
|
22
23
|
return this.runJob("install", async (push) => {
|
|
23
|
-
await this.
|
|
24
|
-
|
|
24
|
+
const mode = await this.detectExecutionMode(push);
|
|
25
|
+
if (mode === "git-checkout") {
|
|
26
|
+
await this.runNpm(["install"], this.rootDir, push);
|
|
27
|
+
await this.buildIfPresent(push);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
await this.runGlobalPackageUpdate(push, "install");
|
|
25
31
|
});
|
|
26
32
|
}
|
|
27
33
|
async updateMcp() {
|
|
28
34
|
return this.runJob("updateMcp", async (push) => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
const mode = await this.detectExecutionMode(push);
|
|
36
|
+
if (mode === "git-checkout") {
|
|
37
|
+
const branch = await this.getGitCurrentBranch(this.rootDir, push);
|
|
38
|
+
if (branch) {
|
|
39
|
+
await this.runCommand("git", ["fetch", "origin", branch], this.rootDir, push);
|
|
40
|
+
await this.runCommand("git", ["pull", "--ff-only", "origin", branch], this.rootDir, push);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
push("Could not determine current branch. Using plain fast-forward pull.");
|
|
44
|
+
await this.runCommand("git", ["pull", "--ff-only"], this.rootDir, push);
|
|
45
|
+
}
|
|
46
|
+
await this.runNpm(["install"], this.rootDir, push);
|
|
47
|
+
await this.buildIfPresent(push);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
await this.runGlobalPackageUpdate(push, "update");
|
|
32
51
|
});
|
|
33
52
|
}
|
|
34
53
|
async updateSkills(options) {
|
|
@@ -178,12 +197,7 @@ export class RuntimeService {
|
|
|
178
197
|
}
|
|
179
198
|
async getGitRemoteUrl(cwd, push) {
|
|
180
199
|
try {
|
|
181
|
-
const
|
|
182
|
-
await this.runCommandCapture("git", ["remote", "get-url", "origin"], cwd, line => {
|
|
183
|
-
push(line);
|
|
184
|
-
lines.push(line);
|
|
185
|
-
});
|
|
186
|
-
const value = lines.join("\n").trim();
|
|
200
|
+
const value = await this.runCommandCapture("git", ["remote", "get-url", "origin"], cwd, push);
|
|
187
201
|
return value || undefined;
|
|
188
202
|
}
|
|
189
203
|
catch {
|
|
@@ -197,12 +211,19 @@ export class RuntimeService {
|
|
|
197
211
|
cwd,
|
|
198
212
|
shell: process.platform === "win32"
|
|
199
213
|
});
|
|
200
|
-
|
|
214
|
+
const lines = [];
|
|
215
|
+
child.stdout.on("data", chunk => {
|
|
216
|
+
const line = String(chunk).trimEnd();
|
|
217
|
+
if (!line)
|
|
218
|
+
return;
|
|
219
|
+
lines.push(line);
|
|
220
|
+
push(line);
|
|
221
|
+
});
|
|
201
222
|
child.stderr.on("data", chunk => push(String(chunk).trimEnd()));
|
|
202
223
|
child.on("error", reject);
|
|
203
224
|
child.on("exit", code => {
|
|
204
225
|
if (code === 0) {
|
|
205
|
-
resolve();
|
|
226
|
+
resolve(lines.join("\n").trim());
|
|
206
227
|
}
|
|
207
228
|
else {
|
|
208
229
|
reject(new Error(`Command failed (${code}): ${command} ${args.join(" ")}`));
|
|
@@ -210,6 +231,80 @@ export class RuntimeService {
|
|
|
210
231
|
});
|
|
211
232
|
});
|
|
212
233
|
}
|
|
234
|
+
async detectExecutionMode(push) {
|
|
235
|
+
const gitDir = path.join(this.rootDir, ".git");
|
|
236
|
+
if (await pathExists(gitDir)) {
|
|
237
|
+
return "git-checkout";
|
|
238
|
+
}
|
|
239
|
+
push("No git checkout found. Falling back to npm-based package management.");
|
|
240
|
+
return "package-install";
|
|
241
|
+
}
|
|
242
|
+
async buildIfPresent(push) {
|
|
243
|
+
const tsconfigPath = path.join(this.rootDir, "tsconfig.json");
|
|
244
|
+
if (!await pathExists(tsconfigPath)) {
|
|
245
|
+
push("Skipping build: tsconfig.json not found.");
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
await this.runNpm(["run", "build"], this.rootDir, push);
|
|
249
|
+
}
|
|
250
|
+
async getGitCurrentBranch(cwd, push) {
|
|
251
|
+
try {
|
|
252
|
+
const name = await this.runCommandCapture("git", ["rev-parse", "--abbrev-ref", "HEAD"], cwd, push);
|
|
253
|
+
const branch = name.trim();
|
|
254
|
+
if (!branch || branch === "HEAD") {
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
return branch;
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async runGlobalPackageUpdate(push, action) {
|
|
264
|
+
if (process.platform === "win32" && this.isLikelyGlobalInstall()) {
|
|
265
|
+
await this.scheduleWindowsSelfUpdate(push, action);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
push(`Running global ${action} for ${PACKAGE_NAME}@latest`);
|
|
269
|
+
await this.runNpm(["install", "-g", `${PACKAGE_NAME}@latest`], this.rootDir, push);
|
|
270
|
+
}
|
|
271
|
+
isLikelyGlobalInstall() {
|
|
272
|
+
const normalizedRoot = path.normalize(this.rootDir).toLowerCase();
|
|
273
|
+
const marker = `${path.sep}node_modules${path.sep}${PACKAGE_NAME}`.toLowerCase();
|
|
274
|
+
return normalizedRoot.includes(marker);
|
|
275
|
+
}
|
|
276
|
+
async scheduleWindowsSelfUpdate(push, action) {
|
|
277
|
+
const npm = await resolveNpmLaunch();
|
|
278
|
+
const controlPlaneScript = path.join(path.dirname(fileURLToPath(import.meta.url)), "index.js");
|
|
279
|
+
const jobId = `${Date.now()}-${process.pid}`;
|
|
280
|
+
const logPath = path.join(os.tmpdir(), `${PACKAGE_NAME}-${action}-${jobId}.log`);
|
|
281
|
+
const scriptPath = path.join(os.tmpdir(), `${PACKAGE_NAME}-${action}-${jobId}.cmd`);
|
|
282
|
+
const installCommand = npm.mode === "node-cli"
|
|
283
|
+
? `"${process.execPath}" "${npm.path}" install -g ${PACKAGE_NAME}@latest`
|
|
284
|
+
: `"${npm.path}" install -g ${PACKAGE_NAME}@latest`;
|
|
285
|
+
const script = [
|
|
286
|
+
"@echo off",
|
|
287
|
+
"setlocal",
|
|
288
|
+
`set \"LOG_PATH=${logPath}\"`,
|
|
289
|
+
`echo [${new Date().toISOString()}] Scheduled ${action}>>\"%LOG_PATH%\"`,
|
|
290
|
+
"timeout /t 2 /nobreak >nul",
|
|
291
|
+
`taskkill /PID ${process.pid} /F >nul 2>nul`,
|
|
292
|
+
`${installCommand} >>\"%LOG_PATH%\" 2>&1`,
|
|
293
|
+
"if errorlevel 1 goto :end",
|
|
294
|
+
`start \"\" \"${process.execPath}\" \"${controlPlaneScript}\" serve`,
|
|
295
|
+
":end",
|
|
296
|
+
`echo [${new Date().toISOString()}] Finished ${action}>>\"%LOG_PATH%\"`,
|
|
297
|
+
"del \"%~f0\" >nul 2>nul"
|
|
298
|
+
].join("\r\n");
|
|
299
|
+
await fs.writeFile(scriptPath, script, "utf8");
|
|
300
|
+
spawn("cmd.exe", ["/d", "/s", "/c", scriptPath], {
|
|
301
|
+
detached: true,
|
|
302
|
+
stdio: "ignore"
|
|
303
|
+
}).unref();
|
|
304
|
+
push(`Scheduled self-${action} in background to avoid Windows file-lock errors.`);
|
|
305
|
+
push("Control plane will stop briefly, then restart automatically.");
|
|
306
|
+
push(`Background update log: ${logPath}`);
|
|
307
|
+
}
|
|
213
308
|
}
|
|
214
309
|
function makeJob(id) {
|
|
215
310
|
return {
|
|
@@ -251,7 +346,8 @@ async function safeRename(from, to) {
|
|
|
251
346
|
// best-effort rollback
|
|
252
347
|
}
|
|
253
348
|
}
|
|
254
|
-
const DEFAULT_SKILLS_REPO = "https://github.com/
|
|
349
|
+
const DEFAULT_SKILLS_REPO = "https://github.com/ashishthomas2202/mcp-for-i-skills.git";
|
|
350
|
+
const PACKAGE_NAME = "mcp-for-i";
|
|
255
351
|
async function pathExists(target) {
|
|
256
352
|
try {
|
|
257
353
|
await fs.access(target);
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import http from "http";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
2
4
|
import { URL } from "url";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
3
6
|
import { ConfigStore } from "../config/store.js";
|
|
4
7
|
import { isKeychainAvailable } from "../security/credentialStore.js";
|
|
5
8
|
import { ConnectionService } from "./connectionService.js";
|
|
@@ -8,7 +11,7 @@ import { renderControlPlaneHtml } from "./ui.js";
|
|
|
8
11
|
export async function startControlPlaneServer(opts) {
|
|
9
12
|
const host = opts?.host || process.env.MCP_FOR_I_CONTROL_HOST || "127.0.0.1";
|
|
10
13
|
const port = normalizePort(opts?.port || Number(process.env.MCP_FOR_I_CONTROL_PORT || 3980));
|
|
11
|
-
const rootDir = opts?.rootDir || process.
|
|
14
|
+
const rootDir = opts?.rootDir || process.env.MCP_FOR_I_ROOT_DIR || getDefaultRootDir();
|
|
12
15
|
const store = new ConfigStore();
|
|
13
16
|
const connections = new ConnectionService(store);
|
|
14
17
|
const runtime = new RuntimeService(rootDir);
|
|
@@ -178,3 +181,11 @@ function normalizePort(port) {
|
|
|
178
181
|
return 3980;
|
|
179
182
|
return Math.floor(port);
|
|
180
183
|
}
|
|
184
|
+
function getDefaultRootDir() {
|
|
185
|
+
const runtimeRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
186
|
+
const packageJsonPath = path.join(runtimeRoot, "package.json");
|
|
187
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
188
|
+
return runtimeRoot;
|
|
189
|
+
}
|
|
190
|
+
return process.cwd();
|
|
191
|
+
}
|
package/dist/controlplane/ui.js
CHANGED
|
@@ -380,7 +380,7 @@ export function renderControlPlaneHtml() {
|
|
|
380
380
|
<div class="grid-2">
|
|
381
381
|
<div class="field">
|
|
382
382
|
<label>Skills Repo URL</label>
|
|
383
|
-
<input id="skillsRepoUrl" placeholder="https://github.com/
|
|
383
|
+
<input id="skillsRepoUrl" placeholder="https://github.com/ashishthomas2202/mcp-for-i-skills.git" />
|
|
384
384
|
</div>
|
|
385
385
|
<div class="field">
|
|
386
386
|
<label>Skills Branch</label>
|
|
@@ -389,7 +389,7 @@ export function renderControlPlaneHtml() {
|
|
|
389
389
|
</div>
|
|
390
390
|
<div class="actions">
|
|
391
391
|
<button id="installBtn" type="button">Install/Repair MCP</button>
|
|
392
|
-
<button id="updateMcpBtn" class="secondary" type="button">Update MCP
|
|
392
|
+
<button id="updateMcpBtn" class="secondary" type="button">Update MCP</button>
|
|
393
393
|
<button id="updateSkillsBtn" class="secondary" type="button">Update Skills</button>
|
|
394
394
|
<button id="refreshStatusBtn" class="secondary" type="button">Refresh Status</button>
|
|
395
395
|
<button id="setupAutostartBtn" class="secondary" type="button">Enable Background Startup</button>
|
|
@@ -398,7 +398,9 @@ export function renderControlPlaneHtml() {
|
|
|
398
398
|
</div>
|
|
399
399
|
<div id="autostartInfo" class="hint">Startup status: checking...</div>
|
|
400
400
|
<div id="logs" class="logs">No jobs yet.</div>
|
|
401
|
-
<div class="hint">
|
|
401
|
+
<div class="hint">Install/Repair uses local git checkout when available, otherwise global npm install. Update MCP follows the same mode.</div>
|
|
402
|
+
<div class="hint">Windows global updates may briefly restart the local control-plane service.</div>
|
|
403
|
+
<div class="hint">Skills update can clone or pull from the repo and branch shown above.</div>
|
|
402
404
|
</section>
|
|
403
405
|
|
|
404
406
|
<section class="card" style="grid-column: 1 / -1;">
|
|
@@ -424,7 +426,7 @@ export function renderControlPlaneHtml() {
|
|
|
424
426
|
const THEME_KEY = "mcp_for_i_theme";
|
|
425
427
|
const SKILLS_REPO_KEY = "mcp_for_i_skills_repo";
|
|
426
428
|
const SKILLS_BRANCH_KEY = "mcp_for_i_skills_branch";
|
|
427
|
-
const DEFAULT_SKILLS_REPO = "https://github.com/
|
|
429
|
+
const DEFAULT_SKILLS_REPO = "https://github.com/ashishthomas2202/mcp-for-i-skills.git";
|
|
428
430
|
const DEFAULT_SKILLS_BRANCH = "main";
|
|
429
431
|
|
|
430
432
|
const state = {
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { getTools, handleTool } from "./mcp/tools.js";
|
|
|
6
6
|
import { McpContext } from "./mcp/context.js";
|
|
7
7
|
import { log } from "./mcp/logger.js";
|
|
8
8
|
import { validateToolInput } from "./mcp/validation.js";
|
|
9
|
-
const server = new Server({ name: "mcp-for-i", version: "0.1.
|
|
9
|
+
const server = new Server({ name: "mcp-for-i", version: "0.1.2" }, { capabilities: { tools: {} } });
|
|
10
10
|
const ctx = new McpContext();
|
|
11
11
|
const tools = getTools();
|
|
12
12
|
const toolMap = new Map(tools.map(tool => [tool.name, tool]));
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-for-i",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Local MCP server and control plane for IBM i workflows",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"homepage": "https://github.com/
|
|
7
|
+
"homepage": "https://github.com/ashishthomas2202/mcp-for-i",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/
|
|
10
|
+
"url": "git+https://github.com/ashishthomas2202/mcp-for-i.git"
|
|
11
11
|
},
|
|
12
12
|
"bugs": {
|
|
13
|
-
"url": "https://github.com/
|
|
13
|
+
"url": "https://github.com/ashishthomas2202/mcp-for-i/issues"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|