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:
Mattt 2025-04-03 05:25:00 -07:00 • committed by GitHub
commit 09da2a1c01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 108 additions and 88 deletions

View file

@ -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 {

View file

@ -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(

View file

@ -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"))
}
}
}