はじめに
「Swift-Selena」(Swift Analyzer MCP Server)を公開しました。MCPの部分は、公式のSwift SDKを利用しています。
「Serena があるのになぜ?」と思われるかもしれません。
Serena
は優れたツールですが、Swift-Selena
はSwiftで実装することで以下を実現しました。自分がMCPを学習したい、実装したい、というモチベーションもありました。
✅ ゼロ設定:Swiftがあれば動く(Python不要、LSP設定不要)
✅ 高速動作:ネイティブビルドによる高速化
✅ 完全な Swift 対応:SwiftSyntax による正確な構文解析
✅ プライバシー重視:完全ローカル実行(外部送信ゼロ) ※ Serena
も同じですが
Swift-Selena
の名称は Serena リスペクトですが、実装は Swiftオリジナルの実装です。
生成 AI による Swift 開発効率化を、よりシンプルに、より高速に実現します。
この記事で分かること
この記事では、Swift SDKを使ったMCP Serverの実装方法を、Swift-Selenaの実装例を交えて解説します。
対象読者:
- Swift でローカル MCP Server を実装したい方
- MCP の仕組みを Swift のコードで理解したい方
- Swift-Selena のような解析ツールを自作したい方
MCP サーバーとは
MCP (Model Context Protocol) は、LLM と外部システムを繋ぐ標準プロトコルです。
USB-C に例えられることが多いです。
- USB-C:様々な機器を接続する標準規格
- MCP:様々なシステムを LLM に接続する標準規格
公式ドキュメント
https://modelcontextprotocol.io/docs/getting-started/intro
Swift-Selena vs Serena
項目 | Swift-Selena | Serena |
---|---|---|
言語 | Swift | Python |
対応言語 | Swift専用 | 多言語(Python, TypeScript, PHP, Go, Java等) |
解析エンジン | SwiftSyntax | LSP (Language Server Protocol) |
セットアップ |
swift build のみ |
Python環境 + LSP設定 |
実行速度 | ネイティブ(高速) | インタープリター |
リポジトリ | BlueEventHorizon/Swift-Selena | oraios/serena |
Swift-Selenaの利点
- 既存の開発環境だけで動作
- SwiftSyntaxによる分析
- ネイティブコンパイルによる高速実行
セットアップがゼロ
# Serena の場合
brew install uv
uv venv
source .venv/bin/activate
uv pip install serena-mcp
# LSP設定ファイルの作成...
# Swift-Selena の場合
swift build --configuration release
# 完了(Swiftは既にインストール済み)
解析精度
SwiftSyntax は Swift コンパイラと同じパーサーを使用しているため:
実装
ここからは、Swift SDK を使った MCP Server の実装方法を、
Swift-Selena のコードを例に見ていきます。
MCP Sereverの機能
MCP Sereverは、MCPを通じてLLMにコンテキストを提供します。
これらのコンテキストには下記の表のように、プロンプト、リソース、ツールの形式があります。
Primitive | Control | Description | Example |
---|---|---|---|
Prompts | User-controlled | あらかじめ定義されたテンプレートや指示で、LLMに指示をする形式 | スラッシュコマンド、メニューオプション |
Resources | Application-controlled | データやコンテンツを返す形式 | ファイルの内容、Git履歴 |
Tools | Model-controlled | アクションを実行したり、情報を返す関数 | 分析情報取得、ファイル書き込み |
初期化
Swift SDKでは、Serverの初期化時にcapabilitiesに対してこのMCP Serverが対応する機能を定義します。
public final class Server: Sendable {
public init(
name: String,
version: String,
capabilities: Capabilities
)
public func start(transport: Transport) async throws
public func withMethodHandler<Method: RequestMethod>(
_ type: Method.Type,
handler: @escaping @Sendable (Method.Params) async throws -> Method.Result
) async
}
下記のようにSwift-Selenaでは、ツールしか対応していません。
これはSwift-Selenaが、機能分析機能が中心ということがあり、他のPrimitiveに対応する意義が薄いからです。
また、ここでは具体的なツールのリストは含まれていません。
単純に「このサーバーはどのPrimitiveに対応しているか」の宣言を行います。
let server = Server(
name: AppConstants.name,
version: AppConstants.version,
capabilities: .init(
tools: .init()
)
)
- tools: .init() → 「ツール機能あり」
- tools: nil → 「ツール機能なし」
機能リストを登録
「具体的にどんなツールがあるか」のリストを登録します。
ツールの登録は、withMethodHandler関数を使って行います。
ここでは、機能実装ではなくツールの説明になるので、下記のようなある意味定型のものになります。
await server.withMethodHandler(ListTools.self) { _ in
ListTools.Result(tools: [
Tool(
name: ToolNames.initializeProject,
description: "Initialize a Swift project for analysis. Must be called first.",
inputSchema: .object([
"type": .string("object"),
"properties": .object([
ParameterKeys.projectPath: .object([
"type": .string("string"),
"description": .string("Absolute path to Swift project root")
])
]),
"required": .array([.string(ParameterKeys.projectPath)])
])
),
Tool(
name: ToolNames.findFiles,
description: "Find Swift files in the project by pattern (glob-like search)",
inputSchema: .object([
"type": .string("object"),
"properties": .object([
ParameterKeys.pattern: .object([
"type": .string("string"),
"description": .string("File name pattern (e.g., '*Controller.swift', 'User*')")
])
]),
"required": .array([.string(ParameterKeys.pattern)])
])
)
// 他15個のツール定義...
// 完全なリストは GitHub を参照
])
}
機能(実行内容)を登録
「ツールが実際に何をするか」という、ツールの実行内容は下記のように登録します。
await server.withMethodHandler(CallTool.self) { params in
switch params.name {
case ToolNames.findFiles:
// パラメータ取得(JSONValueからString抽出)
guard let args = params.arguments,
let patternValue = args[ParameterKeys.pattern],
case .string(let pattern) = patternValue else {
throw MCPError.invalidParams("Missing pattern parameter")
}
// ビジネスロジック実行
let files = try FileSearcher.findFiles(in: projectPath, pattern: pattern)
// 結果を返す
return CallTool.Result(
content: [.text("Found \(files.count) files:\n" + files.joined(separator: "\n"))]
)
case ToolNames.listSymbols:
guard let args = params.arguments,
let filePathValue = args[ParameterKeys.filePath],
case .string(let filePath) = filePathValue else {
throw MCPError.invalidParams("Missing file_path parameter")
}
let symbols = try SwiftSyntaxAnalyzer.listSymbols(filePath: filePath)
let symbolsText = symbols.map { "[\($0.kind)] \($0.name) (line \($0.line))" }
.joined(separator: "\n")
return CallTool.Result(content: [.text(symbolsText)])
default:
throw MCPError.invalidParams("Unknown tool: \(params.name)")
}
}
フロー
Clientからのリクエストを起点とした、全体のフローは下記のようになります。
起動
最後にServerを実行します
// Stdio transport起動
let transport = StdioTransport(logger: logger)
try await server.start(transport: transport)
Swift-Selenaは、Local Server実行ですので、StdioTransportを選択しています。
SDKのアーキテクチャ
ここまでの実装で MCP Server の基本は理解できましたが、
Swift SDK の内部構造にも触れておきます。
SDKの全体構造を見てみましょう。
今までの説明は MCP SDK Layer
の上位2層(Server と Handler)に関連していますが、
MCPの中枢である JSON-RPC Layer
(プロトコルレイヤー)は、
SDKの中に(使う側からすると)隠蔽されています。
レイヤー構造
リクエスト処理フロー
先ほど、Swift-Selena
のServer起動の実装で触れた StdioTransport
は Transport Layer
です。
Transport Layer
もJSON-RPC Layer
と同じく、実装や設定を変更する必要はなく、ほぼ隠蔽されていますが、Transportのインスタンスは選択できます。
Transportの比較
下記に既に用意されているTransport実装を記載します。
特徴 | StdioTransport | HTTPTransport | InMemoryTransport |
---|---|---|---|
通信方式 | stdin/stdout | HTTP/HTTPS | メモリ |
通信特性 | プロセス間通信 | ネットワーク通信 | プロセス内通信 |
I/O | あり(ブロッキング) | あり(非同期) | なし |
パフォーマンス | 高速 | ネットワーク依存 | 最速 |
セットアップ | シンプル | 複雑(エンドポイント設定) | 最もシンプル |
デバッグ | 中(ログで確認) | 難(ネットワークツール必要) | 簡単(メモリ内で完結) |
適用例 | CLIツール、デスクトップアプリ統合 | マイクロサービス、API連携 | ユニットテスト、統合テスト |
認証方式 | プロセス権限 | HTTPヘッダー | 不要 |
SDK実装状態 | 安定版 | 実験的(API変更の可能性) | 安定版 |
※2025年10月13日現在
まとめ
Swift SDK を使えば、短時間で MCP Server を実装できます。
重要なポイント:
- capabilities で機能を宣言:Server 初期化時に対応機能を定義
- ListTools で一覧を返す:利用可能なツールのカタログ
- CallTool で実行:実際のビジネスロジックを実装
ローカル MCP Server の利点:
- ✅ ソースコードが外部に送信されない
- ✅ サーバーインフラ不要(AWS/Azure 等)
- ✅ Swift ネイティブで高速実行
参考リンク
Swift-Selena を試してみたい方は
git clone https://github.com/BlueEventHorizon/Swift-Selena.git
cd Swift-Selena
swift build -c release -Xswiftc -Osize
# Claude Desktop に登録する場合
chmod +x register-mcp-to-claude-desktop.sh
./register-mcp-to-claude-desktop.sh
# Claude Code に登録する場合(特定プロジェクトで使用)
chmod +x register-selena-to-claude-code.sh
./register-selena-to-claude-code.sh /path/to/your/swift/project
完了!Claude Desktop/Code を再起動すれば使えます