Skip to content

Commit 7b8b554

Browse files
chore: updated README.md
1 parent 1cca131 commit 7b8b554

1 file changed

Lines changed: 108 additions & 43 deletions

File tree

README.md

Lines changed: 108 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ of the MCP specification.
2323
- [Completions](#completions)
2424
- [Sampling](#sampling)
2525
- [Elicitation](#elicitation)
26+
- [Roots](#roots)
2627
- [Logging](#logging)
2728
- [Error Handling](#error-handling)
2829
- [Cancellation](#cancellation)
@@ -36,6 +37,7 @@ of the MCP specification.
3637
- [Completions](#completions-1)
3738
- [Sampling](#sampling-1)
3839
- [Elicitations](#elicitations)
40+
- [Roots](#roots-1)
3941
- [Logging](#logging-1)
4042
- [Progress Tracking](#progress-tracking-1)
4143
- [Initialize Hook](#initialize-hook)
@@ -162,11 +164,10 @@ for item in content {
162164
}
163165
case .audio(let data, let mimeType):
164166
print("Received audio data of type \(mimeType)")
165-
case .resource(let uri, let mimeType, let text):
166-
print("Received resource from \(uri) of type \(mimeType)")
167-
if let text = text {
168-
print("Resource text: \(text)")
169-
}
167+
case .resource(let resource, _, _):
168+
print("Received embedded resource: \(resource)")
169+
case .resourceLink(let uri, let name, _, _, let mimeType, _):
170+
print("Resource link: \(name) at \(uri), type: \(mimeType ?? "unknown")")
170171
}
171172
}
172173
```
@@ -185,7 +186,7 @@ let contents = try await client.readResource(uri: "resource://example")
185186
print("Resource content: \(contents)")
186187

187188
// Subscribe to resource updates if supported
188-
if result.capabilities.resources.subscribe {
189+
if result.capabilities.resources?.subscribe == true {
189190
try await client.subscribeToResource(uri: "resource://example")
190191

191192
// Register notification handler
@@ -345,29 +346,37 @@ Register an elicitation handler to respond to server requests:
345346

346347
```swift
347348
// Register an elicitation handler in the client
348-
await client.setElicitationHandler { parameters in
349-
// Display the request to the user
350-
print("Server requests: \(parameters.message)")
351-
352-
// If a schema was provided, validate against it
353-
if let schema = parameters.requestedSchema {
354-
print("Required fields: \(schema.required ?? [])")
355-
print("Schema: \(schema.properties)")
356-
}
357-
358-
// Present UI to collect user input
359-
let userResponse = presentElicitationUI(parameters)
360-
361-
// Return the user's response
362-
if userResponse.accepted {
363-
return CreateElicitation.Result(
364-
action: .accept,
365-
content: userResponse.data
366-
)
367-
} else if userResponse.canceled {
368-
return CreateElicitation.Result(action: .cancel)
369-
} else {
370-
return CreateElicitation.Result(action: .decline)
349+
await client.withElicitationHandler { parameters in
350+
switch parameters {
351+
case .form(let form):
352+
// Display the request to the user
353+
print("Server requests: \(form.message)")
354+
355+
// If a schema was provided, inspect it
356+
if let schema = form.requestedSchema {
357+
print("Required fields: \(schema.required ?? [])")
358+
print("Schema: \(schema.properties)")
359+
}
360+
361+
// Present UI to collect user input
362+
let userResponse = presentElicitationUI(form)
363+
364+
// Return the user's response
365+
if userResponse.accepted {
366+
return CreateElicitation.Result(
367+
action: .accept,
368+
content: userResponse.data
369+
)
370+
} else if userResponse.canceled {
371+
return CreateElicitation.Result(action: .cancel)
372+
} else {
373+
return CreateElicitation.Result(action: .decline)
374+
}
375+
376+
case .url(let url):
377+
// Direct the user to an external URL (e.g., for OAuth)
378+
openURL(url.url)
379+
return CreateElicitation.Result(action: .accept)
371380
}
372381
}
373382
```
@@ -379,6 +388,34 @@ Common use cases for elicitation:
379388
- **Configuration**: Collect preferences or settings during operation
380389
- **Missing information**: Request additional details not provided initially
381390

391+
### Roots
392+
393+
Roots define the filesystem boundaries that a client exposes to servers. Servers discover roots by sending a `roots/list` request to the client; clients notify servers when the list changes.
394+
395+
> [!TIP]
396+
> To use roots, declare the `roots` capability when creating the client.
397+
398+
```swift
399+
let client = Client(
400+
name: "MyApp",
401+
version: "1.0.0",
402+
capabilities: .init(
403+
roots: .init(listChanged: true)
404+
)
405+
)
406+
407+
// Register a handler for roots/list requests from servers
408+
await client.withRootsHandler {
409+
return [
410+
Root(uri: "file:///Users/user/projects", name: "Projects"),
411+
Root(uri: "file:///Users/user/documents", name: "Documents")
412+
]
413+
}
414+
415+
// Notify connected servers whenever roots change
416+
try await client.notifyRootsChanged()
417+
```
418+
382419
### Logging
383420

384421
Clients can control server logging levels and receive structured log messages:
@@ -505,7 +542,7 @@ await client.onNotification(ProgressNotification.self) { message in
505542
let (content, isError) = try await client.callTool(
506543
name: "long-running-tool",
507544
arguments: ["input": "value"],
508-
meta: RequestMeta(progressToken: progressToken)
545+
meta: Metadata(progressToken: progressToken)
509546
)
510547
```
511548

@@ -799,9 +836,9 @@ await server.withMethodHandler(GetPrompt.self) { params in
799836

800837
let description = "Job interview for \(position) position at \(company)"
801838
let messages: [Prompt.Message] = [
802-
.user("You are an interviewer for the \(position) position at \(company)."),
803-
.user("Hello, I'm \(interviewee) and I'm here for the \(position) interview."),
804-
.assistant("Hi \(interviewee), welcome to \(company)! I'd like to start by asking about your background and experience.")
839+
.user(.text(text: "You are an interviewer for the \(position) position at \(company).")),
840+
.user(.text(text: "Hello, I'm \(interviewee) and I'm here for the \(position) interview.")),
841+
.assistant(.text(text: "Hi \(interviewee), welcome to \(company)! I'd like to start by asking about your background and experience."))
805842
]
806843

807844
return .init(description: description, messages: messages)
@@ -902,9 +939,6 @@ await server.withMethodHandler(Complete.self) { params in
902939

903940
Servers can request LLM completions from clients through sampling. This enables agentic behaviors where servers can ask for AI assistance while maintaining human oversight.
904941

905-
> [!NOTE]
906-
> The current implementation provides the correct API design for sampling, but requires bidirectional communication support in the transport layer. This feature will be fully functional when bidirectional transport support is added.
907-
908942
```swift
909943
// Enable sampling capability in server
910944
let server = Server(
@@ -916,7 +950,7 @@ let server = Server(
916950
)
917951
)
918952

919-
// Request sampling from the client (conceptual - requires bidirectional transport)
953+
// Request sampling from the connected client
920954
do {
921955
let result = try await server.requestSampling(
922956
messages: [
@@ -983,6 +1017,35 @@ case .cancel:
9831017
}
9841018
```
9851019

1020+
For URL-based elicitation (e.g., OAuth flows), use the URL overload:
1021+
1022+
```swift
1023+
let result = try await server.requestElicitation(
1024+
message: "Please sign in to continue",
1025+
url: "https://example.com/oauth/authorize?client_id=...",
1026+
elicitationId: UUID().uuidString
1027+
)
1028+
```
1029+
1030+
### Roots
1031+
1032+
Servers can request the list of filesystem roots that the client has exposed:
1033+
1034+
```swift
1035+
// Request roots from the connected client
1036+
// (requires the client to declare the roots capability)
1037+
let roots = try await server.listRoots()
1038+
for root in roots {
1039+
print("Root: \(root.name ?? root.uri) at \(root.uri)")
1040+
}
1041+
1042+
// React to root list changes
1043+
await server.onNotification(RootsListChangedNotification.self) { _ in
1044+
let updatedRoots = try await server.listRoots()
1045+
print("Roots updated: \(updatedRoots.map { $0.uri })")
1046+
}
1047+
```
1048+
9861049
### Logging
9871050

9881051
Servers can send structured log messages to clients:
@@ -1225,12 +1288,14 @@ MCP's transport layer handles communication between clients and servers.
12251288
The Swift SDK provides multiple built-in transports:
12261289

12271290

1228-
| Transport | Description | Platforms | Best for |
1229-
| ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------ |
1230-
| `[StdioTransport](/Sources/MCP/Base/Transports/StdioTransport.swift)` | Implements [stdio transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#stdio) using standard input/output streams | Apple platforms, Linux with glibc | Local subprocesses, CLI tools |
1231-
| `[HTTPClientTransport](/Sources/MCP/Base/Transports/HTTPClientTransport.swift)` | Implements [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http) using Foundation's URL Loading System | All platforms with Foundation | Remote servers, web applications |
1232-
| `[InMemoryTransport](/Sources/MCP/Base/Transports/InMemoryTransport.swift)` | Custom in-memory transport for direct communication within the same process | All platforms | Testing, debugging, same-process client-server communication |
1233-
| `[NetworkTransport](/Sources/MCP/Base/Transports/NetworkTransport.swift)` | Custom transport using Apple's Network framework for TCP/UDP connections | Apple platforms only | Low-level networking, custom protocols |
1291+
| Transport | Description | Platforms | Best for |
1292+
| ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------ |
1293+
| `[StdioTransport](/Sources/MCP/Base/Transports/StdioTransport.swift)` | Implements [stdio transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#stdio) using standard input/output streams | Apple platforms, Linux with glibc | Local subprocesses, CLI tools |
1294+
| `[HTTPClientTransport](/Sources/MCP/Base/Transports/HTTPClientTransport.swift)` | Implements [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http) using Foundation's URL Loading System | All platforms with Foundation | Remote servers, web applications |
1295+
| `[StatelessHTTPServerTransport](/Sources/MCP/Base/Transports/HTTPServer/StatelessHTTPServerTransport.swift)` | HTTP server transport with simple request-response semantics; no session management or SSE streaming | All platforms with Foundation | Simple HTTP servers, serverless/edge functions |
1296+
| `[StatefulHTTPServerTransport](/Sources/MCP/Base/Transports/HTTPServer/StatefulHTTPServerTransport.swift)` | HTTP server transport with full session management and SSE streaming for server-initiated messages | All platforms with Foundation | Full-featured HTTP servers, streaming notifications |
1297+
| `[InMemoryTransport](/Sources/MCP/Base/Transports/InMemoryTransport.swift)` | Custom in-memory transport for direct communication within the same process | All platforms | Testing, debugging, same-process client-server communication |
1298+
| `[NetworkTransport](/Sources/MCP/Base/Transports/NetworkTransport.swift)` | Custom transport using Apple's Network framework for TCP/UDP connections | Apple platforms only | Low-level networking, custom protocols |
12341299

12351300

12361301
### Custom Transport Implementation

0 commit comments

Comments
 (0)