{"id":4652,"date":"2025-04-21T11:13:33","date_gmt":"2025-04-21T18:13:33","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/semantic-kernel\/?p=4652"},"modified":"2025-04-21T11:13:33","modified_gmt":"2025-04-21T18:13:33","slug":"guest-blog-build-an-ai-app-that-can-browse-the-internet-using-microsofts-playwright-mcp-server-semantic-kernel-in-just-4-steps","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/agent-framework\/guest-blog-build-an-ai-app-that-can-browse-the-internet-using-microsofts-playwright-mcp-server-semantic-kernel-in-just-4-steps\/","title":{"rendered":"Guest Blog: Build an AI App That Can Browse the Internet Using Microsoft\u2019s Playwright MCP Server &#038; Semantic Kernel \u2014 in Just 4 Steps"},"content":{"rendered":"<div>Today we&#8217;re excited to feature a returning guest author, <a href=\"https:\/\/medium.com\/@akshaykokane09\" target=\"_blank\" rel=\"noopener\">Akshay Kokane<\/a>\u00a0to share his recent Medium article on <a href=\"https:\/\/ai.gopubby.com\/build-an-ai-app-that-can-browse-the-internet-using-microsofts-playwright-mcp-server-semantic-d7b41de1dcb9\">Building an AI App That Can Browse the Internet Using Microsoft\u2019s Playwright MCP Server &amp; Semantic Kernel<\/a>. We\u2019ll turn it over to him to dive in!<\/div>\n<p><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:1000\/1*nskOer2xNZzlnJv8eV_GKQ.png\" \/><\/p>\n<p id=\"213e\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\"><strong class=\"pm jn\">MCP<\/strong>! It\u2019s the new buzzword in the AI world. So, I thought \u2014 why not be a part of this buzz myself? That\u2019s why I wrote this blog on using the MCP server with Semantic Kernel and Azure AI Foundry.<\/p>\n<p id=\"d408\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\">Let\u2019s start by understanding:\u00a0<strong class=\"pm jn\">What is MCP?<\/strong>\nThere are many blogs and videos that helped me grasp the MCP concept, and I\u2019ll drop those links at the end. But for me, the simplest way to understand MCP was this: just like REST defined a standardized way to interact with Web APIs,\u00a0<strong class=\"pm jn\">Model Context Protocol (MCP)<\/strong>\u00a0by Anthropic provides a standardized way for LLMs to interact with external services.<\/p>\n<p data-selectable-paragraph=\"\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:1000\/1*2AQ5lthsq4EOUnnSk4dK3w.gif\" \/><\/p>\n<p id=\"9787\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\">Whenever I develop an AI app and want to add a new tool or action to my AI agent, I usually need to implement a custom integration. For example, if I want my AI app to connect with AI Search, I have to define a connector to interact with the vector store in AI Search. Now, if I want to add web search capabilities, I need yet another connector to handle that.<\/p>\n<p id=\"3400\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\">AI frameworks like LangChain, Semantic Kernel, AutoGen, etc., do offer some out-of-the-box capabilities and common connectors \u2014 but they don\u2019t always scale well across all applications.<\/p>\n<p id=\"b1e0\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\">With\u00a0<strong class=\"pm jn\">MCP<\/strong>, I no longer need to deal with those complexities. The MCP Server developers have already created these connectors \u2014 and provided a standardized way to access them. All I have to do is connect to these MCP services from my MCP client (which could be Claude Desktop App, Cursor, Chainlit, etc.) and do tool calling without worrying about integration details. Isn\u2019t that cool?<\/p>\n<p id=\"4dd3\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\">Now let\u2019s dive into a use case.\nI want to build an LLM app in\u00a0<strong class=\"pm jn\">.NET<\/strong>\u00a0that reads that opens news website, click on first link and summarize the content. I created a similar agent using AutoGen in a previous\u00a0<a class=\"ag hc\" href=\"https:\/\/medium.com\/data-science-collective\/step-by-step-guide-to-building-an-openais-operator-like-agent-using-microsoft-s-autogen-framework-1b886b08b525\" rel=\"noopener\">blog<\/a>\u00a0\u2014 you can find more details there.<\/p>\n<p id=\"3f31\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\"><strong class=\"pm jn\">Step 1: Setup Semantic Kernel<\/strong><\/p>\n<pre class=\"qe qf qg qh qi rc rd re bp rf bb bk\"><span id=\"7aaa\" class=\"rg rh jm rd b bg ri rj l rk rl\" data-selectable-paragraph=\"\">            \r\n<span class=\"hljs-type\">var<\/span> <span class=\"hljs-variable\">builder<\/span> <span class=\"hljs-operator\">=<\/span> Kernel.CreateBuilder();\r\nbuilder.AddAzureOpenAIChatCompletion(<span class=\"hljs-string\">\"GPT4ov1\"<\/span>, <span class=\"hljs-string\">\"https:\/\/&lt;AzureOpenAI&gt;.openai.azure.com\"<\/span>, <span class=\"hljs-string\">\"&lt;REPLACE_WITH_KEY&gt;&gt;\"<\/span>);\r\n<span class=\"hljs-type\">Kernel<\/span> <span class=\"hljs-variable\">kernel<\/span> <span class=\"hljs-operator\">=<\/span> builder.Build();<\/span><\/pre>\n<p id=\"0a38\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\"><strong class=\"pm jn\">Step 2: Install official c#\u00a0<\/strong><a class=\"ag hc\" href=\"https:\/\/www.nuget.org\/packages\/ModelContextProtocol\" target=\"_blank\" rel=\"noopener ugc nofollow\"><strong class=\"pm jn\">MCP<\/strong><\/a><strong class=\"pm jn\">\u00a0in your .NET App and Setup MCP Client<\/strong><\/p>\n<pre class=\"qe qf qg qh qi rc rd re bp rf bb bk\"><span id=\"21d2\" class=\"rg rh jm rd b bg ri rj l rk rl\" data-selectable-paragraph=\"\">  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">async<\/span> Task&lt;IMcpClient&gt; <span class=\"hljs-title\">GetMCPClientForPlaywright<\/span>()<\/span>\r\n        {\r\n            McpClientOptions options = <span class=\"hljs-keyword\">new<\/span>()\r\n            {\r\n                ClientInfo = <span class=\"hljs-keyword\">new<\/span>() { Name = <span class=\"hljs-string\">\"Playwright\"<\/span>, Version = <span class=\"hljs-string\">\"1.0.0\"<\/span> }\r\n            };\r\n\r\n            <span class=\"hljs-keyword\">var<\/span> config = <span class=\"hljs-keyword\">new<\/span> McpServerConfig\r\n            {\r\n                Id = <span class=\"hljs-string\">\"Playwright\"<\/span>,\r\n                Name = <span class=\"hljs-string\">\"Playwright\"<\/span>,\r\n                TransportType = <span class=\"hljs-string\">\"stdio\"<\/span>,\r\n                TransportOptions = <span class=\"hljs-keyword\">new<\/span> Dictionary&lt;<span class=\"hljs-built_in\">string<\/span>, <span class=\"hljs-built_in\">string<\/span>&gt;\r\n                {\r\n                    [<span class=\"hljs-string\">\"command\"<\/span>] = <span class=\"hljs-string\">\"npx\"<\/span>,\r\n                    [<span class=\"hljs-string\">\"arguments\"<\/span>] = <span class=\"hljs-string\">\"-y @playwright\/mcp@latest\"<\/span>,\r\n                }\r\n            };\r\n\r\n            <span class=\"hljs-keyword\">var<\/span> mcpClient = <span class=\"hljs-keyword\">await<\/span> McpClientFactory.CreateAsync(\r\n        \r\n                config,\r\n                options\r\n                );\r\n\r\n            <span class=\"hljs-keyword\">return<\/span> mcpClient;\r\n        }<\/span><\/pre>\n<p id=\"168c\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\">You can verify your client is setup correctly by printing out avilabale tools from server<\/p>\n<pre class=\"qe qf qg qh qi rc rd re bp rf bb bk\"><span id=\"c596\" class=\"rg rh jm rd b bg ri rj l rk rl\" data-selectable-paragraph=\"\">            <span class=\"hljs-keyword\">var<\/span> mcpClient = <span class=\"hljs-keyword\">await<\/span> GetMCPClientForPlaywright();\r\n\r\n            <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">foreach<\/span> (<span class=\"hljs-keyword\">var<\/span> tool <span class=\"hljs-keyword\">in<\/span> mcpClient.ListToolsAsync())\r\n            {\r\n                Console.WriteLine(<span class=\"hljs-string\">$\"<span class=\"hljs-subst\">{tool.Name}<\/span> (<span class=\"hljs-subst\">{tool.Description}<\/span>)\"<\/span>);\r\n            }<\/span>\r\n\r\n<\/pre>\n<div class=\"ab cd\">\n<div class=\"ck bh hv hw hx hy\">\n<p id=\"c9e2\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\"><strong class=\"pm jn\">Step 3: Convert MCP Functions to KernelFunctions<\/strong><\/p>\n<p id=\"a1bc\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\"><mark class=\"acn aco ap\">Semantic Kernel tools or plugins are wrapped in\u00a0<\/mark><mark class=\"acn aco ap\"><code class=\"cz rm rn ro rd b\">KernelFunctions<\/code><\/mark><mark class=\"acn aco ap\">, so as an extra step when using MCP, we need to convert those functions into\u00a0<\/mark><mark class=\"acn aco ap\"><code class=\"cz rm rn ro rd b\">KernelFunctions<\/code><\/mark><mark class=\"acn aco ap\">.<\/mark>\u00a0There&#8217;s an extension provided by SK for this, but it doesn\u2019t work with the latest version of .NET MCP (at least, not when I tried it). So, I extended it to make it work with the latest version. I\u2019ll share the code in my code reference.<\/p>\n<pre class=\"qe qf qg qh qi rc rd re bp rf bb bk\"><span id=\"d320\" class=\"rg rh jm rd b bg ri rj l rk rl\" data-selectable-paragraph=\"\">\r\n            <span class=\"hljs-keyword\">var<\/span> KernelFunctions = <span class=\"hljs-keyword\">await<\/span> mcpClient.MapToFunctionsAsync();\r\n            kernel.Plugins.AddFromFunctions(<span class=\"hljs-string\">\"Browser\"<\/span>, KernelFunctions);<\/span><\/pre>\n<p id=\"0e7e\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\"><strong class=\"pm jn\">[Update \u2014 14th April 2025] :<\/strong><\/p>\n<p id=\"f989\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\">Semantic Kernel now officially supports MCP, and you can use the out-of-the-box extension to convert MCP Tools into Kernel Functions.<\/p>\n<pre class=\"qe qf qg qh qi rc rd re bp rf bb bk\"><span id=\"d8ce\" class=\"rg rh jm rd b bg ri rj l rk rl\" data-selectable-paragraph=\"\"><span class=\"hljs-keyword\">var<\/span> tools = <span class=\"hljs-keyword\">await<\/span> mcpClient.ListToolsAsync();\r\nkernel.Plugins.AddFromFunctions(<span class=\"hljs-string\">\"Browser\"<\/span>, tools.Select(aiFunction =&gt; aiFunction.AsKernelFunction()));<\/span><\/pre>\n<p id=\"bbfd\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\"><strong class=\"pm jn\">Step 4: Send your first message<\/strong><\/p>\n<pre class=\"qe qf qg qh qi rc rd re bp rf bb bk\"><span id=\"0181\" class=\"rg rh jm rd b bg ri rj l rk rl\" data-selectable-paragraph=\"\">            <span class=\"hljs-comment\">\/\/ Enable automatic function calling<\/span>\r\n            <span class=\"hljs-keyword\">var<\/span> executionSettings = <span class=\"hljs-keyword\">new<\/span> OpenAIPromptExecutionSettings\r\n            {\r\n                Temperature = <span class=\"hljs-number\">0<\/span>,\r\n                FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()\r\n            };\r\n\r\n            <span class=\"hljs-comment\">\/\/ prompt<\/span>\r\n            <span class=\"hljs-keyword\">var<\/span> prompt = <span class=\"hljs-string\">\"Summarize AI news for me related to MCP on bing news. Open first link and summarize content\"<\/span>;\r\n            <span class=\"hljs-keyword\">var<\/span> result = <span class=\"hljs-keyword\">await<\/span> kernel.InvokePromptAsync(prompt, <span class=\"hljs-keyword\">new<\/span>(executionSettings)).ConfigureAwait(<span class=\"hljs-literal\">false<\/span>);\r\n            Console.WriteLine(<span class=\"hljs-string\">$\"\\n\\n<span class=\"hljs-subst\">{prompt}<\/span>\\n<span class=\"hljs-subst\">{result}<\/span>\"<\/span>);<\/span><\/pre>\n<h1 id=\"d82d\" class=\"rp rh jm bf rq rr rs km gm rt ru kp go rv rw rx ry rz sa sb sc sd se sf sg sh bk\" data-selectable-paragraph=\"\"><strong class=\"am\">Result<\/strong>:<\/h1>\n<\/div>\n<\/div>\n<div class=\"im\">\n<div class=\"ab cd\">\n<div class=\"in io ip iq ir is ch it ci iu ck bh\">\n<figure class=\"qe qf qg qh qi im iz ja paragraph-image\">\n<div class=\"jb jc fm jd bh je\" tabindex=\"0\" role=\"button\">\n<div class=\"iv iw si\"><picture><source srcset=\"https:\/\/miro.medium.com\/v2\/resize:fit:640\/format:webp\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 640w, https:\/\/miro.medium.com\/v2\/resize:fit:720\/format:webp\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 720w, https:\/\/miro.medium.com\/v2\/resize:fit:750\/format:webp\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 750w, https:\/\/miro.medium.com\/v2\/resize:fit:786\/format:webp\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 786w, https:\/\/miro.medium.com\/v2\/resize:fit:828\/format:webp\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 828w, https:\/\/miro.medium.com\/v2\/resize:fit:1100\/format:webp\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 1100w, https:\/\/miro.medium.com\/v2\/resize:fit:2000\/format:webp\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 2000w\" type=\"image\/webp\" sizes=\"(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 1000px\" \/><source srcset=\"https:\/\/miro.medium.com\/v2\/resize:fit:640\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 640w, https:\/\/miro.medium.com\/v2\/resize:fit:720\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 720w, https:\/\/miro.medium.com\/v2\/resize:fit:750\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 750w, https:\/\/miro.medium.com\/v2\/resize:fit:786\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 786w, https:\/\/miro.medium.com\/v2\/resize:fit:828\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 828w, https:\/\/miro.medium.com\/v2\/resize:fit:1100\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 1100w, https:\/\/miro.medium.com\/v2\/resize:fit:2000\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif 2000w\" sizes=\"(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 1000px\" data-testid=\"og\" \/><img decoding=\"async\" class=\"bh fx jf c\" role=\"presentation\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:1000\/1*4kU-FMLFMcI7P_cWJO_aRQ.gif\" alt=\"\" width=\"1000\" height=\"523\" \/><\/picture><\/div>\n<\/div>\n<\/figure>\n<div>\n<h1 id=\"f526\" class=\"rp rh jm bf rq rr rs km gm rt ru kp go rv rw rx ry rz sa sb sc sd se sf sg sh bk\" data-selectable-paragraph=\"\">Conclusion:<\/h1>\n<p id=\"13da\" class=\"pw-post-body-paragraph pk pl jm pm b kk sk po pp kn sl pr ps gp sm pu pv gs sn px py gv so qa qb qc hp bk\" data-selectable-paragraph=\"\">MCP is truly revolutionizing how we integrate external services with large language models. With its seamless interface and growing adoption, it\u2019s not hard to imagine a future where every major service offers an MCP-compatible layer, unlocking powerful and intuitive AI interactions. Building AI apps has never been this accessible.<\/p>\n<p id=\"26e5\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\">In my next blog, I\u2019ll take it a step further and show you how to build your own MCP server from scratch. Stay tuned \u2014 exciting things ahead!<\/p>\n<p id=\"2d53\" class=\"pw-post-body-paragraph pk pl jm pm b kk pn po pp kn pq pr ps gp pt pu pv gs pw px py gv pz qa qb qc hp bk\" data-selectable-paragraph=\"\">Happy learning, and cheers! \ud83e\udd42\ud83d\ude80<\/p>\n<h2 id=\"9801\" class=\"sq rh jm bf rq gl sr ea gm gn ss ec go gp st gq gr gs su gt gu gv sv gw gx sw bk\" data-selectable-paragraph=\"\">References:<\/h2>\n<ul class=\"\">\n<li id=\"6e5f\" class=\"pk pl jm pm b kk sk po pp kn sl pr ps gp sm pu pv gs sn px py gv so qa qb qc sx sy sz bk\" data-selectable-paragraph=\"\"><a class=\"ag hc\" href=\"https:\/\/modelcontextprotocol.io\/introduction\" target=\"_blank\" rel=\"noopener ugc nofollow\">modelcontextprotocol.io<\/a><\/li>\n<li id=\"b964\" class=\"pk pl jm pm b kk ta po pp kn tb pr ps gp tc pu pv gs td px py gv te qa qb qc sx sy sz bk\" data-selectable-paragraph=\"\"><a class=\"ag hc\" href=\"https:\/\/github.com\/microsoft\/playwright-mcp\" target=\"_blank\" rel=\"noopener ugc nofollow\">https:\/\/github.com\/microsoft\/playwright-mcp<\/a><\/li>\n<li id=\"4e73\" class=\"pk pl jm pm b kk ta po pp kn tb pr ps gp tc pu pv gs td px py gv te qa qb qc sx sy sz bk\" data-selectable-paragraph=\"\"><a class=\"ag hc\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/tree\/7a19ae350eaff5746ace52d2c894a9975d82ba59\/dotnet\/samples\/Demos\/ModelContextProtocol\" target=\"_blank\" rel=\"noopener ugc nofollow\">https:\/\/github.com\/microsoft\/semantic-kernel\/tree\/7a19ae350eaff5746ace52d2c894a9975d82ba59\/dotnet\/samples\/Demos\/ModelContextProtocol<\/a><\/li>\n<li id=\"db6d\" class=\"pk pl jm pm b kk ta po pp kn tb pr ps gp tc pu pv gs td px py gv te qa qb qc sx sy sz bk\" data-selectable-paragraph=\"\"><strong class=\"pm jn\">As promised earlier, here are sources I used to understand MCP:\u00a0<\/strong><a class=\"ag hc\" href=\"https:\/\/blog.dailydoseofds.com\/p\/visual-guide-to-model-context-protocol\" target=\"_blank\" rel=\"noopener ugc nofollow\">https:\/\/blog.dailydoseofds.com\/p\/visual-guide-to-model-context-protocol<\/a>,\u00a0<a class=\"ag hc\" href=\"https:\/\/www.youtube.com\/watch?v=7j_NE6Pjv-E&amp;t=875s\" target=\"_blank\" rel=\"noopener ugc nofollow\">https:\/\/www.youtube.com\/watch?v=7j_NE6Pjv-E&amp;t=875s<\/a>,\u00a0<a class=\"ag hc\" href=\"https:\/\/norahsakal.com\/blog\/mcp-vs-api-model-context-protocol-explained\/\" target=\"_blank\" rel=\"noopener ugc nofollow\">https:\/\/norahsakal.com\/blog\/mcp-vs-api-model-context-protocol-explained\/<\/a><\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Today we&#8217;re excited to feature a returning guest author, Akshay Kokane\u00a0to share his recent Medium article on Building an AI App That Can Browse the Internet Using Microsoft\u2019s Playwright MCP Server &amp; Semantic Kernel. We\u2019ll turn it over to him to dive in! MCP! It\u2019s the new buzzword in the AI world. So, I thought [&hellip;]<\/p>\n","protected":false},"author":149071,"featured_media":4703,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[117,1],"tags":[48,133,63,9],"class_list":["post-4652","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-guest-blog","category-semantic-kernel","tag-ai","tag-mcp","tag-microsoft-semantic-kernel","tag-semantic-kernel"],"acf":[],"blog_post_summary":"<p>Today we&#8217;re excited to feature a returning guest author, Akshay Kokane\u00a0to share his recent Medium article on Building an AI App That Can Browse the Internet Using Microsoft\u2019s Playwright MCP Server &amp; Semantic Kernel. We\u2019ll turn it over to him to dive in! MCP! It\u2019s the new buzzword in the AI world. So, I thought [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/4652","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/users\/149071"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/comments?post=4652"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/4652\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media\/4703"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media?parent=4652"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/categories?post=4652"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/tags?post=4652"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}