Rename Error to MCPError (#44)
* Rename Error to MCPError * Conform MCPError to Swift.Error * Use unqualified Error instead of Swift.Error * Use unqualified MCPError instead of MCP.MCPError * Rename file back to Error.swift * Introduce top-level MCP namespace with nested Error typealias to provide deprecation notice for existing usage of MCP.Error * Fix markup for MCP enum warning
This commit is contained in:
parent
a9bcbf9ad9
commit
09da2a1c01
10 changed files with 108 additions and 88 deletions
|
|
@ -6,8 +6,24 @@ import Foundation
|
|||
@preconcurrency import SystemPackage
|
||||
#endif
|
||||
|
||||
/// Top-level namespace for backward compatibility
|
||||
///
|
||||
/// This is provided to allow existing code that uses `MCP.Error` to continue
|
||||
/// to work without modification.
|
||||
///
|
||||
/// The MCPError type is now the recommended way to handle errors in MCP.
|
||||
///
|
||||
/// - Warning: This namespace is deprecated and will be removed in a future version.
|
||||
public enum MCP {
|
||||
/// Deprecated type alias for MCPError
|
||||
@available(*, deprecated, renamed: "MCPError", message: "Use MCPError instead of MCP.Error")
|
||||
public typealias Error = MCPError
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
/// A model context protocol error.
|
||||
public enum Error: Sendable {
|
||||
public enum MCPError: Error, Sendable {
|
||||
// Standard JSON-RPC 2.0 errors (-32700 to -32603)
|
||||
case parseError(String?) // -32700
|
||||
case invalidRequest(String?) // -32600
|
||||
|
|
@ -20,7 +36,7 @@ public enum Error: Sendable {
|
|||
|
||||
// Transport specific errors
|
||||
case connectionClosed
|
||||
case transportError(Swift.Error)
|
||||
case transportError(Error)
|
||||
|
||||
/// The JSON-RPC 2.0 error code
|
||||
public var code: Int {
|
||||
|
|
@ -37,7 +53,7 @@ public enum Error: Sendable {
|
|||
}
|
||||
|
||||
/// Check if an error represents a "resource temporarily unavailable" condition
|
||||
public static func isResourceTemporarilyUnavailable(_ error: Swift.Error) -> Bool {
|
||||
public static func isResourceTemporarilyUnavailable(_ error: Error) -> Bool {
|
||||
#if canImport(System)
|
||||
if let errno = error as? System.Errno, errno == .resourceTemporarilyUnavailable {
|
||||
return true
|
||||
|
|
@ -53,7 +69,7 @@ public enum Error: Sendable {
|
|||
|
||||
// MARK: LocalizedError
|
||||
|
||||
extension Error: LocalizedError {
|
||||
extension MCPError: LocalizedError {
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .parseError(let detail):
|
||||
|
|
@ -116,7 +132,7 @@ extension Error: LocalizedError {
|
|||
|
||||
// MARK: CustomDebugStringConvertible
|
||||
|
||||
extension Error: CustomDebugStringConvertible {
|
||||
extension MCPError: CustomDebugStringConvertible {
|
||||
public var debugDescription: String {
|
||||
switch self {
|
||||
case .transportError(let error):
|
||||
|
|
@ -131,7 +147,7 @@ extension Error: CustomDebugStringConvertible {
|
|||
|
||||
// MARK: Codable
|
||||
|
||||
extension Error: Codable {
|
||||
extension MCPError: Codable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case code, message, data
|
||||
}
|
||||
|
|
@ -199,15 +215,15 @@ extension Error: Codable {
|
|||
|
||||
// MARK: Equatable
|
||||
|
||||
extension Error: Equatable {
|
||||
public static func == (lhs: Error, rhs: Error) -> Bool {
|
||||
extension MCPError: Equatable {
|
||||
public static func == (lhs: MCPError, rhs: MCPError) -> Bool {
|
||||
lhs.code == rhs.code
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Hashable
|
||||
|
||||
extension Error: Hashable {
|
||||
extension MCPError: Hashable {
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(code)
|
||||
switch self {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ extension Method {
|
|||
}
|
||||
|
||||
/// Create a response with the given error.
|
||||
public static func response(id: ID, error: Error) -> Response<Self> {
|
||||
public static func response(id: ID, error: MCPError) -> Response<Self> {
|
||||
Response(id: id, error: error)
|
||||
}
|
||||
}
|
||||
|
|
@ -186,14 +186,14 @@ public struct Response<M: Method>: Hashable, Identifiable, Codable, Sendable {
|
|||
/// The response ID.
|
||||
public let id: ID
|
||||
/// The response result.
|
||||
public let result: Swift.Result<M.Result, Error>
|
||||
public let result: Swift.Result<M.Result, MCPError>
|
||||
|
||||
public init(id: ID, result: M.Result) {
|
||||
self.id = id
|
||||
self.result = .success(result)
|
||||
}
|
||||
|
||||
public init(id: ID, error: Error) {
|
||||
public init(id: ID, error: MCPError) {
|
||||
self.id = id
|
||||
self.result = .failure(error)
|
||||
}
|
||||
|
|
@ -224,7 +224,7 @@ public struct Response<M: Method>: Hashable, Identifiable, Codable, Sendable {
|
|||
id = try container.decode(ID.self, forKey: .id)
|
||||
if let result = try? container.decode(M.Result.self, forKey: .result) {
|
||||
self.result = .success(result)
|
||||
} else if let error = try? container.decode(Error.self, forKey: .error) {
|
||||
} else if let error = try? container.decode(MCPError.self, forKey: .error) {
|
||||
self.result = .failure(error)
|
||||
} else {
|
||||
throw DecodingError.dataCorrupted(
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public protocol Transport: Actor {
|
|||
func send(_ data: Data) async throws
|
||||
|
||||
/// Receives data in an async sequence
|
||||
func receive() -> AsyncThrowingStream<Data, Swift.Error>
|
||||
func receive() -> AsyncThrowingStream<Data, Error>
|
||||
}
|
||||
|
||||
/// Standard input/output transport implementation
|
||||
|
|
@ -74,11 +74,11 @@ public actor StdioTransport: Transport {
|
|||
private func setNonBlocking(fileDescriptor: FileDescriptor) throws {
|
||||
let flags = fcntl(fileDescriptor.rawValue, F_GETFL)
|
||||
guard flags >= 0 else {
|
||||
throw Error.transportError(Errno.badFileDescriptor)
|
||||
throw MCPError.transportError(Errno.badFileDescriptor)
|
||||
}
|
||||
let result = fcntl(fileDescriptor.rawValue, F_SETFL, flags | O_NONBLOCK)
|
||||
guard result >= 0 else {
|
||||
throw Error.transportError(Errno.badFileDescriptor)
|
||||
throw MCPError.transportError(Errno.badFileDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ public actor StdioTransport: Transport {
|
|||
messageContinuation.yield(Data(messageData))
|
||||
}
|
||||
}
|
||||
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
|
||||
} catch let error where MCPError.isResourceTemporarilyUnavailable(error) {
|
||||
try? await Task.sleep(for: .milliseconds(10))
|
||||
continue
|
||||
} catch {
|
||||
|
|
@ -133,7 +133,7 @@ public actor StdioTransport: Transport {
|
|||
|
||||
public func send(_ message: Data) async throws {
|
||||
guard isConnected else {
|
||||
throw Error.transportError(Errno.socketNotConnected)
|
||||
throw MCPError.transportError(Errno.socketNotConnected)
|
||||
}
|
||||
|
||||
// Add newline as delimiter
|
||||
|
|
@ -149,16 +149,16 @@ public actor StdioTransport: Transport {
|
|||
if written > 0 {
|
||||
remaining = remaining.dropFirst(written)
|
||||
}
|
||||
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
|
||||
} catch let error where MCPError.isResourceTemporarilyUnavailable(error) {
|
||||
try await Task.sleep(for: .milliseconds(10))
|
||||
continue
|
||||
} catch {
|
||||
throw Error.transportError(error)
|
||||
throw MCPError.transportError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func receive() -> AsyncThrowingStream<Data, Swift.Error> {
|
||||
public func receive() -> AsyncThrowingStream<Data, Error> {
|
||||
return AsyncThrowingStream { continuation in
|
||||
Task {
|
||||
for await message in messageStream {
|
||||
|
|
@ -179,8 +179,8 @@ public actor StdioTransport: Transport {
|
|||
public nonisolated let logger: Logger
|
||||
|
||||
private var isConnected = false
|
||||
private let messageStream: AsyncThrowingStream<Data, Swift.Error>
|
||||
private let messageContinuation: AsyncThrowingStream<Data, Swift.Error>.Continuation
|
||||
private let messageStream: AsyncThrowingStream<Data, Error>
|
||||
private let messageContinuation: AsyncThrowingStream<Data, Error>.Continuation
|
||||
|
||||
// Track connection state for continuations
|
||||
private var connectionContinuationResumed = false
|
||||
|
|
@ -195,7 +195,7 @@ public actor StdioTransport: Transport {
|
|||
)
|
||||
|
||||
// Create message stream
|
||||
var continuation: AsyncThrowingStream<Data, Swift.Error>.Continuation!
|
||||
var continuation: AsyncThrowingStream<Data, Error>.Continuation!
|
||||
self.messageStream = AsyncThrowingStream { continuation = $0 }
|
||||
self.messageContinuation = continuation
|
||||
}
|
||||
|
|
@ -209,9 +209,9 @@ public actor StdioTransport: Transport {
|
|||
|
||||
// Wait for connection to be ready
|
||||
try await withCheckedThrowingContinuation {
|
||||
[weak self] (continuation: CheckedContinuation<Void, Swift.Error>) in
|
||||
[weak self] (continuation: CheckedContinuation<Void, Error>) in
|
||||
guard let self = self else {
|
||||
continuation.resume(throwing: MCP.Error.internalError("Transport deallocated"))
|
||||
continuation.resume(throwing: MCPError.internalError("Transport deallocated"))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +245,7 @@ public actor StdioTransport: Transport {
|
|||
}
|
||||
}
|
||||
|
||||
private func handleConnectionReady(continuation: CheckedContinuation<Void, Swift.Error>)
|
||||
private func handleConnectionReady(continuation: CheckedContinuation<Void, Error>)
|
||||
async
|
||||
{
|
||||
if !connectionContinuationResumed {
|
||||
|
|
@ -259,7 +259,7 @@ public actor StdioTransport: Transport {
|
|||
}
|
||||
|
||||
private func handleConnectionFailed(
|
||||
error: Swift.Error, continuation: CheckedContinuation<Void, Swift.Error>
|
||||
error: Error, continuation: CheckedContinuation<Void, Error>
|
||||
) async {
|
||||
if !connectionContinuationResumed {
|
||||
connectionContinuationResumed = true
|
||||
|
|
@ -268,13 +268,13 @@ public actor StdioTransport: Transport {
|
|||
}
|
||||
}
|
||||
|
||||
private func handleConnectionCancelled(continuation: CheckedContinuation<Void, Swift.Error>)
|
||||
private func handleConnectionCancelled(continuation: CheckedContinuation<Void, Error>)
|
||||
async
|
||||
{
|
||||
if !connectionContinuationResumed {
|
||||
connectionContinuationResumed = true
|
||||
logger.warning("Connection cancelled")
|
||||
continuation.resume(throwing: MCP.Error.internalError("Connection cancelled"))
|
||||
continuation.resume(throwing: MCPError.internalError("Connection cancelled"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -288,7 +288,7 @@ public actor StdioTransport: Transport {
|
|||
|
||||
public func send(_ message: Data) async throws {
|
||||
guard isConnected else {
|
||||
throw MCP.Error.internalError("Transport not connected")
|
||||
throw MCPError.internalError("Transport not connected")
|
||||
}
|
||||
|
||||
// Add newline as delimiter
|
||||
|
|
@ -299,9 +299,9 @@ public actor StdioTransport: Transport {
|
|||
var sendContinuationResumed = false
|
||||
|
||||
try await withCheckedThrowingContinuation {
|
||||
[weak self] (continuation: CheckedContinuation<Void, Swift.Error>) in
|
||||
[weak self] (continuation: CheckedContinuation<Void, Error>) in
|
||||
guard let self = self else {
|
||||
continuation.resume(throwing: MCP.Error.internalError("Transport deallocated"))
|
||||
continuation.resume(throwing: MCPError.internalError("Transport deallocated"))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +316,7 @@ public actor StdioTransport: Transport {
|
|||
if let error = error {
|
||||
self.logger.error("Send error: \(error)")
|
||||
continuation.resume(
|
||||
throwing: MCP.Error.internalError("Send error: \(error)"))
|
||||
throwing: MCPError.internalError("Send error: \(error)"))
|
||||
} else {
|
||||
continuation.resume()
|
||||
}
|
||||
|
|
@ -326,7 +326,7 @@ public actor StdioTransport: Transport {
|
|||
}
|
||||
}
|
||||
|
||||
public func receive() -> AsyncThrowingStream<Data, Swift.Error> {
|
||||
public func receive() -> AsyncThrowingStream<Data, Error> {
|
||||
return AsyncThrowingStream { continuation in
|
||||
Task {
|
||||
do {
|
||||
|
|
@ -363,7 +363,7 @@ public actor StdioTransport: Transport {
|
|||
} catch let error as NWError {
|
||||
if !Task.isCancelled {
|
||||
logger.error("Network error occurred", metadata: ["error": "\(error)"])
|
||||
messageContinuation.finish(throwing: MCP.Error.transportError(error))
|
||||
messageContinuation.finish(throwing: MCPError.transportError(error))
|
||||
}
|
||||
break
|
||||
} catch {
|
||||
|
|
@ -382,9 +382,9 @@ public actor StdioTransport: Transport {
|
|||
var receiveContinuationResumed = false
|
||||
|
||||
return try await withCheckedThrowingContinuation {
|
||||
[weak self] (continuation: CheckedContinuation<Data, Swift.Error>) in
|
||||
[weak self] (continuation: CheckedContinuation<Data, Error>) in
|
||||
guard let self = self else {
|
||||
continuation.resume(throwing: MCP.Error.internalError("Transport deallocated"))
|
||||
continuation.resume(throwing: MCPError.internalError("Transport deallocated"))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -394,12 +394,12 @@ public actor StdioTransport: Transport {
|
|||
if !receiveContinuationResumed {
|
||||
receiveContinuationResumed = true
|
||||
if let error = error {
|
||||
continuation.resume(throwing: MCP.Error.transportError(error))
|
||||
continuation.resume(throwing: MCPError.transportError(error))
|
||||
} else if let content = content {
|
||||
continuation.resume(returning: content)
|
||||
} else {
|
||||
continuation.resume(
|
||||
throwing: MCP.Error.internalError("No data received"))
|
||||
throwing: MCPError.internalError("No data received"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,16 +112,16 @@ public actor Client {
|
|||
private var task: Task<Void, Never>?
|
||||
|
||||
/// An error indicating a type mismatch when decoding a pending request
|
||||
private struct TypeMismatchError: Swift.Error {}
|
||||
private struct TypeMismatchError: Error {}
|
||||
|
||||
/// A pending request with a continuation for the result
|
||||
private struct PendingRequest<T> {
|
||||
let continuation: CheckedContinuation<T, Swift.Error>
|
||||
let continuation: CheckedContinuation<T, Error>
|
||||
}
|
||||
|
||||
/// A type-erased pending request
|
||||
private struct AnyPendingRequest {
|
||||
private let _resume: (Result<Any, Swift.Error>) -> Void
|
||||
private let _resume: (Result<Any, Error>) -> Void
|
||||
|
||||
init<T: Sendable & Decodable>(_ request: PendingRequest<T>) {
|
||||
_resume = { result in
|
||||
|
|
@ -146,7 +146,7 @@ public actor Client {
|
|||
_resume(.success(value))
|
||||
}
|
||||
|
||||
func resume(throwing error: Swift.Error) {
|
||||
func resume(throwing error: Error) {
|
||||
_resume(.failure(error))
|
||||
}
|
||||
}
|
||||
|
|
@ -201,7 +201,7 @@ public actor Client {
|
|||
"Unexpected message received by client", metadata: metadata)
|
||||
}
|
||||
}
|
||||
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
|
||||
} catch let error where MCPError.isResourceTemporarilyUnavailable(error) {
|
||||
try? await Task.sleep(for: .milliseconds(10))
|
||||
continue
|
||||
} catch {
|
||||
|
|
@ -217,7 +217,7 @@ public actor Client {
|
|||
public func disconnect() async {
|
||||
// Cancel all pending requests
|
||||
for (id, request) in pendingRequests {
|
||||
request.resume(throwing: Error.internalError("Client disconnected"))
|
||||
request.resume(throwing: MCPError.internalError("Client disconnected"))
|
||||
pendingRequests.removeValue(forKey: id)
|
||||
}
|
||||
|
||||
|
|
@ -247,7 +247,7 @@ public actor Client {
|
|||
/// Send a request and receive its response
|
||||
public func send<M: Method>(_ request: Request<M>) async throws -> M.Result {
|
||||
guard let connection = connection else {
|
||||
throw Error.internalError("Client connection not initialized")
|
||||
throw MCPError.internalError("Client connection not initialized")
|
||||
}
|
||||
|
||||
let requestData = try JSONEncoder().encode(request)
|
||||
|
|
@ -274,7 +274,7 @@ public actor Client {
|
|||
|
||||
private func addPendingRequest<T: Sendable & Decodable>(
|
||||
id: ID,
|
||||
continuation: CheckedContinuation<T, Swift.Error>,
|
||||
continuation: CheckedContinuation<T, Error>,
|
||||
type: T.Type
|
||||
) {
|
||||
pendingRequests[id] = AnyPendingRequest(PendingRequest(continuation: continuation))
|
||||
|
|
@ -439,10 +439,10 @@ public actor Client {
|
|||
{
|
||||
if configuration.strict {
|
||||
guard let capabilities = serverCapabilities else {
|
||||
throw Error.methodNotFound("Server capabilities not initialized")
|
||||
throw MCPError.methodNotFound("Server capabilities not initialized")
|
||||
}
|
||||
guard capabilities[keyPath: keyPath] != nil else {
|
||||
throw Error.methodNotFound("\(name) is not supported by the server")
|
||||
throw MCPError.methodNotFound("\(name) is not supported by the server")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,9 +195,9 @@ public actor Server {
|
|||
requestID = .number(intValue)
|
||||
}
|
||||
}
|
||||
throw Error.parseError("Invalid message format")
|
||||
throw MCPError.parseError("Invalid message format")
|
||||
}
|
||||
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
|
||||
} catch let error where MCPError.isResourceTemporarilyUnavailable(error) {
|
||||
// Resource temporarily unavailable, retry after a short delay
|
||||
try? await Task.sleep(for: .milliseconds(10))
|
||||
continue
|
||||
|
|
@ -206,8 +206,8 @@ public actor Server {
|
|||
"Error processing message", metadata: ["error": "\(error)"])
|
||||
let response = AnyMethod.response(
|
||||
id: requestID ?? .random,
|
||||
error: error as? Error
|
||||
?? Error.internalError(error.localizedDescription)
|
||||
error: error as? MCPError
|
||||
?? MCPError.internalError(error.localizedDescription)
|
||||
)
|
||||
try? await send(response)
|
||||
}
|
||||
|
|
@ -265,7 +265,7 @@ public actor Server {
|
|||
/// Send a response to a request
|
||||
public func send<M: Method>(_ response: Response<M>) async throws {
|
||||
guard let connection = connection else {
|
||||
throw Error.internalError("Server connection not initialized")
|
||||
throw MCPError.internalError("Server connection not initialized")
|
||||
}
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
|
|
@ -278,7 +278,7 @@ public actor Server {
|
|||
/// Send a notification to connected clients
|
||||
public func notify<N: Notification>(_ notification: Message<N>) async throws {
|
||||
guard let connection = connection else {
|
||||
throw Error.internalError("Server connection not initialized")
|
||||
throw MCPError.internalError("Server connection not initialized")
|
||||
}
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
|
|
@ -311,7 +311,7 @@ public actor Server {
|
|||
|
||||
// Find handler for method name
|
||||
guard let handler = methodHandlers[request.method] else {
|
||||
let error = Error.methodNotFound("Unknown method: \(request.method)")
|
||||
let error = MCPError.methodNotFound("Unknown method: \(request.method)")
|
||||
let response = AnyMethod.response(id: request.id, error: error)
|
||||
try await send(response)
|
||||
throw error
|
||||
|
|
@ -322,7 +322,7 @@ public actor Server {
|
|||
let response = try await handler(request)
|
||||
try await send(response)
|
||||
} catch {
|
||||
let mcpError = error as? Error ?? Error.internalError(error.localizedDescription)
|
||||
let mcpError = error as? MCPError ?? MCPError.internalError(error.localizedDescription)
|
||||
let response = AnyMethod.response(id: request.id, error: mcpError)
|
||||
try await send(response)
|
||||
throw error
|
||||
|
|
@ -361,7 +361,7 @@ public actor Server {
|
|||
|
||||
private func checkInitialized() throws {
|
||||
guard isInitialized else {
|
||||
throw Error.invalidRequest("Server is not initialized")
|
||||
throw MCPError.invalidRequest("Server is not initialized")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -371,16 +371,16 @@ public actor Server {
|
|||
// Initialize
|
||||
withMethodHandler(Initialize.self) { [weak self] params in
|
||||
guard let self = self else {
|
||||
throw Error.internalError("Server was deallocated")
|
||||
throw MCPError.internalError("Server was deallocated")
|
||||
}
|
||||
|
||||
guard await !self.isInitialized else {
|
||||
throw Error.invalidRequest("Server is already initialized")
|
||||
throw MCPError.invalidRequest("Server is already initialized")
|
||||
}
|
||||
|
||||
// Validate protocol version
|
||||
guard Version.latest == params.protocolVersion else {
|
||||
throw Error.invalidRequest(
|
||||
throw MCPError.invalidRequest(
|
||||
"Unsupported protocol version: \(params.protocolVersion)")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ struct ClientTests {
|
|||
do {
|
||||
try await client.connect(transport: transport)
|
||||
#expect(Bool(false), "Expected connection to fail")
|
||||
} catch let error as Error {
|
||||
if case Error.transportError = error {
|
||||
} catch let error as MCPError {
|
||||
if case MCPError.transportError = error {
|
||||
#expect(Bool(true))
|
||||
} else {
|
||||
#expect(Bool(false), "Expected transport error")
|
||||
|
|
@ -112,8 +112,8 @@ struct ClientTests {
|
|||
do {
|
||||
try await client.ping()
|
||||
#expect(Bool(false), "Expected ping to fail")
|
||||
} catch let error as Error {
|
||||
if case Error.transportError = error {
|
||||
} catch let error as MCPError {
|
||||
if case MCPError.transportError = error {
|
||||
#expect(Bool(true))
|
||||
} else {
|
||||
#expect(Bool(false), "Expected transport error")
|
||||
|
|
@ -132,12 +132,12 @@ struct ClientTests {
|
|||
try await client.connect(transport: transport)
|
||||
|
||||
// Create a task for listPrompts
|
||||
let promptsTask = Task<Void, Swift.Error> {
|
||||
let promptsTask = Task<Void, Error> {
|
||||
do {
|
||||
_ = try await client.listPrompts()
|
||||
#expect(Bool(false), "Expected listPrompts to fail in strict mode")
|
||||
} catch let error as Error {
|
||||
if case Error.methodNotFound = error {
|
||||
} catch let error as MCPError {
|
||||
if case MCPError.methodNotFound = error {
|
||||
#expect(Bool(true))
|
||||
} else {
|
||||
#expect(Bool(false), "Expected methodNotFound error, got \(error)")
|
||||
|
|
@ -185,7 +185,7 @@ struct ClientTests {
|
|||
// Create an error response with the same ID
|
||||
let errorResponse = Response<ListPrompts>(
|
||||
id: decodedRequest.id,
|
||||
error: Error.methodNotFound("Test: Prompts capability not available")
|
||||
error: MCPError.methodNotFound("Test: Prompts capability not available")
|
||||
)
|
||||
try await transport.queue(response: errorResponse)
|
||||
|
||||
|
|
@ -193,8 +193,8 @@ struct ClientTests {
|
|||
do {
|
||||
_ = try await client.listPrompts()
|
||||
#expect(Bool(false), "Expected listPrompts to fail in non-strict mode")
|
||||
} catch let error as Error {
|
||||
if case Error.methodNotFound = error {
|
||||
} catch let error as MCPError {
|
||||
if case MCPError.methodNotFound = error {
|
||||
#expect(Bool(true))
|
||||
} else {
|
||||
#expect(Bool(false), "Expected methodNotFound error, got \(error)")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
import Foundation
|
||||
import class Foundation.JSONEncoder
|
||||
import class Foundation.JSONDecoder
|
||||
import struct Foundation.Data
|
||||
import struct Foundation.POSIXError
|
||||
|
||||
import Logging
|
||||
|
||||
@testable import MCP
|
||||
|
|
@ -26,7 +30,7 @@ actor MockTransport: Transport {
|
|||
private var dataToReceive: [Data] = []
|
||||
private(set) var receivedMessages: [String] = []
|
||||
|
||||
private var dataStreamContinuation: AsyncThrowingStream<Data, Swift.Error>.Continuation?
|
||||
private var dataStreamContinuation: AsyncThrowingStream<Data, Error>.Continuation?
|
||||
|
||||
var shouldFailConnect = false
|
||||
var shouldFailSend = false
|
||||
|
|
@ -37,7 +41,7 @@ actor MockTransport: Transport {
|
|||
|
||||
public func connect() async throws {
|
||||
if shouldFailConnect {
|
||||
throw Error.transportError(POSIXError(.ECONNREFUSED))
|
||||
throw MCPError.transportError(POSIXError(.ECONNREFUSED))
|
||||
}
|
||||
isConnected = true
|
||||
}
|
||||
|
|
@ -50,13 +54,13 @@ actor MockTransport: Transport {
|
|||
|
||||
public func send(_ message: Data) async throws {
|
||||
if shouldFailSend {
|
||||
throw Error.transportError(POSIXError(.EIO))
|
||||
throw MCPError.transportError(POSIXError(.EIO))
|
||||
}
|
||||
sentData.append(message)
|
||||
}
|
||||
|
||||
public func receive() -> AsyncThrowingStream<Data, Swift.Error> {
|
||||
return AsyncThrowingStream<Data, Swift.Error> { continuation in
|
||||
public func receive() -> AsyncThrowingStream<Data, Error> {
|
||||
return AsyncThrowingStream<Data, Error> { continuation in
|
||||
dataStreamContinuation = continuation
|
||||
for message in dataToReceive {
|
||||
continuation.yield(message)
|
||||
|
|
@ -76,7 +80,7 @@ actor MockTransport: Transport {
|
|||
shouldFailSend = shouldFail
|
||||
}
|
||||
|
||||
func queue<M: MCP.Method>(request: Request<M>) throws {
|
||||
func queue<M: Method>(request: Request<M>) throws {
|
||||
let data = try encoder.encode(request)
|
||||
if let continuation = dataStreamContinuation {
|
||||
continuation.yield(data)
|
||||
|
|
@ -85,12 +89,12 @@ actor MockTransport: Transport {
|
|||
}
|
||||
}
|
||||
|
||||
func queue<M: MCP.Method>(response: Response<M>) throws {
|
||||
func queue<M: Method>(response: Response<M>) throws {
|
||||
let data = try encoder.encode(response)
|
||||
dataToReceive.append(data)
|
||||
}
|
||||
|
||||
func queue<N: MCP.Notification>(notification: Message<N>) throws {
|
||||
func queue<N: Notification>(notification: Message<N>) throws {
|
||||
let data = try encoder.encode(notification)
|
||||
dataToReceive.append(data)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ struct ResponseTests {
|
|||
@Test("Error response initialization and encoding")
|
||||
func testErrorResponse() throws {
|
||||
let id: ID = "test-id"
|
||||
let error = MCP.Error.parseError(nil)
|
||||
let error = MCPError.parseError(nil)
|
||||
let response = Response<TestMethod>(id: id, error: error)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
|
|
@ -65,7 +65,7 @@ struct ResponseTests {
|
|||
@Test("Error response with detail")
|
||||
func testErrorResponseWithDetail() throws {
|
||||
let id: ID = "test-id"
|
||||
let error = MCP.Error.parseError("Invalid syntax")
|
||||
let error = MCPError.parseError("Invalid syntax")
|
||||
let response = Response<TestMethod>(id: id, error: error)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ struct ServerTests {
|
|||
|
||||
try await server.start(transport: transport) { clientInfo, _ in
|
||||
if clientInfo.name == "BlockedClient" {
|
||||
throw Error.invalidRequest("Client not allowed")
|
||||
throw MCPError.invalidRequest("Client not allowed")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ struct StdioTransportTests {
|
|||
try writer.close()
|
||||
|
||||
// Start receiving messages
|
||||
let stream: AsyncThrowingStream<Data, Swift.Error> = await transport.receive()
|
||||
let stream: AsyncThrowingStream<Data, Error> = await transport.receive()
|
||||
var iterator = stream.makeAsyncIterator()
|
||||
|
||||
// Get first message
|
||||
|
|
@ -79,7 +79,7 @@ struct StdioTransportTests {
|
|||
try writer.writeAll(invalidJSON.data(using: .utf8)!)
|
||||
try writer.close()
|
||||
|
||||
let stream: AsyncThrowingStream<Data, Swift.Error> = await transport.receive()
|
||||
let stream: AsyncThrowingStream<Data, Error> = await transport.receive()
|
||||
var iterator = stream.makeAsyncIterator()
|
||||
|
||||
_ = try await iterator.next()
|
||||
|
|
@ -100,7 +100,7 @@ struct StdioTransportTests {
|
|||
try await transport.connect()
|
||||
#expect(Bool(false), "Expected connect to throw an error")
|
||||
} catch {
|
||||
#expect(error is MCP.Error)
|
||||
#expect(error is MCPError)
|
||||
}
|
||||
|
||||
await transport.disconnect()
|
||||
|
|
@ -119,7 +119,7 @@ struct StdioTransportTests {
|
|||
try await transport.connect()
|
||||
#expect(Bool(false), "Expected connect to throw an error")
|
||||
} catch {
|
||||
#expect(error is MCP.Error)
|
||||
#expect(error is MCPError)
|
||||
}
|
||||
|
||||
await transport.disconnect()
|
||||
|
|
|
|||
Loading…
Reference in a new issue