* Add test coverage for Client with HTTPClientTransport
* Configure HTTP client transport to stream by default
* Add example usage of streaming HTTP transport to README
* Explicitly set streaming to false in test
* support 405 response from servers that don’t support streaming
* Rephrase comment
---------
Co-authored-by: Stephen Tallent <stallent@mercury.io>
Co-authored-by: Mattt Zmuda <mattt@loopwork.com>
* Optimized code in `connectToEventStream` to use `.lines` computed value of `AsyncSequence` to produce a `AsyncLineSequence` instead of building a lines manually.
* - Reverter use of `lines` (it swallows newlines)
- Fiexed original issue I experienced with line 229 `while let newlineIndex = buffer.firstIndex(of: "\n") {` not handling "\r\n" properly
- Added unit test to test for "\r\n" scenario
- Simplified `end of event` test - `line` creation trims newline, added code trims carriage return. Only thing that should be left is an empty line
* Update AnyNotification to not wipe out params that come with a notification
* Add test coverage for notification with params
* Allow params to be omitted when empty
---------
Co-authored-by: Stephen Tallent <stallent@mercury.io>
Co-authored-by: Mattt Zmuda <mattt@loopwork.com>
* Rename file to Transport.swift
* Rename file to StdioTransportTests.swift
* Add .index-build/ to .gitignore
* Implement HTTP client transport
* Add test coverage for streamable HTTP client transport
* Conditionally import FoundationNetworking
* Conditionalize streaming for unsupported platforms
* Import FoundationNetworking in tests
* Add 5 minute timeout to CI jobs
* Remove debug logging
* Formatting
* Skip SSE tests on platforms that don't support streaming
* Update StdioTransport documentation comments to indicate support for JSON-RPC batches
* Add server support for JSON-RPC batching
* Add client support for JSON-RPC batching
* Fix bug that caused error messages to be wrapped unnecessarily
* Conditionally import Glibc on Linux for fcntl calls
* Extract transport implementations into separate files
* Fix warning in test
* Add ubuntu-latest to CI test matrix
* Switch to vapor/swiftly-action for setup step
* Configure Prettier extension to format GitHub Actions workflows
* Setup with different actions depending on platform
* Rename step
* Rename job
* Update README
* 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
* Adding unit test
* Decode entire request to strongly typed Method call. This allows NotRequired parameters to properly decode from null, which wouldn't be possible when decoding from the 'null' JSON encoding directly.
* Add unit test to check that AnyRequest handles missing parameters
* Conform Value to NotRequired
* Add test for decoding AnyRequest with empty parameters
---------
Co-authored-by: Mattt Zmuda <mattt@loopwork.com>
* Allow `params` field to be omitted in requests for methods with empty parameters
* Add ping request to roundtrip test
* Generalize decoding of non-required parameters
* Conform Server.Capabilities types to ExpressibleByBooleanLiteral
* Conform Client.Capabilities types to ExpressibleByBooleanLiteral
* Use Boolean literatls for capabilities in tests
* Update README
* Allow decoding Decodable type directly from Value
Summary: I noticed we are not converting value associated with response to the strong types requests recorded
This change will help to decode the value type later once we support the rest of plumbing (next commit)
* Store and pass original request when response arrives
Summary: Looks like there were multiple issues with parsing response:
1. It appears that we would mistakenly pass response both for response and request arguments in the private func handleResponse(_ response: Response<AnyMethod>, for request: Any)
2. Later I couldn't figure out how to win against swift type system, so ended up creating a type-erased request to store in the pendingRequests instead of original type under Any (that wouldn't allow to downcast original type later)
Test Plan:
1. Standup iMCP client from https://github.com/loopwork-ai/iMCP
2. Create a dummy project setting up MCP client against "/private/var/folders/26/8gncz37x7slbfrr95d9jcr400000gn/T/AppTranslocation/62ADEC4D-3545-4E98-A612-0E6DF52CE525/d/iMCP.app/Contents/MacOS/imcp-server" and call initialize
Note response is being parsed correctly and client.initialize() does not hang indefinitely
* Fix warning: 'Cast from Client.AnyPendingRequest to unrelated type Client.PendingRequest<Any> always fails'
* Fix warning: 'Conditional cast from NWError to NWError always succeeds'
* Uncomment code in RoundtripTests
* Formatting
* Reorganize declarations
* Inline JSONDecoder extension
* Expand roundtrip tests
---------
Co-authored-by: Sash Zats sash@zats.io <>
Co-authored-by: Mattt Zmuda <mattt@loopwork.com>
Changes AsyncStream to AsyncThrowingStream to ensure network errors are correctly propagated to callers. Updates receive() to handle errors from the underlying message stream.
Adds a Configuration struct to control server behavior around client initialization.
When strict mode is enabled, server enforces MCP spec requiring clients to initialize
before sending requests. Default mode is more permissive for non-compliant clients.