关于 SwiftMCP
SwiftMCP 是用 Swift 实现的 MCP 框架,基于 JSON-RPC 2.0,支持 stdio、HTTP+SSE 与 TCP+Bonjour 等多种传输方式。它面向希望用 Swift 构建 MCP 服务或客户端的开发者,通过宏声明工具、资源和提示词。
主要功能
- 01支持 stdio、HTTP+SSE 与 TCP+Bonjour 传输
- 02通过 @MCPTool 等宏声明工具、资源与提示词
- 03内置授权与可选的 OAuth 令牌验证
- 04可根据服务生成类型化客户端代理
- 05通过 SwiftPM 特性开关按需裁剪依赖
适用场景
- 01用 Swift 编写可通过命令行被 MCP 客户端调用的工具服务
- 02为 Web 应用提供基于 HTTP+SSE 的 MCP 服务
- 03为无法直接访问的远程 MCP 服务生成 Swift 客户端代理
MCP 相关
既可作为 MCP 服务端,将 @MCPTool、@MCPResource 与 @MCPPrompt 声明的工具、资源和提示词暴露给 MCP 客户端;也包含客户端 MCPServerProxy,用于连接其他 MCP 服务。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
SwiftMCP
Swift 实现的 MCP(Model Context Protocol),支持通过多种传输方式使用 JSON-RPC。
功能
- 多种传输选项
- 用于命令行的标准输入/输出(stdio)
- 用于 Web 应用的 HTTP+SSE(Server-Sent Events)
- 用于通过原始 TCP 进行本地发现的 TCP+Bonjour
- 符合 JSON-RPC 2.0,并支持生成 OpenAPI
- 内置授权和可选的 OAuth 验证
- 支持 MCP 和 OpenAPI 的透明 OAuth 代理模式
- 跨平台兼容
服务端功能
- 工具 – 使用
@MCPTool暴露函数 - 资源 – 使用
@MCPResource发布数据 - 提示词 – 使用
@MCPPrompt构建提示词 - 实用功能
- 通过
RequestContext.current发送进度通知 - 通过
Session.current流式传输结构化日志 - 为参数提供补全建议(为
Bool和CaseIterable提供默认值)
- 通过
客户端功能
- 根目录 – 由客户端公布的动态文件系统根目录
- 采样 – 请求客户端文件的小型预览
安装
将 SwiftMCP 添加为 Package.swift 中的依赖项:
dependencies: [
.package(url: "https://github.com/Cocoanetics/SwiftMCP.git", branch: "main")
]
Package traits
SwiftMCP 将可选功能领域作为 SwiftPM package traits 提供,默认全部启用——现有使用方和普通的 swift build 均不受影响。单一的 import SwiftMCP 模块保持不变。
| Trait | 启用内容 | 额外依赖 |
|---|---|---|
Server | HTTP/SSE + TCP 服务端传输 | swift-nio, swift-crypto, swift-certificates |
Client | MCP 客户端(MCPServerProxy) | — |
OpenAPI | OpenAPI / AI 插件清单模型和路由 | — |
工具/Schema 基础功能——JSONValue、JSONSchema、MCPToolProviding、@MCPTool / @MCPServer 宏、错误——始终包含在核心中,无需启用 trait。
禁用 Server 会完全移除 swift-nio(以及 swift-crypto/swift-certificates),使软件包可在 Windows 上构建,并为仅使用客户端/工具的使用方提供更轻量的依赖图。仅与远程 MCP 服务通信的使用方只需选择所需功能(你的清单必须使用 swift-tools-version: 6.1 或更高版本才能选择 traits):
.package(
url: "https://github.com/Cocoanetics/SwiftMCP.git",
branch: "main",
traits: ["Client"] // tool/schema core + client, no swift-nio
)
AppIntents 桥接(
@MCPAppIntentTool、AppShortcuts 发现)不是 trait:它已由#if canImport(AppIntents)控制,因此在不支持 AppIntents 的平台(Linux、Windows、Android)上会自动排除。
使用方法
命令行演示
随附的演示应用展示了如何通过不同的传输选项使用 SwiftMCP:
# Using stdio transport
SwiftMCPDemo stdio
# Using HTTP+SSE transport
SwiftMCPDemo httpsse --port 8080
# Using HTTP+SSE with authorization
SwiftMCPDemo httpsse --port 8080 --token your-secret-token
# Using HTTP+SSE with OpenAPI support
SwiftMCPDemo httpsse --port 8080 --openapi
# Using HTTP+SSE with authorization and OpenAPI support
SwiftMCPDemo httpsse --port 8080 --token your-secret-token --openapi
# Using HTTP+SSE with OAuth (JSON config)
SwiftMCPDemo httpsse --port 8080 --oauth oauth-config-example.json
# Using TCP+Bonjour transport
SwiftMCPDemo tcp --name "SwiftMCP Demo"
# Using HTTP+SSE plus TCP+Bonjour in parallel
SwiftMCPDemo httpsse --port 8080 --tcp
通过 HTTP+SSE 传输使用 --token 选项时,客户端必须在请求中包含 Authorization 标头:
Authorization: Bearer your-secret-token
OpenAPI 支持
--openapi 选项会启用用于 AI 插件集成的 OpenAPI 端点。使用此选项时,服务端会在 /openapi.json 提供 OpenAPI 规范,并在 /.well-known/ai-plugin.json 提供 AI 插件清单。这使其能够轻松集成支持 OpenAPI 的 AI 模型和其他工具。
OAuth 支持
使用 OAuthConfiguration 配置 HTTPSSETransport 后,传输层会通过配置的 OAuth 提供方验证传入的 bearer token。
验证可以使用 introspection 端点;如果 introspection 不可用,也可以根据提供方的 JWKS 检查 JWT claims。传输层还会在 /.well-known/oauth-authorization-server 和 /.well-known/oauth-protected-resource 提供元数据,供客户端发现。
进度、日志、根目录和采样
SwiftMCP 可在工具运行时发送进度更新、向已连接的客户端流式传输结构化日志消息、处理由客户端公布的动态文件系统根目录,以及请求小型数据样本用于预览。有关这些功能的简单实现,请参阅演示服务端。doc:ServerCapabilities 和 doc:Sampling 文章详细介绍了相关 API。
自定义服务实现
要实现自己的 MCP 服务:
- 将
@MCPServer宏附加到 class 或 actor 等引用类型 - 使用
@MCPTool属性定义工具 - 选择并配置传输方式(stdio、HTTP+SSE 或 TCP+Bonjour)
示例:
@MCPServer
class MyServer {
@MCPTool
func add(a: Int, b: Int) -> Int {
return a + b
}
}
// Using HTTP+SSE transport with authorization
let server = MyServer()
let transport = HTTPSSETransport(server: server, port: 8080)
// Optional: Add authorization
transport.authorizationHandler = { token in
guard let token = token, token == "your-secret-token" else {
return .unauthorized("Invalid token")
}
return .authorized
}
// Or configure OAuth validation
transport.oauthConfiguration = OAuthConfiguration(
issuer: URL(string: "https://example.com")!,
authorizationEndpoint: URL(string: "https://example.com/authorize")!,
tokenEndpoint: URL(string: "https://example.com/oauth/token")!,
introspectionEndpoint: URL(string: "https://example.com/oauth/introspect")!,
jwksEndpoint: URL(string: "https://example.com/.well-known/jwks.json")!,
audience: "your-api-identifier",
clientID: "client",
clientSecret: "secret"
)
try transport.run()
要改为使用 TCP+Bonjour 提供服务:
let server = MyServer()
let tcpTransport = TCPBonjourTransport(server: server)
try await tcpTransport.run()
类型化客户端代理
SwiftMCP 可以为任何服务生成类型化客户端代理。此代理会镜像
@MCPTool、@MCPResource 和 @MCPPrompt 的签名,并通过
MCPServerProxy 转发调用。在服务宏上设置 generateClient: true 即可启用。
@MCPServer(generateClient: true)
actor Calculator {
@MCPTool
func add(a: Int, b: Int) -> Int {
a + b
}
}
let url = URL(string: "http://localhost:8080/mcp")!
let config = MCPServerConfig.sse(config: MCPServerSseConfig(url: url))
let proxy = MCPServerProxy(config: config)
try await proxy.connect()
let client = Calculator.Client(proxy: proxy)
let result = try await client.add(a: 2, b: 3)
使用 TCP+Bonjour 进行发现:
let config = MCPServerConfig.tcp(config: MCPServerTcpConfig(instanceName: "SwiftMCP Demo"))
let proxy = MCPServerProxy(config: config)
try await proxy.connect()
发现范围
每个 MCP 服务都通过单一服务类型 _mcp._tcp 发布。身份由 Bonjour 实例名称标识,而该名称的可见范围只需做一个决定:
| 范围 | 可见范围 | 基础名称为 Post 时的发布名称 |
|---|---|---|
.localUser (默认) | 回环,名称按用户限定 | Post (oliver) |
.localMachine | 回环,不限定名称 | Post |
.localNetwork | 所连接的网络链路,不限定名称 | Post |
只有 .localUser 会修饰名称,而且这样做仅仅是因为客户端和服务端两端都能推导出该修饰信息——客户端和服务端位于同一台机器上,且属于同一用户。名称不会按主机限定:DNS-SD 已能将服务解析到其目标主机,而且机器重命名时主机名也会改变。两台机器发布同一名称时,mDNS 会将第二个名称改为 Post (2),以此区分。
范围会同时控制绑定、发布和浏览,因此服务的发布范围绝不会大于其服务范围。客户端和服务端传入相同的基础名称,由范围来推导其余部分:
// server
let transport = TCPBonjourTransport(server: server) // .localUser
// client
let config = MCPServerTcpConfig(instanceName: server.serverName) // .localUser
.localUser 是默认值,因为实例名称的作用范围是整台机器:否则,运行同一服务的两个账户会发生名称冲突,而第二个用户的客户端可能会在无提示的情况下连接到第一个用户的进程。该设置可避免这种错误绑定——但它不是访问边界,因为机器上的所有账户都能访问回环套接字。如有需要,请进行身份验证。
.localNetwork 需显式启用——TCP 传输没有授权钩子,因此除非你添加自己的安全层,否则任何可访问该服务的对象都能在未经身份验证的情况下连接。
无法使用服务发现时,可直接连接并跳过发现:
let config = MCPServerTcpConfig(host: "127.0.0.1", port: 8181)
注意:
- 客户端生成需显式启用(
generateClient默认为false)。 - 客户端方法始终会
throw,以便呈现传输或服务端错误。 - 对于新客户端,优先使用 Streamable HTTP
/mcp端点。为保持向后兼容,旧版/sse端点仍可使用。
客户端通知处理器
MCPServerProxy 还可以接收服务端发出的类型化 JSON-RPC 通知。
对于自定义应用/领域事件,请使用 setNotificationHandler(_:as:handler:);
对于内置的便捷处理方式,请使用 setLogNotificationHandler(_:) /
setProgressNotificationHandler(_:)。
struct RunStatusUpdate: Codable, Sendable {
let runID: String
let status: String
}
await proxy.setNotificationHandler("notifications/runStatusChanged", as: RunStatusUpdate.self) { update in
print("Run \(update.runID) is now \(update.status)")
}
SwiftMCPUtility 代理生成
使用 SwiftMCPUtility generate-proxy 为任何 MCP 服务生成客户端代理,
包括非 SwiftMCP 服务。生成的代理会在底层调用 MCPServerProxy,根据 MCP 工具架构生成类型化工具方法,并在服务端发布相应功能时,提供一流的资源/提示词便捷 API。
输入参数根据服务端的工具架构推断,只有 date-time、uri、uuid 和 byte 等字符串格式才能映射为原生类型(Date、URL、UUID、Data)。
SwiftMCPUtility generate-proxy --sse http://localhost:8080/mcp -o ToolsProxy.swift
所有生成的方法都是 async throws,以便呈现传输和服务端错误。
OpenAPI 返回类型
如果 MCP 服务公开了 OpenAPI JSON 文档,请将其 URL(或文件路径)
传递给 --openapi,以丰富返回类型。生成器会将 OpenAPI 响应
架构叠加到 MCP 工具列表上,为结构化响应生成 Codable 结构体和枚举,
并在代理的返回签名中使用这些类型。
SwiftMCPUtility generate-proxy \
--sse http://localhost:8080/mcp \
--openapi http://localhost:8080/openapi.json \
-o ToolsProxy.swift
生成的 Codable 类型可直接使用;如果你有本地定义,也可以稍后替换为自己的模型。
文档提取
@MCPServer 和 @MCPTool 宏会提取文档注释,用于描述类、参数和返回值。
宏功能
此仓库中的宏为在 SwiftMCP 框架中定义和公开工具及服务提供功能。以下是这些宏的主要功能:
@MCPServer:此宏用于将类或 actor 定义为 MCP 服务。它会从文档注释(或可选的description:覆盖项)中提取服务描述。可以在Demos/SwiftMCPDemo/Calculator.swift文件中看到使用示例,其中Calculatoractor 使用@MCPServer(name: "SwiftMCP Demo")注解。@MCPTool:此宏用于定义 MCP 服务中可作为工具调用的函数。它还会提取文档注释,用于描述函数、参数和返回值。可以在Demos/SwiftMCPDemo/Calculator.swift文件中看到使用示例,其中add、subtract、testArray、multiply、divide、greet、ping和noop等函数都使用了@MCPTool注解。@MCPResource:此宏用于通过 URI 模板公开只读数据。资源允许客户端使用带有路径和查询参数的结构化 URI 访问数据。该宏会自动生成必要的基础设施,以便将 URI 与模板匹配并提取参数。
使用 @MCPResource
@MCPResource 宏允许你将函数公开为可通过 URI 模式访问的资源:
@MCPServer(name: "ResourceServer")
actor ResourceServer {
/// Get user profile by ID
@MCPResource("users://{user_id}/profile")
func getUserProfile(user_id: Int) -> String {
return "Profile for user \(user_id)"
}
/// Search users with pagination
@MCPResource("users://search?q={query}&page={page}", mimeType: "application/json")
func searchUsers(query: String, page: Int = 1) -> String {
return """
{"query": "\(query)", "page": \(page), "results": [...]}
"""
}
}
主要功能:
- URI 模板:使用花括号
{param}中的占位符定义模式 - 路径参数:从 URI 路径中提取值(例如,
/users/{id}) - 查询参数:从查询字符串中提取值(例如,
?page={page}) - 可选参数:支持为可选参数设置默认值
- MIME 类型:可使用
mimeType参数指定内容类型 - 类型安全:参数会自动转换为正确的 Swift 类型
服务会自动提供:
- 通过
mcpResourceTemplates发现资源 - URI 匹配和参数提取
- 类型转换和验证
- 对缺失或无效参数进行错误处理
这些宏有助于自动生成 MCP 服务及其工具所需的元数据和文档,从而更轻松地通过 JSON-RPC 通信将它们公开,并与 AI 模型集成。
许可证
本项目采用 BSD 2-clause 许可证授权,详情请参阅 LICENSE 文件。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。