install
install
¶
One command that wires up both halves.
Installing used to be four steps across two worlds: pip install, work out which
Houdini packages directory is the real one, write a JSON file there, then hand
your MCP client a command line whose Python path you had to discover yourself.
Every one of those steps fails quietly. Houdini skips a package file it cannot
resolve without saying so, and Claude Desktop does not inherit your PATH, so a
bare python in its config reads as "disconnected" with no explanation.
python -m fxhoudinimcp install # do both halves
python -m fxhoudinimcp install --dry-run # say what it would do
python -m fxhoudinimcp install --houdini-dir DIR # just this one directory
python -m fxhoudinimcp install --client none # wire the client yourself
It asks nothing and it finishes. Two earlier versions did neither, in ways worth recording because both looked reasonable:
- It refused to choose between candidate packages directories, and exited. The reasoning was sound, that a wrong choice is silent, and the conclusion was wrong, because writing the same file into all of them is never a wrong choice.
- It reported a Claude Code entry pointing somewhere else, printed the two commands to repair it, and stopped. It knew both values and had already been told to install. Printing homework is not finishing.
What remains genuinely undecidable is still refused, not guessed: if no Houdini packages directory exists at all, this says so rather than inventing one, since a package file in a directory Houdini never reads is the silent no-op the whole command exists to prevent.
Functions:
| Name | Description |
|---|---|
build_parser |
The argument parser, exposed so the README's flag table can be checked. |
claude_code_add_argv |
The |
claude_code_current_command |
The command Claude Code has registered for us, if any. |
claude_code_remove_argv |
The |
client_command |
The argv an MCP client should run to start this server. |
config_file_note |
Name the config file the Claude Code CLI actually wrote. |
desktop_config_path |
Claude Desktop's config file for this platform, whether or not it exists. |
install_claude_code |
Register with Claude Code via its own CLI. Returns report lines. |
install_desktop |
Register the server in Claude Desktop's config. Returns report lines. |
pinned_port_warning |
Warn when a config pins HOUDINI_PORT, which disables port discovery. |
printable_argv |
An argv a person can paste back into a shell. |
repoint_claude_code |
Replace a Claude Code entry that points at a different interpreter. |
resolve_houdini_dirs |
Where the package file goes. An empty list means there is nowhere yet. |
Functions:¶
build_parser
¶
build_parser() -> ArgumentParser
The argument parser, exposed so the README's flag table can be checked.
The table in the README is the first thing anyone reads, so a flag that is renamed here and not there is a documented lie. tests/test_install.py compares the two.
claude_code_add_argv
¶
The claude mcp add invocation, for running or for printing verbatim.
claude_code_current_command
¶
claude_code_current_command() -> str | None
The command Claude Code has registered for us, if any.
Read with claude mcp get, whose output is meant for humans, so this only
looks for the "Command:" line rather than trying to parse the whole thing.
Returns None when the server is not registered or the output is unfamiliar.
claude_code_remove_argv
¶
The claude mcp remove invocation, for running or for printing.
Lives next to its counterpart because install needs it too: claude mcp
add cannot update an entry in place, so repointing one means removing it
first. uninstall imports it from here.
client_command
¶
The argv an MCP client should run to start this server.
sys.executable, never a bare "python". Claude Desktop launches its servers without the user's shell environment, so a bare interpreter name resolves against a PATH that may not contain the Python this package is installed into. That failure surfaces only as "disconnected", which is why the README had to explain it; an absolute path removes the class of problem.
config_file_note
¶
config_file_note(result: CompletedProcess) -> list[str]
Name the config file the Claude Code CLI actually wrote.
It already prints File modified: <path> and we were swallowing it, in
favour of "registered with Claude Code (user scope)". That reads as complete
and is not, because "user scope" is not one place: CLAUDE_CONFIG_DIR decides
which profile is user scope, and a machine can have several. On one with a
second profile, a correct, connected registration was invisible to every
claude mcp get run from the other one, and looked like a failed install
for an afternoon.
Naming the file costs one line and removes the ambiguity, so a report of success can be checked rather than believed.
desktop_config_path
¶
desktop_config_path() -> Path | None
Claude Desktop's config file for this platform, whether or not it exists.
install_claude_code
¶
Register with Claude Code via its own CLI. Returns report lines.
install_desktop
¶
Register the server in Claude Desktop's config. Returns report lines.
pinned_port_warning
¶
Warn when a config pins HOUDINI_PORT, which disables port discovery.
An explicit HOUDINI_PORT is honoured deliberately by the server: it means "this session, not whichever answers first". But it also switches off the scan of 8100-8115, so a second Houdini that moved itself to 8101 becomes unreachable. Worth saying out loud, since the value is usually left over from an older config rather than chosen.
printable_argv
¶
An argv a person can paste back into a shell.
repoint_claude_code
¶
Replace a Claude Code entry that points at a different interpreter.
claude mcp add has no --force, so an existing entry is an error rather
than an update. This used to be reported back with the two commands needed
to fix it, which was the installer declining to finish its own job: it knows
the value that is there, it knows the one that should be, and the operator
consented by running install. Printing homework instead is the same "four
steps across two worlds" this command exists to remove.
Removing first is safe in a way a blind overwrite would not be, because the old value is read and reported before anything changes.
resolve_houdini_dirs
¶
Where the package file goes. An empty list means there is nowhere yet.
Every candidate, not one of them. This went through two wrong answers before landing here, and the reasoning matters because it looks like carelessness.
The original code refused to choose, on the grounds that choosing wrongly is invisible: Houdini skips a package file it cannot resolve without a word, so the wrong directory produces silence rather than an error. True, and it made the command exit rather than finish. The second answer was to ask, which only moved the decision without removing it, and made the whole thing depend on there being a terminal.
Both missed that the premise does not apply to "all of them". The files are byte-identical and point at the same plugin, so whichever directory Houdini reads, it finds a correct one. There is no last-one-wins hazard between copies of the same file, which is the only reason ambiguity was dangerous. OneDrive's Documents redirection stops being a question to answer and becomes two paths that both work.
The cost is an MCP menu in a Houdini version you may not use, removable in
one uninstall. That is a much smaller price than a command that stops.