2026-02-21 03:10:39 +00:00
|
|
|
{
|
|
|
|
|
"name": "mcpctl",
|
2026-02-27 17:05:05 +00:00
|
|
|
"version": "0.0.1",
|
2026-02-21 03:10:39 +00:00
|
|
|
"private": true,
|
|
|
|
|
"description": "kubectl-like CLI for managing MCP servers",
|
|
|
|
|
"type": "module",
|
|
|
|
|
"scripts": {
|
|
|
|
|
"build": "pnpm -r run build",
|
|
|
|
|
"test": "vitest",
|
|
|
|
|
"test:run": "vitest run",
|
|
|
|
|
"test:coverage": "vitest run --coverage",
|
2026-03-03 19:07:39 +00:00
|
|
|
"test:smoke": "pnpm --filter mcplocal run test:smoke",
|
2026-02-21 03:10:39 +00:00
|
|
|
"test:ui": "vitest --ui",
|
|
|
|
|
"lint": "eslint 'src/*/src/**/*.ts'",
|
|
|
|
|
"lint:fix": "eslint 'src/*/src/**/*.ts' --fix",
|
|
|
|
|
"clean": "pnpm -r run clean && rimraf node_modules",
|
|
|
|
|
"db:up": "docker compose -f deploy/docker-compose.yml up -d",
|
|
|
|
|
"db:down": "docker compose -f deploy/docker-compose.yml down",
|
fix(pi): repair the /mcpctl menu, skills target, and typecheck the extension
The pi extension shipped in `src/pi-ext/` was covered by no tsconfig and no
eslint config, so nothing ever checked it against pi's API. Pointing tsc at
the published @earendil-works/pi-coding-agent types found the command surface
to be inert.
Fixes:
- `/mcpctl` did nothing. `ctx.ui.select` takes `string[]` and returns the
chosen string; it was called with `{value,label}` objects, so the menu
rendered five `[object Object]` rows and `choice === "status"` never
matched any branch. Labels are now plain strings mapped back to actions.
- The headless branch returned a status string from a handler typed
`Promise<void>`; pi drops it. Reports via notify instead.
- "Sync skills" omitted `--agent pi`, writing into ~/.claude/skills — in an
integration whose stated purpose is to not depend on ~/.claude — and said
so in its own success message. It also ran execSync with `stdio: "inherit"`,
painting raw output over pi's TUI, and interpolated the project name into a
shell string. Now execFile with `--agent pi` and captured output.
- Tool results typed `content[].type` as `string`; pi's AgentToolResult wants
the `"text"` literal.
- `callTool` asserted `Promise<unknown>` to `ToolCallResult`.
- Sanitising MCP tool names to `[a-z0-9_]` can collide (`docs.search` vs
`docs-search`). The colliding tool was silently never registered but still
reported active, so its calls were forwarded to the first tool. Names are
now disambiguated and tracked with the MCP tool they forward to.
- `registerWithPi` rewrote settings.json even when nothing changed. Since
parsing strips `//` comments, a no-op run destroyed them.
Guards, so this class of bug can't return:
- `src/pi-ext/tsconfig.json` checks the extension against the real published
pi types (dev dependency, not a shim — a shim drifting from the published
API is the exact failure being guarded). Wired into `pnpm typecheck`.
- eslint now covers `src/pi-ext/*.ts` like every other source file.
- A test fails if the embedded copy in `config/pi-extension.ts` is stale;
editing the sources without regenerating silently shipped old code.
Also: the branch added `config pi` without regenerating shell completions
(the committed-completions test was failing), and the doc advertised
`mcpctl pi sync-skills`, which does not exist. Both corrected, plus a note
on the session-token vs `mcpctl_pat_` bearer difference that would bite
against an authenticated `mcplocal serve`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BMXdb2qZbPSh8Q7XpTyjB
2026-08-08 17:30:42 +01:00
|
|
|
"typecheck": "tsc --build && pnpm run typecheck:pi-ext",
|
2026-02-27 17:05:05 +00:00
|
|
|
"completions:generate": "tsx scripts/generate-completions.ts --write",
|
|
|
|
|
"completions:check": "tsx scripts/generate-completions.ts --check",
|
2026-02-21 14:00:24 +00:00
|
|
|
"rpm:build": "bash scripts/build-rpm.sh",
|
2026-03-13 23:01:51 +00:00
|
|
|
"rpm:build:amd64": "MCPCTL_TARGET_ARCH=amd64 bash scripts/build-rpm.sh",
|
|
|
|
|
"rpm:build:arm64": "MCPCTL_TARGET_ARCH=arm64 bash scripts/build-rpm.sh",
|
2026-02-21 14:04:07 +00:00
|
|
|
"rpm:publish": "bash scripts/publish-rpm.sh",
|
2026-03-09 22:43:40 +00:00
|
|
|
"deb:build": "bash scripts/build-deb.sh",
|
2026-03-13 23:01:51 +00:00
|
|
|
"deb:build:amd64": "MCPCTL_TARGET_ARCH=amd64 bash scripts/build-deb.sh",
|
|
|
|
|
"deb:build:arm64": "MCPCTL_TARGET_ARCH=arm64 bash scripts/build-deb.sh",
|
2026-03-09 22:43:40 +00:00
|
|
|
"deb:publish": "bash scripts/publish-deb.sh",
|
2026-02-22 22:24:35 +00:00
|
|
|
"release": "bash scripts/release.sh",
|
2026-03-13 23:01:51 +00:00
|
|
|
"release:both": "bash scripts/release.sh --both-arches",
|
2026-02-22 22:24:35 +00:00
|
|
|
"mcpd:build": "bash scripts/build-mcpd.sh",
|
|
|
|
|
"mcpd:deploy": "bash deploy.sh",
|
|
|
|
|
"mcpd:deploy-dry": "bash deploy.sh --dry-run",
|
fix(pi): repair the /mcpctl menu, skills target, and typecheck the extension
The pi extension shipped in `src/pi-ext/` was covered by no tsconfig and no
eslint config, so nothing ever checked it against pi's API. Pointing tsc at
the published @earendil-works/pi-coding-agent types found the command surface
to be inert.
Fixes:
- `/mcpctl` did nothing. `ctx.ui.select` takes `string[]` and returns the
chosen string; it was called with `{value,label}` objects, so the menu
rendered five `[object Object]` rows and `choice === "status"` never
matched any branch. Labels are now plain strings mapped back to actions.
- The headless branch returned a status string from a handler typed
`Promise<void>`; pi drops it. Reports via notify instead.
- "Sync skills" omitted `--agent pi`, writing into ~/.claude/skills — in an
integration whose stated purpose is to not depend on ~/.claude — and said
so in its own success message. It also ran execSync with `stdio: "inherit"`,
painting raw output over pi's TUI, and interpolated the project name into a
shell string. Now execFile with `--agent pi` and captured output.
- Tool results typed `content[].type` as `string`; pi's AgentToolResult wants
the `"text"` literal.
- `callTool` asserted `Promise<unknown>` to `ToolCallResult`.
- Sanitising MCP tool names to `[a-z0-9_]` can collide (`docs.search` vs
`docs-search`). The colliding tool was silently never registered but still
reported active, so its calls were forwarded to the first tool. Names are
now disambiguated and tracked with the MCP tool they forward to.
- `registerWithPi` rewrote settings.json even when nothing changed. Since
parsing strips `//` comments, a no-op run destroyed them.
Guards, so this class of bug can't return:
- `src/pi-ext/tsconfig.json` checks the extension against the real published
pi types (dev dependency, not a shim — a shim drifting from the published
API is the exact failure being guarded). Wired into `pnpm typecheck`.
- eslint now covers `src/pi-ext/*.ts` like every other source file.
- A test fails if the embedded copy in `config/pi-extension.ts` is stale;
editing the sources without regenerating silently shipped old code.
Also: the branch added `config pi` without regenerating shell completions
(the committed-completions test was failing), and the doc advertised
`mcpctl pi sync-skills`, which does not exist. Both corrected, plus a note
on the session-token vs `mcpctl_pat_` bearer difference that would bite
against an authenticated `mcplocal serve`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BMXdb2qZbPSh8Q7XpTyjB
2026-08-08 17:30:42 +01:00
|
|
|
"mcpd:logs": "bash logs.sh",
|
|
|
|
|
"typecheck:pi-ext": "tsc -p src/pi-ext/tsconfig.json"
|
2026-02-21 03:10:39 +00:00
|
|
|
},
|
|
|
|
|
"engines": {
|
|
|
|
|
"node": ">=20.0.0",
|
|
|
|
|
"pnpm": ">=9.0.0"
|
|
|
|
|
},
|
|
|
|
|
"packageManager": "pnpm@9.15.0",
|
|
|
|
|
"devDependencies": {
|
fix(pi): repair the /mcpctl menu, skills target, and typecheck the extension
The pi extension shipped in `src/pi-ext/` was covered by no tsconfig and no
eslint config, so nothing ever checked it against pi's API. Pointing tsc at
the published @earendil-works/pi-coding-agent types found the command surface
to be inert.
Fixes:
- `/mcpctl` did nothing. `ctx.ui.select` takes `string[]` and returns the
chosen string; it was called with `{value,label}` objects, so the menu
rendered five `[object Object]` rows and `choice === "status"` never
matched any branch. Labels are now plain strings mapped back to actions.
- The headless branch returned a status string from a handler typed
`Promise<void>`; pi drops it. Reports via notify instead.
- "Sync skills" omitted `--agent pi`, writing into ~/.claude/skills — in an
integration whose stated purpose is to not depend on ~/.claude — and said
so in its own success message. It also ran execSync with `stdio: "inherit"`,
painting raw output over pi's TUI, and interpolated the project name into a
shell string. Now execFile with `--agent pi` and captured output.
- Tool results typed `content[].type` as `string`; pi's AgentToolResult wants
the `"text"` literal.
- `callTool` asserted `Promise<unknown>` to `ToolCallResult`.
- Sanitising MCP tool names to `[a-z0-9_]` can collide (`docs.search` vs
`docs-search`). The colliding tool was silently never registered but still
reported active, so its calls were forwarded to the first tool. Names are
now disambiguated and tracked with the MCP tool they forward to.
- `registerWithPi` rewrote settings.json even when nothing changed. Since
parsing strips `//` comments, a no-op run destroyed them.
Guards, so this class of bug can't return:
- `src/pi-ext/tsconfig.json` checks the extension against the real published
pi types (dev dependency, not a shim — a shim drifting from the published
API is the exact failure being guarded). Wired into `pnpm typecheck`.
- eslint now covers `src/pi-ext/*.ts` like every other source file.
- A test fails if the embedded copy in `config/pi-extension.ts` is stale;
editing the sources without regenerating silently shipped old code.
Also: the branch added `config pi` without regenerating shell completions
(the committed-completions test was failing), and the doc advertised
`mcpctl pi sync-skills`, which does not exist. Both corrected, plus a note
on the session-token vs `mcpctl_pat_` bearer difference that would bite
against an authenticated `mcplocal serve`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BMXdb2qZbPSh8Q7XpTyjB
2026-08-08 17:30:42 +01:00
|
|
|
"@earendil-works/pi-ai": "^0.84.1",
|
|
|
|
|
"@earendil-works/pi-coding-agent": "0.84.1",
|
2026-02-21 03:46:14 +00:00
|
|
|
"@types/node": "^25.3.0",
|
2026-02-21 03:10:39 +00:00
|
|
|
"@typescript-eslint/eslint-plugin": "^8.56.0",
|
|
|
|
|
"@typescript-eslint/parser": "^8.56.0",
|
|
|
|
|
"@vitest/coverage-v8": "^4.0.18",
|
|
|
|
|
"eslint": "^10.0.1",
|
|
|
|
|
"eslint-config-prettier": "^10.1.8",
|
|
|
|
|
"rimraf": "^6.1.3",
|
|
|
|
|
"tsx": "^4.21.0",
|
fix(pi): repair the /mcpctl menu, skills target, and typecheck the extension
The pi extension shipped in `src/pi-ext/` was covered by no tsconfig and no
eslint config, so nothing ever checked it against pi's API. Pointing tsc at
the published @earendil-works/pi-coding-agent types found the command surface
to be inert.
Fixes:
- `/mcpctl` did nothing. `ctx.ui.select` takes `string[]` and returns the
chosen string; it was called with `{value,label}` objects, so the menu
rendered five `[object Object]` rows and `choice === "status"` never
matched any branch. Labels are now plain strings mapped back to actions.
- The headless branch returned a status string from a handler typed
`Promise<void>`; pi drops it. Reports via notify instead.
- "Sync skills" omitted `--agent pi`, writing into ~/.claude/skills — in an
integration whose stated purpose is to not depend on ~/.claude — and said
so in its own success message. It also ran execSync with `stdio: "inherit"`,
painting raw output over pi's TUI, and interpolated the project name into a
shell string. Now execFile with `--agent pi` and captured output.
- Tool results typed `content[].type` as `string`; pi's AgentToolResult wants
the `"text"` literal.
- `callTool` asserted `Promise<unknown>` to `ToolCallResult`.
- Sanitising MCP tool names to `[a-z0-9_]` can collide (`docs.search` vs
`docs-search`). The colliding tool was silently never registered but still
reported active, so its calls were forwarded to the first tool. Names are
now disambiguated and tracked with the MCP tool they forward to.
- `registerWithPi` rewrote settings.json even when nothing changed. Since
parsing strips `//` comments, a no-op run destroyed them.
Guards, so this class of bug can't return:
- `src/pi-ext/tsconfig.json` checks the extension against the real published
pi types (dev dependency, not a shim — a shim drifting from the published
API is the exact failure being guarded). Wired into `pnpm typecheck`.
- eslint now covers `src/pi-ext/*.ts` like every other source file.
- A test fails if the embedded copy in `config/pi-extension.ts` is stale;
editing the sources without regenerating silently shipped old code.
Also: the branch added `config pi` without regenerating shell completions
(the committed-completions test was failing), and the doc advertised
`mcpctl pi sync-skills`, which does not exist. Both corrected, plus a note
on the session-token vs `mcpctl_pat_` bearer difference that would bite
against an authenticated `mcplocal serve`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BMXdb2qZbPSh8Q7XpTyjB
2026-08-08 17:30:42 +01:00
|
|
|
"typebox": "1.3.11",
|
2026-02-21 03:10:39 +00:00
|
|
|
"typescript": "^5.9.3",
|
|
|
|
|
"vitest": "^4.0.18"
|
|
|
|
|
}
|
|
|
|
|
}
|