Skip to main content
Glama
Ahmetshbzz
by Ahmetshbzz

apple-docs-mcp

An MCP server and CLI that answer Apple Developer Documentation questions from the documentation corpus Xcode already has on disk — no network, no Xcode process, no approval dialog.

Coding agents recall Apple APIs from training data that lags the installed SDK. This server hands them the real text: complete pages with their code listings, the declaration, and the availability windows.

Measured against Xcode's own DocumentationSearch

Xcode 27 exposes an MCP tool, DocumentationSearch, that answers from the same corpus through mcpbridge. It is a good tool, and this project uses it — but only when its semantic ranking is wanted. The two paths measured on this machine (6 queries, same session, 2026-09-17):

Xcode DocumentationSearch

this server, mode: offline

Requires

Xcode running, workspace open, per-process approval, 24 h expiry

nothing

Latency, mean of 6 queries

264–371 ms across runs

5.9 ms in the MCP server; 2–17 ms across runs

Latency, single page fetch

not available

2 ms

Corpus reachable

the 20 documents the tool returns

263,513 pages, searchable

Text per result

fragment, 46–5,305 chars (median 437)

the whole page (up to 375,908 chars)

Fields per result

title, uri, contents, score, kind

plus declaration, availability, framework, kind, USR

Index build

n/a

263,513 pages in 5.3 s, 128 MB

Reproduce all of it on your own machine — uv run python tools/benchmark.py. The offline figures move with the OS page cache, so the script reports the first call of a fresh process separately from the steady state: 5 ms first call, 17 ms mean over six queries in a standalone process, 5.9 ms mean over the same six in a running MCP server that warmed itself at startup.

Evaluated, not asserted

Six queries and an opinion is not evidence, so ranking is measured on two sets — uv run python tools/evaluate.py, ground truth stated per query:

  • 40 identifier queries, sampled from the corpus, asked twice: as the bare title, and inside a sentence the way a person types it ("I want to use ARAnchor in my app, how does it work"). The expected answer is the page's URI and no judgement is involved.

  • 12 questions ("how do I download a file and show progress"). Answers were judged from the pooled results of both engines, so an equally good page is not marked wrong for not being the one the question writer had in mind.

Recall, with @k meaning the expected page is in the first k results:

Identifier, bare title (n=40)

@1

@3

@5

MRR

mean latency

this server, offline and auto

87.5%

92.5%

92.5%

0.900

1.4–5.7 ms

Xcode DocumentationSearch

57.5%

65.0%

67.5%

0.615

294 ms

Identifier inside a sentence (n=40)

@1

@3

@5

MRR

mean latency

this server, offline and auto

90.0%

92.5%

92.5%

0.912

5–28 ms

Xcode DocumentationSearch

35.0%

45.0%

47.5%

0.402

353 ms

Questions (n=12)

@1

@3

@5

MRR

mean latency

this server, offline

41.7%

66.7%

75.0%

0.544

15 ms

this server, auto

41.7%

83.3%

91.7%

0.600

282 ms

Xcode DocumentationSearch

41.7%

83.3%

91.7%

0.614

319 ms

One trade-off is measured rather than hidden: in hybrid, weighting the local list equally with the bridge raises recall@1 from 41.7% to 58.3% and lowers recall@5 from 91.7% to 75.0% (MRR 0.646 against 0.600). Bridge-weighted is kept because the reported metric is recall and because an agent that reads three results cares more about the answer being inside them.

The script also audits its own ground truth, because the person who wrote the questions also judged the pooled answers. Where the accepted pages came from: 9 found by both engines, 13 only by the bridge's pool, 4 only by this server's — the labelling leans toward the bridge, not toward this project. A further 12 accepted pages were returned by neither engine; nobody judged those, which is the blind spot of pooling and it flatters both engines equally.

Read that honestly, because it cuts both ways:

  • For a named API — the lookup an agent makes constantly — this server is clearly better and 50–100x faster, with no approval dialog. The bridge scored 65% at @3 on bare names and 45% when the name arrived inside a sentence; the local index scored 92.5% on both.

  • For a question, the bridge is better than /offline (91.7% vs 75.0% at @5). Semantic search reaches wording that no term index has seen, and this project does not reproduce Apple's embedding space (measured cosine ≈ 0.01–0.03 for the very same page text), so it does not pretend to.

  • auto — the default — is never worse than the better engine on any of the three sets, because it reads the query and picks. A query that names an API is answered locally in about a millisecond; a question that names no API gets the bridge's semantic order fused in. A framework name is not an API name: it scopes a question rather than being one.

The bridge's own weakness is visible in the data as well: 39 of the 118 documents it returned across an earlier six-query run were under 100 characters, because it ranks short "…: Relationships" stubs highly, and a stub cannot answer a question.

Two things this project does not claim. It does not reproduce Xcode's semantic ranker offline: the stored page vectors are 512-dimensional but live in a space NLContextualEmbedding does not reproduce (measured cosine ≈ 0.01–0.03 for the same page text). And it is not a better search engine than Xcode's — it is the same corpus with different plumbing.

Related MCP server: Apple Docs MCP

Relationship to Xcode's own MCP server

Xcode ships an MCP server (xcrun mcpbridge) that advertises 54 tools. Read the list, because the comparison is narrower than the counts suggest: exactly one of the 54 is documentation.

What the 54 cover

Examples

Building, running, testing, debugging

BuildProject, RunProject, RunAllTests, InvokeDebuggerCommand, GetBuildLog

Devices and previews

DeviceInteractionSynthesize, RenderPreview, RunCodeSnippet

Project files and settings

XcodeRead, XcodeWrite, XcodeGrep, UpdateTargetBuildSetting

Localisation, crash and performance retrieval

StringCatalogEdit, GetTopCrashIssues

Documentation

DocumentationSearch

So this server is not a replacement for that one and does not try to be: it answers documentation questions, and only the last row of that table overlaps with what it does. If you want the other 53 — build, run, debug, device control — register Xcode's server as well:

claude mcp add xcode-tools -- xcrun mcpbridge

Two things are worth knowing before you do. That server needs Xcode running with an approved workspace, and it hands the agent write and execute access to your project; this one reads documentation and nothing else. Run both if you want both, and route documentation at whichever answers your kind of question better — the evaluation above is the evidence for that choice.

Install

Requires macOS and Xcode with the Developer Documentation asset installed. uv for the toolchain.

git clone https://github.com/Ahmetshbzz/apple-docs-mcp
cd apple-docs-mcp
uv sync
uv tool install --editable .

Register with an MCP client

Claude Code:

claude mcp add apple-docs --scope user -- \
  uv run --quiet --project /path/to/apple-docs-mcp apple-docs-mcp

Codex (~/.codex/config.toml):

[mcp_servers.apple-docs]
command = "uv"
args = ["run", "--quiet", "--project", "/path/to/apple-docs-mcp", "apple-docs-mcp"]
startup_timeout_sec = 60

Tools

Tool

Purpose

search_docs

Ranked pages with declaration, availability, and a snippet. Offline by default; mode picks the semantic or hybrid path

get_document

One whole page by URI: prose, code listings, declaration, availability

list_frameworks

Every framework with its page count (375 frameworks)

doc_status

Corpus, index, and bridge state, with the remedy when something is missing

swift_playbook

The Swift/Apple-platform engineering playbook and its reference files

build_index

Build or rebuild the derived index (search builds it automatically on first use)

The playbook is also served as the swift://playbook resource, the swift://reference/{topic} resource template, and the swift-playbook prompt.

Modes

Mode

What answers

Measured latency

Xcode needed

auto (default)

the index for API names, the bridge for questions

1.5 ms / 296 ms

only for questions

offline

the local corpus index

2–28 ms

no

semantic

Xcode's bridge

185–739 ms

yes, approved

hybrid

both, fused by reciprocal rank

308–313 ms

no (falls back)

hybrid labels each hit local, bridge, or hybrid, so a caller can see where an answer came from. If the bridge fails in hybrid, the offline results are returned with a bridgeError note instead of an error.

CLI

apple-docs search "SwiftData model inheritance" --limit 5
apple-docs search "AVAudioSession category" --framework AVFAudio --json --full
apple-docs get /documentation/SwiftUI/View
apple-docs frameworks
apple-docs status
apple-docs index --rebuild

Exit codes are distinct per failure so scripts can branch: 0 success, 1 usage, 2 not approved, 3 Xcode unavailable, 4 timeout, 5 protocol, 6 asset missing, 7 page not found.

Where the text comes from

Xcode's Developer Documentation asset keeps every page as a JSON document in a SQLite database:

/System/Library/AssetsV2/com_apple_MobileAsset_AppleDeveloperDocumentation/
  <uuid>.asset/AssetData/documentation-db/index.sql

documents holds one JSON row per page — uri, title, framework, kind, content (prose and code listings), symbol (identity and USR), platforms (availability) — and observations holds precomputed 512-dimensional vectors. The neighbouring documentation-cache/ is a different thing: an HTTP-style blob store (cache.db refs into fs/<n> segments) for images and cached payloads.

The server derives a full-text index from documents and leaves the corpus alone: it is opened read-only and immutable, and never written to.

The derived index

  • Built once per corpus version, in ~/Library/Caches/apple-docs-mcp/.

  • 118 MB for 263,513 pages; 5.3 s to build; atomic swap, so an interrupted build never leaves a half-index. An index from an older schema is deleted on the next build instead of lingering.

  • Contentless FTS5 — the index holds tokens, and page text is read back from the corpus for the handful of pages a query returns. That is why it is 118 MB and not 500 MB.

  • Term statistics live in the index (fts5vocab), which is what lets a query be built from its selective words without touching the corpus.

  • Freshness is decided from the corpus file's size and mtime plus the index schema version.

The Swift playbook

swift_playbook serves an authored engineering playbook — what to do, what never to do, and which reference file answers an architecture question — while search_docs supplies signatures and availability, which the playbook deliberately does not carry. The playbook stays in its own repository and is read in place; point APPLE_DOCS_SWIFT_SKILL at it. When it is absent, the tool says where it looked instead of returning nothing.

Configuration

Variable

Default

Meaning

APPLE_DOCS_ASSET_ROOT

the system asset root

Where the documentation asset lives

APPLE_DOCS_CACHE_DIR

~/Library/Caches/apple-docs-mcp

Where the derived index lives

APPLE_DOCS_SWIFT_SKILL

~/Desktop/tools/claude-skills/swift

Where the playbook lives

APPLE_DOCS_BRIDGE_COMMAND

xcrun mcpbridge

How to launch Xcode's bridge

Limitations

  • Ranking is BM25 over the query's selective terms, with column weights biased toward the URI and title plus an identifier boost. It is not semantic; use semantic or hybrid when meaning matters more than terms.

  • The corpus is written by Xcode, so a page can be a section rather than an article ("…: Relationships"). Such sections are short by construction.

  • Xcode can purge the asset (…xml.purged appears next to it). If the corpus disappears, searches fail with a remedy rather than returning nothing.

  • Attribute rows in index.sql carry framework, title, and type but no text; the text lives in documents. The server reads documents.

Development

uv run pytest tests/ -q                    # 148 tests, no Xcode needed
uv run pytest tests/ -m integration        # live bridge tests
uv run python tools/benchmark.py           # latency, offline against the bridge
uv run python tools/evaluate.py            # recall, on judged ground truth
uv run ruff check src tests tools

Unit tests build synthetic corpus and skill fixtures, so they run anywhere. The integration tests exercise the live bridge and skip themselves when it is unavailable. The MCP surface itself is tested over a real stdio transport in tests/test_server_surface.py.

Verified environment

Measured 2026-09-17, not assumed:

Thing

Value

Xcode

27.0 (27A266a)

Swift

6.4 (swiftlang-6.4.0.34.1)

Documentation corpus

263,513 pages, 375 frameworks, ~375 MB of text

Derived index

118 MB, built in 5.3 s

License

MIT — see LICENSE.

Available Tools

3 tools
doc_statusA

Report whether documentation search is usable right now: asset presence, bridge path, and whether this process is approved to use Xcode's tools.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the burden of disclosing behavior. It does so well by framing the tool as a pure report and listing the three checks it performs, which implicitly signals a non-mutating status operation. It could be more explicit about having no side effects, but 'Report whether' plus the enumerated checks provides strong transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single front-loaded sentence followed by a compact colon-separated list. Every phrase earns its place, and there is no filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter status tool with an output schema available, the description covers what the tool reports, when it is relevant, and which aspects are checked. It could have explicitly instructed the agent to call it before search_docs, but nothing essential for invoking it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the baseline is 4. There is no parameter information needed in the description, and the description does not attempt to add any because none is required.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Report') and a specific subject ('whether documentation search is usable right now'), then enumerates the scope: asset presence, bridge path, and Xcode approval. This clearly distinguishes it from sibling tools like search_docs and list_frameworks, which perform different actions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'usable right now' makes it clear this is a readiness/precondition check, so an agent understands to call it when it needs to verify documentation search is available before searching. It does not explicitly name alternatives or exclusion conditions, but the intended timing is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_frameworksA

List every framework in Xcode's local documentation index. Runs offline and needs no Xcode approval.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Since no annotations are provided, the description carries the full burden of behavioral disclosure. It meaningfully discloses that the tool runs offline and needs no Xcode approval, which addresses common permission and environment concerns. It does not describe ordering or other return details, but the output schema exists to cover return structure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no filler; the first states the core purpose and the second adds two key behavioral constraints. Everything present earns its place, and the description is immediately scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter list operation with an output schema, the description is complete: it names the resource, clarifies it covers every framework, and adds offline/no-approval context. An agent has everything it needs to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters, so there is nothing for the description to explain about parameter usage. With 100% schema coverage of an empty schema, the baseline of 4 is appropriate, and no further parameter documentation is needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('List') and a precise resource ('every framework in Xcode's local documentation index'), making the tool's scope unmistakable. It clearly differentiates this from siblings like search_docs and doc_status by stating it enumerates all frameworks rather than searching or checking status.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear context for when this tool is appropriate: when a complete framework list is needed, and it works offline without requiring Xcode approval. It does not explicitly name alternatives or exclusion conditions, but the usage context is clear enough for an agent to select it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_docsA

Search Apple Developer Documentation by meaning, using Xcode's local documentation index. Returns full document text including code examples, with each result's uri and match score. Use this before answering from memory about Swift or Apple platform APIs.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYesNatural-language or API search query.
timeoutNoSeconds to wait for the bridge before failing.
frameworksNoRestrict the search to these frameworks, e.g. ['SwiftData'].

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses that the search is semantic ('by meaning'), uses a local Xcode index, and returns full document text with code examples, uri, and match score. It does not mention failure modes or side effects, but this is a read-only search operation and the core behavior is well conveyed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three concise sentences with no filler. The first sentence states the core purpose, the second describes the return value, and the third gives actionable usage guidance. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers purpose, usage context, return contents, and the underlying local-index mechanism. An output schema exists to document the exact return shape, and the schema documents all parameters. It could add a note about prerequisites or when to use list_frameworks first, but it is otherwise complete for a search tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds context about the search approach and return format but does not add meaning to the parameters themselves beyond what the schema already provides for query, timeout, and frameworks.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb and resource: 'Search Apple Developer Documentation by meaning, using Xcode's local documentation index.' It also explains what is returned (full document text, code examples, uri, match score), making the tool's function unmistakable and distinct from the sibling tools list_frameworks and doc_status.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: 'Use this before answering from memory about Swift or Apple platform APIs.' It does not explicitly mention when not to use it or alternatives, but the sibling tools are clearly different in purpose, so no exclusion is necessary.

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.

  1. 3 tool updatesv0.1.0
    • First observeddoc_status
    • First observedlist_frameworks
    • First observedsearch_docs

TDQS

A4.4/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct role: search_docs finds documentation, list_frameworks enumerates available documentation domains, and doc_status reports tooling health. There is no meaningful overlap or ambiguity between them.

Naming Consistency4/5

search_docs and list_frameworks follow a clear verb_noun snake_case pattern, while doc_status is a noun_noun name rather than a verb-based one. The naming is still consistent in style and readable, but the health-check tool deviates slightly from the verb-led convention.

Tool Count5/5

Three tools is well-scoped for a documentation lookup server: one core search action, one discovery action, and one operational status check. Each tool clearly earns its place without redundancy or bloat.

Completeness4/5

The server covers the main documentation workflow well: searching docs, listing available frameworks, and verifying tool readiness. A direct fetch-by-URI option is missing, but since search_docs returns full document text, it is not a serious dead end.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides comprehensive access to Apple's development documentation ecosystem including hidden Xcode docs, Swift Evolution proposals, GitHub repositories, and WWDC session notes. Enables developers to search and retrieve advanced Apple development resources not available through public channels.
    16
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Provides access to Apple's official developer documentation, frameworks, APIs, and WWDC session transcripts across all Apple platforms. It enables AI assistants to search technical guides, sample code, and platform compatibility information using natural language queries.
    18
    1,132 npm
    1,381
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides access to Apple documentation and WWDC transcripts with semantic, keyword, and hybrid search capabilities, enabling developers to quickly find relevant code examples and technical information.
    120
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Search and retrieve information from Apple's complete developer documentation, including API references, code examples, and Human Interface Guidelines, across all Apple platforms and versions.
    4
    26 npm
    8
    MIT