Every "run your local LLM on your own Apple Health data" tutorial ends the same way: install Ollama, done. Then nothing works. The reason is simple and worth saying plainly.
Ollama does not speak MCP.
Ollama is an inference server. It runs the model and exposes an OpenAI-compatible chat endpoint on http://localhost:11434. That is the whole job. MCP is a different protocol, one that runs between a client (the agent) and a server (the tool provider) over stdio or HTTP. Nothing in Ollama knows what a tool call over MCP is.
So the tutorials are not wrong about the model. They just skip the part that holds the connection and translates tool calls: an MCP-aware client.
One sentence to keep: Ollama is the model, the MCP client is the agent, the MCP server is the data.
What you are actually wiring up
- A local model server. Ollama, serving a tool-calling model.
ollama pull qwen3is a fine start. - An MCP-aware client that can drive Ollama. Goose, LM Studio, mcphost, or Open WebUI behind mcpo.
- The MCP server itself.
health-export-mcpis a zero-dependency Node server that exposes 16 read-only tools and 22 prompts over a local Apple Health export. - An export to read. The MetricBridge iOS app writes clean JSON from Apple Health to a folder you choose.
The server config is the same everywhere
Every client wants the same two values: the command that starts the server, and the folder holding the export. The server is on npm, so there is nothing to clone.
{
"mcpServers": {
"health-export": {
"command": "npx",
"args": ["-y", "health-export-mcp"],
"env": {
"HEALTH_DATA_DIR": "/Users/you/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents"
}
}
}
}
Keep the quotes around HEALTH_DATA_DIR. The default path contains spaces and an iCloud~ prefix, and a bare path will fail to resolve. On Linux the same path expands to ~/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents.
If you do not have an export yet, npx -y health-export-mcp --demo starts the server against bundled sample data so you can test the client wiring before you have real numbers.
Goose
Edit ~/.config/goose/config.yaml:
extensions:
health-export:
type: stdio
cmd: npx
args: ["-y", "health-export-mcp"]
envs:
HEALTH_DATA_DIR: /Users/you/Library/Mobile Documents/iCloud~ai~healthexport~app/Documents
enabled: true
Then goose session and the tools show up. Goose talks to Ollama on its own, so you only configure the MCP server here.
mcpHost (the short path for a pure Ollama stack)
mcphost is the leanest option when Ollama is the only provider you care about. It runs the model and the MCP client in one process.
Create ~/health-mcp.json with the same mcpServers block, then:
mcphost -m ollama:qwen3 --config ~/health-mcp.json
That is the whole stack: one binary, one model, one server, nothing off the machine.
LM Studio
LM Studio has its own MCP support and reads ~/.lmstudio/mcp.json. Use the same mcpServers shape. Point the chat at a local model and the server appears in the tools list for any conversation.
Open WebUI via mcpo
Open WebUI does not speak MCP either. The bridge is mcpo, which wraps a stdio MCP server and exposes it as an OpenAPI HTTP server that Open WebUI can call as a tool.
pip install mcpo
mcpo --port 8080 -- npx -y health-export-mcp
Set HEALTH_DATA_DIR in the environment before you run it, then add http://localhost:8080 as a tool server in Open WebUI. Your local model now has the tools.
What a real turn looks like
You: Using my data, how did my HRV trend this week compared with last week?
[qwen3] -> get_freshness
-> compare_periods { metric: "hrv", thisWeek: true, lastWeek: true }
Your HRV averaged 61 ms this week, up 4.4% from 58 ms last
week. Resting heart rate fell from 56 to 55 bpm. Both are
deviations from your own recent baseline, not a verdict.
The model never leaves your machine. The export never leaves your machine. The only network call in the whole loop is the one Ollama makes to itself.
Two things that trip people up
Composer-style clients do not always auto-discover MCP tools. If the model claims it cannot see your data, name the server in the prompt. This is the most common cause of "my local model ignores the tools."
And check staleness before you trust a trend. get_freshness and get_health_metrics report the coverage window the server actually read, so you can tell a real change from a gap in the export.
The server is read-only by design: 16 tools, 22 prompts, zero write paths back into HealthKit. That is deliberate. The interesting question was never whether a local model can read your health data. It is whether it can do it without the data ever leaving the room.
Source and setup: [healthexport.dev/blog/run-apple-health-data-with-local-llm-ollama-mcp](https://dub.sh/9Xcc4Aq
Top comments (0)