@yawlabs/mcph 0.41.0 → 0.43.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/CHANGELOG.md +9 -0
- package/README.md +32 -2
- package/dist/index.js +253 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@yawlabs/mcph` are documented here. This project uses [semantic versioning](https://semver.org) and a CI-gated release flow: pushing a `vX.Y.Z` tag triggers `.github/workflows/release.yml`, which publishes to npm.
|
|
4
4
|
|
|
5
|
+
## 0.43.0 — 2026-04-18
|
|
6
|
+
|
|
7
|
+
- **`mcph servers <namespace-filter>` — positional filter** — Passing a bare positional argument now filters the listing to servers whose namespace contains that substring (case-insensitive): `mcph servers git` matches both `github` and `gitlab`. Applies to both the text table and the `--json` output so the two surfaces agree. Summary line reflects the filtered count, and a filter that matches nothing prints an explanatory "No servers match …" instead of an empty table (which previously looked like an empty account).
|
|
8
|
+
- **README catch-up — `CLI reference` block + `doctor --json` documented** — The README was missing the subcommands that landed in v0.38.0 onward (`servers`, `bundles`, `reset-learning`, `completion`) and hadn't been updated to mention doctor's `--json` mode. New compact "Other CLI subcommands" block lists every user-facing command with a one-line purpose, documents the `--json` pattern as the pipeline interface across doctor/servers/bundles, and includes copy-paste install snippets for bash/zsh/fish/powershell completions. The doctor paragraph now lists the actual section coverage (env overrides, persisted state, reliability rollup, shell-shadow hits, upgrade check) so first-time readers know what they get.
|
|
9
|
+
|
|
10
|
+
## 0.42.0 — 2026-04-18
|
|
11
|
+
|
|
12
|
+
- **`mcph completion <shell>` — shell completion scripts** — Prints a completion script for `bash`, `zsh`, `fish`, or `powershell` to stdout so users can one-line it into their completions directory. Each script covers every known subcommand (install, doctor, servers, bundles, compliance, reset-learning, completion) with positional choices (install clients, bundles actions, completion shells) and per-subcommand flags (`--json`, `--scope`, `--token`, `--force`, etc.). Every template derives from a single `SUBCOMMAND_SPEC` table so adding a new subcommand elsewhere updates all four shells at once — no drift between what the CLI accepts and what it completes. Install hints are inlined as comments at the top of each generated script: the bash file drops into `~/.local/share/bash-completion/completions/mcph`, zsh into any `$fpath` dir as `_mcph`, fish into `~/.config/fish/completions/mcph.fish`, pwsh appended to `$PROFILE`.
|
|
13
|
+
|
|
5
14
|
## 0.41.0 — 2026-04-18
|
|
6
15
|
|
|
7
16
|
- **`mcph doctor --json` — machine-readable diagnostic output** — Doctor already tracks a lot of state (config files, token source, env overrides, persisted learning, installed clients, shell-history shadow hits, upgrade availability, diagnosis summary) and the text output optimises for pasting into a support ticket. `--json` emits the same data as a single structured blob so dashboards, CI scripts, and support tooling can pick fields with `jq` instead of parsing the text layout. Token is fingerprinted the same way in both modes (never raw). Section data is 1:1 with the text renderer: config (token/apiBase/loadedFiles/warnings), env overrides (null when unset), state (path/savedAt/entries; `disabled: true` when `MCPH_DISABLE_PERSISTENCE` is set), reliability (same `selectFlakyNamespaces` rollup that `mcp_connect_health` and the text RELIABILITY section use), clients probe results, shell shadow hits, upgrade info, and the exit-code diagnosis. Completes the `--json` pattern across `servers`, `bundles`, and now `doctor` — every CLI that reads state has a pipeline mode.
|
package/README.md
CHANGED
|
@@ -70,10 +70,40 @@ Or [edit the JSON by hand](#manual-install) if you'd rather.
|
|
|
70
70
|
### Diagnose problems — `mcph doctor`
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
npx -y @yawlabs/mcph doctor
|
|
73
|
+
npx -y @yawlabs/mcph doctor # human-readable report
|
|
74
|
+
npx -y @yawlabs/mcph doctor --json # machine-readable snapshot for pipelines
|
|
74
75
|
```
|
|
75
76
|
|
|
76
|
-
Prints the loaded config files, your token's source + fingerprint (last 4 chars), the API base URL,
|
|
77
|
+
Prints the loaded config files, your token's source + fingerprint (last 4 chars), the API base URL, installed clients, env overrides, persisted learning state, flaky-namespace reliability rollup, shell-history "shadow" hits (CLIs you run that an MCP server could replace), and an upgrade check against the npm registry. Exits `0` healthy / `1` no token / `2` warnings (e.g. world-readable token file). Paste the text output into a support ticket; the `--json` blob is the same data as a structured snapshot, so dashboards and CI scripts can `jq` instead of parsing the text layout.
|
|
78
|
+
|
|
79
|
+
### Other CLI subcommands
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
mcph servers [<namespace-filter>] [--json] # list servers; optional substring filter on namespace
|
|
83
|
+
mcph bundles [list|match] [--json] # browse curated multi-server bundles (PR review, DevOps incident, etc.)
|
|
84
|
+
mcph reset-learning # clear cross-session learning history (~/.mcph/state.json)
|
|
85
|
+
mcph completion <bash|zsh|fish|powershell> # print shell completion script
|
|
86
|
+
mcph compliance <target> [--publish] # run the compliance suite against an MCP server
|
|
87
|
+
mcph --version # print version
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Every CLI that reads state has a `--json` mode for pipeline use. `mcph servers` hits the backend; `mcph bundles list` and `mcph completion` are fully static (no network, no token). `mcph bundles match` partitions the curated set against your enabled servers so you see the same ready-to-activate vs. partially-installed view the LLM-facing `mcp_connect_bundles` meta-tool produces.
|
|
91
|
+
|
|
92
|
+
To wire up shell completion:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# bash
|
|
96
|
+
mcph completion bash > ~/.local/share/bash-completion/completions/mcph
|
|
97
|
+
|
|
98
|
+
# zsh (must be on $fpath, then rebuild compinit)
|
|
99
|
+
mcph completion zsh > "${fpath[1]}/_mcph"
|
|
100
|
+
|
|
101
|
+
# fish
|
|
102
|
+
mcph completion fish > ~/.config/fish/completions/mcph.fish
|
|
103
|
+
|
|
104
|
+
# powershell
|
|
105
|
+
mcph completion powershell >> $PROFILE
|
|
106
|
+
```
|
|
77
107
|
|
|
78
108
|
### Getting your token
|
|
79
109
|
|
package/dist/index.js
CHANGED
|
@@ -648,6 +648,222 @@ function renderMatch(match, installed, print) {
|
|
|
648
648
|
}
|
|
649
649
|
}
|
|
650
650
|
|
|
651
|
+
// src/completion-cmd.ts
|
|
652
|
+
var COMPLETION_USAGE = `Usage: mcph completion <bash|zsh|fish|powershell>
|
|
653
|
+
|
|
654
|
+
Print a shell completion script to stdout. Redirect it to the right
|
|
655
|
+
location for your shell:
|
|
656
|
+
|
|
657
|
+
bash mcph completion bash > ~/.local/share/bash-completion/completions/mcph
|
|
658
|
+
zsh mcph completion zsh > "\${fpath[1]}/_mcph" (must be on $fpath)
|
|
659
|
+
fish mcph completion fish > ~/.config/fish/completions/mcph.fish
|
|
660
|
+
powershell mcph completion powershell >> $PROFILE`;
|
|
661
|
+
var INSTALL_CLIENTS = ["claude-code", "claude-desktop", "cursor", "vscode"];
|
|
662
|
+
var SUBCOMMAND_SPEC = [
|
|
663
|
+
{
|
|
664
|
+
name: "install",
|
|
665
|
+
positional: [...INSTALL_CLIENTS],
|
|
666
|
+
flags: ["--scope", "--token", "--project-dir", "--os", "--force", "--skip", "--dry-run", "--no-mcph-config"]
|
|
667
|
+
},
|
|
668
|
+
{ name: "doctor", flags: ["--json", "--help"] },
|
|
669
|
+
{ name: "servers", flags: ["--json", "--help"] },
|
|
670
|
+
{ name: "bundles", positional: ["list", "match"], flags: ["--json", "--help"] },
|
|
671
|
+
{ name: "compliance", flags: ["--publish", "--help"] },
|
|
672
|
+
{ name: "reset-learning", flags: ["--help"] },
|
|
673
|
+
{ name: "completion", positional: ["bash", "zsh", "fish", "powershell"], flags: ["--help"] },
|
|
674
|
+
{ name: "help", flags: [] }
|
|
675
|
+
];
|
|
676
|
+
function parseCompletionArgs(argv) {
|
|
677
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
678
|
+
return { ok: false, error: COMPLETION_USAGE };
|
|
679
|
+
}
|
|
680
|
+
const positional = argv.filter((a) => !a.startsWith("-"));
|
|
681
|
+
if (positional.length === 0) {
|
|
682
|
+
return { ok: false, error: `mcph completion: missing shell argument
|
|
683
|
+
|
|
684
|
+
${COMPLETION_USAGE}` };
|
|
685
|
+
}
|
|
686
|
+
if (positional.length > 1) {
|
|
687
|
+
return { ok: false, error: `mcph completion: too many arguments
|
|
688
|
+
|
|
689
|
+
${COMPLETION_USAGE}` };
|
|
690
|
+
}
|
|
691
|
+
const shell = positional[0];
|
|
692
|
+
if (shell !== "bash" && shell !== "zsh" && shell !== "fish" && shell !== "powershell") {
|
|
693
|
+
return { ok: false, error: `mcph completion: unknown shell "${shell}"
|
|
694
|
+
|
|
695
|
+
${COMPLETION_USAGE}` };
|
|
696
|
+
}
|
|
697
|
+
return { ok: true, options: { shell } };
|
|
698
|
+
}
|
|
699
|
+
async function runCompletion(opts = {}) {
|
|
700
|
+
const write = opts.out ?? ((s) => process.stdout.write(s));
|
|
701
|
+
const writeErr = opts.err ?? ((s) => process.stderr.write(s));
|
|
702
|
+
const lines = [];
|
|
703
|
+
const print = (s) => {
|
|
704
|
+
lines.push(s);
|
|
705
|
+
write(`${s}
|
|
706
|
+
`);
|
|
707
|
+
};
|
|
708
|
+
if (!opts.shell) {
|
|
709
|
+
writeErr(`mcph completion: missing shell argument
|
|
710
|
+
${COMPLETION_USAGE}
|
|
711
|
+
`);
|
|
712
|
+
return { exitCode: 2, lines };
|
|
713
|
+
}
|
|
714
|
+
const script = renderScript(opts.shell);
|
|
715
|
+
print(script);
|
|
716
|
+
return { exitCode: 0, lines };
|
|
717
|
+
}
|
|
718
|
+
function renderScript(shell) {
|
|
719
|
+
switch (shell) {
|
|
720
|
+
case "bash":
|
|
721
|
+
return renderBash();
|
|
722
|
+
case "zsh":
|
|
723
|
+
return renderZsh();
|
|
724
|
+
case "fish":
|
|
725
|
+
return renderFish();
|
|
726
|
+
case "powershell":
|
|
727
|
+
return renderPowershell();
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
function renderBash() {
|
|
731
|
+
const subcommandList = SUBCOMMAND_SPEC.map((s) => s.name).join(" ");
|
|
732
|
+
const topLevelFlags = "--help -h --version -V";
|
|
733
|
+
const cases = SUBCOMMAND_SPEC.map((spec) => {
|
|
734
|
+
const posClause = spec.positional ? ` if [[ $cword -eq 2 ]]; then
|
|
735
|
+
COMPREPLY=( $(compgen -W "${spec.positional.join(" ")} ${spec.flags.join(" ")}" -- "$cur") )
|
|
736
|
+
return 0
|
|
737
|
+
fi` : "";
|
|
738
|
+
return ` ${spec.name})
|
|
739
|
+
${posClause}
|
|
740
|
+
COMPREPLY=( $(compgen -W "${spec.flags.join(" ")}" -- "$cur") )
|
|
741
|
+
return 0
|
|
742
|
+
;;`;
|
|
743
|
+
}).join("\n");
|
|
744
|
+
return `# bash completion for mcph \u2014 generated by \`mcph completion bash\`
|
|
745
|
+
# Install: save this to ~/.local/share/bash-completion/completions/mcph
|
|
746
|
+
# or source it from your .bashrc.
|
|
747
|
+
_mcph() {
|
|
748
|
+
local cur prev words cword
|
|
749
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
750
|
+
cword=$COMP_CWORD
|
|
751
|
+
|
|
752
|
+
if [[ $cword -eq 1 ]]; then
|
|
753
|
+
COMPREPLY=( $(compgen -W "${subcommandList} ${topLevelFlags}" -- "$cur") )
|
|
754
|
+
return 0
|
|
755
|
+
fi
|
|
756
|
+
|
|
757
|
+
case "\${COMP_WORDS[1]}" in
|
|
758
|
+
${cases}
|
|
759
|
+
esac
|
|
760
|
+
}
|
|
761
|
+
complete -F _mcph mcph
|
|
762
|
+
`;
|
|
763
|
+
}
|
|
764
|
+
function renderZsh() {
|
|
765
|
+
const subcommandDescriptions = {
|
|
766
|
+
install: "Auto-edit an MCP client's config",
|
|
767
|
+
doctor: "Print diagnostic of mcph setup",
|
|
768
|
+
servers: "List servers in your mcp.hosting dashboard",
|
|
769
|
+
bundles: "Browse curated multi-server bundles",
|
|
770
|
+
compliance: "Run the compliance suite against a server",
|
|
771
|
+
"reset-learning": "Clear cross-session learning history",
|
|
772
|
+
completion: "Print a shell completion script",
|
|
773
|
+
help: "Show usage"
|
|
774
|
+
};
|
|
775
|
+
const subcommandList = SUBCOMMAND_SPEC.map((s) => ` '${s.name}:${subcommandDescriptions[s.name] ?? ""}'`).join(
|
|
776
|
+
"\n"
|
|
777
|
+
);
|
|
778
|
+
const argsCases = SUBCOMMAND_SPEC.map((spec) => {
|
|
779
|
+
const lines = [` ${spec.name})`];
|
|
780
|
+
if (spec.positional) {
|
|
781
|
+
lines.push(` _arguments '1: :(${spec.positional.join(" ")})' '*: :(${spec.flags.join(" ")})'`);
|
|
782
|
+
} else {
|
|
783
|
+
lines.push(` _arguments '*: :(${spec.flags.join(" ")})'`);
|
|
784
|
+
}
|
|
785
|
+
lines.push(" ;;");
|
|
786
|
+
return lines.join("\n");
|
|
787
|
+
}).join("\n");
|
|
788
|
+
return `#compdef mcph
|
|
789
|
+
# zsh completion for mcph \u2014 generated by \`mcph completion zsh\`
|
|
790
|
+
# Install: save this to a file on your $fpath named _mcph
|
|
791
|
+
# (e.g., ~/.zsh/completions/_mcph), then rebuild completions:
|
|
792
|
+
# autoload -U compinit && compinit
|
|
793
|
+
_mcph() {
|
|
794
|
+
local context state line
|
|
795
|
+
_arguments -C \\
|
|
796
|
+
'1: :->cmd' \\
|
|
797
|
+
'*::arg:->args'
|
|
798
|
+
|
|
799
|
+
case $state in
|
|
800
|
+
cmd)
|
|
801
|
+
_values 'mcph subcommand' \\
|
|
802
|
+
${subcommandList}
|
|
803
|
+
;;
|
|
804
|
+
args)
|
|
805
|
+
case $line[1] in
|
|
806
|
+
${argsCases}
|
|
807
|
+
esac
|
|
808
|
+
;;
|
|
809
|
+
esac
|
|
810
|
+
}
|
|
811
|
+
_mcph "$@"
|
|
812
|
+
`;
|
|
813
|
+
}
|
|
814
|
+
function renderFish() {
|
|
815
|
+
const header = `# fish completion for mcph \u2014 generated by \`mcph completion fish\`
|
|
816
|
+
# Install: save this to ~/.config/fish/completions/mcph.fish
|
|
817
|
+
complete -c mcph -f`;
|
|
818
|
+
const subcommandLines = SUBCOMMAND_SPEC.map((spec) => {
|
|
819
|
+
return `complete -c mcph -n __fish_use_subcommand -a ${spec.name}`;
|
|
820
|
+
});
|
|
821
|
+
const positionalLines = [];
|
|
822
|
+
const flagLines = [];
|
|
823
|
+
for (const spec of SUBCOMMAND_SPEC) {
|
|
824
|
+
if (spec.positional) {
|
|
825
|
+
for (const p of spec.positional) {
|
|
826
|
+
positionalLines.push(`complete -c mcph -n "__fish_seen_subcommand_from ${spec.name}" -a ${p}`);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
for (const f of spec.flags) {
|
|
830
|
+
const long = f.replace(/^--/, "");
|
|
831
|
+
flagLines.push(`complete -c mcph -n "__fish_seen_subcommand_from ${spec.name}" -l ${long}`);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return [header, "", ...subcommandLines, "", ...positionalLines, "", ...flagLines, ""].join("\n");
|
|
835
|
+
}
|
|
836
|
+
function renderPowershell() {
|
|
837
|
+
const subcommandNames = SUBCOMMAND_SPEC.map((s) => `'${s.name}'`).join(", ");
|
|
838
|
+
const caseBranches = SUBCOMMAND_SPEC.map((spec) => {
|
|
839
|
+
const positional = spec.positional ? spec.positional.map((p) => `'${p}'`).join(", ") : "";
|
|
840
|
+
const flags = spec.flags.map((f) => `'${f}'`).join(", ");
|
|
841
|
+
const positionalLine = positional ? ` $completions += @(${positional})
|
|
842
|
+
` : "";
|
|
843
|
+
return ` '${spec.name}' {
|
|
844
|
+
${positionalLine} $completions += @(${flags})
|
|
845
|
+
}`;
|
|
846
|
+
}).join("\n");
|
|
847
|
+
return `# PowerShell completion for mcph \u2014 generated by \`mcph completion powershell\`
|
|
848
|
+
# Install: append this script to your profile ($PROFILE) and reload.
|
|
849
|
+
Register-ArgumentCompleter -CommandName mcph -ScriptBlock {
|
|
850
|
+
param($wordToComplete, $commandAst, $cursorPosition)
|
|
851
|
+
$tokens = $commandAst.CommandElements | ForEach-Object { $_.ToString() }
|
|
852
|
+
$completions = @()
|
|
853
|
+
if ($tokens.Count -le 2) {
|
|
854
|
+
$completions = @(${subcommandNames}, '--help', '-h', '--version', '-V')
|
|
855
|
+
} else {
|
|
856
|
+
switch ($tokens[1]) {
|
|
857
|
+
${caseBranches}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
$completions | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
|
861
|
+
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
`;
|
|
865
|
+
}
|
|
866
|
+
|
|
651
867
|
// src/compliance-cmd.ts
|
|
652
868
|
import { spawn } from "child_process";
|
|
653
869
|
import { request as request2 } from "undici";
|
|
@@ -1219,7 +1435,7 @@ function selectFlakyNamespaces(entries, limit) {
|
|
|
1219
1435
|
}
|
|
1220
1436
|
|
|
1221
1437
|
// src/doctor-cmd.ts
|
|
1222
|
-
var VERSION = true ? "0.
|
|
1438
|
+
var VERSION = true ? "0.43.0" : "dev";
|
|
1223
1439
|
async function runDoctor(opts = {}) {
|
|
1224
1440
|
if (opts.json) return runDoctorJson(opts);
|
|
1225
1441
|
const lines = [];
|
|
@@ -4303,7 +4519,7 @@ function categorizeSpawnError(err) {
|
|
|
4303
4519
|
}
|
|
4304
4520
|
async function connectToUpstream(config, onDisconnect, onListChanged) {
|
|
4305
4521
|
const client = new Client(
|
|
4306
|
-
{ name: "mcph", version: true ? "0.
|
|
4522
|
+
{ name: "mcph", version: true ? "0.43.0" : "dev" },
|
|
4307
4523
|
{ capabilities: {} }
|
|
4308
4524
|
);
|
|
4309
4525
|
let transport;
|
|
@@ -4784,7 +5000,7 @@ var ConnectServer = class _ConnectServer {
|
|
|
4784
5000
|
this.apiUrl = apiUrl6;
|
|
4785
5001
|
this.token = token6;
|
|
4786
5002
|
this.server = new Server(
|
|
4787
|
-
{ name: "mcph", version: true ? "0.
|
|
5003
|
+
{ name: "mcph", version: true ? "0.43.0" : "dev" },
|
|
4788
5004
|
{
|
|
4789
5005
|
capabilities: {
|
|
4790
5006
|
tools: { listChanged: true },
|
|
@@ -6839,24 +7055,33 @@ To load the top pack in one step, call \`mcp_connect_activate\` with namespaces=
|
|
|
6839
7055
|
// src/servers-cmd.ts
|
|
6840
7056
|
function parseServersArgs(argv) {
|
|
6841
7057
|
let json = false;
|
|
7058
|
+
let filter;
|
|
6842
7059
|
for (const a of argv) {
|
|
6843
7060
|
if (a === "--json") {
|
|
6844
7061
|
json = true;
|
|
6845
7062
|
} else if (a === "--help" || a === "-h") {
|
|
6846
7063
|
return { ok: false, error: SERVERS_USAGE };
|
|
6847
|
-
} else {
|
|
7064
|
+
} else if (a.startsWith("-")) {
|
|
6848
7065
|
return { ok: false, error: `mcph servers: unknown argument "${a}"
|
|
6849
7066
|
|
|
7067
|
+
${SERVERS_USAGE}` };
|
|
7068
|
+
} else if (filter === void 0) {
|
|
7069
|
+
filter = a;
|
|
7070
|
+
} else {
|
|
7071
|
+
return { ok: false, error: `mcph servers: unexpected extra argument "${a}"
|
|
7072
|
+
|
|
6850
7073
|
${SERVERS_USAGE}` };
|
|
6851
7074
|
}
|
|
6852
7075
|
}
|
|
6853
|
-
return { ok: true, options: { json } };
|
|
7076
|
+
return { ok: true, options: { json, ...filter !== void 0 ? { filter } : {} } };
|
|
6854
7077
|
}
|
|
6855
|
-
var SERVERS_USAGE = `Usage: mcph servers [--json]
|
|
7078
|
+
var SERVERS_USAGE = `Usage: mcph servers [<namespace-filter>] [--json]
|
|
6856
7079
|
|
|
6857
7080
|
List the servers configured in your mcp.hosting dashboard.
|
|
6858
7081
|
|
|
6859
|
-
|
|
7082
|
+
<namespace-filter> Case-insensitive substring filter on namespace (e.g.,
|
|
7083
|
+
\`mcph servers git\` matches github + gitlab).
|
|
7084
|
+
--json Emit machine-readable JSON instead of a table.`;
|
|
6860
7085
|
async function runServersCommand(opts = {}) {
|
|
6861
7086
|
const write = opts.out ?? ((s) => process.stdout.write(s));
|
|
6862
7087
|
const writeErr = opts.err ?? ((s) => process.stderr.write(s));
|
|
@@ -6893,11 +7118,19 @@ async function runServersCommand(opts = {}) {
|
|
|
6893
7118
|
printErr("mcph servers: backend returned no data (unexpected 304).");
|
|
6894
7119
|
return { exitCode: 2, lines };
|
|
6895
7120
|
}
|
|
7121
|
+
const filtered = opts.filter ? {
|
|
7122
|
+
...backend,
|
|
7123
|
+
servers: backend.servers.filter((s) => s.namespace.toLowerCase().includes(opts.filter.toLowerCase()))
|
|
7124
|
+
} : backend;
|
|
6896
7125
|
if (opts.json) {
|
|
6897
|
-
print(JSON.stringify(
|
|
7126
|
+
print(JSON.stringify(filtered, null, 2));
|
|
6898
7127
|
return { exitCode: 0, lines };
|
|
6899
7128
|
}
|
|
6900
|
-
|
|
7129
|
+
if (opts.filter && filtered.servers.length === 0) {
|
|
7130
|
+
print(`No servers match "${opts.filter}". Run \`mcph servers\` to see the full list.`);
|
|
7131
|
+
return { exitCode: 0, lines };
|
|
7132
|
+
}
|
|
7133
|
+
renderTable(filtered, print);
|
|
6901
7134
|
return { exitCode: 0, lines };
|
|
6902
7135
|
}
|
|
6903
7136
|
function renderTable(cfg, print) {
|
|
@@ -6948,6 +7181,7 @@ var KNOWN_SUBCOMMANDS = [
|
|
|
6948
7181
|
"reset-learning",
|
|
6949
7182
|
"servers",
|
|
6950
7183
|
"bundles",
|
|
7184
|
+
"completion",
|
|
6951
7185
|
"help",
|
|
6952
7186
|
"--help",
|
|
6953
7187
|
"-h",
|
|
@@ -6999,6 +7233,14 @@ if (subcommand === "compliance") {
|
|
|
6999
7233
|
process.exit(2);
|
|
7000
7234
|
}
|
|
7001
7235
|
runBundlesCommand(parsed.options).then((r) => process.exit(r.exitCode));
|
|
7236
|
+
} else if (subcommand === "completion") {
|
|
7237
|
+
const parsed = parseCompletionArgs(process.argv.slice(3));
|
|
7238
|
+
if (!parsed.ok) {
|
|
7239
|
+
process.stderr.write(`${parsed.error}
|
|
7240
|
+
`);
|
|
7241
|
+
process.exit(2);
|
|
7242
|
+
}
|
|
7243
|
+
runCompletion(parsed.options).then((r) => process.exit(r.exitCode));
|
|
7002
7244
|
} else if (subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
7003
7245
|
const installBlock = ` ${INSTALL_USAGE.replace(/^Usage: /, "").replace(/\n/g, "\n ")}`;
|
|
7004
7246
|
process.stdout.write(
|
|
@@ -7013,6 +7255,7 @@ if (subcommand === "compliance") {
|
|
|
7013
7255
|
mcph bundles [list|match] Browse curated multi-server bundles
|
|
7014
7256
|
mcph compliance <target> [flags] Run the compliance suite against an MCP server
|
|
7015
7257
|
mcph reset-learning Clear cross-session learning history (~/.mcph/state.json)
|
|
7258
|
+
mcph completion <shell> Print a shell completion script (bash|zsh|fish|powershell)
|
|
7016
7259
|
mcph --version Print version
|
|
7017
7260
|
|
|
7018
7261
|
Install:
|
|
@@ -7033,7 +7276,7 @@ ${installBlock}
|
|
|
7033
7276
|
);
|
|
7034
7277
|
process.exit(0);
|
|
7035
7278
|
} else if (subcommand === "--version" || subcommand === "-V") {
|
|
7036
|
-
process.stdout.write(`mcph ${true ? "0.
|
|
7279
|
+
process.stdout.write(`mcph ${true ? "0.43.0" : "dev"}
|
|
7037
7280
|
`);
|
|
7038
7281
|
process.exit(0);
|
|
7039
7282
|
} else if (subcommand && !subcommand.startsWith("-")) {
|
package/package.json
CHANGED