About
Swift — Model Context Protocol server
README
Swift MCP Server (Swift docs + evolution + lint/format)
Quick start (macOS)
Install dependencies:
- Node 18+
- Optional:
brew install swift-format swiftformat swiftlint
In this folder:
npm installnpm run dev(runs server over stdio)npm run inspector(UI to test tools)
Tools
swift_docs_search: search TSPL (swift-book) and API Design Guidelines.apple_docs_search: search local Apple DocC/docsets (AppKit/SwiftUI/Foundation...), supports filters:frameworks,kinds,topics.swift_evolution_lookup: lookup Swift Evolution proposals by ID or keyword.swift_lint_run: run SwiftLint if installed.swift_format_apply: format Swift source via swift-format or SwiftFormat.swift_guidelines_check: heuristic API guideline checks on Swift code.swift_update_sync: mirror swift-evolution and swift-book into.cache.cocoa_patterns_search: search curated Cocoa patterns (keyboard/focus/window).- Additional patterns include responder chain basics, child windows, sheets, and menu shortcut conventions.
hig_search: search local HIG snapshots.swift_symbol_lookup: resolve a symbol/selector to Apple doc hits.search_hybrid: unified search across Apple DocC, HIG, and patterns.- Returns
{ results, facets }wherefacetscontains sorted counts forsources,frameworks,kinds,topics, andtags.
- Returns
index_status: report cache directory and index statuses (apple/hig/patterns/hybrid).- Example:
node -e "import('./dist/tools/index_status.js').then(m=>m.indexStatus()).then(r=>console.log(JSON.stringify(r,null,2)))"
- Example:
apple_docsets_import: import Apple DocC/Dash content from a local path or URL into.cache/apple-docs/<Framework>/, then reindex Apple and Hybrid.- Input:
sourcePathOrUrl: string,framework?: string,reindex?: boolean - Example (local folder with framework subdir):
node -e "import('./dist/tools/docsets_import.js').then(m=>m.importDocsets({sourcePathOrUrl:'content/sample-docc'})).then(console.log)" - Example (archive URL):
node -e "import('./dist/tools/docsets_import.js').then(m=>m.importDocsets({sourcePathOrUrl:'https://example.com/AppKit-docs.zip'})).then(console.log)"
- Input:
swift_recipe_lookup: lookup YAML-backed development recipes (e.g., video overlays, export).- Input:
queryOrId: string,limit?: number - Example:
node -e "import('./dist/tools/recipes.js').then(m=>m.swiftRecipeLookup({queryOrId:'overlay',limit:3})).then(r=>console.log(JSON.stringify(r,null,2)))"
- Input:
Tool Usage
swift_update_sync:- Input: none
- Behavior: mirrors
swift-evolution,swift-book, caches API Design Guidelines + HIG pages, seeds sample DocC, and builds indexes (Apple, HIG, patterns, hybrid). - Example:
node dist/tools/update.js
swift_docs_search:- Input:
query: string,limit?: number - Sources: TSPL (swift-book) + API Design Guidelines
- Example:
node -e "import('./dist/tools/docs.js').then(m=>m.docsSearch({query:'Optionals',limit:3})).then(console.log)"
- Input:
swift_evolution_lookup:- Input:
query: string,limit?: number - Example:
node -e "import('./dist/tools/evolution.js').then(m=>m.evolutionLookup({query:'SE-0001',limit:3})).then(console.log)"
- Input:
swift_lint_run:- Input:
path?: string,configPath?: string,strict?: boolean - Requires:
swiftlintin PATH - Example:
node -e "import('./dist/tools/lint.js').then(m=>m.lintRun({path:'/tmp/ci.swift'})).then(console.log)"
- Input:
swift_format_apply:- Input:
code: string,swiftVersion?: string,assumeFilepath?: string - Requires:
swift-formatorswiftformatin PATH (server falls back gracefully) - Example:
node -e "import('./dist/tools/format.js').then(m=>m.formatApply({code:'struct A{}'})).then(console.log)"
- Input:
swift_guidelines_check:- Input:
code: string - Heuristics: naming, acronym casing, AppKit/SwiftUI bridge checks (monitors, first responder, child windows, identifiers)
- Example:
node -e "import('./dist/tools/guidelines.js').then(m=>m.guidelinesCheck({code:'class v{}'})).then(console.log)"
- Input:
apple_docs_search:- Input:
query: string,frameworks?: string[],kinds?: string[],topics?: string[],limit?: number - Uses MiniSearch index if present; falls back to file scan under
.cache/apple-docs - Example:
node -e "import('./dist/tools/apple_docs.js').then(m=>m.appleDocsSearch({query:'NSWindow',frameworks:['AppKit'],limit:5})).then(console.log)"
- Input:
swift_symbol_lookup:- Input:
symbolOrSelector: string - Resolves aliases from
content/symbols/aliases.yaml, then queries Apple docs - Example:
node -e "import('./dist/tools/apple_docs.js').then(m=>m.swiftSymbolLookup('performKeyEquivalent:')).then(console.log)"
- Input:
cocoa_patterns_search:- Input:
queryOrTag: string,limit?: number - Searches curated YAML patterns in repo
content/patterns/and.cache/content/patterns/ - Example:
node -e "import('./dist/tools/patterns.js').then(m=>m.cocoaPatternsSearch({queryOrTag:'keyboard',limit:5})).then(console.log)"
- Input:
hig_search:- Input:
query: string,limit?: number - Searches
.cache/higsnapshots; prefers HTML<title>and canonical links - Example:
node -e "import('./dist/tools/hig.js').then(m=>m.higSearch({query:'keyboard',limit:5})).then(console.log)"
- Input:
search_hybrid:- Input:
query: string,sources?: ('apple'|'hig'|'pattern')[],frameworks?: string[],kinds?: string[],topics?: string[],tags?: string[],limit?: number - Returns:
{ results, facets }with facet counts - Example (class):
node -e "import('./dist/tools/hybrid.js').then(m=>m.hybridSearch({query:'NSWindow',sources:['apple'],frameworks:['AppKit'],limit:5})).then(r=>console.log(JSON.stringify(r,null,2)))" - Example (method):
node -e "import('./dist/tools/hybrid.js').then(m=>m.hybridSearch({query:'performKeyEquivalent',sources:['apple'],frameworks:['AppKit'],kinds:['method'],limit:5})).then(r=>console.log(JSON.stringify(r,null,2)))"
- Input:
index_status:- Input: none
- Reports cache directory and index statuses (apple/hig/patterns/hybrid)
- Example:
node -e "import('./dist/tools/index_status.js').then(m=>m.indexStatus()).then(r=>console.log(JSON.stringify(r,null,2)))"
apple_docsets_import:- Input:
sourcePathOrUrl: string,framework?: string,reindex?: boolean - Imports Apple DocC/Dash content into
.cache/apple-docs/<Framework>/and reindexes - Example:
node -e "import('./dist/tools/docsets_import.js').then(m=>m.importDocsets({sourcePathOrUrl:'content/sample-docc'})).then(console.log)"
- Input:
swift_recipe_lookup:- Input:
queryOrId: string,limit?: number - Looks up YAML-backed development recipes stored in
content/recipes/ - Example:
node -e "import('./dist/tools/recipes.js').then(m=>m.swiftRecipeLookup({queryOrId:'video overlay'})).then(r=>console.log(JSON.stringify(r,null,2)))"
- Input:
Docker
- Build:
docker build -t swift-mcp-server . - Run:
docker run --rm -it swift-mcp-server - Note: This base image does not include Swift formatters/linters. The server degrades gracefully if binaries are missing. Extend the image if you need them.
Full Docker image (with tools)
- Build:
npm run docker:build:full(uses Dockerfile.full) - Run:
npm run docker:run:full- Mounts
.cachesoswift_update_syncpersists across runs
- Mounts
- Includes:
swift-format,swiftformat,swiftlintbuilt for Linux - Base:
swift:6.0-jammywith Node 20 installed
Notes:
- Building Swift tools from source can take several minutes on first build.
- The runtime image includes the Swift runtime by using the
swift:6.0-jammybase.
MCP wiring
- Most MCP clients accept a stdio command. Example:
node /ABSOLUTE/PATH/swift-mcp-server/dist/server.js
Cache & Offline
- Run
swift_update_syncfirst to populate.cachewithswift-evolutionandswift-book.swift_docs_searchandswift_evolution_lookupuse this cache. - For Apple/HIG:
- Place DocC/Dash docsets under
.cache/apple-docs/<Framework>/...or runswift_update_syncto fetch a small HIG snapshot into.cache/hig. - Alternatively use
apple_docsets_importto ingest content and reindex automatically. - Curated patterns live in
content/patterns/*.yamland symbol aliases incontent/symbols/aliases.yaml. - A scheduled workflow refreshes HIG weekly; use
workflow_dispatchto run it on-demand. - The first successful
swift_update_syncwill build a MiniSearch index for Apple docs into.cache/index/apple-docs.json. - The sync also builds HIG (
.cache/index/hig.json) and patterns (.cache/index/patterns.json) indexes for the hybrid search tool. - A small sample DocC page is bundled under
content/sample-docc/and is copied into.cache/apple-docs/byswift_update_syncto enable CI smoke tests and local try-outs.
- Place DocC/Dash docsets under
Contributing Content
Patterns (
content/patterns/*.yaml):- Fields:
id: string(unique),title: string,tags?: string[],summary?: string,snippet?: string (multiline with |),takeaways?: string[]. - Keep IDs stable; use kebab-case (e.g.,
appkit-child-window-attach). - After adding, run
npm run build && node dist/tools/update.jsto reindex.
- Fields:
Symbol Aliases (
content/symbols/aliases.yaml):- Map canonical symbol -> list of aliases/selectors (e.g.,
NSWindow.makeFirstResponder:->-[NSWindow makeFirstResponder:]). - Used by
swift_symbol_lookupand improves Apple docs resolution.
- Map canonical symbol -> list of aliases/selectors (e.g.,
Apple DocC / Dash Docsets (
.cache/apple-docs/<Framework>/...):- Place DocC JSON or Dash-extracted content under framework subfolders (AppKit/SwiftUI/Foundation/etc.).
- Run
swift_update_syncto index. Bundled samples provide minimal Apple coverage for CI/local dev.
Known Limitations
HIG content requires JavaScript: The Apple HIG pages are JavaScript-rendered SPAs. The cached HTML contains "This page requires JavaScript" placeholders instead of actual content. A headless browser scraper would be needed for full HIG support.
Patterns and Recipes are user-defined: The
cocoa_patterns_searchandswift_recipe_lookuptools return empty results by default. These are designed for user-contributed content:- Add patterns to
content/patterns/*.yaml - Add recipes to
content/recipes/*.yaml - Run
swift_update_syncto reindex after adding content.
- Add patterns to
Apple docs require population: The Apple docs index starts empty. Populate it by:
- Running
apple_docs_populatetool with specific frameworks - Using
apple_docsets_importto import DocC/Dash content - Placing DocC JSON files under
.cache/apple-docs/<Framework>/
- Running
Troubleshooting
Empty Apple results:
- Ensure
.cache/apple-docs/contains DocC JSON (runswift_update_syncto seed samples). - Check
.cache/index/apple-docs.jsonexists; if not, re-runswift_update_sync. - If ingesting docsets, try
apple_docsets_importand thenindex_status.
- Ensure
Empty hybrid results:
- Ensure indexes exist in
.cache/index/(apple-docs, hig, patterns, hybrid). Re-runswift_update_sync. - Verify filters aren’t too narrow (try without
kinds/topics/tags).
- Ensure indexes exist in
HIG fetch failures:
- Non-fatal. The sync is best-effort; you can manually place HTML/MD into
.cache/hig/and re-run the sync to index.
- Non-fatal. The sync is best-effort; you can manually place HTML/MD into
Swift tools missing:
- Install via Homebrew (
brew install swift-format swiftformat swiftlint) or use the full Docker image.
- Install via Homebrew (
CI / Release Quick Reference
CI (
.github/workflows/ci.yml):- macOS runner; caches npm and Homebrew; runs
npm ci, build, smoke tests (docs/evolution/format/lint),swift_update_sync, and hybrid smoke tests (class + method).
- macOS runner; caches npm and Homebrew; runs
Weekly Refresh (
.github/workflows/refresh-cache.yml):- Scheduled Mondays 06:00 UTC (and manual) to run
swift_update_syncand keep caches/indexes fresh.
- Scheduled Mondays 06:00 UTC (and manual) to run
Release (
.github/workflows/release.yml):- Trigger: tag push
v*.*.*. - Builds
dist/and attachesdist.tar.gzto a GitHub Release. - Builds and pushes the full Docker image to GHCR as
ghcr.io/<owner>/swift-mcp-server:{tag},latest. - Permissions:
contents: write,packages: write(usesGITHUB_TOKEN).
- Trigger: tag push
Examples
- Hybrid Apple class search (with facets):
node -e "import('./dist/tools/hybrid.js').then(m=>m.hybridSearch({query:'NSWindow', sources:['apple'], frameworks:['AppKit'], limit:5})).then(r=>console.log(JSON.stringify(r,null,2)))"
- Hybrid Apple method search with kind filter:
node -e "import('./dist/tools/hybrid.js').then(m=>m.hybridSearch({query:'performKeyEquivalent', sources:['apple'], frameworks:['AppKit'], kinds:['method'], limit:5})).then(r=>console.log(JSON.stringify(r,null,2)))"
See docs/quickstart.md for a quick setup, and docs/recipes/video_overlay.md for an end-to-end overlay module walkthrough.
See CONTRIBUTING.md for guidelines on adding content and tools.
Installing Swift
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/gzaal/swift-mcp-serverFAQ
Is Swift MCP free?
Yes, Swift MCP is free — one-click install via Unyly at no cost.
Does Swift need an API key?
No, Swift runs without API keys or environment variables.
Is Swift hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Swift in Claude Desktop, Claude Code or Cursor?
Open Swift on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectCompare Swift with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
