fm-mcp
Delegates simple text work to Apple's on-device Foundation Models via the fm tool on macOS, providing summarisation, field extraction, classification, and OCR capabilities that run locally and offline.
fm-mcp
An MCP server that lets coding agents such as Claude Code and Codex hand simple text work to the on-device model for Apple Foundation Models, the fm that ships with macOS 27. It's free, private, and runs offline.
mcp-name: io.github.yrangana/fm-mcp
Site: yrangana.github.io/fm-mcp, with what we learned building it: the measured limits of the on-device model.
Created by Yasiru Rangana, AI Architect and AI Engineer, Sydney.
Why
Coding agents spend paid, remote tokens on simple jobs, like summarising a log or pulling fields out of a document. A small model already on your Mac can do much of that for nothing, and your text never leaves the machine. fm-mcp lets the agent hand off that work, and tells it plainly what the small model can't do.

Related MCP server: apple-fm-mcp
Install
fm-mcp is a public beta (0.1.x): it works and is tested, but tool details may change between releases. CHANGELOG.md lists what changed.
You need a Mac with Apple Silicon (Intel Macs are not supported), macOS 27 with Apple Intelligence turned on, and the fm licence accepted once (fm license). That's the whole support policy: fm-mcp doctor checks each of these, and nothing else is supported.
No Homebrew yet? Install it from brew.sh first. Its installer asks to install Xcode's command line tools: accept, and let it finish.
brew install yrangana/tap/fm-mcp
fm-mcp install # sets up Claude Code and Codex
fm-mcp doctor # checks everything fm-mcp needs
Then start a new Claude Code or Codex session. fm-mcp starts the model server (fm serve) itself the first time a tool is called, and stops it when the session ends.
Other ways to get the binary:
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/yrangana/fm-mcp/releases/latest/download/fm-mcp-installer.sh | sh
cargo install fm-mcpWhat fm-mcp install changes
Claude Code: adds the
fm-mcpMCP server to~/.claude.json(throughclaude mcp addwhen theclaudecommand is there), and installs thefm-delegateskill in~/.claude/skills/.Codex: adds
[mcp_servers.fm-mcp]to~/.codex/config.toml, and a marked section in~/.codex/AGENTS.md(or inAGENTS.override.md, if you use one).
It backs up each file before changing it and prints every path it touched; running it again changes nothing. --claude or --codex picks one agent, --dry-run shows the changes without writing, and --no-guidance skips the skill and the AGENTS.md section. fm-mcp install --uninstall removes everything it added.
The skill and the AGENTS.md section tell the agent when to delegate. Without them the agent sees only the tool descriptions, and delegates less well.
Or: the Claude Code plugin
The plugin gives Claude Code the MCP server and the skill, without fm-mcp install. It still needs the binary on your PATH, so install that first (Homebrew above); otherwise Claude Code reports the server as failed to connect.
/plugin marketplace add yrangana/fm-mcp
/plugin install fm-mcp@fm-mcpUse the plugin or fm-mcp install for Claude Code, not both: both together give Claude Code two fm-mcp servers. With the plugin, run fm-mcp install --codex to set up Codex only.
Other MCP clients
fm-mcp is a plain stdio MCP server, so other clients that run local servers on the same Mac can use it. fm-mcp install doesn't set them up, and they don't get the delegation guidance: the agent decides from the tool descriptions alone. Each client below was tried on a real Mac; others may work but are untested.
Claude Desktop (tried with 2.31226.1, 2026-10-11). In Settings › Developer › Edit Config, add this to mcpServers in claude_desktop_config.json, then quit and reopen Claude Desktop:
"fm-mcp": {
"command": "/opt/homebrew/bin/fm-mcp",
"args": []
}Use the full path (which fm-mcp prints it). fm-mcp helps most with files on your Mac: give Claude the file's path and it passes path, so the text never goes through Claude. For a web page, Claude Desktop reads the page itself first, so delegating it saves nothing.
Devin (formerly Windsurf) (tried with Devin.app 3.8.20, 2026-10-11). Add this to mcpServers in ~/.config/devin/mcp_config.json:
"fm-mcp": {
"type": "stdio",
"command": "/opt/homebrew/bin/fm-mcp",
"args": []
}Tools
Tool | What it does | How much it takes |
| Condenses logs, documents, notes and transcripts into a gist: a paragraph, or at most 7 bullets. Not a full record. | About 30,000 words of prose, but only about 1,000 lines of a dense log. Long input is split and combined, which takes a minute or two and can drop details. |
| Pulls named fields out of one text as JSON, from a JSON Schema you give. Works best with a flat schema. | About 3,500 words of prose. |
| Sorts one text into labels you choose (one label, or several with | About 3,500 words of prose. |
| Reads the text in a PNG, JPEG, HEIC, TIFF, GIF or BMP image. Not PDF. | One image. |
summarise, extract and classify take text, or a path to a text file (up to 1 MB) so the agent never has to read the file itself. docs/TOOLS.md lists every parameter, with example calls.
Limits
Small model, small context: about 8K tokens, shared by the input and the answer. Logs full of IDs and numbers use far more tokens per word than prose.
Not for code, maths, reasoning, facts the text doesn't contain, or anything where a wrong answer is costly and you can't check it.
It makes mistakes. Summaries can drop or distort details.
extractoften returnsnullfor a field the text doesn't contain, but not reliably: on short invoices a missing PO number took the supplier's name in 10 of 25 runs. When the model gets stuck on a field, fm-mcp keeps the finished fields, sets the stuck one tonulland says so; that call takes about 15 s. Ask only for fields the text is likely to have. Nested schemas are less reliable than flat ones. Check what matters.One request at a time. The model is shared by every session on the Mac, so calls queue: a short
extracttakes 1–2 s, a longsummarisea minute or more.Safety filter: the on-device model sometimes refuses harmless input. fm-mcp reports that clearly, and the agent does the task itself.
Privacy
Everything runs on your Mac. fm-mcp talks to fm serve over a local Unix socket and sends nothing over the network. Your text goes only to the on-device model. SECURITY.md has the details, and how to report a security problem privately.
Troubleshooting
Run fm-mcp doctor. It checks the Mac, macOS, fm, the licence, the model, a test request, and both agents' setup, and says how to fix anything that fails.
Problem | Fix |
Licence not agreed | Run |
Model not available | Turn on Apple Intelligence in System Settings and wait for the model to finish downloading. |
A tool says the model "got stuck" | Usually a schema with fields the text doesn't contain, or another session using the model. Try a flatter schema. |
A tool times out on long input | Raise the limit: set |
You need more detail | Set |
Uninstall
fm-mcp install --uninstall
brew uninstall fm-mcpDevelopment
git clone https://github.com/yrangana/fm-mcp.git
cd fm-mcp
cargo build --release
./target/release/fm-mcp install # points your agents at this build
cargo test --features fake-fm # needs no Apple Intelligence: uses a fake fm
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --check
scripts/real_fm_smoke.sh # checks against the real fm on this MacAGENTS.md has the architecture, the tested facts about fm serve, and the project rules. docs/MANUAL_TEST.md is the checklist for each release.
Licence
MIT. fm-mcp is not affiliated with or endorsed by Apple. It calls the fm tool installed on your Mac and includes nothing from Apple.
Created by Yasiru Rangana.
Available Tools
4 toolsclassifyARead-only
Pick the best label for a text from a list you give, with the on-device model for Apple Foundation Models (free, private, offline). Good for triage: sorting tickets, emails, comments or log lines into categories. The answer is always one of your labels (or several, with multi). Input up to about 3,500 words, as text or as path to a text file; 2 to 50 labels. Subtle or ambiguous text can be mislabelled, so spot-check. Not for code, maths or reasoning.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Absolute path to a UTF-8 text file to classify (as one text) instead of `text`. | |
| text | No | The text to classify. Up to about 3,500 words. Give this or `path`. | |
| multi | No | Allow several labels instead of exactly one. Defaults to false. | |
| labels | Yes | The labels to choose from: 2 to 50 distinct, non-empty strings. | |
| instructions | No | Optional guidance, for example what each label means. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the readOnly/openWorld annotations: it discloses the privacy model (free, private, offline, on-device), hard input bounds (~3,500 words, 2-50 labels), an output guarantee (the answer is always one of your labels, or several with `multi`), and an accuracy caveat with mitigation ('subtle or ambiguous text can be mislabelled, so spot-check'). That is unusually rich behavioral disclosure for a pure-inference tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, each doing distinct work: purpose first, then use cases, then limits, then exclusions. No filler or repetition, and the most decision-relevant information (what it does and where it applies) is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Full picture for a five-parameter inference tool with no output schema: input constraints, output constraint, multi-label behavior, accuracy risk, privacy posture and scope exclusions are all present. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so text, path, multi, labels and instructions are all already documented. The description mostly restates those fields (3,500 words, 2-50 labels, text-or-path) and only marginally adds the framing that the answer is drawn from the label set. Baseline 3 is correct when the schema carries the parameter burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: pick the best label for a text from a caller-supplied list, running on the on-device Apple Foundation Models. The scope exclusion ('Not for code, maths or reasoning') sharpens the boundary, but it never names the sibling tools (extract, ocr, summarise), so routing among them relies on inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Concrete use cases are given ('triage: sorting tickets, emails, comments or log lines into categories') plus an explicit when-not ('Not for code, maths or reasoning'). It lacks any named alternative tool or a rule for choosing between this and summarise, so it falls short of full when/when-not/alternatives coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extractARead-only
Extract fields from text into JSON matching a JSON Schema, with the on-device model for Apple Foundation Models (free, private, offline). Good for names, dates, amounts and IDs in short documents, emails, logs. Input up to about 3,500 words, as text or path to a text file. Ask only for fields the text likely states: a missing one is often null but may take a wrong value from nearby text. Flat schemas work best; nested ones are unreliable. Allowed keywords: type, properties, required, items, enum, const, description, minItems, maxItems. Not for code or reasoning; check values that matter.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Absolute path to a UTF-8 text file to extract from instead of `text`. | |
| text | No | The text to extract from. Up to about 3,500 words. Give this or `path`. | |
| schema | Yes | A JSON Schema for the result. The top level must be an object, for example {"type": "object", "properties": {"invoice": {"type": "string"}, "total": {"type": "number"}}}. | |
| instructions | No | Optional extra guidance, for example "amounts in AUD without the currency sign". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/non-destructive/non-open-world, so the bar is lower, yet the description adds substantial context: free/private/offline on-device execution, ~3,500-word input cap, the risk that absent fields take wrong values from nearby text, and the unreliability of nested schemas. This is exactly the behavioral context annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: capability first, then good-use cases, limits, accuracy caveats, and schema constraints. Every sentence adds operational value, though it packs enough caveats that it reads as a block rather than distinct scannable points.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers input sourcing, size limits, accuracy expectations, and schema restrictions for a tool with no output schema, and annotations cover the safety profile. An agent has everything needed to call this correctly and to know when results should be verified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description goes beyond the schema by enumerating the JSON Schema keywords the tool actually honors (type, properties, required, items, enum, const, description, minItems, maxItems) and clarifying that text and path are alternates, which the schema only implies via defaults.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (extract) plus resource (fields into JSON matching a JSON Schema) and the engine (on-device model for Apple Foundation Models). It is clearly distinguishable from classify, ocr, and summarise, which all transform rather than populate a caller-supplied schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete when-to-use context (names, dates, amounts, IDs in short documents, emails, logs), an explicit exclusion ('Not for code or reasoning'), and input-size guidance. It never names a sibling tool as the alternative, so routing to classify/ocr/summarise is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ocrARead-only
Read the text in an image file (screenshot, scanned page, receipt, handwriting) with the on-device model for Apple Foundation Models (free, private, offline). Give an absolute path to a PNG, JPEG, HEIC, TIFF, GIF or BMP file; PDFs are not supported. Returns the text line by line, or answers prompt about the image instead. Small or unusual text can be misread; check numbers that matter. Not for code review or reasoning.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path to a PNG, JPEG, HEIC, TIFF, GIF or BMP image. | |
| prompt | No | Optional question or instruction about the image. Leave empty to get all the text. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safe/read-only and closed-world profile, and the description goes well beyond them: on-device/free/private/offline processing model, an accuracy caveat ('small or unusual text can be misread; check numbers that matter'), and the exact return shape (line-by-line text or a prompt answer). That is the kind of behavior an agent needs before deciding to trust the output.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with the action and inputs, then return behavior, then caveats. No filler; each clause carries a constraint or capability an agent must know.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still describes the return value (line-by-line text or a prompt-driven answer) and the failure mode (misread text). For a two-parameter read tool with full schema coverage and annotations, nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real meaning the schema lacks: accepted formats are constrained (PDFs explicitly unsupported, absolute path required) and the empty-prompt case is spelled out as 'return all the text' rather than an answer.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read the text in an image file') with example inputs and the underlying engine. It also distinguishes itself from siblings by excluding code review and reasoning, which would otherwise collide with classify/extract/summarise.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when the tool applies (image files, absolute path) and key exclusions ('PDFs are not supported', 'Not for code review or reasoning'). It does not name a specific sibling to use instead for those excluded cases, so the routing guidance is clear but not fully closed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
summariseARead-only
Summarise text with the on-device model for Apple Foundation Models. Free, private and offline. Good for condensing logs, documents, notes and transcripts into a gist (a paragraph, or at most 7 bullets), not a full record. Limit: about 30,000 words of prose but only about 1,000 lines of a dense log; filter bigger logs first (grep the errors). Pass path to a text file instead of text to avoid reading it yourself. Long input is split and combined: slower, and it can drop details. Not for code, maths, reasoning or facts. Summaries can miss or distort details; check anything important.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Absolute path to a UTF-8 text file to summarise instead of `text`. | |
| text | No | The text to summarise: plain text, Markdown or logs. Give this or `path`. | |
| focus | No | Optional focus, for example "errors only" or "decisions and owners". Leave empty for a general summary. | |
| length | No | How long the summary should be: `short` (one or two sentences), `medium` (one paragraph of three to five sentences) or `bullets` (three to seven bullet points). Defaults to `medium`. | medium |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover only the safety profile (readOnly/openWorld/destructive), while the description discloses free/private/offline operation, concrete input ceilings (~30k words vs ~1000 dense log lines), the long-input split-and-combine behaviour with its latency and detail-loss cost, and the accuracy caveat ('can miss or distort details; check anything important'). This is unusually rich behavioral context beyond structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first clause and every following sentence carries distinct information (cost, scope, limits, path hint, degradation, exclusions, caveat). It is dense and semicolon-heavy rather than cleanly chunked, which is the only thing keeping it below a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-shape burden and does so ('a paragraph, or at most 7 bullets'), matching the `length` enum. Input limits, degradation behaviour, the two input modes and the accuracy caveat are all present, so an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds genuine decision value: 'Pass `path` to a text file instead of `text` to avoid reading it yourself' explains the cost tradeoff between the two mutually exclusive inputs. It also reinforces the enum contract ('at most 7 bullets', 'a paragraph'), though it does not explain the `focus` parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('summarise') plus the resource and the execution substrate ('on-device model for Apple Foundation Models'), and immediately frames the output as a gist rather than a full record. An agent can distinguish this from classify/extract/ocr without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use ('condensing logs, documents, notes and transcripts into a gist') and explicit when-not ('Not for code, maths, reasoning or facts', 'not a full record'), plus a precondition ('filter bigger logs first (grep the errors)'). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.3- First observed
classify - First observed
extract - First observed
ocr - First observed
summarise
TDQS
Scored across 4 tools
Each tool targets a clearly distinct operation: classify (pick from given labels), extract (schema-bound fields), ocr (read text from images), and summarise (condense prose). There is no overlap in verb, input type, or output shape, and each description even states what it is NOT for. An agent can select unambiguously.
Three tools are lowercase verbs (classify, extract, summarise) in a consistent style with no noun collisions. The single deviation is 'ocr', an acronym/process name rather than a verb, but it is a standard, unambiguous term and the overall set still reads as a predictable pattern.
Four tools is well-scoped for a focused on-device text-processing server. Each tool covers a genuinely different capability (classification, extraction, OCR, summarisation) and none feels redundant or extraneous.
The surface covers the main on-device operations: classify, extract, ocr, and summarise, with clear input/output behavior for each. Minor gaps exist, such as no explicit translation, Q&A, or generic generation tool, but the core text-processing lifecycle is well covered and workable.
Maintenance
Related MCP Connectors
Your AI apps as one team: hand work to Codex, Claude Code or Cursor on your Mac, with a logbook.
Use your Mac, Windows or Linux computer from ChatGPT, Claude or Codex: files, commands, documents.
Mac & Windows: let ChatGPT, Claude & Cursor use your email, calendar, iMessage, Teams, files.
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Related MCP Servers
- AlicenseAqualityBmaintenanceBridges Claude Code and Claude Desktop to a locally-running LLM, optimized for MLX LM on Apple Silicon with support for any OpenAI-compatible backend.41MIT
- AlicenseNot gradedqualityCmaintenanceExposes Apple's on-device 3B parameter LLM to Claude Code and Claude Desktop via MCP. Zero API cost, fully private, runs on Neural Engine.29 PyPI1MIT

ToolPiperofficial
AlicenseNot gradedqualityAmaintenance426+ MCP tools for macOS, all on-device — local AI inference (llama.cpp on Metal), voice, vision OCR, local RAG, browser automation, and ~140 system actions across 26 macOS domains. Nothing leaves your Mac.3MIT- AlicenseAqualityAmaintenanceLocal OCR & image analysis via Apple Vision Framework — private, offline, no API keys. Extracts text from images and PDFs, detects faces, barcodes, QR codes, and document corners. Works with Claude Code, Claude Desktop, and Cursor.697 npm8MIT