内容
# Swift MCP 服务器
一个 [模型上下文协议](https://modelcontextprotocol.io) 服务器,为 AI 代理和编辑器提供 **语义** 访问 Swift 代码的功能。它通过 `stdio` 或 HTTP 公开 SourceKit-LSP — 苹果官方的语言服务器 — 以便客户端可以使用编译器的理解来导航、检查、重构和诊断 Swift 代码,而不是使用文本启发式。
## 概述
AI 编程代理读取代码库的方式与搜索框相同:作为文本。对于散文来说,这是可以的,但源代码是一个由声明、引用、类型和一致性组成的图,文本无法看到。从 `grep` 工作的工作代理无法可靠地区分一个 `save()` 和另一个重载,区分一个被隐藏的局部变量和它所隐藏的属性,知道哪些类型符合一个协议,或者在文件中找到一个符号的所有实际用法。
### 问题
当代理从文本中猜测结构时,错误是沉默但昂贵的:
- **破碎的重构** — 查找并替换重命名丢失调用站点在其他文件中,或重写注释和字符串中的匹配文本。
- **错误的导航** — “转到定义”落在无关文件中具有相同名称的符号上。
- **错过关系** — 代理无法回答“谁调用此?”或“什么实现了此协议?”而无需阅读整个项目并且仍然进行猜测。
### 解决了什么
服务器将每个请求路由到 SourceKit-LSP 并返回编译器的答案,而不是文本匹配:
- **安全、整个工作区范围的重命名**,更新每个真正的引用,而不仅仅是其他内容。
- **精确导航** — 准确的定义、实现和引用由类型检查器解析。
- **结构理解** — 调用和类型层次结构,以便代理在不读取每个文件的情况下掌握大型代码库的组织结构。
- **编译器诊断和修复** — 读取实际错误,然后应用编译器建议的修复。
简而言之,它将“从文本中猜测”转变为“查询编译器”。
服务器故意设计得很小:它只封装了真正需要语言服务器的操作。LLM 已经可以很好地从源文本完成的所有操作 — 摘要、解释、代码生成 — 故意留给客户端,这使得每个工具都基于真正的编译器语义。
## 需求
- 带有 Xcode 工具链的 macOS
- Swift 5.9 或更高版本用于构建
- `sourcekit-lsp` 可通过 Xcode 或 `PATH` 获得(与工具链捆绑)
每个工具都依赖于 SourceKit-LSP。核心导航工具适用于任何最近的工具链;索引支持的工具(`search_workspace_symbols`、`rename_symbol`、`call_hierarchy`、`type_hierarchy`、`get_implementations`)和 `code_actions` 修复最好与当前工具链(Xcode 16 / Swift 6 或更高版本)一起使用,该工具链提供了它们所依赖的后台索引。
## 安装
```bash
swift build --configuration release
```
二进制文件生成在 `.build/release/swift-mcp-server`。
## 用法
通过 STDIO 运行(适用于编辑器和 AI 客户端):
```bash
.build/release/swift-mcp-server --transport stdio --workspace /path/to/project
```
通过 HTTP 运行(适用于本地 API 使用和测试):
```bash
.build/release/swift-mcp-server --transport http --workspace /path/to/project --port 8080
```
工作区可以通过 `--workspace <path>` 或作为位置参数传递。还提供了一个帮助脚本:
```bash
./swift-mcp.sh build
./swift-mcp.sh health
./swift-mcp.sh stdio
```
### 客户端配置
将任何支持 `stdio` 的 MCP 客户端指向生成的二进制文件:
```json
{
"mcp": {
"servers": {
"swift-mcp-server": {
"command": "/path/to/swift-mcp-server/.build/release/swift-mcp-server",
"args": ["--transport", "stdio", "--workspace", "/path/to/project"]
}
}
}
}
```
此配置适用于任何本地 MCP 客户端,包括 Claude Code / Claude Desktop 和 Cursor / VS Code 样式的设置。一个现成的示例位于 [`vscode-mcp-config.json`](vscode-mcp-config.json)。
## 工具
所有工具都由 SourceKit-LSP 支持。行和字符参数均为 **0-based**。
**导航和搜索**
| 工具 | 用途 | 参数 |
| --- | --- | --- |
| `find_symbols` | 列出文件中声明的符号,按名称过滤 | `file_path`、`name_pattern` |
| `search_workspace_symbols` | 在整个工作区中按名称查找符号 | `query` |
| `find_references` | 查找位置处符号的所有引用 | `file_path`、`line`、`character` |
| `get_definition` | 解析位置处符号的定义 | `file_path`、`line`、`character` |
| `get_implementations` | 查找协议要求或方法的具体实现 | `file_path`、`line`、`character` |
**检查**
| 工具 | 用途 | 参数 |
| --- | --- | --- |
| `get_hover_info` | 获取位置处符号的类型和文档 | `file_path`、`line`、`character` |
| `get_diagnostics` | 获取文件的编译器错误和警告 | `file_path` |
**结构**
| 工具 | 用途 | 参数 |
| --- | --- | --- |
| `call_hierarchy` | 函数的调用者(`incoming`)或被调用者(`outgoing`) | `file_path`、`line`、`character`、`direction` |
| `type_hierarchy` | 类型 `supertypes` 或 `subtypes`/conformers | `file_path`、`line`、`character`、`direction` |
**编辑**(写入磁盘)
| 工具 | 用途 | 参数 |
| --- | --- | --- |
| `format_document` | 格式化文件并返回生成的编辑 | `file_path` |
| `rename_symbol` | 在工作区中重命名符号并应用编辑 | `file_path`、`line`、`character`、`new_name` |
| `code_actions` | 列出行上的编译器修复/重构,或按标题应用一个 | `file_path`、`line`、`apply` |
服务器还实现了 `initialize`、`tools/list`、`tools/call`、`resources/list` 和 `resources/read`,并公开了一个描述活动工作区的 `swift://workspace` 资源。
> 索引支持的工具依赖于 SourceKit-LSP 的全局索引。启动后,索引可能仍在构建中,因此这些工具会在返回之前等待一段有限的时间,以便索引准备就绪。服务器还会在启动时在后台预热索引,以便第一个调用不会受到惩罚。`rename_symbol` 和应用的 `code_actions` 会修改磁盘上的文件。
## 语言
所有工具都适用于 Swift,包括 SwiftUI(SwiftUI 代码是普通的 Swift)。
还支持 Objective-C、C 和 C++。服务器根据文件扩展名(`.m` → Objective-C,`.mm` → Objective-C++,`.h` → Objective-C,`.c` → C,`.cpp`/`.cc`/… → C++)从文件扩展名中选择 LSP `languageId`,因此 SourceKit-LSP 将这些文件路由到 `clangd`。C 家族文件还需要工作区中的 `compile_commands.json`,以便 `clangd` 可以解析编译器参数 — 纯 SwiftPM 包不会发出一个,因此为混合 Swift/Objective-C 项目从构建中生成它(例如 Xcode 或 CMake 导出)。
## 工作原理
服务器保持一个绑定到工作区的单个 SourceKit-LSP 会话,并将每个 MCP 工具调用转换为匹配的 LSP 请求:
| 工具 | LSP 请求 |
| --- | --- |
| `find_symbols` | `textDocument/documentSymbol`(按名称过滤) |
| `search_workspace_symbols` | `workspace/symbol` |
| `find_references` | `textDocument/references` |
| `get_definition` | `textDocument/definition` |
| `get_implementations` | `textDocument/implementation` |
| `get_hover_info` | `textDocument/hover` |
| `get_diagnostics` | `textDocument/publishDiagnostics` |
| `call_hierarchy` | `textDocument/prepareCallHierarchy` + `callHierarchy/incomingCalls` \| `outgoingCalls` |
| `type_hierarchy` | `textDocument/prepareTypeHierarchy` + `typeHierarchy/supertypes` \| `subtypes` |
| `format_document` | `textDocument/formatting` |
| `rename_symbol` | `textDocument/rename`(编辑应用于磁盘) |
| `code_actions` | `textDocument/codeAction`(应用的操作将其编辑写入磁盘) |
由于结果来自编译器自己的索引,因此它们反映了真正的语言语义,而不是文本匹配。
## 架构
```text
Sources/
├── SwiftMCPServer/ CLI 入口点和传输引导
├── SwiftMCPCore/ MCP 协议、传输和配置
└── SourceKitLSP/ 独立的 SourceKit-LSP 客户端和语言类型
Tests/
└── SwiftMCPServerTests/ 协议和 SourceKit-LSP 集成测试
```
`SourceKitLSP` 是一个自包含的库(仅依赖于 Foundation 和 swift-log),它公开了 `SwiftLanguageServer` 和 LSP 值类型。它没有 MCP 知识,因此可以作为可重用的 SourceKit-LSP 客户端独立依赖。`SwiftMCPCore` 在其上层实现了 MCP 协议和传输 — 依赖是严格单向的。
## 开发
```bash
swift test
```
测试涵盖了 JSON-RPC / MCP 请求和响应形状、公开的工具表面和 SourceKit-LSP 支持的操作端到端。需要 SourceKit-LSP 的测试在不可用时会自动跳过。
## 备注
- 日志写入 `stderr` 以保持 STDIO MCP 输出的清洁。
- HTTP 模式支持通过 `--port-min` / `--port-max` 自动端口选择。
- 设置 `SOURCEKIT_LSP_PATH` 以使用特定的 `sourcekit-lsp` 二进制文件(例如自定义工具链);否则会探测常见的安装位置。
## 许可证
请参阅 [LICENSE](LICENSE)。