📦modelcontextprotocol / swift-sdk
← 返回首页
The official Swift SDK for Model Context Protocol servers and clients. Maintained in collaboration with Apple
⚖️ NOASSERTION#mcp#swift📅 创建于 2025-02-05🔄 更新于 2026-10-31
🔗 GitHub Swift

📄 仓库 README

在 GitHub 查看 ↗
来自 GitHub 仓库自述文件 · 版权归原作者所有

MCP Swift SDK

Official Swift SDK for the [Model Context Protocol][mcp] (MCP).

Overview

The Model Context Protocol (MCP) defines a standardized way for applications to communicate with AI and ML models. This Swift SDK implements both client and server components according to the [2025-11-25][mcp-spec-2025-11-25] (latest) version of the MCP specification.

Table of contents

Requirements

  • Swift 6.0+ (Xcode 16+)

See the Platform Availability section below for platform-specific requirements.

Installation

Swift Package Manager

Add the following to your Package.swift file:

dependencies: [
    .package(url: "https://github.com/modelcontextprotocol/swift-sdk.git", from: "0.11.0")
]

Then add the dependency to your target:

.target(
    name: "YourTarget",
    dependencies: [
        .product(name: "MCP", package: "swift-sdk")
    ]
)

Client Usage

The client component allows your application to connect to MCP servers.

Basic Client Setup

import MCP

// Initialize the client
let client = Client(name: "MyApp", version: "1.0.0")

// Create a transport and connect
let transport = StdioTransport()
let result = try await client.connect(transport: transport)

// Check server capabilities
if result.capabilities.tools != nil {
    // Server supports tools (implicitly including tool calling if the 'tools' capability object is present)
}

[!NOTE] The Client.connect(transport:) method returns the initialization result. This return value is discardable, so you can ignore it if you don't need to check server capabilities.

Transport Options for Clients

Stdio Transport

For local subprocess communication:

// Create a stdio transport (simplest option)
let transport = StdioTransport()
try await client.connect(transport: transport)

HTTP Transport

For remote server communication:

// Create a streaming HTTP transport
let transport = HTTPClientTransport(
    endpoint: URL(string: "http://localhost:8080")!,
    streaming: true  // Enable Server-Sent Events for real-time updates
)
try await client.connect(transport: transport)

Tools

Tools represent functions that can be called by the client:

// List available tools
let (tools, cursor) = try await client.listTools()
print("Available tools: \(tools.map { $0.name }.joined(separator: ", "))")

// Call a tool with arguments and get the result
let (content, isError) = try await client.callTool(
    name: "image-generator",
    arguments: [
        "prompt": "A serene mountain landscape at sunset",
        "style": "photorealistic",
        "width": 1024,
        "height": 768
    ]
)

// Handle tool content
for item in content {
    switch item {
    case .text(let text):
        print("Generated text: \(text)")
    case .image(let data, let mimeType, let metadata):
        if let width = metadata?["width"] as? Int,
           let height = metadata?["height"] as? Int {
            print("Generated \(width)x\(height) image of type \(mimeType)")
            // Save or display the image data
        }
    case .audio(let data, let mimeType):
        print("Received audio data of type \(mimeType)")
    case .resource(let resource, _, _):
        print("Received embedded resource: \(resource)")
    case .resourceLink(let uri, let name, _, _, let mimeType, _):
        print("Resource link: \(name) at \(uri), type: \(mimeType ?? "unknown")")
    }
}

Resources

Resources represent data that can be accessed and potentially subscribed to:

// List available resources
let (resources, nextCursor) = try await client.listResources()
print("Available resources: \(resources.map { $0.uri }.joined(separator: ", "))")

// Read a resource
let contents = try await client.readResource(uri: "resource://example")
print("Resource content: \(contents)")

// Subscribe to resource updates if supported
if result.capabilities.resources?.subscribe == true {
    try await client.subscribeToResource(uri: "resource://example")

    // Register notification handler
    await client.onNotification(ResourceUpdatedNotification.self) { message in
        let uri = message.params.uri
        print("Resource \(uri) updated with new content")

        // Fetch the updated resource content
        let updatedContents = try await client.readResource(uri: uri)
        print("Updated resource content received")
    }
}

Prompts

Prompts represent templated conversation starters:

// List available prompts
let (prompts, nextCursor) = try await client.listPrompts()
print("Available prompts: \(prompts.map { $0.name }.joined(separator: ", "))")

// Get a prompt with arguments
let (description, messages) = try await client.getPrompt(
    name: "customer-service",
    arguments: [
        "customerName": "Alice",
        "orderNumber": "ORD-12345",
        "issue": "delivery delay"
    ]
)

// Use the prompt messages in your application
print("Prompt description: \(description)")
for message in messages {
    if case .text(text: let text) = message.content {
        print("\(message.role): \(text)")
    }
}

Completions

Completions allow servers to provide autocompletion suggestions for prompt and resource template arguments as users type:

// Request completions for a prompt argument
let completion = try await client.complete(
    promptName: "code_review",
    argumentName: "language",
    argumentValue: "py"
)

// Display suggestions to the user
for value in completion.values {
    print("Suggestion: \(value)")
}

if completion.hasMore == true {
    print("More suggestions available (total: \(completion.total ?? 0))")
}

You can also provide context with already-resolved arguments:

// First, user selects a language
let languageCompletion = try await client.complete(
    promptName: "code_review",
    argumentName: "language",
    argumentValue: "py"
)
// User selects "python"

// Then get framework suggestions based on the selected language
let frameworkCompletion = try await client.complete(
    promptName: "code_review",
    argumentName: "framework",
    argumentValue: "fla",
    context: ["language": .string("python")]
)
// Returns: ["flask"]

Completions work for resource templates as well:

// Get path completions for a resource URI template
let pathCompletion = try await client.complete(
    resourceURI: "file:///{path}",
    argumentName: "path",
    argumentValue: "/usr/"
)
// Returns: ["/usr/bin", "/usr/lib", "/usr/local"]

Sampling

Sampling allows servers to request LLM completions through the client, enabling agentic behaviors while maintaining human-in-the-loop control. Clients register a handler to process incoming sampling requests from servers.

[!TIP] Sampling requests flow from server to client, not client to server. This enables servers to request AI assistance while clients maintain control over model access and user approval.

// Register a sampling handler in the client
await client.withSamplingHandler { parameters in
    // Review the sampling request (human-in-the-loop step 1)
    print("Server requests completion for: \(parameters.messages)")

    // Optionally modify the request based on user input
    var messages = parameters.messages
    if let systemPrompt = parameters.systemPrompt {
        print("System prompt: \(systemPrompt)")
    }

    // Sample from your LLM (this is where you'd call your AI service)
    let completion = try await callYourLLMService(
        messages: messages,
        maxTokens: parameters.maxTokens,
        temperature: parameters.temperature
    )

    // Review the completion (human-in-the-loop step 2)
    print("LLM generated: \(completion)")
    // User can approve, modify, or reject the completion here

    // Return the result to the server
    return CreateSamplingMessage.Result(
        model: "your-model-name",
        stopReason: .endTurn,
        role: .assistant,
        content: .text(completion)
    )
}

Elicitation

Elicitation allows servers to request structured information directly from users through the client. This is useful when servers need user input that wasn't provided in the original request, such as credentials, configuration choices, or approval for sensitive operations.

[!TIP] Elicitation requests flow from server to client, similar to sampling. Clients must register a handler to respond to elicitation requests from servers.

Client-Side: Handling Elicitation Requests

Register an elicitation handler to respond to server requests:

```swift // Register an elicitation handler in the client await client.withElicitationHandler { parameters in switch parameters { case .form(let form): // Display the request to the user print("Server requests: (form.message)")

    // If a schema was provided, inspect

📈 近 7 天 Star 趋势

每日新增 Star(柱)与累计 Star(线)· 数据来自 GitHub

🏆 排名变化趋势

在各榜单中的排名历史(数字越小越靠前)

📋 历史上榜记录

每次快照的详细数据
日期 榜单 排名 周期新增 总 STAR