1
1
using Microsoft . Extensions . AI ;
2
2
using Microsoft . Extensions . DependencyInjection ;
3
3
using ModelContextProtocol . Client ;
4
+ using ModelContextProtocol . Protocol . Messages ;
4
5
using ModelContextProtocol . Protocol . Transport ;
5
6
using ModelContextProtocol . Protocol . Types ;
6
7
using ModelContextProtocol . Server ;
@@ -61,29 +62,39 @@ public async Task CreateSamplingHandler_ShouldHandleTextMessages(float? temperat
61
62
}
62
63
] ,
63
64
Temperature = temperature ,
64
- MaxTokens = maxTokens
65
+ MaxTokens = maxTokens ,
66
+ Meta = new RequestParamsMetadata
67
+ {
68
+ ProgressToken = new ProgressToken ( ) ,
69
+ }
65
70
} ;
66
71
67
72
var cancellationToken = CancellationToken . None ;
68
- var expectedResponse = new ChatResponse
69
- {
70
- Messages = { new ChatMessage { Role = ChatRole . Assistant , Contents = { new TextContent ( "Hi there!" ) } } } ,
71
- ModelId = "test-model" ,
72
- FinishReason = ChatFinishReason . Stop
73
- } ;
73
+ var expectedResponse = new [ ] {
74
+ new ChatResponseUpdate
75
+ {
76
+ ModelId = "test-model" ,
77
+ FinishReason = ChatFinishReason . Stop ,
78
+ Role = ChatRole . Assistant ,
79
+ Contents =
80
+ [
81
+ new TextContent ( "Hello, World!" ) { RawRepresentation = "Hello, World!" }
82
+ ]
83
+ }
84
+ } . ToAsyncEnumerable ( ) ;
74
85
75
86
mockChatClient
76
- . Setup ( client => client . GetResponseAsync ( It . IsAny < IList < ChatMessage > > ( ) , It . IsAny < ChatOptions > ( ) , cancellationToken ) )
77
- . ReturnsAsync ( expectedResponse ) ;
87
+ . Setup ( client => client . GetStreamingResponseAsync ( It . IsAny < IEnumerable < ChatMessage > > ( ) , It . IsAny < ChatOptions > ( ) , cancellationToken ) )
88
+ . Returns ( expectedResponse ) ;
78
89
79
90
var handler = McpClientExtensions . CreateSamplingHandler ( mockChatClient . Object ) ;
80
91
81
92
// Act
82
- var result = await handler ( requestParams , cancellationToken ) ;
93
+ var result = await handler ( requestParams , Mock . Of < IProgress < ProgressNotificationValue > > ( ) , cancellationToken ) ;
83
94
84
95
// Assert
85
96
Assert . NotNull ( result ) ;
86
- Assert . Equal ( "Hi there !" , result . Content . Text ) ;
97
+ Assert . Equal ( "Hello, World !" , result . Content . Text ) ;
87
98
Assert . Equal ( "test-model" , result . Model ) ;
88
99
Assert . Equal ( "assistant" , result . Role ) ;
89
100
Assert . Equal ( "endTurn" , result . StopReason ) ;
@@ -96,42 +107,49 @@ public async Task CreateSamplingHandler_ShouldHandleImageMessages()
96
107
var mockChatClient = new Mock < IChatClient > ( ) ;
97
108
var requestParams = new CreateMessageRequestParams
98
109
{
99
- Messages = new [ ]
100
- {
101
- new SamplingMessage
102
- {
103
- Role = Role . User ,
104
- Content = new Content
110
+ Messages =
111
+ [
112
+ new SamplingMessage
105
113
{
106
- Type = "image" ,
107
- MimeType = "image/png" ,
108
- Data = Convert . ToBase64String ( new byte [ ] { 1 , 2 , 3 } )
114
+ Role = Role . User ,
115
+ Content = new Content
116
+ {
117
+ Type = "image" ,
118
+ MimeType = "image/png" ,
119
+ Data = Convert . ToBase64String ( new byte [ ] { 1 , 2 , 3 } )
120
+ }
109
121
}
110
- }
111
- } ,
122
+ ] ,
112
123
MaxTokens = 100
113
124
} ;
114
- var cancellationToken = CancellationToken . None ;
115
125
116
- var expectedResponse = new ChatResponse
117
- {
118
- Messages = { new ChatMessage { Role = ChatRole . Assistant , Contents = new [ ] { new TextContent ( "Image received!" ) } } } ,
119
- ModelId = "test-model" ,
120
- FinishReason = ChatFinishReason . Stop
121
- } ;
126
+ const string expectedData = "SGVsbG8sIFdvcmxkIQ==" ;
127
+ var cancellationToken = CancellationToken . None ;
128
+ var expectedResponse = new [ ] {
129
+ new ChatResponseUpdate
130
+ {
131
+ ModelId = "test-model" ,
132
+ FinishReason = ChatFinishReason . Stop ,
133
+ Role = ChatRole . Assistant ,
134
+ Contents =
135
+ [
136
+ new DataContent ( $ "data:image/png;base64,{ expectedData } ") { RawRepresentation = "Hello, World!" }
137
+ ]
138
+ }
139
+ } . ToAsyncEnumerable ( ) ;
122
140
123
141
mockChatClient
124
- . Setup ( client => client . GetResponseAsync ( It . IsAny < IList < ChatMessage > > ( ) , It . IsAny < ChatOptions > ( ) , cancellationToken ) )
125
- . ReturnsAsync ( expectedResponse ) ;
142
+ . Setup ( client => client . GetStreamingResponseAsync ( It . IsAny < IEnumerable < ChatMessage > > ( ) , It . IsAny < ChatOptions > ( ) , cancellationToken ) )
143
+ . Returns ( expectedResponse ) ;
126
144
127
145
var handler = McpClientExtensions . CreateSamplingHandler ( mockChatClient . Object ) ;
128
146
129
147
// Act
130
- var result = await handler ( requestParams , cancellationToken ) ;
148
+ var result = await handler ( requestParams , Mock . Of < IProgress < ProgressNotificationValue > > ( ) , cancellationToken ) ;
131
149
132
150
// Assert
133
151
Assert . NotNull ( result ) ;
134
- Assert . Equal ( "Image received!" , result . Content . Text ) ;
152
+ Assert . Equal ( expectedData , result . Content . Data ) ;
135
153
Assert . Equal ( "test-model" , result . Model ) ;
136
154
Assert . Equal ( "assistant" , result . Role ) ;
137
155
Assert . Equal ( "endTurn" , result . StopReason ) ;
@@ -141,55 +159,65 @@ public async Task CreateSamplingHandler_ShouldHandleImageMessages()
141
159
public async Task CreateSamplingHandler_ShouldHandleResourceMessages ( )
142
160
{
143
161
// Arrange
162
+ const string data = "SGVsbG8sIFdvcmxkIQ==" ;
163
+ string content = $ "data:application/octet-stream;base64,{ data } ";
144
164
var mockChatClient = new Mock < IChatClient > ( ) ;
165
+ var resource = new BlobResourceContents
166
+ {
167
+ Blob = data ,
168
+ MimeType = "application/octet-stream" ,
169
+ Uri = "data:application/octet-stream"
170
+ } ;
171
+
145
172
var requestParams = new CreateMessageRequestParams
146
173
{
147
- Messages = new [ ]
148
- {
149
- new SamplingMessage
150
- {
151
- Role = Role . User ,
152
- Content = new Content
174
+ Messages =
175
+ [
176
+ new SamplingMessage
153
177
{
154
- Type = "resource" ,
155
- Resource = new ResourceContents
178
+ Role = Role . User ,
179
+ Content = new Content
156
180
{
157
- Text = "Resource text" ,
158
- Blob = Convert . ToBase64String ( new byte [ ] { 4 , 5 , 6 } ) ,
159
- MimeType = "application/octet-stream"
160
- }
181
+ Type = "resource" ,
182
+ Resource = resource
183
+ } ,
161
184
}
162
- }
163
- } ,
185
+ ] ,
164
186
MaxTokens = 100
165
187
} ;
166
- var cancellationToken = CancellationToken . None ;
167
188
168
- var expectedResponse = new ChatResponse
169
- {
170
- Messages = { new ChatMessage { Role = ChatRole . Assistant , Contents = new [ ] { new TextContent ( "Resource processed!" ) } } } ,
171
- ModelId = "test-model" ,
172
- FinishReason = ChatFinishReason . Stop
173
- } ;
189
+ var cancellationToken = CancellationToken . None ;
190
+ var expectedResponse = new [ ] {
191
+ new ChatResponseUpdate
192
+ {
193
+ ModelId = "test-model" ,
194
+ FinishReason = ChatFinishReason . Stop ,
195
+ AuthorName = "bot" ,
196
+ Role = ChatRole . Assistant ,
197
+ Contents =
198
+ [
199
+ resource . ToAIContent ( )
200
+ ]
201
+ }
202
+ } . ToAsyncEnumerable ( ) ;
174
203
175
204
mockChatClient
176
- . Setup ( client => client . GetResponseAsync ( It . IsAny < IList < ChatMessage > > ( ) , It . IsAny < ChatOptions > ( ) , cancellationToken ) )
177
- . ReturnsAsync ( expectedResponse ) ;
205
+ . Setup ( client => client . GetStreamingResponseAsync ( It . IsAny < IEnumerable < ChatMessage > > ( ) , It . IsAny < ChatOptions > ( ) , cancellationToken ) )
206
+ . Returns ( expectedResponse ) ;
178
207
179
208
var handler = McpClientExtensions . CreateSamplingHandler ( mockChatClient . Object ) ;
180
209
181
210
// Act
182
- var result = await handler ( requestParams , cancellationToken ) ;
211
+ var result = await handler ( requestParams , Mock . Of < IProgress < ProgressNotificationValue > > ( ) , cancellationToken ) ;
183
212
184
213
// Assert
185
214
Assert . NotNull ( result ) ;
186
- Assert . Equal ( "Resource processed!" , result . Content . Text ) ;
187
215
Assert . Equal ( "test-model" , result . Model ) ;
188
- Assert . Equal ( "assistant" , result . Role ) ;
216
+ Assert . Equal ( ChatRole . Assistant . ToString ( ) , result . Role ) ;
189
217
Assert . Equal ( "endTurn" , result . StopReason ) ;
190
218
}
191
219
192
- public ValueTask DisposeAsync ( )
220
+ public async ValueTask DisposeAsync ( )
193
221
{
194
222
await _cts . CancelAsync ( ) ;
195
223
0 commit comments