TypeMismatchError unrecoverable when server response doesn't round-trip through CallTool.Result codable
メンテナーはふだん 7 日以内に返信
@EhsanAzish80 がすでに取り組んでいます。
2026年9月24日 から。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 45/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 静か
- 技術スタック
- swift
調査の方向性
Start in Sources/MCP/Base/PendingRequest.swift at PendingRequest.AnyPendingRequest._resume and trace how the decoded Value is discarded when decoding CallTool.Result fails. Reproduce against @adeze/raindrop-mcp and inspect TypeMismatchError handling. Done should provide clients with enough underlying decoding or raw-response information to diagnose and recover from incompatible tools/call responses.
索引モデルが issue の本文から書いたものです。
説明
Summary
PendingRequest.AnyPendingRequest._resume (in Sources/MCP/Base/PendingRequest.swift) throws TypeMismatchError() whenever the Value returned by the server can be encoded as JSON but the subsequent JSONDecoder().decode(T.self, from: ...) fails. When this happens with CallTool.Result, there is no way for client code to recover the raw response — the decoded Value is discarded before it reaches the client, and TypeMismatchError() carries no diagnostics (not even the underlying DecodingError, not even which key/path was missing).
This breaks interoperability with real MCP servers in the wild whose tools/call responses are "codable-close but not strictly compliant" with the Swift CallTool.Result shape (extra fields, slightly different casing, optional wrapping, etc.).
Reproduction
Client: swift-sdk 0.12.0 on macOS 26.
Server: @adeze/raindrop-mcp (stdio transport, npx -y @adeze/raindrop-mcp).
Request:
{ "method": "tools/call",
"params": { "name": "list_raindrops",
"arguments": {"collectionId": 0, "perPage": 3} } }
Every response decodes to TypeMismatchError(). Because the SDK doesn't surface the underlying DecodingError, downstream consumers cannot tell whether the issue is a missing content key, an unexpected extra field, a union-type mismatch inside Tool.Content, or something else entirely. We see only the opaque error string TypeMismatchError().
We tried several tools on the same server (list_raindrops, bookmark_search, collection_list) and all fail identically — the server is simply using a response shape the SDK rejects.
Why this matters
MCP is meant to be a cross-language/cross-vendor protocol. A Python server and a Swift client should be able to talk even when the server's Zod schema and the client's Codable model don't line up perfectly — at minimum the client should have enough information to recover, log, or surface the raw payload.
Today the Swift SDK is materially harder to use than the TypeScript or Python SDKs in these cases.
Proposed fix (any of)
-
Leak the
DecodingError: changeTypeMismatchErrorfrom a marker to an error that wrapsDecodingErrorand the rawValue. This alone would unblock debugging.struct TypeMismatchError: Error { let expected: Any.Type let underlying: Error let rawValue: Value } -
Expose a raw-response escape hatch on
Client:func callToolRaw(...) async throws -> Valuethat returns the protocol-levelValuewithout attempting to decode intoCallTool.Result. Downstream clients can implement lenient parsing themselves. -
Use
decodeIfPresent-style lenient decoding forCallTool.Resultso extra fields are ignored and optional fields can be missing. This is the TypeScript SDK behavior.
Option 1 is the cheapest and unblocks the most users — it's a couple of lines in PendingRequest.swift. Option 2 is the most flexible. Option 3 is the most user-friendly.
Workaround we're using
We catch the error by type name (errorType.contains(\"TypeMismatchError\")) and surface a generic "tool call decode failed" string to the end user. This is obviously fragile and hides the real bug.
Environment
- swift-sdk: 0.12.0
- Swift: 6.0, strict concurrency
- macOS: Tahoe 26.4
- Xcode: 26.4.1
- Project: trapias/EasyChat, see
Data/Services/MCP/MCPManager.swift
- 主要言語
- Swift
- スター
- 1.5k
- フォーク
- 252
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
modelcontextprotocol/swift-sdk のほかの issue
-
NetworkTransport leaks the underlying socket (CLOSE_WAIT) when reconnection is disabled and the receive loop terminates対応中かも @skirrellyjones が 40 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
modelcontextprotocol/swift-sdk#282 ·
メンテナーはふだん 7 日以内に返信
-
Value decoding changes data-URL-looking JSON strings into Value.data対応中かも @bitbemol が 50 日前に担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
modelcontextprotocol/swift-sdk#277 ·
メンテナーはふだん 7 日以内に返信
-
enhancement
難易度 1/5 1時間未満 初心者へのやさしさ 78/100
modelcontextprotocol/swift-sdk#274 ·
メンテナーはふだん 7 日以内に返信
-
`HTTPClientTransport` fails to build on Windows: `#if !os(Linux)` guards no longer match the `EventSource` platform condition再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
modelcontextprotocol/swift-sdk#261 ·
メンテナーはふだん 7 日以内に返信
-
Value: add numberValue (Double?) that coerces .int and .double対応中かも @gsdali が 161 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
modelcontextprotocol/swift-sdk#225 ·
メンテナーはふだん 7 日以内に返信
modelcontextprotocol/swift-sdk の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 83/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
openwatersio/slackwater-ios#736 ·
メンテナーはふだん 1 日以内に返信
-
agent/sec-check help wanted security stage/010-actionable
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
hivecommons/hotshot#235 ·
メンテナーはふだん 1 日以内に返信
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
MustacheCase/zanadir#254 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100