swift-mcp-server-generator
작성자: github
공식 SDK를 사용하여 Swift로 완전하고 프로덕션 준비가 된 MCP 서버 프로젝트를 생성합니다. Package.swift, 기능별로 구성된 소스 파일(Tools, Resources, Prompts), 단위 테스트를 포함한 전체 프로젝트 구조를 스캐폴딩합니다. ServiceLifecycle 통합이 포함된 main.swift, Server.swift 구성, 도구, 리소스 및 프롬프트에 대한 핸들러 구현을 위한 템플릿을 제공합니다. 적절한 오류 처리와 함께 예제 도구 정의(greet, calculate) 및 리소스/프롬프트 핸들러를 제공합니다.
npx skills add https://github.com/github/awesome-copilot --skill swift-mcp-server-generatorSwift 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
// swift-tools-version: 6.0
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)
])
}
// Keep service running
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)
let serviceGroup = ServiceGroup(
services: [service],
configuration: .init(
gracefulShutdownSignals: [.sigterm, .sigint]
),
logger: logger
)
try await serviceGroup.run()
} catch {
logger.error("Fatal error", metadata: ["error": .string("\(error)")])
throw 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)
)
)
// Register tool handlers
await registerToolHandlers(server: server)
// Register resource handlers
await registerResourceHandlers(server: server)
// Register prompt handlers
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")
]),
"b": .object([
"type": .string("number"),
"description": .string("Second operand")
])
]),
"required": .array([
.string("operation"),
.string("a"),
.string("b")
])
])
)
]
}
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.Params) -> CallTool.Result {
guard let name = params.arguments?["name"]?.stringValue else {
return .init(
content: [.text("Missing 'name' parameter")],
isError: true
)
}
let greeting = "Hello, \(name)! Welcome to MCP."
logger.debug("Generated greeting", metadata: ["name": .string(name)])
return .init(
content: [.text(greeting)],
isError: false
)
}
private func handleCalculate(params: CallTool.Params) -> CallTool.Result {
guard let operation = params.arguments?["operation"]?.stringValue,
let a = params.arguments?["a"]?.doubleValue,
let b = params.arguments?["b"]?.doubleValue else {
return .init(
content: [.text("Missing or invalid parameters")],
isError: true
)
}
let result: Double
switch operation {
case "add":
result = a + b
case "subtract":
result = a - b
case "multiply":
result = a * b
case "divide":
guard b != 0 else {
return .init(
content: [.text("Division by zero")],
isError: true
)
}
result = a / b
default:
return .init(
content: [.text("Unknown operation: \(operation)")],
isError: true
)
}
logger.debug("Calculation performed", metadata: [
"operation": .string(operation),
"result": .string("\(result)")
])
return .init(
content: [.text("Result: \(result)")],
isError: false
)
}
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.self) { params in
logger.info("Reading resource", metadata: ["uri": .string(params.uri)])
switch params.uri {
case "resource://data/example":
let jsonData = """
{
"message": "Example resource data",
"timestamp": "\(Date())"
}
"""
return .init(contents: [
.text(jsonData, uri: params.uri, mimeType: "application/json")
])
case "resource://config":
let config = """
{
"serverName": "MyMCPServer",
"version": "1.0.0"
}
"""
return .init(contents: [
.text(config, uri: params.uri, mimeType: "application/json")
])
default:
logger.warning("Unknown resource requested", metadata: ["uri": .string(params.uri)])
throw MCPError.invalidParams("Unknown resource URI: \(params.uri)")
}
}
await server.withMethodHandler(ResourceSubscribe.self) { params in
logger.info("Client subscribed to resource", metadata: ["uri": .string(params.uri)])
await state.addSubscription(params.uri)
return .init()
}
await server.withMethodHandler(ResourceUnsubscribe.self) { params in
logger.info("Client unsubscribed from resource", metadata: ["uri": .string(params.uri)])
await state.removeSubscription(params.uri)
return .init()
}
}
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?["language"]?.stringValue else {
return .init(
description: "Missing language parameter",
messages: []
)
}
let focus = params.arguments?["focus"]?.stringValue ?? "general quality"
let description = "Code review for \(language) with focus on \(focus)"
let messages: [Prompt.Message] = [
.user("Please review this \(language) code with focus on \(focus)."),
.assistant("I'll review the code focusing on \(focus). Please share the code."),
.user("Here's the code to review: [paste code here]")
]
logger.debug("Generated code review prompt", metadata: [
"language": .string(language),
"focus": .string(focus)
])
return .init(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),
"b": .number(3)
]
)
let result = handleCalculate(params: params)
XCTAssertFalse(result.isError ?? true)
XCTAssertEqual(result.content.count, 1)
if case .text(let message) = result.content[0] {
XCTAssertTrue(message.contains("8"))
} else {
XCTFail("Expected text content")
}
}
func testDivideByZero() async throws {
let params = CallTool.Params(
name: "calculate",
arguments: [
"operation": .string("divide"),
"a": .number(10),
"b": .number(0)
]
)
let result = handleCalculate(params: params)
XCTAssertTrue(result.isError ?? false)
}
}
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:
- MCP Swift SDK - MCP protocol implementation
- swift-log - Structured logging
- swift-service-lifecycle - Graceful shutdown
Project Structure
Sources/MyMCPServer/main.swift- Entry point with ServiceLifecycleSources/MyMCPServer/Server.swift- Server configurationSources/MyMCPServer/Tools/- Tool definitions and handlersSources/MyMCPServer/Resources/- Resource definitions and handlersSources/MyMCPServer/Prompts/- Prompt definitions and handlersTests/- 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"
}
}
}
github의 다른 스킬
console-rendering
github
Go에서 struct 태그 기반 콘솔 렌더링 시스템 사용 지침
official
acquire-codebase-knowledge
github
사용자가 기존 코드베이스에 대한 매핑, 문서화, 또는 온보딩을 명시적으로 요청할 때 이 스킬을 사용하세요. "이 코드베이스를 매핑해줘", "문서화해줘"와 같은 프롬프트에서 트리거됩니다.
official
acreadiness-assess
github
현재 리포
official
acreadiness-generate-instructions
github
AgentRC 명령어를 통해 맞춤형 AI 에이전트 지침 파일을 생성합니다. .github/copilot-instructions.md 파일을 생성합니다(기본값, VS Code의 Copilot에 권장됨).
official
acreadiness-policy
github
사용자가 AgentRC 정책을 선택, 작성 또는 적용할 수 있도록 지원합니다. 정책은 관련 없는 검사를 비활성화하고, 영향/수준을 재정의하며, 설정을 통해 준비 상태 점수를 사용자 지정합니다.
official
add-educational-comments
github
코드 파일에 교육용 주석을 추가하여 효과적인 학습 자료로 변환합니다. 설명의 깊이와 어조를 세 가지 설정 가능한 지식 수준(초급, 중급, 고급)에 맞게 조정합니다. 파일이 제공되지 않으면 자동으로 요청하며, 빠른 선택을 위해 번호 목록 매칭을 제공합니다. 교육용 주석만을 사용하여 파일을 최대 125%까지 확장합니다(엄격한 제한: 새 줄 400개, 1,000줄 초과 파일의 경우 300개). 파일 인코딩, 들여쓰기 스타일, 구문 정확성 등을 유지합니다.
official
adobe-illustrator-scripting
github
Adobe Illustrator 자동화 스크립트를 ExtendScript(JavaScript/JSX)로 작성, 디버깅 및 최적화합니다. 스크립트를 생성하거나 수정하여 조작할 때 사용합니다.
official
agent-governance
github
선언적 정책, 의도 분류, AI 에이전트 도구 접근 및 행동 제어를 위한 감사 추적. 구성 가능한 거버넌스 정책은 허용/차단된 도구, 콘텐츠 필터, 속도 제한, 승인 요구 사항을 정의하며, 코드가 아닌 구성으로 저장됨. 의미론적 의도 분류는 패턴 기반 신호를 사용하여 도구 실행 전에 위험한 프롬프트(데이터 유출, 권한 상승, 프롬프트 인젝션)를 탐지함. 도구 수준 거버넌스 데코레이터는 함수에서 정책을 적용함...
official