@@ -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<Newtonsoft.Json.Linq.JObject>(preserveContent: true)?["method"]?.ToString()) ?? string.Empty)" />
46+ <set-variable name="rpcId" value="@((context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true)?["id"]?.ToString()) ?? "1")" />
47+ <set-variable name="toolName" value="@((context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true)?.SelectToken("params.name")?.ToString()) ?? string.Empty)" />
48+ <set-variable name="toolId" value="@((context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true)?.SelectToken("params.arguments.id")?.ToString()) ?? "1")" />
49+ <set-variable name="createTodoText" value="@((context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true)?.SelectToken("params.arguments.text")?.ToString()) ?? "Prepare APIOps demo")" />
50+ <set-variable name="createCompleted" value="@((context.Request.Body?.As<Newtonsoft.Json.Linq.JObject>(preserveContent: true)?.SelectToken("params.arguments.completed")?.ToString()) ?? "false")" />
51+ <choose>
52+ <when condition="@((string)context.Variables["rpcMethod"] == "initialize")">
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["rpcMethod"] == "tools/list")">
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["rpcMethod"] == "tools/call" && (string)context.Variables["toolName"] == "healthCheck")">
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["rpcMethod"] == "tools/call" && (string)context.Variables["toolName"] == "listItems")">
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["dummyResp"]).Body.As<string>(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["rpcMethod"] == "tools/call" && (string)context.Variables["toolName"] == "getItem")">
240+ <send-request mode="new" response-variable-name="dummyResp" timeout="20" ignore-error="false">
241+ <set-url>@($"https://dummyjson.com/todos/{(string)context.Variables["toolId"]}")</set-url>
242+ <set-method>GET</set-method>
243+ </send-request>
244+ <set-variable name="dummyBody" value="@(((IResponse)context.Variables["dummyResp"]).Body.As<string>(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["rpcMethod"] == "tools/call" && (string)context.Variables["toolName"] == "createItem")">
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["dummyResp"]).Body.As<string>(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["rpcMethod"] == "notifications/initialized")">
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+
41366var 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+
72402resource 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+
99438resource policyRestriction 'Microsoft.ApiManagement/service/policyRestrictions@2025-09-01-preview' = if (isClassicSku ) {
100439 parent : apim
101440 name : 'src-restriction-ip'
0 commit comments