Skip to content

Commit d37a972

Browse files
committed
Saving update for working mcp server from kitchen sink.
1 parent 601f36a commit d37a972

2 files changed

Lines changed: 473 additions & 25 deletions

File tree

tests/integration/all-resource-types/source-apim-post-activation.bicep

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,331 @@ var apiPolicyXml = '''
3838
</policies>
3939
'''
4040

41+
var mcpApiPolicyXml = '''
42+
<policies>
43+
<inbound>
44+
<base />
45+
<set-variable name="rpcMethod" value="@((context.Request.Body?.As&lt;Newtonsoft.Json.Linq.JObject&gt;(preserveContent: true)?[&quot;method&quot;]?.ToString()) ?? string.Empty)" />
46+
<set-variable name="rpcId" value="@((context.Request.Body?.As&lt;Newtonsoft.Json.Linq.JObject&gt;(preserveContent: true)?[&quot;id&quot;]?.ToString()) ?? &quot;1&quot;)" />
47+
<set-variable name="toolName" value="@((context.Request.Body?.As&lt;Newtonsoft.Json.Linq.JObject&gt;(preserveContent: true)?.SelectToken(&quot;params.name&quot;)?.ToString()) ?? string.Empty)" />
48+
<set-variable name="toolId" value="@((context.Request.Body?.As&lt;Newtonsoft.Json.Linq.JObject&gt;(preserveContent: true)?.SelectToken(&quot;params.arguments.id&quot;)?.ToString()) ?? &quot;1&quot;)" />
49+
<set-variable name="createTodoText" value="@((context.Request.Body?.As&lt;Newtonsoft.Json.Linq.JObject&gt;(preserveContent: true)?.SelectToken(&quot;params.arguments.text&quot;)?.ToString()) ?? &quot;Prepare APIOps demo&quot;)" />
50+
<set-variable name="createCompleted" value="@((context.Request.Body?.As&lt;Newtonsoft.Json.Linq.JObject&gt;(preserveContent: true)?.SelectToken(&quot;params.arguments.completed&quot;)?.ToString()) ?? &quot;false&quot;)" />
51+
<choose>
52+
<when condition="@((string)context.Variables[&quot;rpcMethod&quot;] == &quot;initialize&quot;)">
53+
<return-response>
54+
<set-status code="200" reason="OK" />
55+
<set-header name="Content-Type" exists-action="override">
56+
<value>application/json</value>
57+
</set-header>
58+
<set-header name="MCP-Protocol-Version" exists-action="override">
59+
<value>2025-03-26</value>
60+
</set-header>
61+
<set-body>@{
62+
var req = context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true) ?? new Newtonsoft.Json.Linq.JObject();
63+
var idRaw = req["id"]?.ToString() ?? "1";
64+
long idLong;
65+
Newtonsoft.Json.Linq.JToken idToken = long.TryParse(idRaw, out idLong) ? (Newtonsoft.Json.Linq.JToken)new Newtonsoft.Json.Linq.JValue(idLong) : new Newtonsoft.Json.Linq.JValue(idRaw);
66+
var response = new Newtonsoft.Json.Linq.JObject
67+
{
68+
["jsonrpc"] = "2.0",
69+
["id"] = idToken,
70+
["result"] = new Newtonsoft.Json.Linq.JObject
71+
{
72+
["protocolVersion"] = "2025-03-26",
73+
["serverInfo"] = new Newtonsoft.Json.Linq.JObject
74+
{
75+
["name"] = "apim-mcp-demo",
76+
["version"] = "1.1.0"
77+
},
78+
["capabilities"] = new Newtonsoft.Json.Linq.JObject
79+
{
80+
["tools"] = new Newtonsoft.Json.Linq.JObject()
81+
}
82+
}
83+
};
84+
return response.ToString(Newtonsoft.Json.Formatting.None);
85+
}</set-body>
86+
</return-response>
87+
</when>
88+
<when condition="@((string)context.Variables[&quot;rpcMethod&quot;] == &quot;tools/list&quot;)">
89+
<return-response>
90+
<set-status code="200" reason="OK" />
91+
<set-header name="Content-Type" exists-action="override">
92+
<value>application/json</value>
93+
</set-header>
94+
<set-body>@{
95+
var req = context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true) ?? new Newtonsoft.Json.Linq.JObject();
96+
var idRaw = req["id"]?.ToString() ?? "1";
97+
long idLong;
98+
Newtonsoft.Json.Linq.JToken idToken = long.TryParse(idRaw, out idLong) ? (Newtonsoft.Json.Linq.JToken)new Newtonsoft.Json.Linq.JValue(idLong) : new Newtonsoft.Json.Linq.JValue(idRaw);
99+
var tools = new Newtonsoft.Json.Linq.JArray
100+
{
101+
new Newtonsoft.Json.Linq.JObject
102+
{
103+
["name"] = "healthCheck",
104+
["description"] = "Return APIM MCP server health",
105+
["inputSchema"] = new Newtonsoft.Json.Linq.JObject
106+
{
107+
["type"] = "object",
108+
["properties"] = new Newtonsoft.Json.Linq.JObject()
109+
}
110+
},
111+
new Newtonsoft.Json.Linq.JObject
112+
{
113+
["name"] = "listItems",
114+
["description"] = "List todo items from DummyJSON",
115+
["inputSchema"] = new Newtonsoft.Json.Linq.JObject
116+
{
117+
["type"] = "object",
118+
["properties"] = new Newtonsoft.Json.Linq.JObject()
119+
}
120+
},
121+
new Newtonsoft.Json.Linq.JObject
122+
{
123+
["name"] = "getItem",
124+
["description"] = "Get a todo item by id from DummyJSON",
125+
["inputSchema"] = new Newtonsoft.Json.Linq.JObject
126+
{
127+
["type"] = "object",
128+
["properties"] = new Newtonsoft.Json.Linq.JObject
129+
{
130+
["id"] = new Newtonsoft.Json.Linq.JObject
131+
{
132+
["type"] = "integer"
133+
}
134+
},
135+
["required"] = new Newtonsoft.Json.Linq.JArray { "id" }
136+
}
137+
},
138+
new Newtonsoft.Json.Linq.JObject
139+
{
140+
["name"] = "createItem",
141+
["description"] = "Create a todo item in DummyJSON",
142+
["inputSchema"] = new Newtonsoft.Json.Linq.JObject
143+
{
144+
["type"] = "object",
145+
["properties"] = new Newtonsoft.Json.Linq.JObject
146+
{
147+
["text"] = new Newtonsoft.Json.Linq.JObject { ["type"] = "string" },
148+
["completed"] = new Newtonsoft.Json.Linq.JObject { ["type"] = "boolean" }
149+
},
150+
["required"] = new Newtonsoft.Json.Linq.JArray { "text" }
151+
}
152+
}
153+
};
154+
155+
var response = new Newtonsoft.Json.Linq.JObject
156+
{
157+
["jsonrpc"] = "2.0",
158+
["id"] = idToken,
159+
["result"] = new Newtonsoft.Json.Linq.JObject { ["tools"] = tools }
160+
};
161+
return response.ToString(Newtonsoft.Json.Formatting.None);
162+
}</set-body>
163+
</return-response>
164+
</when>
165+
<when condition="@((string)context.Variables[&quot;rpcMethod&quot;] == &quot;tools/call&quot; &amp;&amp; (string)context.Variables[&quot;toolName&quot;] == &quot;healthCheck&quot;)">
166+
<return-response>
167+
<set-status code="200" reason="OK" />
168+
<set-header name="Content-Type" exists-action="override">
169+
<value>application/json</value>
170+
</set-header>
171+
<set-body>@{
172+
var req = context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true) ?? new Newtonsoft.Json.Linq.JObject();
173+
var idRaw = req["id"]?.ToString() ?? "1";
174+
long idLong;
175+
Newtonsoft.Json.Linq.JToken idToken = long.TryParse(idRaw, out idLong) ? (Newtonsoft.Json.Linq.JToken)new Newtonsoft.Json.Linq.JValue(idLong) : new Newtonsoft.Json.Linq.JValue(idRaw);
176+
var payload = new Newtonsoft.Json.Linq.JObject
177+
{
178+
["status"] = "ok",
179+
["source"] = "apim",
180+
["timestampUtc"] = System.DateTime.UtcNow.ToString("o")
181+
};
182+
var response = new Newtonsoft.Json.Linq.JObject
183+
{
184+
["jsonrpc"] = "2.0",
185+
["id"] = idToken,
186+
["result"] = new Newtonsoft.Json.Linq.JObject
187+
{
188+
["content"] = new Newtonsoft.Json.Linq.JArray
189+
{
190+
new Newtonsoft.Json.Linq.JObject
191+
{
192+
["type"] = "text",
193+
["text"] = payload.ToString(Newtonsoft.Json.Formatting.None)
194+
}
195+
}
196+
}
197+
};
198+
return response.ToString(Newtonsoft.Json.Formatting.None);
199+
}</set-body>
200+
</return-response>
201+
</when>
202+
<when condition="@((string)context.Variables[&quot;rpcMethod&quot;] == &quot;tools/call&quot; &amp;&amp; (string)context.Variables[&quot;toolName&quot;] == &quot;listItems&quot;)">
203+
<send-request mode="new" response-variable-name="dummyResp" timeout="20" ignore-error="false">
204+
<set-url>https://dummyjson.com/todos?limit=10</set-url>
205+
<set-method>GET</set-method>
206+
</send-request>
207+
<set-variable name="dummyBody" value="@(((IResponse)context.Variables[&quot;dummyResp&quot;]).Body.As&lt;string&gt;(preserveContent: true))" />
208+
<return-response>
209+
<set-status code="200" reason="OK" />
210+
<set-header name="Content-Type" exists-action="override">
211+
<value>application/json</value>
212+
</set-header>
213+
<set-body>@{
214+
var req = context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true) ?? new Newtonsoft.Json.Linq.JObject();
215+
var idRaw = req["id"]?.ToString() ?? "1";
216+
long idLong;
217+
Newtonsoft.Json.Linq.JToken idToken = long.TryParse(idRaw, out idLong) ? (Newtonsoft.Json.Linq.JToken)new Newtonsoft.Json.Linq.JValue(idLong) : new Newtonsoft.Json.Linq.JValue(idRaw);
218+
var text = (string)context.Variables["dummyBody"];
219+
var response = new Newtonsoft.Json.Linq.JObject
220+
{
221+
["jsonrpc"] = "2.0",
222+
["id"] = idToken,
223+
["result"] = new Newtonsoft.Json.Linq.JObject
224+
{
225+
["content"] = new Newtonsoft.Json.Linq.JArray
226+
{
227+
new Newtonsoft.Json.Linq.JObject
228+
{
229+
["type"] = "text",
230+
["text"] = text
231+
}
232+
}
233+
}
234+
};
235+
return response.ToString(Newtonsoft.Json.Formatting.None);
236+
}</set-body>
237+
</return-response>
238+
</when>
239+
<when condition="@((string)context.Variables[&quot;rpcMethod&quot;] == &quot;tools/call&quot; &amp;&amp; (string)context.Variables[&quot;toolName&quot;] == &quot;getItem&quot;)">
240+
<send-request mode="new" response-variable-name="dummyResp" timeout="20" ignore-error="false">
241+
<set-url>@($"https://dummyjson.com/todos/{(string)context.Variables[&quot;toolId&quot;]}")</set-url>
242+
<set-method>GET</set-method>
243+
</send-request>
244+
<set-variable name="dummyBody" value="@(((IResponse)context.Variables[&quot;dummyResp&quot;]).Body.As&lt;string&gt;(preserveContent: true))" />
245+
<return-response>
246+
<set-status code="200" reason="OK" />
247+
<set-header name="Content-Type" exists-action="override">
248+
<value>application/json</value>
249+
</set-header>
250+
<set-body>@{
251+
var req = context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true) ?? new Newtonsoft.Json.Linq.JObject();
252+
var idRaw = req["id"]?.ToString() ?? "1";
253+
long idLong;
254+
Newtonsoft.Json.Linq.JToken idToken = long.TryParse(idRaw, out idLong) ? (Newtonsoft.Json.Linq.JToken)new Newtonsoft.Json.Linq.JValue(idLong) : new Newtonsoft.Json.Linq.JValue(idRaw);
255+
var text = (string)context.Variables["dummyBody"];
256+
var response = new Newtonsoft.Json.Linq.JObject
257+
{
258+
["jsonrpc"] = "2.0",
259+
["id"] = idToken,
260+
["result"] = new Newtonsoft.Json.Linq.JObject
261+
{
262+
["content"] = new Newtonsoft.Json.Linq.JArray
263+
{
264+
new Newtonsoft.Json.Linq.JObject
265+
{
266+
["type"] = "text",
267+
["text"] = text
268+
}
269+
}
270+
}
271+
};
272+
return response.ToString(Newtonsoft.Json.Formatting.None);
273+
}</set-body>
274+
</return-response>
275+
</when>
276+
<when condition="@((string)context.Variables[&quot;rpcMethod&quot;] == &quot;tools/call&quot; &amp;&amp; (string)context.Variables[&quot;toolName&quot;] == &quot;createItem&quot;)">
277+
<send-request mode="new" response-variable-name="dummyResp" timeout="20" ignore-error="false">
278+
<set-url>https://dummyjson.com/todos/add</set-url>
279+
<set-method>POST</set-method>
280+
<set-header name="Content-Type" exists-action="override">
281+
<value>application/json</value>
282+
</set-header>
283+
<set-body>@{
284+
var text = ((string)context.Variables["createTodoText"] ?? "Prepare APIOps demo").Replace("\\", "\\\\").Replace("\"", "\\\"");
285+
var completedRaw = ((string)context.Variables["createCompleted"] ?? "false").ToLowerInvariant();
286+
var completed = (completedRaw == "true") ? "true" : "false";
287+
return "{\"todo\":\"" + text + "\",\"completed\":" + completed + ",\"userId\":1}";
288+
}</set-body>
289+
</send-request>
290+
<set-variable name="dummyBody" value="@(((IResponse)context.Variables[&quot;dummyResp&quot;]).Body.As&lt;string&gt;(preserveContent: true))" />
291+
<return-response>
292+
<set-status code="200" reason="OK" />
293+
<set-header name="Content-Type" exists-action="override">
294+
<value>application/json</value>
295+
</set-header>
296+
<set-body>@{
297+
var req = context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true) ?? new Newtonsoft.Json.Linq.JObject();
298+
var idRaw = req["id"]?.ToString() ?? "1";
299+
long idLong;
300+
Newtonsoft.Json.Linq.JToken idToken = long.TryParse(idRaw, out idLong) ? (Newtonsoft.Json.Linq.JToken)new Newtonsoft.Json.Linq.JValue(idLong) : new Newtonsoft.Json.Linq.JValue(idRaw);
301+
var text = (string)context.Variables["dummyBody"];
302+
var response = new Newtonsoft.Json.Linq.JObject
303+
{
304+
["jsonrpc"] = "2.0",
305+
["id"] = idToken,
306+
["result"] = new Newtonsoft.Json.Linq.JObject
307+
{
308+
["content"] = new Newtonsoft.Json.Linq.JArray
309+
{
310+
new Newtonsoft.Json.Linq.JObject
311+
{
312+
["type"] = "text",
313+
["text"] = text
314+
}
315+
}
316+
}
317+
};
318+
return response.ToString(Newtonsoft.Json.Formatting.None);
319+
}</set-body>
320+
</return-response>
321+
</when>
322+
<when condition="@((string)context.Variables[&quot;rpcMethod&quot;] == &quot;notifications/initialized&quot;)">
323+
<return-response>
324+
<set-status code="202" reason="Accepted" />
325+
</return-response>
326+
</when>
327+
<otherwise>
328+
<return-response>
329+
<set-status code="200" reason="OK" />
330+
<set-header name="Content-Type" exists-action="override">
331+
<value>application/json</value>
332+
</set-header>
333+
<set-body>@{
334+
var req = context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true) ?? new Newtonsoft.Json.Linq.JObject();
335+
var idRaw = req["id"]?.ToString() ?? "1";
336+
long idLong;
337+
Newtonsoft.Json.Linq.JToken idToken = long.TryParse(idRaw, out idLong) ? (Newtonsoft.Json.Linq.JToken)new Newtonsoft.Json.Linq.JValue(idLong) : new Newtonsoft.Json.Linq.JValue(idRaw);
338+
var response = new Newtonsoft.Json.Linq.JObject
339+
{
340+
["jsonrpc"] = "2.0",
341+
["id"] = idToken,
342+
["error"] = new Newtonsoft.Json.Linq.JObject
343+
{
344+
["code"] = -32601,
345+
["message"] = "Method not found"
346+
}
347+
};
348+
return response.ToString(Newtonsoft.Json.Formatting.None);
349+
}</set-body>
350+
</return-response>
351+
</otherwise>
352+
</choose>
353+
</inbound>
354+
<backend>
355+
<base />
356+
</backend>
357+
<outbound>
358+
<base />
359+
</outbound>
360+
<on-error>
361+
<base />
362+
</on-error>
363+
</policies>
364+
'''
365+
41366
var productPolicyXml = '''
42367
<policies>
43368
<inbound>
@@ -69,6 +394,11 @@ resource apiRestOpenapi 'Microsoft.ApiManagement/service/apis@2025-09-01-preview
69394
name: 'src-rest-openapi'
70395
}
71396

397+
resource apiMcpFromApi 'Microsoft.ApiManagement/service/apis@2025-09-01-preview' existing = {
398+
parent: apim
399+
name: 'src-mcp-from-api'
400+
}
401+
72402
resource servicePolicy 'Microsoft.ApiManagement/service/policies@2025-09-01-preview' = {
73403
parent: apim
74404
name: 'policy'
@@ -96,6 +426,15 @@ resource apiRestPolicy 'Microsoft.ApiManagement/service/apis/policies@2025-09-01
96426
}
97427
}
98428

429+
resource apiMcpFromApiPolicy 'Microsoft.ApiManagement/service/apis/policies@2025-09-01-preview' = {
430+
parent: apiMcpFromApi
431+
name: 'policy'
432+
properties: {
433+
format: 'rawxml'
434+
value: mcpApiPolicyXml
435+
}
436+
}
437+
99438
resource policyRestriction 'Microsoft.ApiManagement/service/policyRestrictions@2025-09-01-preview' = if (isClassicSku) {
100439
parent: apim
101440
name: 'src-restriction-ip'

0 commit comments

Comments
 (0)