🧩

SwiftでMCPを実装する方法

に公開

概要

この記事では、UUIDv7ジェネレーターMCPを実装することで、SwiftでのModel Context Protocol (MCP) の実装方法を紹介します。

作り方

プロジェクト作成

まずはSwiftパッケージを作成します:

$ mkdir /path/to/uuid-v7-swift-mcp
$ cd /path/to/uuid-v7-swift-mcp
$ swift package init --type executable --name uuid-v7-mcp
Creating executable package: uuid-v7-mcp
Creating Package.swift
Creating .gitignore
Creating Sources/
Creating Sources/main.swift

Package.swiftの設定

パッケージの依存関係を追加します:

Package.swift
// swift-tools-version: 6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "uuid-v7-mcp",
+   platforms: [.macOS(.v15)],
+   dependencies: [
+       .package(url: "https://github.com/modelcontextprotocol/swift-sdk.git", from: "0.7.1")
+   ],
    targets: [
        // Targets are the basic building blocks of a package, defining a module or a test suite.
        // Targets can depend on other targets in this package and products from dependencies.
        .executableTarget(
            name: "UUIDv7MCP",
+           dependencies: [
+               .product(name: "MCP", package: "swift-sdk"),
+           ]
        )
    ]
)

UUIDv7の実装

まずはUUIDv7を生成するための拡張を作成します。UUIDv7はタイムスタンプベースのUUIDで、ミリ秒単位の現在時刻を上位ビットに含めることで時系列順にソート可能なUUIDを生成します:

Sources/UUID+v7.swift
import Foundation

extension UUID {
    static func v7(now: Date) -> Self {
        var value = UUID().uuid

        // 現在のタイムスタンプ[ms]
        let timestamp: Int = .init(now.timeIntervalSince1970 * 1000)

        // タイムスタンプを48ビットに分割して上位バイトに格納
        value.0 = .init((timestamp >> 40) & 0xFF)
        value.1 = .init((timestamp >> 32) & 0xFF)
        value.2 = .init((timestamp >> 24) & 0xFF)
        value.3 = .init((timestamp >> 16) & 0xFF)
        value.4 = .init((timestamp >> 8) & 0xFF)
        value.5 = .init(timestamp & 0xFF)

        // バージョン(7)とバリアントビットを設定
        value.6 = (value.6 & 0x0F) | 0x70  // バージョン7を設定
        value.8 = (value.8 & 0x3F) | 0x80  // RFCに準拠したバリアントビットを設定

        return .init(uuid: value)
    }
}

MCPサーバーの実装

次にMCPサーバーの実装を行います。以下のコードではMCPサーバーを定義し、UUIDv7を生成するツールを登録しています:

Sources/main.swift
import Foundation
import Logging
import MCP

let server = Server(name: "UUID v7 Generator", version: "1.0.0")
let transport = StdioTransport()

enum UUIDv7を生成: Sendable {
    static let name = "generate_uuid_v7"
    static let tool: MCP.Tool = .init(
        name: Self.name,
        description:
            "UUIDv7を指定されたcountの数だけ生成し、[UUID]を返します。countが指定されない場合1つだけ生成します。",
        inputSchema: .object([
            "type": "object",
            "properties": [
                "count": [
                    "description": "生成するUUIDの個数。1以上またはnil",
                    "type": "number",
                ]
            ],
        ])
    )
    static func handle(params: CallTool.Parameters) async throws -> CallTool.Result {
        let count = params.arguments?["count"]?.intValue ?? 1
        guard count >= 1 else {
            throw MCPError.invalidParams("countはnilまたは1以上である必要があります。")
        }

        let now = Date()
        let result: [UUID] = (1...count).map { _ in .v7(now: now) }
        return .init(content: [.text("\(result)")])
    }
}

await server.withMethodHandler(ListResources.self) { _ in .init(resources: []) }
await server.withMethodHandler(ListPrompts.self) { _ in .init(prompts: []) }
await server.withMethodHandler(ListTools.self) { params in
    .init(tools: [UUIDv7を生成.tool])
}
await server.withMethodHandler(CallTool.self) { params in
    switch params.name {
    case UUIDv7を生成.name: try await UUIDv7を生成.handle(params: params)
    default: throw MCPError.methodNotFound(nil)
    }
}

try await server.start(transport: transport)
await server.waitUntilCompleted()

ビルド

実行ファイルをビルドします。以下のコマンドでリリースビルドを作成します:

cd /path/to/uuid-v7-swift-mcp
swift build -c release

Claude Desktop設定

Claude Desktopの設定ファイルにMCPサーバーを追加します。設定ファイルは以下の場所にあります:

/Users/<ユーザー名>/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "uuidv7": {
      "command": "/path/to/uuid-v7-swift-mcp/.build/release/UUIDv7MCP"
    }
  }
}

結果

以下のように、Claude Desktopから実際にUUIDv7を生成できました。AIアシスタントがツールを呼び出し、結果を表示しています。

サーバーのログからも、MCPが正しく動作していることが確認できます。下記のログでは、Claude DesktopがMCPサーバーに接続し、ツールの一覧を取得した後、実際にUUIDv7を7個生成するリクエストを送信して結果を受け取っているのが分かります。

/Users/<ユーザー名>/Library/Logs/Claude/mcp-server-uuidv7.log
2025-04-06T16:30:05.351Z [uuidv7] [info] Initializing server...
2025-04-06T16:30:05.390Z [uuidv7] [info] Server started and connected successfully
2025-04-06T16:30:05.391Z [uuidv7] [info] Message from client: {"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"claude-ai","version":"0.1.0"}},"jsonrpc":"2.0","id":0}
2025-04-06T16:30:05.398Z [uuidv7] [info] Message from server: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{},"protocolVersion":"2024-11-05","serverInfo":{"name":"UUID v7 Generator","version":"1.0.0"}}}
...
# ここでClaudeがツールリストを取得
2025-04-06T16:30:05.639Z [uuidv7] [info] Message from client: {"method":"tools/list","params":{},"jsonrpc":"2.0","id":2}
2025-04-06T16:30:05.646Z [uuidv7] [info] Message from server: {"jsonrpc":"2.0","id":2,"result":{"tools":[{"description":"UUIDv7を指定されたcountの数だけ生成し、[UUID]を返します。countが指定されない場合1つだけ生成します。","inputSchema":{"properties":{"count":{"description":"生成するUUIDの個数。1以上またはnil","type":"number"}},"type":"object"},"name":"generate_uuid_v7"}]}}
...
# ここでUUIDを7個生成するリクエストが来て、結果を返している
2025-04-06T16:30:15.350Z [uuidv7] [info] Message from client: {"method":"tools/call","params":{"name":"generate_uuid_v7","arguments":{"count":7}},"jsonrpc":"2.0","id":11}
2025-04-06T16:30:15.361Z [uuidv7] [info] Message from server: {"jsonrpc":"2.0","id":11,"result":{"content":[{"text":"[01960C95-860B-7214-AE41-B0082D47E3F3, 01960C95-860B-7F1C-9505-9FE1165128A3, 01960C95-860B-71BF-9DA7-F2BAF297E5FB, 01960C95-860B-7FF2-8035-FC68207A196D, 01960C95-860B-741B-9AD3-56C1B0442E75, 01960C95-860B-74E6-AC81-2C5DA0B4F397, 01960C95-860B-72BB-99E5-8E1629D3591C]","type":"text"}]}}
...

あとがき

Model Context Protocolは比較的シンプルな概念ですが、Claudeに認識されるまでが詰まりました。また、Swift SDKの現状では、ListToolsハンドラが自動生成されなかったり、Method Protocolの定義は整っているものの実際の呼び出しはCallToolハンドラで処理する必要があったりと面倒なところもあります。

今回、MCPの作り方を知ったことで、作りたいMCPがたくさん浮かび上がってきました。意外とAIにそんなに興味なくてもワクワクできる概念なのでMCP一度作ってみてもいいのではないかと思います。

https://github.com/lemo-nade-room/uuid-v7-swift-mcp

nextbeat Tech Blog

Discussion