pmcp

Commands

Three of them, and the one you will type least is the one a host runs.

The invocation a host uses

pmcp run the MCP server on stdio; the same as serve
pmcp --root ./node_modules a leading option with no command is still a server, because hosts pass options without one

An unrecognised command does not fall through to a server the caller did not ask for. Only an empty argument list, or one that begins with an option, takes that path.

serve

pmcp serve [--root <dir>] [--scope <prefix>]

Reachable by name so it appears in help. It writes nothing to standard output: from the moment it starts, standard output is the protocol, and a diagnostic printed there corrupts the stream.

list

pmcp list [--root <dir>] [--scope <prefix>] [--json]

The skills discovered in node_modules, as two aligned columns, or as JSON for a script. This is the command that answers "would the server see anything from here".

An empty catalog is a finding rather than a success. It exits 1 and names the roots it walked, because a project that installed this and sees nothing has a misconfiguration worth an exit code.

index

pmcp index [--root <dir>] [--model <id>] [--json]

Encodes each description once so ranking can be semantic, and stores the vectors beside the tree they describe, so two projects never share one index. Only what changed is re-encoded; an unchanged description produces the same vector at the same cost as the first time.

Vectors written by one model are never scored against another, so --model is part of the key rather than a preference. Without the optional peer installed it exits 3 and tells you ranking stays lexical, which is the default and not a failure.

A partial index is reported rather than called success: it exits 1 and says how many of the catalog it covered, because ranking needs a vector for every entry and falls back to lexical without one.

The written skills

The commands above read what is already installed and need no account. The ones below reach the catalogue we write; reading it is free, and installing from it needs a subscription.

All four take --project <dir>, --api <origin>, --json, and --catalog <file>, which reads a saved response so the command runs with no network at all.

available

pmcp available [--project <dir>] [--catalog <file>] [--json]

Which written skills match the dependencies this project already has. It reads your package.json to decide what matches and does not upload it. No account needed.

preview

pmcp preview <skill-package> [--json]

A skill's contents and one complete example, before paying for it. The sample is taken from the skill's own bytes rather than described, so it cannot drift from what you would receive. No account needed.

login · logout · whoami

pmcp login [--issuer <url>]
pmcp logout
pmcp whoami [--json]

login signs this machine in without a browser: it prints a code and a URL to open anywhere. The credential is kept outside the project, so it cannot be committed or copied into an image. whoami answers on stdout, so a script can read it.

install · sync

pmcp install <skill-package>... | --all [--dry-run | --yes]
pmcp sync [--project <dir>] [--dry-run | --yes]

install adds skill packages as dev dependencies with your own package manager, and what lands is checked against the digest the catalogue published — not its name and version, which any registry can claim. sync updates the ones already declared and removes nothing else.

Both show the project and lockfile changes and stop: --yes approves them, --dry-run prints the plan and changes nothing.

Options

Option Where Effect
--root <dir> all three a node_modules directory to walk; repeatable, and the first one wins on a duplicate package
--scope <prefix> all three only packages whose names start with this; repeatable, matched with a plain prefix test
--model <id> index the encoder to use; rows from another model are never scored
--json list, index emit JSON on standard output rather than a table or a summary
--help, -h anywhere the help for that command, generated from the command itself
--version on its own the version, on standard output

Options are parsed against the command's own list, so an unknown flag is an error rather than a silently ignored typo. Giving a non-repeatable option twice, or leaving off a value it needs, is the same error.

Exit codes

Code Means For example
0 it did what you asked skills listed, or the whole catalog indexed
1 it ran and found a problem no skills under those roots, a partial index, or no SQLite in this runtime to store vectors in
2 the arguments were unusable an unknown command, an unknown option, a missing value
3 an optional dependency is missing index without @huggingface/transformers

The distinction between 1 and 3 is worth wiring into a script: 1 says the project is not what you expected, and 3 says the machine is missing something optional and the server still works without it.

Data on stdout, everything else on stderr. The JSON from --json and the string from --version go to standard output so they can be piped. Tables, help and messages go to standard error, which is what keeps a pipeline's input clean.

Runtime