The PawFlow MCP client package connects one local client instance to one published PawFlow conversation and agent through a local stdio bridge. It provides isolated launchers for Claude Code, Codex, Agy/Gemini, OpenCode, JCode, Pi, and Hermes, plus configuration fragments for any MCP-compatible stdio client. The bridge also registers the selected project directory as that conversation's CLI relay without changing the conversation's default relay.
- Python 3.10 or newer.
- A published conversation URL ending in
/mcp/srv_.... - A PawFlow MCP API key created for that publication.
- The Private Gateway key when the PawFlow deployment uses the gateway.
- At least one supported harness already installed on the client workstation: Claude Code, Codex, Agy/Gemini, OpenCode, JCode, Pi, or Hermes.
A publication accepts one active client instance. Create another published conversation when two client instances must run at the same time.
Each PawFlow release provides two universal archives with identical contents:
pawflow-mcp-client-VERSION.zippawflow-mcp-client-VERSION.tar.gz
The package contains only Python source, so either archive works on Windows, Linux, and macOS. Download the ZIP on Windows or either format on Linux/macOS.
Extract the archive before running an installer.
Command Prompt:
install.cmdPowerShell:
powershell -ExecutionPolicy Bypass -File .\install.ps1tar -xzf pawflow-mcp-client-VERSION.tar.gz
cd pawflow-mcp-client-VERSION
./install.shtar -xzf pawflow-mcp-client-VERSION.tar.gz
cd pawflow-mcp-client-VERSION
./install.shThe wizard asks for:
- The local MCP server name, normally
pawflow. - The published PawFlow MCP URL copied from the conversation Resources panel.
- The publication API key. Input is hidden.
- The optional Private Gateway key. Input is hidden.
- The local project directory shared through the relay.
- The clients to configure:
cc,codex,agy,opencode,jcode,pi,hermes, or a comma-separated subset. - Whether the relay is read-only.
- Whether shell execution is allowed.
- Whether explicitly approved FRP service tunnels are allowed.
The default relay is read/write with shell execution disabled. File edits are therefore available, while commands remain denied until the operator explicitly enables them.
FRP service tunnels are opt-in. When enabled, the installer downloads the
platform-specific official frpc binary, verifies its pinned SHA-256 checksum,
and stores it inside the private MCP runtime. The automatic MCP relay then
advertises the existing allow_service_tunnels capability. Local services
still require explicit approval in the relay service catalogue.
The installer prints one launch command for every selected client. Always start that instance with the printed command. Starting the client normally does not activate the PawFlow session.
The runtime is installed per user:
| Platform | Default runtime directory |
|---|---|
| Windows | %LOCALAPPDATA%\PawFlow\MCP |
| macOS | ~/Library/Application Support/PawFlow/MCP |
| Linux | $XDG_DATA_HOME/pawflow/mcp or ~/.local/share/pawflow/mcp |
Secrets are written once to sessions/NAME/profile.json under that runtime. On
POSIX systems the installer applies mode 0600 to the profile and 0700 to
its directory. Generated MCP configurations contain only the Python executable,
launcher path, private profile path, and project directory; they do not duplicate
API or gateway keys.
Each server name creates one isolated session directory:
| File | Purpose |
|---|---|
session.json |
Non-secret manifest used by the client launcher. |
profile.json |
Private endpoint, API keys, relay directory, and permissions. |
claude.mcp.json |
Strict per-invocation Claude Code MCP configuration. |
agy-home/ |
Isolated Agy/Gemini home and MCP configuration. |
mcp.json |
Generic {"mcpServers": {...}} configuration. |
entry.json |
One generic stdio server entry for clients with their own envelope format. |
claude.settings.json |
Session-only Claude lifecycle hooks. |
codex-home/hooks.json |
Session-only Codex lifecycle hooks and approval state. |
opencode-home/ |
Isolated OpenCode config and conversation plugin. |
jcode-home/ |
Isolated JCode MCP config, lifecycle hooks, and sessions. |
pi-home/extensions/pawflow.js |
Pi extension providing PawFlow tools and conversation synchronization. |
hermes-home/ |
Isolated Hermes MCP config and PawFlow plugin. |
hook-state-CLIENT.json |
Locked per-client conversation cursor. |
injected-prompts.jsonl |
Short-lived IDs and hashes used to suppress webchat prompt mirroring. |
The installer never reads or writes the user's global configuration for any supported harness. Re-running the same server name replaces only that PawFlow session bundle. Use a different name for a different published conversation or agent.
The generated launcher enforces one session bundle per local process:
- Claude Code: launches
claude --mcp-config SESSION/claude.mcp.json --strict-mcp-config --settings SESSION/claude.settings.json, so global MCP servers and hooks are excluded from that instance. - Codex: launches with
-C PROJECTand a per-invocation-c mcp_servers=...override containing only the selected PawFlow publication.CODEX_HOMEpoints toSESSION/codex-home, so generated hooks cannot affect another Codex instance. Complete login and approve the hooks with/hooksonce inside this isolated home when requested. - Agy/Gemini: launches with
HOMEandUSERPROFILEset toSESSION/agy-home, isolating both its MCP settings and client state. Complete the client login once inside that isolated home when required. - OpenCode: launches the project with
OPENCODE_CONFIGandOPENCODE_CONFIG_DIRpointing toSESSION/opencode-home. Its native local MCP entry provides the PawFlow tools; the generated plugin synchronizes prompts, context deltas, and final assistant messages. - JCode: launches with
JCODE_HOME=SESSION/jcode-home. JCode loads its native stdio MCP entry from that home. Observer hooks mirror local prompts and final assistant messages from the isolated JCode session file. Its isolatedprompt-overlay.mddirects the model to fetch bootstrap and incremental context through the native PawFlow conversation tools. JCode observer hooks cannot modify an in-flight model request, so this model-directed tool call is the closest native equivalent to the mutable pre-model hooks of other clients. - Pi: launches with
PI_CODING_AGENT_DIR=SESSION/pi-homeand the generated extension explicitly loaded. Because Pi intentionally has no built-in MCP client, the extension discovers the published PawFlow tools and registers equivalent native Pi tools. It also injects bootstrap/delta context and mirrors prompts and final assistant messages. - Hermes: launches with
HERMES_HOME=SESSION/hermes-home. Its native MCP configuration exposes the PawFlow tools; its generated plugin injects bootstrap/delta context atpre_llm_calland persists the completed turn atpost_llm_call.
Arguments after the launch command are forwarded to the underlying client. For
example, append -- --model sonnet to the generated Claude Code command.
For another MCP-compatible client, create a dedicated client profile or
per-invocation configuration and point it at SESSION/mcp.json. If the client
expects only one server object rather than an mcpServers map, use
SESSION/entry.json. Do not merge that file into a shared global profile:
one running local instance must load exactly one session configuration, and that
session maps to exactly one PawFlow conversation and agent.
The generated launch command owns the terminal rather than starting a throwaway client process:
- Linux and macOS create or reattach a deterministic
tmuxsession.tmuxis required and the client keeps running after the operator detaches. - Windows keeps the client in the inherited host console and starts an authenticated loopback listener. PawFlow injects Unicode console input through that listener; its random secret stays in the child environment and is never returned by relay status APIs.
After the MCP stdio bridge connects its existing automatic relay, it registers
the terminal under the same client lease. A text prompt sent from webchat is
authorized, processed by pre_user_message, and persisted before it is injected
into the TUI. Immediately before Enter, the transport writes the prompt's
message_id and SHA-256 marker. The prompt hook consumes that marker and does
not call send_user_message a second time.
An external_mcp agent never falls back to a PawFlow LLM. If its publication is
active but its terminal cannot be reached, webchat submission returns
external_mcp_terminal_unavailable with HTTP 503; the canonical user message
remains persisted for recovery.
The session-scoped hook program uses the four published conversation tools:
- The first native pre-turn lifecycle event calls
get_initial_contextand injects its document as hidden context where the harness supports mutable pre-model hooks. - Before later turns, the hook calls
get_context_updates(after_seq)under a local file lock. The cursor advances only after a successful response. - A prompt typed directly in the terminal is persisted with
send_user_message. A server-injected webchat prompt is recognized by its marker and skipped. - The native completed-turn event persists the final assistant response. Agy and JCode read their isolated transcript/session because their hook payloads do not always contain the full response text.
Hook writes derive stable message_id values from client session/turn identity
and content. Server-side idempotence makes retries safe. Hook failures are
fail-open for the local TUI and never print profile contents or keys.
Automation supplies secrets through environment variables, never command-line arguments:
export PAWFLOW_MCP_API_KEY='publication key'
export PAWFLOW_GATEWAY_KEY='gateway key'
./install.sh \
--non-interactive \
--name pawflow \
--url https://pawflow.example/mcp/srv_example \
--relay-dir /path/to/project \
--clients cc,codex,agy,opencode,jcode,pi,hermesOmit PAWFLOW_GATEWAY_KEY when the deployment has no Private Gateway. Add
--readonly or --allow-exec when required. --install-dir, --home,
and --python support managed or test installations. Add
--allow-service-tunnels to enable the verified FRP integration for the
automatic MCP relay.
- Copy the session-bound launch command printed by the installer.
- Start one client instance with that command in the configured project.
- List MCP servers using the client's normal MCP status command and confirm that the selected PawFlow server is the only PawFlow publication loaded.
- Call
pawflow_relay_status. It reports the local process, published server, relay ID, permissions, andauto_default: falsewithout returning secrets. - Call a read-only PawFlow tool, then test writes or shell execution only if those permissions were selected.
The bridge exposes four local lifecycle tools:
pawflow_relay_connect, pawflow_relay_disconnect,
pawflow_relay_status, and pawflow_relay_reconnect.
Run the installer again with the same server name. It replaces the bundled runtime and that session's private profile and generated configurations. Global client configuration remains untouched.
To change only the project directory or permissions, run the wizard again. Close every active instance first so the publication lease can be released.
mcp_server_already_in_use: close the first client, revoke its session from the PawFlow publication dialog, or publish a second conversation.- Client cannot start Python: install Python 3.10+ and rerun with
--pythonpointing to the stable interpreter. - Authentication failure: create a new publication API key and rerun the installer. Verify the Private Gateway key separately.
- Relay connection failure: confirm the shared directory exists locally and that outbound HTTPS/WebSocket traffic can reach PawFlow.
- Agy/Gemini asks for authentication: complete login inside the isolated session launched by PawFlow; credentials from the normal global home are intentionally not reused.
- Codex reports untrusted hooks: run
/hooksin the isolated PawFlow Codex instance and approve the three generated lifecycle hooks. - POSIX launcher reports that
tmuxis missing: installtmux, then rerun the same session-bound launch command. - Webchat returns
external_mcp_terminal_unavailable: reattach or restart the generated client command and confirmpawflow_relay_statusreports both the relay and terminal as ready. - A generic client also loads another PawFlow publication: use a dedicated
profile or per-invocation config rather than merging
mcp.jsonglobally.
From the PawFlow repository:
python scripts/build-mcp-client-installer.pyArtifacts are written to dist/mcp-client-installers/. The ZIP and tar.gz use
fixed timestamps, ownership, permissions, and sorted entries so the same source
and version produce byte-for-byte reproducible archives. The release-assets
workflow builds both universal packages once and publishes them with the other
PawFlow release downloads.
See Published Conversation MCP Servers for endpoint, identity, relay selection, lease, and revocation behavior.