Content
# SwiftMCPClient
A small, transport-injectable [Model Context Protocol](https://modelcontextprotocol.io)
client for Swift, over the neutral
[`SwiftMCPCore`](https://github.com/mihaelamj/SwiftMCPCore) wire types. Built to
talk to the [`cupertino`](https://github.com/mihaelamj/cupertino) MCP server, but
the client and transport seam carry no cupertino-specific types.
- The wire types come from **`SwiftMCPCore`** (the external
[`SwiftMCPCore`](https://github.com/mihaelamj/SwiftMCPCore) package):
Foundation-only JSON-RPC / MCP value types under the `MCP.Core.Protocols.*`
namespace, shared with other MCP clients and servers. Only `SwiftMCPClient`
imports it.
- **`SwiftMCPTransport`** the `Transport.Channel` seam: a protocol that moves
one raw JSON-RPC frame (`Data`) at a time. Foundation-only, cross-platform.
- **`SwiftMCPClientAPI`** the `Client.MCP` / `Client.Argument` seam: the verb
contract a consumer depends on, so it can hold `any Client.MCP` (and a fake for
tests) without importing the concrete client. Foundation-only.
- **`SwiftMCPSubprocessTransport`** a macOS `Transport.Channel` that spawns a
command (for example `cupertino serve`) and frames JSON-RPC over its stdio,
newline-delimited.
- **`SwiftMCPClient`** an `actor`-based `MCPClient` that conforms `Client.MCP`
and speaks the `initialize` handshake and `tools/call` / `resources/read` over any
injected `Transport.Channel`, multiplexing concurrent requests by id with a
per-request timeout.
## Why a separate kit
The client deliberately does not build on a stdio-hardcoded MCP client. The
transport is injected (`any Transport.Channel`), so the same client drives a
subprocess on macOS today and a remote channel later, and is testable with a fake
channel and no process at all. The wire core is isolated and Foundation-only so it
can lift, unchanged, into a future neutral `SwiftMCPCore` package shared by more
than one project.
## Install
Add the package and depend on the products you need:
```swift
.package(url: "https://github.com/mihaelamj/SwiftMCPClient.git", from: "0.1.0"),
```
```swift
.target(
name: "YourFeature",
dependencies: [
.product(name: "SwiftMCPClient", package: "SwiftMCPClient"),
.product(name: "SwiftMCPSubprocessTransport", package: "SwiftMCPClient"), // macOS
],
)
```
## Usage
```swift
import SwiftMCPClient
import SwiftMCPSubprocessTransport
// macOS: drive a local `cupertino serve` over stdio.
let transport = Transport.Subprocess(command: "cupertino", arguments: ["serve"])
let client = MCPClient(transport: transport)
try await client.connect() // spawn + initialize
let markdown = try await client.callTool("list_frameworks", arguments: [:])
await client.disconnect()
```
To drive a different transport (remote, in-memory, test fake), conform to
`Transport.Channel` and pass it to `MCPClient(transport:)`. A consumer that only
needs the verb surface can depend on the `Client.MCP` protocol and be tested with
a fake.
## Requirements
- Swift 6.2+
- macOS 13+ / iOS 16+ for the cross-platform products; the subprocess transport is
macOS-only. The core, transport seam, and client also build on Linux.
## Building
```sh
swift build
swift test
CUPERTINO_INTEGRATION=1 swift test # opt-in live tests; needs `cupertino` on PATH
```
## Documentation
- [docs/DESIGN.md](docs/DESIGN.md) the architecture and the layer boundaries.
- [docs/package-import-contract.md](docs/package-import-contract.md) the per-target
import contract.
- [CONTRIBUTING.md](CONTRIBUTING.md) setup, conventions, and workflow.
## License
[MIT](LICENSE).
Connection Info
You Might Also Like
Train-in-Silence
The first Task-Aware MCP server and automated VRAM calculator for LLM...
stacklit
108,000 lines of code. 4,000 tokens of index. One command makes any repo...
AppClaw
AI-powered mobile automation agent — describe what you want in plain...
pdf-mcp
Production-ready MCP server for PDF processing with intelligent caching....
kotadb
Local-only code intelligence API for AI developer workflows (Bun +...
gemini-api-docs-mcp
A remote HTTP MCP server for searching Google Gemini API documentation.