Remove nonstandard read and list capabilities for resources (#15)
* Remove nonstandard read and list capabilities for server * Update README
This commit is contained in:
parent
dccaa3a411
commit
a2a0044abb
4 changed files with 74 additions and 14 deletions
|
|
@ -51,11 +51,11 @@ let server = Server(
|
||||||
name: "MyServer",
|
name: "MyServer",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
capabilities: .init(
|
capabilities: .init(
|
||||||
|
prompts: .init(),
|
||||||
resources: .init(
|
resources: .init(
|
||||||
list: true,
|
|
||||||
read: true,
|
|
||||||
subscribe: true
|
subscribe: true
|
||||||
)
|
),
|
||||||
|
tools: .init()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -313,7 +313,7 @@ public actor Client {
|
||||||
// MARK: - Resources
|
// MARK: - Resources
|
||||||
|
|
||||||
public func readResource(uri: String) async throws -> [Resource.Content] {
|
public func readResource(uri: String) async throws -> [Resource.Content] {
|
||||||
_ = try checkCapability(\.resources?.read, "Resource reading")
|
_ = try checkCapability(\.resources, "Resources")
|
||||||
let request = ReadResource.request(.init(uri: uri))
|
let request = ReadResource.request(.init(uri: uri))
|
||||||
let result = try await send(request)
|
let result = try await send(request)
|
||||||
return result.contents
|
return result.contents
|
||||||
|
|
@ -322,7 +322,7 @@ public actor Client {
|
||||||
public func listResources(cursor: String? = nil) async throws -> (
|
public func listResources(cursor: String? = nil) async throws -> (
|
||||||
resources: [Resource], nextCursor: String?
|
resources: [Resource], nextCursor: String?
|
||||||
) {
|
) {
|
||||||
_ = try checkCapability(\.resources?.list, "Resource listing")
|
_ = try checkCapability(\.resources, "Resources")
|
||||||
let request = ListResources.request(.init(cursor: cursor))
|
let request = ListResources.request(.init(cursor: cursor))
|
||||||
let result = try await send(request)
|
let result = try await send(request)
|
||||||
return (resources: result.resources, nextCursor: result.nextCursor)
|
return (resources: result.resources, nextCursor: result.nextCursor)
|
||||||
|
|
|
||||||
|
|
@ -44,23 +44,15 @@ public actor Server {
|
||||||
public struct Capabilities: Hashable, Codable, Sendable {
|
public struct Capabilities: Hashable, Codable, Sendable {
|
||||||
/// Resources capabilities
|
/// Resources capabilities
|
||||||
public struct Resources: Hashable, Codable, Sendable {
|
public struct Resources: Hashable, Codable, Sendable {
|
||||||
/// Whether the list of resources has changed
|
|
||||||
public var list: Bool?
|
|
||||||
/// Whether the resource can be read
|
|
||||||
public var read: Bool?
|
|
||||||
/// Whether the resource can be subscribed to
|
/// Whether the resource can be subscribed to
|
||||||
public var subscribe: Bool?
|
public var subscribe: Bool?
|
||||||
/// Whether the list of resources has changed
|
/// Whether the list of resources has changed
|
||||||
public var listChanged: Bool?
|
public var listChanged: Bool?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
list: Bool? = nil,
|
|
||||||
read: Bool? = nil,
|
|
||||||
subscribe: Bool? = nil,
|
subscribe: Bool? = nil,
|
||||||
listChanged: Bool? = nil
|
listChanged: Bool? = nil
|
||||||
) {
|
) {
|
||||||
self.list = list
|
|
||||||
self.read = read
|
|
||||||
self.subscribe = subscribe
|
self.subscribe = subscribe
|
||||||
self.listChanged = listChanged
|
self.listChanged = listChanged
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,11 @@ struct RoundtripTests {
|
||||||
let server = Server(
|
let server = Server(
|
||||||
name: "TestServer",
|
name: "TestServer",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
capabilities: .init(prompts: .init(), tools: .init())
|
capabilities: .init(
|
||||||
|
prompts: .init(),
|
||||||
|
resources: .init(),
|
||||||
|
tools: .init()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
await server.withMethodHandler(ListTools.self) { _ in
|
await server.withMethodHandler(ListTools.self) { _ in
|
||||||
return ListTools.Result(tools: [
|
return ListTools.Result(tools: [
|
||||||
|
|
@ -61,6 +65,32 @@ struct RoundtripTests {
|
||||||
return CallTool.Result(content: [.text("\(a + b)")])
|
return CallTool.Result(content: [.text("\(a + b)")])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add resource handlers to server
|
||||||
|
await server.withMethodHandler(ListResources.self) { _ in
|
||||||
|
return ListResources.Result(resources: [
|
||||||
|
Resource(
|
||||||
|
name: "Example Text",
|
||||||
|
uri: "test://example.txt",
|
||||||
|
description: "A test resource",
|
||||||
|
mimeType: "text/plain"
|
||||||
|
),
|
||||||
|
Resource(
|
||||||
|
name: "Test Data",
|
||||||
|
uri: "test://data.json",
|
||||||
|
description: "JSON test data",
|
||||||
|
mimeType: "application/json"
|
||||||
|
),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
await server.withMethodHandler(ReadResource.self) { request in
|
||||||
|
guard request.uri == "test://example.txt" else {
|
||||||
|
return ReadResource.Result(contents: [.text("Resource not found", uri: request.uri)]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return ReadResource.Result(contents: [.text("Hello, World!", uri: request.uri)])
|
||||||
|
}
|
||||||
|
|
||||||
let client = Client(name: "TestClient", version: "1.0")
|
let client = Client(name: "TestClient", version: "1.0")
|
||||||
|
|
||||||
try await server.start(transport: serverTransport)
|
try await server.start(transport: serverTransport)
|
||||||
|
|
@ -104,8 +134,12 @@ struct RoundtripTests {
|
||||||
group.addTask {
|
group.addTask {
|
||||||
try await Task.sleep(for: .seconds(1))
|
try await Task.sleep(for: .seconds(1))
|
||||||
listToolsTask.cancel()
|
listToolsTask.cancel()
|
||||||
|
callToolTask.cancel()
|
||||||
throw CancellationError()
|
throw CancellationError()
|
||||||
}
|
}
|
||||||
|
group.addTask {
|
||||||
|
try await listToolsTask.value
|
||||||
|
}
|
||||||
group.addTask {
|
group.addTask {
|
||||||
try await callToolTask.value
|
try await callToolTask.value
|
||||||
}
|
}
|
||||||
|
|
@ -113,6 +147,40 @@ struct RoundtripTests {
|
||||||
group.cancelAll()
|
group.cancelAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test listing resources
|
||||||
|
let listResourcesTask = Task {
|
||||||
|
let result = try await client.listResources()
|
||||||
|
#expect(result.resources.count == 2)
|
||||||
|
#expect(result.resources[0].uri == "test://example.txt")
|
||||||
|
#expect(result.resources[0].name == "Example Text")
|
||||||
|
#expect(result.resources[1].uri == "test://data.json")
|
||||||
|
#expect(result.resources[1].name == "Test Data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test reading a resource
|
||||||
|
let readResourceTask = Task {
|
||||||
|
let result = try await client.readResource(uri: "test://example.txt")
|
||||||
|
#expect(result.count == 1)
|
||||||
|
#expect(result[0] == .text("Hello, World!", uri: "test://example.txt"))
|
||||||
|
}
|
||||||
|
|
||||||
|
try await withThrowingTaskGroup(of: Void.self) { group in
|
||||||
|
group.addTask {
|
||||||
|
try await Task.sleep(for: .seconds(1))
|
||||||
|
listResourcesTask.cancel()
|
||||||
|
readResourceTask.cancel()
|
||||||
|
throw CancellationError()
|
||||||
|
}
|
||||||
|
group.addTask {
|
||||||
|
try await listResourcesTask.value
|
||||||
|
}
|
||||||
|
group.addTask {
|
||||||
|
try await readResourceTask.value
|
||||||
|
}
|
||||||
|
try await group.next()
|
||||||
|
group.cancelAll()
|
||||||
|
}
|
||||||
|
|
||||||
await server.stop()
|
await server.stop()
|
||||||
await client.disconnect()
|
await client.disconnect()
|
||||||
try? clientToServerRead.close()
|
try? clientToServerRead.close()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue