diff --git a/src/ModelContextProtocol/Client/McpClient.cs b/src/ModelContextProtocol/Client/McpClient.cs
index d871af108..cf27a6b52 100644
--- a/src/ModelContextProtocol/Client/McpClient.cs
+++ b/src/ModelContextProtocol/Client/McpClient.cs
@@ -10,7 +10,7 @@
namespace ModelContextProtocol.Client;
///
-internal sealed class McpClient : McpJsonRpcEndpoint, IMcpClient
+internal sealed class McpClient : McpEndpoint, IMcpClient
{
private readonly IClientTransport _clientTransport;
private readonly McpClientOptions _options;
diff --git a/src/ModelContextProtocol/Configuration/McpServerConfig.cs b/src/ModelContextProtocol/Configuration/McpServerConfig.cs
index c8d0a26eb..27cd39e41 100644
--- a/src/ModelContextProtocol/Configuration/McpServerConfig.cs
+++ b/src/ModelContextProtocol/Configuration/McpServerConfig.cs
@@ -27,11 +27,6 @@ public record McpServerConfig
///
public string? Location { get; set; }
- ///
- /// Arguments (if any) to pass to the executable.
- ///
- public string[]? Arguments { get; init; }
-
///
/// Additional transport-specific configuration.
///
diff --git a/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs b/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs
index d375aa663..359de5ea8 100644
--- a/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs
+++ b/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs
@@ -76,7 +76,8 @@ public async Task SendMessageAsync(IJsonRpcMessage message, CancellationToken ca
throw new InvalidOperationException($"Transport is not connected. Make sure to call {nameof(RunAsync)} first.");
}
- await _outgoingSseChannel.Writer.WriteAsync(new SseItem(message), cancellationToken);
+ // Emit redundant "event: message" lines for better compatibility with other SDKs.
+ await _outgoingSseChannel.Writer.WriteAsync(new SseItem(message, SseParser.EventTypeDefault), cancellationToken);
}
///
diff --git a/src/ModelContextProtocol/Server/McpServer.cs b/src/ModelContextProtocol/Server/McpServer.cs
index 80a28d362..499f2efa8 100644
--- a/src/ModelContextProtocol/Server/McpServer.cs
+++ b/src/ModelContextProtocol/Server/McpServer.cs
@@ -9,7 +9,7 @@
namespace ModelContextProtocol.Server;
///
-internal sealed class McpServer : McpJsonRpcEndpoint, IMcpServer
+internal sealed class McpServer : McpEndpoint, IMcpServer
{
private readonly EventHandler? _toolsChangedDelegate;
private readonly EventHandler? _promptsChangedDelegate;
diff --git a/src/ModelContextProtocol/Shared/McpJsonRpcEndpoint.cs b/src/ModelContextProtocol/Shared/McpEndpoint.cs
similarity index 94%
rename from src/ModelContextProtocol/Shared/McpJsonRpcEndpoint.cs
rename to src/ModelContextProtocol/Shared/McpEndpoint.cs
index 052cc1649..8b50a8052 100644
--- a/src/ModelContextProtocol/Shared/McpJsonRpcEndpoint.cs
+++ b/src/ModelContextProtocol/Shared/McpEndpoint.cs
@@ -17,7 +17,7 @@ namespace ModelContextProtocol.Shared;
/// This is especially true as a client represents a connection to one and only one server, and vice versa.
/// Any multi-client or multi-server functionality should be implemented at a higher level of abstraction.
///
-internal abstract class McpJsonRpcEndpoint : IAsyncDisposable
+internal abstract class McpEndpoint : IAsyncDisposable
{
private readonly RequestHandlers _requestHandlers = [];
private readonly NotificationHandlers _notificationHandlers = [];
@@ -31,10 +31,10 @@ internal abstract class McpJsonRpcEndpoint : IAsyncDisposable
protected readonly ILogger _logger;
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The logger factory.
- protected McpJsonRpcEndpoint(ILoggerFactory? loggerFactory = null)
+ protected McpEndpoint(ILoggerFactory? loggerFactory = null)
{
_logger = loggerFactory?.CreateLogger(GetType()) ?? NullLogger.Instance;
}
@@ -64,7 +64,7 @@ public Task SendMessageAsync(IJsonRpcMessage message, CancellationToken cancella
///
/// Task that processes incoming messages from the transport.
///
- protected Task? MessageProcessingTask { get; set; }
+ protected Task? MessageProcessingTask { get; private set; }
[MemberNotNull(nameof(MessageProcessingTask))]
protected void StartSession(ITransport sessionTransport)
diff --git a/src/ModelContextProtocol/Shared/McpSession.cs b/src/ModelContextProtocol/Shared/McpSession.cs
index 46c327903..e9aed2f32 100644
--- a/src/ModelContextProtocol/Shared/McpSession.cs
+++ b/src/ModelContextProtocol/Shared/McpSession.cs
@@ -45,7 +45,7 @@ internal sealed class McpSession : IDisposable
///
private readonly ConcurrentDictionary _handlingRequests = new();
private readonly ILogger _logger;
-
+
private readonly string _id = Guid.NewGuid().ToString("N");
private long _nextRequestId;
diff --git a/tests/ModelContextProtocol.Tests/SseServerIntegrationTests.cs b/tests/ModelContextProtocol.Tests/SseServerIntegrationTests.cs
index 004e54a4f..b73a9c06e 100644
--- a/tests/ModelContextProtocol.Tests/SseServerIntegrationTests.cs
+++ b/tests/ModelContextProtocol.Tests/SseServerIntegrationTests.cs
@@ -1,6 +1,8 @@
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Types;
using ModelContextProtocol.Tests.Utils;
+using System.Net;
+using System.Text;
namespace ModelContextProtocol.Tests;
@@ -30,6 +32,12 @@ private Task GetClientAsync(McpClientOptions? options = null)
cancellationToken: TestContext.Current.CancellationToken);
}
+ private HttpClient GetHttpClient() =>
+ new()
+ {
+ BaseAddress = new(_fixture.DefaultConfig.Location!),
+ };
+
[Fact]
public async Task ConnectAndPing_Sse_TestServer()
{
@@ -271,4 +279,44 @@ public async Task CallTool_Sse_EchoServer_Concurrently()
Assert.Equal($"Echo: Hello MCP! {i}", textContent.Text);
}
}
+
+ [Fact]
+ public async Task EventSourceStream_Includes_MessageEventType()
+ {
+ // Simulate our own MCP client handshake using a plain HttpClient so we can look for "event: message"
+ // in the raw SSE response stream which is not exposed by the real MCP client.
+ using var httpClient = GetHttpClient();
+ await using var sseResponse = await httpClient.GetStreamAsync("", TestContext.Current.CancellationToken);
+ using var streamReader = new StreamReader(sseResponse);
+
+ var endpointEvent = await streamReader.ReadLineAsync(TestContext.Current.CancellationToken);
+ Assert.Equal("event: endpoint", endpointEvent);
+
+ var endpointData = await streamReader.ReadLineAsync(TestContext.Current.CancellationToken);
+ Assert.NotNull(endpointData);
+ Assert.StartsWith("data: ", endpointData);
+ var messageEndpoint = endpointData["data: ".Length..];
+
+ const string initializeRequest = """
+ {"jsonrpc":"2.0","id":"1","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"IntegrationTestClient","version":"1.0.0"}}}
+ """;
+ using (var initializeRequestBody = new StringContent(initializeRequest, Encoding.UTF8, "application/json"))
+ {
+ var response = await httpClient.PostAsync(messageEndpoint, initializeRequestBody, TestContext.Current.CancellationToken);
+ Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
+ }
+
+ const string initializedNotification = """
+ {"jsonrpc":"2.0","method":"notifications/initialized"}
+ """;
+ using (var initializedNotificationBody = new StringContent(initializedNotification, Encoding.UTF8, "application/json"))
+ {
+ var response = await httpClient.PostAsync(messageEndpoint, initializedNotificationBody, TestContext.Current.CancellationToken);
+ Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
+ }
+
+ Assert.Equal("", await streamReader.ReadLineAsync(TestContext.Current.CancellationToken));
+ var messageEvent = await streamReader.ReadLineAsync(TestContext.Current.CancellationToken);
+ Assert.Equal("event: message", messageEvent);
+ }
}