forked from modelcontextprotocol/csharp-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStdioServerTransport.cs
More file actions
104 lines (91 loc) · 5.23 KB
/
StdioServerTransport.cs
File metadata and controls
104 lines (91 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using ModelContextProtocol.Server;
using ModelContextProtocol.Utils;
namespace ModelContextProtocol.Protocol.Transport;
/// <summary>
/// Provides a server MCP transport implemented via "stdio" (standard input/output).
/// </summary>
public sealed class StdioServerTransport : StreamServerTransport
{
/// <summary>
/// Initializes a new instance of the <see cref="StdioServerTransport"/> class, using
/// <see cref="Console.In"/> and <see cref="Console.Out"/> for input and output streams.
/// </summary>
/// <param name="serverOptions">The server options.</param>
/// <param name="loggerFactory">Optional logger factory used for logging employed by the transport.</param>
/// <exception cref="ArgumentNullException"><paramref name="serverOptions"/> is <see langword="null"/> or contains a null name.</exception>
/// <remarks>
/// <para>
/// By default, no logging is performed. If a <paramref name="loggerFactory"/> is supplied, it must not log
/// to <see cref="Console.Out"/>, as that will interfere with the transport's output.
/// </para>
/// </remarks>
public StdioServerTransport(IOptions<McpServerOptions> serverOptions, ILoggerFactory? loggerFactory = null)
: this(serverOptions?.Value!, loggerFactory: loggerFactory)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="StdioServerTransport"/> class, using
/// <see cref="Console.In"/> and <see cref="Console.Out"/> for input and output streams.
/// </summary>
/// <param name="serverOptions">The server options.</param>
/// <param name="loggerFactory">Optional logger factory used for logging employed by the transport.</param>
/// <exception cref="ArgumentNullException"><paramref name="serverOptions"/> is <see langword="null"/> or contains a null name.</exception>
/// <remarks>
/// <para>
/// By default, no logging is performed. If a <paramref name="loggerFactory"/> is supplied, it must not log
/// to <see cref="Console.Out"/>, as that will interfere with the transport's output.
/// </para>
/// </remarks>
public StdioServerTransport(McpServerOptions serverOptions, ILoggerFactory? loggerFactory = null)
: this(GetServerName(serverOptions), loggerFactory: loggerFactory)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="StdioServerTransport"/> class, using
/// <see cref="Console.In"/> and <see cref="Console.Out"/> for input and output streams.
/// </summary>
/// <param name="serverName">The name of the server.</param>
/// <param name="loggerFactory">Optional logger factory used for logging employed by the transport.</param>
/// <exception cref="ArgumentNullException"><paramref name="serverName"/> is <see langword="null"/>.</exception>
/// <remarks>
/// <para>
/// By default, no logging is performed. If a <paramref name="loggerFactory"/> is supplied, it must not log
/// to <see cref="Console.Out"/>, as that will interfere with the transport's output.
/// </para>
/// </remarks>
public StdioServerTransport(string serverName, ILoggerFactory? loggerFactory = null)
: base(new CancellableStdinStream(Console.OpenStandardInput()),
new BufferedStream(Console.OpenStandardOutput()),
serverName ?? throw new ArgumentNullException(nameof(serverName)),
loggerFactory)
{
}
private static string GetServerName(McpServerOptions serverOptions)
{
Throw.IfNull(serverOptions);
return serverOptions.ServerInfo?.Name ?? McpServer.DefaultImplementation.Name;
}
// Neither WindowsConsoleStream nor UnixConsoleStream respect CancellationTokens or cancel any I/O on Dispose.
// WindowsConsoleStream will return an EOS on Ctrl-C, but that is not the only reason the shutdownToken may fire.
private sealed class CancellableStdinStream(Stream stdinStream) : Stream
{
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
=> stdinStream.ReadAsync(buffer, offset, count, cancellationToken).WaitAsync(cancellationToken);
#if NET
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
=> new(stdinStream.ReadAsync(buffer, cancellationToken).AsTask().WaitAsync(cancellationToken));
#endif
public override long Length => throw new NotSupportedException();
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
public override void Flush() => throw new NotSupportedException();
public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
}
}