Skip to content

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.

fxhoudinimcp install                      # do both halves
fxhoudinimcp install --dry-run            # say what it would do, change nothing
fxhoudinimcp install --houdini-dir DIR    # when the packages directory is ambiguous
fxhoudinimcp install --client none        # plugin only, wire the client yourself

The Houdini destination is still not guessed when it is genuinely ambiguous. One candidate means there is nothing to choose and it is used; several means the operator picks, because choosing wrongly on Windows with OneDrive's Documents redirection recreates the silent no-op this 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 mcp add invocation, for running or for printing verbatim.

claude_code_current_command

The command Claude Code has registered for us, if any.

client_command

The argv an MCP client should run to start this server.

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.

resolve_houdini_dir

Decide where the package file goes.

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

claude_code_add_argv(scope: str = 'user') -> list[str]

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.

client_command

client_command() -> list[str]

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.

desktop_config_path

desktop_config_path() -> Path | None

Claude Desktop's config file for this platform, whether or not it exists.

install_claude_code

install_claude_code(dry_run: bool) -> list[str]

Register with Claude Code via its own CLI. Returns report lines.

install_desktop

install_desktop(config: Path, command: list[str], dry_run: bool) -> list[str]

Register the server in Claude Desktop's config. Returns report lines.

pinned_port_warning

pinned_port_warning(entry: dict | None) -> list[str]

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.

resolve_houdini_dir

resolve_houdini_dir(
    explicit: str | None,
) -> tuple[Path | None, list[Path], str]

Decide where the package file goes.

Returns (chosen, candidates, reason). chosen is None when the operator has to decide, with reason explaining why rather than making it up.