---
title: "How to Run Claude Code on a Local Model on Mac"
description: "Point Claude Code at a model running on your own Mac. One MCP call installs a helper that launches claude against ToolPiper, and writes nothing to ~/.claude."
date: 2026-08-29
author: "Ben Racicot"
tags: ["Claude Code", "Text Generation", "Local Inference", "Privacy", "macOS", "Apple Silicon", "Developer Tools"]
type: "article"
canonical: "https://modelpiper.com/blog/claude-code-local-model-mac"
---

# How to Run Claude Code on a Local Model on Mac

> Point Claude Code at a model running on your own Mac. One MCP call installs a helper that launches claude against ToolPiper, and writes nothing to ~/.claude.

## TL;DR

Ask Claude Code to run claude_code_install. ToolPiper mints an inference bearer, writes a mode-0600 config, and symlinks a helper called claude-tp into ~/.local/bin. Running claude-tp instead of claude launches Claude Code against a model on your own Mac. Nothing under ~/.claude is read or written, so plain claude keeps working exactly as before.

Claude Code talks to Anthropic. That is the whole product, and most days it is the right answer. But some work cannot leave the machine, some of it happens on a plane, and some of it is a loop you do not want metered. For those, you want the same editor pointed at a model that runs on your own hardware.

This is that setup. It takes one MCP call, it is reversible in one more, and the part worth knowing up front is what it refuses to touch: your existing Claude Code configuration is never read and never written.

## What actually changes when you do this?

A helper binary named claude-tp is symlinked into ~/.local/bin. When you run it, it launches the official claude CLI with a settings file and an MCP config that point at ToolPiper on 127.0.0.1:9998. Your ~/.claude directory is not read, not written, and not backed up, because nothing in it is involved.

That last point is the design, not a side effect. An earlier version of this integration edited `~/.claude/settings.json` directly through a 500-line writer service. It worked until it did not: stale marker files, half-written settings after a crash, and shell environment variables silently overriding whatever had been written. Your Claude Code install had become shared state that another app could break.

The replacement moves the whole integration outside `~/.claude`. The settings live in a temp file created per launch and deleted when the process exits. If you want your normal Claude Code back, you type `claude` instead of `claude-tp`. There is nothing to undo because nothing was changed.

## What you need

**You don't need:** an API key, a Docker container, Python, a config file you write by hand, or an internet connection once the model is downloaded.

**You do need:** a Mac with Apple Silicon, ToolPiper running with a chat model loaded, the official `claude` CLI on your PATH, and `~/.local/bin` on your PATH. The helper checks the last one for you and tells you if it is missing.

## How does the helper get the credential?

ToolPiper mints an inference bearer during install and writes it to a config file at ~/Library/Application Support/ToolPiper/claude-tp-config.json with mode 0600. The helper reads that file at launch. The bearer never appears in the command line, so it cannot be read out of ps.

Two refusals are built into the read. If the config file's permissions are wider than `0600`, the helper stops and tells you to `chmod` it, because the file holds a credential in cleartext and something has touched it. If the bearer does not match the expected `tp_` followed by 64 hex characters, it stops as well rather than sending a malformed token.

The install is idempotent. Running it again revokes the previous bearer and writes a fresh one, which is also the repair path when something has drifted.

## How to tell it worked

Run the helper's own diagnostic:

```
claude-tp --status
```

It reports four things independently: whether the symlink is valid, whether the config is readable and well-formed, whether `~/.local/bin` is actually on your PATH, and whether ToolPiper answers from the helper's point of view. A green line on all four means the next `claude-tp` launch will reach your local model.

To see exactly what will be handed to `claude` without launching anything, run `claude-tp --print-config`. It prints the resolved settings and MCP config with the bearer redacted. That is the honest way to check what the wrapper is doing, and it is the first thing to read before filing a bug against it.

## When it doesn't work

### "config file missing"

Exit code 2. The install never ran, or the config was deleted. Ask Claude Code to run `claude_code_install` again.

### "config file has unsafe permissions"

Exit code 3. Something widened the file past `0600`. The error names the exact `chmod` to run. Re-running the install also fixes it and rotates the bearer, which is the better choice if you do not know what widened it.

### "ToolPiper unreachable"

Exit code 4. ToolPiper is not running, or it is not listening where the config says. Note that the address is the IPv4 literal `127.0.0.1` and not the name `localhost`. macOS resolves `localhost` to the IPv6 address first, and ToolPiper's listener is pinned to IPv4 loopback, so a client that resolves the name gets a refused connection from a server that is running perfectly well.

### "bearer rejected by ToolPiper"

Exit code 5. The token no longer matches what the server will accept, usually because the install was run again from somewhere else and rotated it. Re-run `claude_code_install`.

### "claude not on PATH"

Exit code 6. The helper wraps the official CLI rather than replacing it, so `claude` has to be installed and findable first.

### Nothing happens after a fresh install

Open a new terminal tab. The symlink lands in `~/.local/bin` during install, and a shell that was already running may not pick it up.

## Why not just set an environment variable?

Because shell configuration wins. Claude Code reads ANTHROPIC\_ environment variables, and anything exported from your .zshrc would silently override the wrapper's settings on every launch. The helper strips every ANTHROPIC\_ variable from the child process environment so your shell cannot shadow it.

This is the failure mode that is worst to debug, because it looks like the integration is working. The editor starts, the prompt appears, and requests quietly go somewhere else. Stripping the variables makes the wrapper's configuration the only configuration in play for that launch.

## What about the tools?

Inference is one half. The helper also hands `claude` an MCP config, so the same launch gets ToolPiper's local tool catalog: browser automation, screen capture, transcription, system control, scraping, and the rest.

Mounting tools does not require any of this, though. If tools are all you want, one command does it and no helper is involved:

```
claude mcp add --transport http toolpiper http://127.0.0.1:9998/mcp
```

That registration works on stock Claude Code, talking to Anthropic as usual. The helper exists for the other half, which is the part a CLI flag cannot do: choosing where the model runs.

## What this does not do

It does not make a local model behave like a frontier model. The gap is real on long multi-file refactors and on tasks that need deep reasoning across a large context, and no amount of wiring closes it. Pick the model to fit the task: local for the loop you run fifty times a day, for anything under NDA, and for the flight. Anthropic's models for the hard thinking.

It also does not migrate anything. Your existing setup is untouched by design, which means it is also unimproved. Both CLIs stay on your PATH, and which one you type is the whole decision.

## Try it

Download ToolPiper at [modelpiper.com](https://modelpiper.com), load a chat model, then ask Claude Code to install the helper. Type `claude-tp` when you want the local model and `claude` when you want Anthropic's.

## Steps

### 1. Start ToolPiper and load a chat model

The helper asks ToolPiper for its live list of chat-capable models at launch, so at least one has to be loaded or there is nothing to point Claude Code at. Any text-to-text model works.

### 2. Ask Claude Code to install the helper

In a Claude Code session with ToolPiper already mounted over MCP, ask it to install ToolPiper as your Claude Code inference backend. That runs `claude_code_install`, which symlinks the bundled `claude-tp` binary into `~/.local/bin`, mints an inference bearer, and writes the helper's config file with mode `0600`. The tool is idempotent, so running it a second time rotates the bearer and refreshes everything rather than erroring.

### 3. Open a new terminal tab

The symlink lands in `~/.local/bin` during the install, and a shell that was already open will not see it. This is the step people skip, and it presents as "command not found" for a helper that installed correctly.

### 4. Confirm the install before launching anything

Run `claude-tp --status`. It checks the symlink, the config file, whether `~/.local/bin` is on your PATH, and whether ToolPiper answers. Fix anything it reports here rather than after a failed launch, because the diagnostic names the cause and a failed launch only gives you an exit code.

### 5. Launch Claude Code against your local model

Run `claude-tp` where you would normally run `claude`. Every argument you pass is forwarded, so your usual flags and prompts work unchanged. The wrapper writes its settings and MCP config to temp files for that launch and deletes them when the process exits.

### 6. Switch back whenever you want

Type `claude`. Nothing about your original setup was modified, so the stock CLI behaves exactly as it did before. To remove the helper entirely, ask Claude Code to run `claude_code_uninstall`, which deletes the symlink and the config file and revokes the bearer.

## FAQ

### Does this change my existing Claude Code setup?

No. Nothing under `~/.claude` is read or written. The helper passes a settings file and an MCP config to the `claude` CLI per launch, both written to temp files with mode `0600` and deleted when the process exits. Running plain `claude` afterwards behaves exactly as it did before, because nothing it reads was touched.

### Can I use both the local model and Anthropic's models?

Yes, and that is the intended way to run it. Both commands stay on your PATH. `claude-tp` launches against ToolPiper, `claude` launches against Anthropic. There is no mode to toggle and no state that carries between them.

### Where is the credential stored, and can other processes read it?

The inference bearer is written to `~/Library/Application Support/ToolPiper/claude-tp-config.json` with mode `0600`, so only your user account can read it. The helper refuses to load the file at all if its permissions are wider than that. The bearer is never passed as a command-line argument, so it does not appear in `ps` output.

### Why does the helper need to exist? Why not point Claude Code at a base URL?

Two reasons. Environment variables exported from your shell profile take precedence over most configuration, so an `ANTHROPIC_` variable in your `.zshrc` would silently override the setup on every launch; the helper strips those from the child environment. And the credential has to reach the process without landing in your shell history or in `ps`, which a base URL and an exported key cannot do.

### Do I need this to use ToolPiper's tools in Claude Code?

No. Mounting the tools is one command and involves no helper: `claude mcp add --transport http toolpiper http://127.0.0.1:9998/mcp`. That works on stock Claude Code talking to Anthropic. The helper is for choosing where the model runs, which is a separate question from which tools are available.

### How do I remove it?

Ask Claude Code to run `claude_code_uninstall`. It removes the `~/.local/bin/claude-tp` symlink, deletes the helper's config file, and revokes the inference bearer. It is idempotent, so running it on a machine where the helper is already gone reports which pieces were already absent instead of erroring.
