| name | swift-mcp-server-generator |
| description | Generate a complete Model Context Protocol server project in Swift using the official MCP Swift SDK package. |
Swift MCP Server Generator
Generate a complete, production-ready MCP server in Swift using the official Swift SDK package.
Project Generation
When asked to create a Swift MCP server, generate a complete project with this structure:
my-mcp-server/
├── Package.swift
├── Sources/
│ └── MyMCPServer/
│ ├── main.swift
│ ├── Server.swift
│ ├── Tools/
│ │ ├── ToolDefinitions.swift
│ │ └── ToolHandlers.swift
│ ├── Resources/
│ │ ├── ResourceDefinitions.swift
│ │ └── ResourceHandlers.swift
│ └── Prompts/
│ ├── PromptDefinitions.swift
│ └── PromptHandlers.swift
├── Tests/
│ └── MyMCPServerTests/
│ └── ServerTests.swift
└── README.md
Package.swift Template
import PackageDescription
let package = Package(
name: "MyMCPServer",
platforms: [
.macOS(.v13),
.iOS(.v16),
.watchOS(.v9),
.tvOS(.v16),
.visionOS(.v1)
],
dependencies: [
.package(
url: "https://github.com/modelcontextprotocol/swift-sdk.git",
from: "0.10.0"
),
.package(
url: "https://github.com/apple/swift-log.git",
from: "1.5.0"
),
.package(
url: "https://github.com/swift-server/swift-service-lifecycle.git",
from: "2.0.0"
)
],
targets: [
.executableTarget(
name: "MyMCPServer",
dependencies: [
.product(name: "MCP", package: "swift-sdk"),
.product(name: "Logging", package: "swift-log"),
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle")
]
),
.testTarget(
name: "MyMCPServerTests",
dependencies: ["MyMCPServer"]
)
]
)
main.swift Template
import MCP
import Logging
import ServiceLifecycle
struct MCPService: Service {
let server: Server
let transport: Transport
func run() async throws {
try await server.start(transport: transport) { clientInfo, capabilities in
logger.info("Client connected", metadata: [
"name": .string(clientInfo.name),
"version": .string(clientInfo.version)
])
}
try await Task.sleep(for: .days(365 * 100))
}
func shutdown() async throws {
logger.info("Shutting down MCP server")
await server.stop()
}
}
var logger = Logger(label: "com.example.mcp-server")
logger.logLevel = .info
do {
let server = await createServer()
let transport = StdioTransport(logger: logger)
let service = MCPService(server: server, transport: transport)
serviceGroup (
services: [service],
configuration: .(
gracefulShutdownSignals: [.sigterm, .sigint]
),
logger: logger
)
serviceGroup.run()
} {
logger.error(, metadata: [: .string()])
error
}
Server.swift Template
import MCP
import Logging
func createServer() async -> Server {
let server = Server(
name: "MyMCPServer",
version: "1.0.0",
capabilities: .init(
prompts: .init(listChanged: true),
resources: .init(subscribe: true, listChanged: true),
tools: .init(listChanged: true)
)
)
await registerToolHandlers(server: server)
await registerResourceHandlers(server: server)
await registerPromptHandlers(server: server)
return server
}
ToolDefinitions.swift Template
import MCP
func getToolDefinitions() -> [Tool] {
[
Tool(
name: "greet",
description: "Generate a greeting message",
inputSchema: .object([
"type": .string("object"),
"properties": .object([
"name": .object([
"type": .string("string"),
"description": .string("Name to greet")
])
]),
"required": .array([.string("name")])
])
),
Tool(
name: "calculate",
description: "Perform mathematical calculations",
inputSchema: .object([
"type": .string("object"),
"properties": .object([
"operation": .object([
"type": .string("string"),
"enum": .array([
.string("add"),
.string("subtract"),
.string("multiply"),
.string("divide")
]),
"description": .string("Operation to perform")
]),
"a": .object([
"type": .string("number"),
"description": .string("First operand")
]),
: .object([
: .string(),
: .string()
])
]),
: .array([
.string(),
.string(),
.string()
])
])
)
]
}
ToolHandlers.swift Template
import MCP
import Logging
private let logger = Logger(label: "com.example.mcp-server.tools")
func registerToolHandlers(server: Server) async {
await server.withMethodHandler(ListTools.self) { _ in
logger.debug("Listing available tools")
return .init(tools: getToolDefinitions())
}
await server.withMethodHandler(CallTool.self) { params in
logger.info("Tool called", metadata: ["name": .string(params.name)])
switch params.name {
case "greet":
return handleGreet(params: params)
case "calculate":
return handleCalculate(params: params)
default:
logger.warning("Unknown tool requested", metadata: ["name": .string(params.name)])
return .init(
content: [.text("Unknown tool: \(params.name)")],
isError: true
)
}
}
}
private func handleGreet(params: CallTool.) -> . {
name params.arguments[].stringValue {
.(
content: [.text()],
isError:
)
}
greeting
logger.debug(, metadata: [: .string(name)])
.(
content: [.text(greeting)],
isError:
)
}
(: .) -> . {
operation params.arguments[].stringValue,
a params.arguments[].doubleValue,
b params.arguments[].doubleValue {
.(
content: [.text()],
isError:
)
}
result:
operation {
:
result a b
:
result a b
:
result a b
:
b {
.(
content: [.text()],
isError:
)
}
result a b
:
.(
content: [.text()],
isError:
)
}
logger.debug(, metadata: [
: .string(operation),
: .string()
])
.(
content: [.text()],
isError:
)
}
ResourceDefinitions.swift Template
import MCP
func getResourceDefinitions() -> [Resource] {
[
Resource(
name: "Example Data",
uri: "resource://data/example",
description: "Example resource data",
mimeType: "application/json"
),
Resource(
name: "Configuration",
uri: "resource://config",
description: "Server configuration",
mimeType: "application/json"
)
]
}
ResourceHandlers.swift Template
import MCP
import Logging
import Foundation
private let logger = Logger(label: "com.example.mcp-server.resources")
actor ResourceState {
private var subscriptions: Set<String> = []
func addSubscription(_ uri: String) {
subscriptions.insert(uri)
}
func removeSubscription(_ uri: String) {
subscriptions.remove(uri)
}
func isSubscribed(_ uri: String) -> Bool {
subscriptions.contains(uri)
}
}
private let state = ResourceState()
func registerResourceHandlers(server: Server) async {
await server.withMethodHandler(ListResources.self) { params in
logger.debug("Listing available resources")
return .init(resources: getResourceDefinitions(), nextCursor: nil)
}
await server.withMethodHandler(ReadResource.) { params
logger.info(, metadata: [: .string(params.uri)])
params.uri {
:
jsonData
.(contents: [
.text(jsonData, uri: params.uri, mimeType: )
])
:
config
.(contents: [
.text(config, uri: params.uri, mimeType: )
])
:
logger.warning(, metadata: [: .string(params.uri)])
.invalidParams()
}
}
server.withMethodHandler(.) { params
logger.info(, metadata: [: .string(params.uri)])
state.addSubscription(params.uri)
.()
}
server.withMethodHandler(.) { params
logger.info(, metadata: [: .string(params.uri)])
state.removeSubscription(params.uri)
.()
}
}
PromptDefinitions.swift Template
import MCP
func getPromptDefinitions() -> [Prompt] {
[
Prompt(
name: "code-review",
description: "Generate a code review prompt",
arguments: [
.init(name: "language", description: "Programming language", required: true),
.init(name: "focus", description: "Review focus area", required: false)
]
)
]
}
PromptHandlers.swift Template
import MCP
import Logging
private let logger = Logger(label: "com.example.mcp-server.prompts")
func registerPromptHandlers(server: Server) async {
await server.withMethodHandler(ListPrompts.self) { params in
logger.debug("Listing available prompts")
return .init(prompts: getPromptDefinitions(), nextCursor: nil)
}
await server.withMethodHandler(GetPrompt.self) { params in
logger.info("Getting prompt", metadata: ["name": .string(params.name)])
switch params.name {
case "code-review":
return handleCodeReviewPrompt(params: params)
default:
logger.warning("Unknown prompt requested", metadata: ["name": .string(params.name)])
throw MCPError.invalidParams("Unknown prompt: \(params.name)")
}
}
}
private func handleCodeReviewPrompt(params: GetPrompt.Params) -> GetPrompt.Result {
guard let language params.arguments[].stringValue {
.(
description: ,
messages: []
)
}
focus params.arguments[].stringValue
description
messages: [.] [
.user(),
.assistant(),
.user()
]
logger.debug(, metadata: [
: .string(language),
: .string(focus)
])
.(description: description, messages: messages)
}
ServerTests.swift Template
import XCTest
@testable import MyMCPServer
final class ServerTests: XCTestCase {
func testGreetTool() async throws {
let params = CallTool.Params(
name: "greet",
arguments: ["name": .string("Swift")]
)
let result = handleGreet(params: params)
XCTAssertFalse(result.isError ?? true)
XCTAssertEqual(result.content.count, 1)
if case .text(let message) = result.content[0] {
XCTAssertTrue(message.contains("Swift"))
} else {
XCTFail("Expected text content")
}
}
func testCalculateTool() async throws {
let params = CallTool.Params(
name: "calculate",
arguments: [
"operation": .string("add"),
"a": .number(5),
: .number()
]
)
result handleCalculate(params: params)
(result.isError )
(result.content.count, )
.text( message) result.content[] {
(message.contains())
} {
()
}
}
() {
params .(
name: ,
arguments: [
: .string(),
: .number(),
: .number()
]
)
result handleCalculate(params: params)
(result.isError )
}
}
README.md Template
# MyMCPServer
A Model Context Protocol server built with Swift.
## Features
- ✅ Tools: greet, calculate
- ✅ Resources: example data, configuration
- ✅ Prompts: code-review
- ✅ Graceful shutdown with ServiceLifecycle
- ✅ Structured logging with swift-log
- ✅ Full test coverage
## Requirements
- Swift 6.0+
- macOS 13+, iOS 16+, or Linux
## Installation
```bash
swift build -c release
Usage
Run the server:
swift run
Or with logging:
LOG_LEVEL=debug swift run
Testing
swift test
Development
The server uses:
Project Structure
Sources/MyMCPServer/main.swift - Entry point with ServiceLifecycle
Sources/MyMCPServer/Server.swift - Server configuration
Sources/MyMCPServer/Tools/ - Tool definitions and handlers
Sources/MyMCPServer/Resources/ - Resource definitions and handlers
Sources/MyMCPServer/Prompts/ - Prompt definitions and handlers
Tests/ - Unit tests
License
MIT
## Generation Instructions
1. **Ask for project name and description**
2. **Generate all files** with proper naming
3. **Use actor-based state** for thread safety
4. **Include comprehensive logging** with swift-log
5. **Implement graceful shutdown** with ServiceLifecycle
6. **Add tests** for all handlers
7. **Use modern Swift concurrency** (async/await)
8. **Follow Swift naming conventions** (camelCase, PascalCase)
9. **Include error handling** with proper MCPError usage
10. **Document public APIs** with doc comments
## Build and Run
```bash
# Build
swift build
# Run
swift run
# Test
swift test
# Release build
swift build -c release
# Install
swift build -c release
cp .build/release/MyMCPServer /usr/local/bin/
Integration with Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"my-mcp-server": {
"command": "/path/to/MyMCPServer"
}
}
}