6
6
package software .amazon .smithy .java .mcp .server ;
7
7
8
8
import static org .junit .jupiter .api .Assertions .assertEquals ;
9
+ import static org .junit .jupiter .api .Assertions .assertNotNull ;
9
10
import static org .junit .jupiter .api .Assertions .assertTrue ;
10
11
12
+ import java .math .BigDecimal ;
13
+ import java .math .BigInteger ;
14
+ import java .nio .charset .StandardCharsets ;
15
+ import java .util .List ;
11
16
import java .util .Map ;
17
+ import java .util .concurrent .atomic .AtomicReference ;
12
18
import org .junit .jupiter .api .AfterEach ;
13
19
import org .junit .jupiter .api .BeforeEach ;
14
20
import org .junit .jupiter .api .Test ;
21
+ import software .amazon .smithy .java .client .core .interceptors .ClientInterceptor ;
22
+ import software .amazon .smithy .java .client .core .interceptors .InputHook ;
15
23
import software .amazon .smithy .java .core .serde .document .Document ;
24
+ import software .amazon .smithy .java .dynamicschemas .StructDocument ;
16
25
import software .amazon .smithy .java .json .JsonCodec ;
17
26
import software .amazon .smithy .java .json .JsonSettings ;
18
27
import software .amazon .smithy .java .mcp .model .JsonRpcRequest ;
21
30
import software .amazon .smithy .java .server .Server ;
22
31
import software .amazon .smithy .model .Model ;
23
32
import software .amazon .smithy .model .shapes .ShapeId ;
33
+ import software .amazon .smithy .model .shapes .ShapeType ;
24
34
25
35
public class McpServerTest {
26
36
private static final JsonCodec CODEC = JsonCodec .builder ()
@@ -84,6 +94,9 @@ public void validateToolStructure() {
84
94
var list = properties .get ("list" ).asStringMap ();
85
95
assertEquals ("array" , list .get ("type" ).asString ());
86
96
97
+ var bigDecimal = properties .get ("bigDecimalField" ).asStringMap ();
98
+ assertEquals ("string" , bigDecimal .get ("type" ).asString ());
99
+
87
100
var listItems = list .get ("items" ).asStringMap ();
88
101
assertEquals ("object" , listItems .get ("type" ).asString ());
89
102
var listItemProperties = listItems .get ("properties" ).asStringMap ();
@@ -106,6 +119,111 @@ public void validateToolStructure() {
106
119
validateNestedStructure (doubleNestedProperties );
107
120
}
108
121
122
+ @ Test
123
+ void testInputAdaptation () {
124
+ AtomicReference <StructDocument > capturedInput = new AtomicReference <>();
125
+ server = McpServer .builder ()
126
+ .input (input )
127
+ .output (output )
128
+ .addService (ProxyService .builder ()
129
+ .service (ShapeId .from ("smithy.test#TestService" ))
130
+ .proxyEndpoint ("http://localhost" )
131
+ .clientConfigurator (
132
+ clientConfigurator -> clientConfigurator .addInterceptor (new ClientInterceptor () {
133
+ @ Override
134
+ public void readBeforeSerialization (InputHook <?, ?> hook ) {
135
+ capturedInput .set ((StructDocument ) hook .input ());
136
+ }
137
+ }))
138
+ .model (MODEL )
139
+ .build ())
140
+ .build ();
141
+
142
+ server .start ();
143
+
144
+ var bigDecimalValue = BigDecimal .valueOf (Integer .MAX_VALUE ).add (BigDecimal .TEN );
145
+ var bigIntegerValue = BigInteger .valueOf (Long .MAX_VALUE ).add (BigInteger .valueOf (100 ));
146
+ var blobValue = "Hello, World!" ;
147
+ var nestedBigDecimalValue = new BigDecimal ("123.456" );
148
+ var nestedBigIntegerValue = new BigInteger ("9876543210" );
149
+ var nestedBlobValue = "Nested blob content" ;
150
+
151
+ write ("tools/call" ,
152
+ Document .of (
153
+ Map .of ("name" ,
154
+ Document .of ("TestOperation" ),
155
+ "arguments" ,
156
+ Document .of (Map .of (
157
+ "bigDecimalField" ,
158
+ Document .of (bigDecimalValue .toString ()),
159
+ "bigIntegerField" ,
160
+ Document .of (bigIntegerValue .toString ()),
161
+ "blobField" ,
162
+ Document .of (blobValue ),
163
+ "nestedWithBigNumbers" ,
164
+ Document .of (Map .of (
165
+ "nestedBigDecimal" ,
166
+ Document .of (nestedBigDecimalValue .toString ()),
167
+ "nestedBigInteger" ,
168
+ Document .of (nestedBigIntegerValue .toString ()),
169
+ "nestedBlob" ,
170
+ Document .of (nestedBlobValue ),
171
+ "bigDecimalList" ,
172
+ Document .of (List .of (
173
+ Document .of ("100.25" ),
174
+ Document .of ("200.75" ))))))))));
175
+ assertNotNull (read ());
176
+ var inputDocument = capturedInput .get ();
177
+
178
+ var bigDecimalField = inputDocument .getMember ("bigDecimalField" );
179
+ assertNotNull (bigDecimalField );
180
+ assertEquals (ShapeType .BIG_DECIMAL , bigDecimalField .type ());
181
+ assertEquals (bigDecimalValue , bigDecimalField .asBigDecimal ());
182
+
183
+ var bigIntegerField = inputDocument .getMember ("bigIntegerField" );
184
+ assertNotNull (bigIntegerField );
185
+ assertEquals (ShapeType .BIG_INTEGER , bigIntegerField .type ());
186
+ assertEquals (bigIntegerValue , bigIntegerField .asBigInteger ());
187
+
188
+ var blobField = inputDocument .getMember ("blobField" );
189
+ assertNotNull (blobField );
190
+ assertEquals (ShapeType .BLOB , blobField .type ());
191
+ assertEquals (blobValue , new String (blobField .asBlob ().array (), StandardCharsets .UTF_8 ));
192
+
193
+ var nestedWithBigNumbers = inputDocument .getMember ("nestedWithBigNumbers" );
194
+ assertNotNull (nestedWithBigNumbers );
195
+ assertEquals (ShapeType .STRUCTURE , nestedWithBigNumbers .type ());
196
+
197
+ var nestedStruct = (StructDocument ) nestedWithBigNumbers ;
198
+
199
+ var nestedBigDecimalField = nestedStruct .getMember ("nestedBigDecimal" );
200
+ assertNotNull (nestedBigDecimalField );
201
+ assertEquals (ShapeType .BIG_DECIMAL , nestedBigDecimalField .type ());
202
+ assertEquals (nestedBigDecimalValue , nestedBigDecimalField .asBigDecimal ());
203
+
204
+ var nestedBigIntegerField = nestedStruct .getMember ("nestedBigInteger" );
205
+ assertNotNull (nestedBigIntegerField );
206
+ assertEquals (ShapeType .BIG_INTEGER , nestedBigIntegerField .type ());
207
+ assertEquals (nestedBigIntegerValue , nestedBigIntegerField .asBigInteger ());
208
+
209
+ var nestedBlobField = nestedStruct .getMember ("nestedBlob" );
210
+ assertNotNull (nestedBlobField );
211
+ assertEquals (ShapeType .BLOB , nestedBlobField .type ());
212
+ assertEquals (nestedBlobValue , new String (nestedBlobField .asBlob ().array (), StandardCharsets .UTF_8 ));
213
+
214
+ var bigDecimalListField = nestedStruct .getMember ("bigDecimalList" );
215
+ assertNotNull (bigDecimalListField );
216
+ assertEquals (ShapeType .LIST , bigDecimalListField .type ());
217
+ var bigDecimalList = bigDecimalListField .asList ();
218
+ assertEquals (2 , bigDecimalList .size ());
219
+ assertEquals (ShapeType .BIG_DECIMAL , bigDecimalList .get (0 ).type ());
220
+ assertEquals (ShapeType .BIG_DECIMAL , bigDecimalList .get (1 ).type ());
221
+ assertEquals (new BigDecimal ("100.25" ), bigDecimalList .get (0 ).asBigDecimal ());
222
+ assertEquals (new BigDecimal ("200.75" ), bigDecimalList .get (1 ).asBigDecimal ());
223
+
224
+ server .shutdown ().join ();
225
+ }
226
+
109
227
private void validateNestedStructure (Map <String , Document > properties ) {
110
228
var nestedStr = properties .get ("nestedStr" ).asStringMap ();
111
229
assertEquals ("string" , nestedStr .get ("type" ).asString ());
@@ -154,6 +272,7 @@ private JsonRpcResponse read() {
154
272
/// A TestOperation
155
273
operation TestOperation {
156
274
input: TestInput
275
+ output: TestInput
157
276
}
158
277
159
278
/// An input for TestOperation with a nested member
@@ -167,6 +286,14 @@ private JsonRpcResponse read() {
167
286
list: NestedList
168
287
169
288
doubleNestedList: DoubleNestedList
289
+
290
+ bigDecimalField: BigDecimal
291
+
292
+ bigIntegerField: BigInteger
293
+
294
+ blobField: Blob
295
+
296
+ nestedWithBigNumbers: NestedWithBigNumbers
170
297
}
171
298
172
299
list NestedList {
@@ -193,6 +320,25 @@ private JsonRpcResponse read() {
193
320
structure Recursive {
194
321
/// the nested field that points back to us
195
322
nested: Nested
323
+ }
324
+
325
+ /// A structure containing big number types
326
+ structure NestedWithBigNumbers {
327
+ /// A nested BigDecimal
328
+ nestedBigDecimal: BigDecimal
329
+
330
+ /// A nested BigInteger
331
+ nestedBigInteger: BigInteger
332
+
333
+ /// A nested Blob
334
+ nestedBlob: Blob
335
+
336
+ /// A list of BigDecimals
337
+ bigDecimalList: BigDecimalList
338
+ }
339
+
340
+ list BigDecimalList {
341
+ member: BigDecimal
196
342
}""" ;
197
343
198
344
private static final Model MODEL = Model .assembler ()
0 commit comments