DEV Community

Philip D'Souza
Philip D'Souza

Posted on Originally published at healthexport.dev

Ollama does not speak MCP: wiring local Apple Health into a local LLM

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

  1. A local model server. Ollama, serving a tool-calling model. ollama pull qwen3 is a fine start.
  2. An MCP-aware client that can drive Ollama. Goose, LM Studio, mcphost, or Open WebUI behind mcpo.
  3. The MCP server itself. health-export-mcp is a zero-dependency Node server that exposes 16 read-only tools and 22 prompts over a local Apple Health export.
  4. 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"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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)