{"id":60361,"date":"2026-06-30T10:00:00","date_gmt":"2026-06-30T17:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=60361"},"modified":"2026-06-30T10:00:00","modified_gmt":"2026-06-30T17:00:00","slug":"mcp-build-diagnostics-workflows","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/mcp-build-diagnostics-workflows\/","title":{"rendered":"MCP Beyond the Chat Window: Build Diagnostics in CI"},"content":{"rendered":"<p>In a <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/msbuild-binlog-mcp-server\/\">previous post<\/a>\nwe introduced the\n<strong>Microsoft Binlog MCP Server<\/strong> and showed how an AI assistant can investigate\nMSBuild binary logs through natural language. Picture the payoff in CI: a pull\nrequest build fails, and instead of a human downloading the binlog and scrolling\nthe Structured Log Viewer, an agent opens it, pinpoints the failing target and\ntask, and posts the root cause straight back to the PR.<\/p>\n<p>That first post was a great start, but it told only part of the story. It\nhighlighted 15 tools &#8211; the server&#8217;s surface has since grown well beyond that &#8211;\nand it focused on the interactive, sit-at-your-keyboard experience. In practice,\nthe same <a href=\"https:\/\/modelcontextprotocol.io\/\">Model Context Protocol<\/a>\n(MCP) tools are doing real work <em>unattended<\/em>, inside a continuous integration\npipeline on GitHub Actions.<\/p>\n<p>This post fills in the rest. We&#8217;ll:<\/p>\n<ul>\n<li>Watch those tools run unattended inside a <strong>GitHub Actions<\/strong> workflow on the\npublic <a href=\"https:\/\/github.com\/microsoft\/testfx\"><code>microsoft\/testfx<\/code><\/a> repository &#8211; a\nreal PR build failure, analyzed and explained automatically<\/li>\n<li>Walk through the <strong>23 Binlog MCP tools the first post never mentioned<\/strong><\/li>\n<li>Back the efficiency claims with <strong>evaluation data<\/strong> instead of vibes<\/li>\n<\/ul>\n<p>If you lead a team, here is the outcome that matters: red builds get a\nplain-language root cause posted to the PR automatically, so engineers stop\nlosing time downloading logs and decoding MSBuild output. That means faster PR\nturnaround, fewer interruptions for your build experts, and junior developers\nwho can unblock themselves instead of waiting for someone who &#8220;knows the build.&#8221;\nAnd because it runs as advisory automation on infrastructure you already have,\nyour team can adopt it without changing how anyone works.<\/p>\n<h2>MCP in a GitHub Actions Workflow<\/h2>\n<p>Start with the payoff. The\n<code>microsoft\/testfx<\/code> repository runs MCP-powered agents directly in CI using\n<a href=\"https:\/\/github.com\/githubnext\/gh-aw\">GitHub Agentic Workflows<\/a> (<code>gh aw<\/code>), where\neach workflow is authored in Markdown and compiled to a <code>.lock.yml<\/code> file. The\nworkflows are public, so you can read the exact source:\n<a href=\"https:\/\/github.com\/microsoft\/testfx\/blob\/main\/.github\/workflows\/build-failure-analysis.md\"><code>build-failure-analysis.md<\/code><\/a>,\nits on-demand companion\n<a href=\"https:\/\/github.com\/microsoft\/testfx\/blob\/main\/.github\/workflows\/build-failure-analysis-command.md\"><code>build-failure-analysis-command.md<\/code><\/a>,\nand the\n<a href=\"https:\/\/github.com\/microsoft\/testfx\/blob\/main\/.github\/agents\/build-failure-analyst.agent.md\"><code>build-failure-analyst<\/code> agent<\/a>\nthey delegate to. GitHub Agentic Workflows are still evolving, so treat these as\na reference implementation to copy from rather than a turnkey feature every\nrepository has today.<\/p>\n<h3>Build failure analysis, on every PR<\/h3>\n<p>The <code>build-failure-analysis<\/code> workflow runs the repository build on every pull\nrequest, and <strong>only when the build fails<\/strong> wakes up an agent that queries the\nbinlog live through the Binlog MCP Server. The MCP server runs as a container,\nwith the binlog mounted read-only:<\/p>\n<pre><code class=\"language-yaml\">mcp-servers:\n  binlog-mcp:\n    container: \"mcr.microsoft.com\/dotnet-buildtools\/prereqs:azurelinux-3.0-binlog-mcp-amd64\"\n    mounts:\n      - \"\/tmp\/build.binlog:\/data\/build.binlog:ro\"\n    allowed: [\"*\"]<\/code><\/pre>\n<p>The workflow spells out its own flow: it runs\n<code>.\/build.sh --binaryLog<\/code>, and on failure &#8220;delegates to the\n<code>build-failure-analyst<\/code> agent (which queries the binlog live via the\ncontainerized <code>binlog-mcp<\/code> MCP server) to identify root causes, post a PR\ncomment summarizing them, and attach inline <code>suggestion<\/code> blocks tied to the\ndiff.&#8221; It is explicitly <strong>advisory, not gating<\/strong>: the agent&#8217;s comment never\ndecides whether the PR passes. The repository&#8217;s normal required build workflow\nstays the merge gate; this MCP-powered workflow only analyzes failures and\ncomments on the PR.<\/p>\n<p>A companion <code>build-failure-analysis-command<\/code> workflow lets a maintainer rerun\nthe same analysis on demand by commenting <code>\/analyze-build-failure<\/code>.<\/p>\n<p>Concretely, a single failed-build run might have the agent call\n<code>binlog_overview<\/code> to see the build failed, <code>binlog_errors<\/code> to get the failing\nerror with its target and task context, and <code>binlog_target_reasons<\/code> or\n<code>binlog_task_details<\/code> to explain why that step ran the way it did &#8211; then\nsummarize the root cause in a PR comment with an inline suggestion. That whole\nchain happens without anyone opening a log viewer.<\/p>\n<p>Here is an actual comment the workflow left on a <code>microsoft\/testfx<\/code> pull\nrequest. This is a real CI failure &#8211; not a hand-picked toy example, but a\nformatting (<code>IDE0055<\/code>) failure in a full multi-project build &#8211; showing the same\ntools at work in a real repository, posting the root\ncause, the exact file and line, a ready-to-apply fix, and a build overview\npulled straight from the binlog:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2026\/06\/demo-real-pr-comment.webp\" alt=\"Real Build Failure Analysis comment posted by the workflow on a microsoft\/testfx pull request\" \/><\/p>\n<p>Look at what is in that comment: the MSBuild version, the 46 projects that built,\nthe five errors, the four failing projects, and the precise <code>IDE0055<\/code> location\ndown to the column. All of it came from the agent querying the binlog live\nthrough the containerized Binlog MCP Server &#8211; nobody downloaded a log or opened\na viewer. When the binlog can&#8217;t be parsed, the same comment degrades gracefully\nto a short status note with a link back to the run, so you always know what\nhappened.<\/p>\n<h2>See the Tools in Action<\/h2>\n<p>You just saw those tools deliver a verdict inside CI. Now let&#8217;s slow down and\nlook at what a few of them actually hand back, up close. Everything below is\n<strong>unedited output<\/strong>, captured against a tiny console app built with\n<code>dotnet build \/bl<\/code>.<\/p>\n<h3>Diagnosing a failing build<\/h3>\n<p>The app has a one-character typo &#8211; <code>Consolee.WriteLine<\/code> instead of\n<code>Console.WriteLine<\/code> &#8211; so <code>dotnet build<\/code> fails with <code>CS0103<\/code>:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2026\/06\/demo-real-build-failure-scaled.webp\" alt=\"Real dotnet build failure showing CS0103: the name &apos;Consolee&apos; does not exist in the current context\" \/><\/p>\n<p>Because we built with <code>\/bl<\/code>, that same failure also produced a binlog. Point an\nassistant at it and it walks the path a human would, only faster:\n<code>binlog_overview<\/code> to confirm the build failed and where, then <code>binlog_errors<\/code>\nfor the exact file, line, target, and task. Here is a real session against the\nlive server:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2026\/06\/demo-real-mcp-output-scaled.webp\" alt=\"Real Binlog MCP server session: binlog_overview and binlog_errors tool calls against the failing build&apos;s binlog\" \/><\/p>\n<p>That structured payload &#8211; <code>code<\/code>, <code>file<\/code>, <code>line<\/code>, <code>targetName<\/code>, <code>taskName<\/code> &#8211; is\nexactly what lets an assistant explain the failure and propose a fix without\never scrolling a raw log.<\/p>\n<h3>Letting the server take the first pass<\/h3>\n<p>You don&#8217;t have to drive the tools one at a time, either. <code>binlog_diagnose<\/code>\ndoes the first pass for you &#8211; it reads the binlog, groups the errors, picks\nout the root cause, and even suggests a fix:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2026\/06\/demo-real-diagnose-scaled.webp\" alt=\"Real binlog_diagnose output: CS0103 root cause, a suggested fix, and error categories\" \/><\/p>\n<p>For a one-character typo that is overkill. But on a real CI failure with a\nwall of cascading errors, having the server name the <em>root cause<\/em> up front &#8211;\nand point you at the next tool to run &#8211; is the difference between a two-minute\nfix and a half-hour log dive.<\/p>\n<h3>Comparing two builds<\/h3>\n<p>Now take two successful builds of the same project that differ only in a\nproject setting and an added package, and ask <code>binlog_compare<\/code> to diff them.\nThis is the unedited output:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2026\/06\/demo-real-compare-scaled.webp\" alt=\"Real binlog_compare output diffing two builds: LangVersion and a new Newtonsoft.Json reference\" \/><\/p>\n<p>The two changes that matter jump right out: <code>LangVersion<\/code> went from <code>14.0<\/code> to\n<code>preview<\/code>, and a <code>Newtonsoft.Json<\/code> 13.0.3 reference appeared. The rest &#8211; the\ntelemetry session IDs and the restore session GUID &#8211; is expected per-run\nnoise. Surfacing everything in one structured call is exactly what lets an\nassistant separate the signal from it, instead of opening two logs and\ncomparing them by hand. (<code>binlog_compare<\/code> was one of the original 15 tools from\nthe first post, so you won&#8217;t see it in the catalog tables below &#8211; those list\nonly the 23 the first post didn&#8217;t cover.)<\/p>\n<h2>The Tools the First Post Didn&#8217;t Cover<\/h2>\n<p>You have now seen a handful of these tools at work, both interactively and in\nCI. Here is the full set the first post skipped. The first post highlighted 15\ntools for interactive investigation. As of this\nwriting the server source tree exposes *<em>38 `binlog_<\/em><code>tools** in total - so the tables below list the **23 tools the first post didn't mention**, grouped by what you use them for. (The exact set evolves, and the published container image can lag the source tree, so treat this as the current snapshot rather than a frozen contract -<\/code>binlog_capabilities` always reports what your installed server\nactually supports.)<\/p>\n<h3>Targets and tasks<\/h3>\n<p>When a build does something you didn&#8217;t expect &#8211; a target fires that shouldn&#8217;t,\nor one you need gets skipped &#8211; these walk the execution tree for you, no\n<code>\/v:diag<\/code> log-diving required.<\/p>\n<table>\n<thead>\n<tr>\n<th>Tool<\/th>\n<th>What it does<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>binlog_project_targets<\/code><\/td>\n<td>List the targets executed in a specific project<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_search_targets<\/code><\/td>\n<td>Search targets by name across all projects<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_target_reasons<\/code><\/td>\n<td>Explain why a target ran or was skipped &#8211; the usual answer to &#8220;why does this rebuild every time?&#8221;<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_tasks_in_target<\/code><\/td>\n<td>List the tasks within a target<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_task_details<\/code><\/td>\n<td>Details for a specific task execution<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_explore_node<\/code><\/td>\n<td>Explore an arbitrary node in the build tree<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_diagnose<\/code><\/td>\n<td>Automated, high-level build diagnosis &#8211; a good first stop that points at the likely culprit<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Properties and evaluation<\/h3>\n<p>MSBuild evaluation is where most &#8220;works on my machine&#8221; mysteries hide. These\nexpose the exact properties &#8211; and global properties &#8211; each project was\nevaluated with, so you can compare a CI agent against your laptop.<\/p>\n<table>\n<thead>\n<tr>\n<th>Tool<\/th>\n<th>What it does<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>binlog_compare_property<\/code><\/td>\n<td>Compare a single property across two binlogs &#8211; pinpoint the one setting that drifted<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_preprocess<\/code><\/td>\n<td>Preprocessed project view (the <code>msbuild \/pp<\/code> equivalent) &#8211; the fully expanded project after every import<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_evaluations<\/code><\/td>\n<td>List project evaluations<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_evaluation_properties<\/code><\/td>\n<td>Properties for a specific evaluation<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_evaluation_global_properties<\/code><\/td>\n<td>Global properties for a specific evaluation<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Performance analysis<\/h3>\n<p>Reach for these when the build <em>works<\/em> but is slow. They turn a binlog into a\nranked list of where the time actually went.<\/p>\n<table>\n<thead>\n<tr>\n<th>Tool<\/th>\n<th>What it does<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>binlog_expensive_analyzers<\/code><\/td>\n<td>Slowest Roslyn analyzers and source generators &#8211; the usual suspects behind slow compiles<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_analyzer_summary<\/code><\/td>\n<td>Analyzer execution summary<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_project_target_times<\/code><\/td>\n<td>Target-level timing breakdown for a specific project<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_incremental_analysis<\/code><\/td>\n<td>Which targets were skipped vs rebuilt &#8211; how you catch a broken incremental build<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Graph, dependencies, and toolchain<\/h3>\n<p>These answer the &#8220;how is everything wired together?&#8221; questions &#8211; build order,\nrestore, and the assemblies that actually made it onto the compiler command\nline.<\/p>\n<table>\n<thead>\n<tr>\n<th>Tool<\/th>\n<th>What it does<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>binlog_build_graph<\/code><\/td>\n<td>Project dependency graph and critical path &#8211; what&#8217;s really gating your build time<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_target_graph<\/code><\/td>\n<td>Executed-target timeline for one evaluation<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_nuget<\/code><\/td>\n<td>Restore info: versions, sources, duration<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_assembly_conflicts<\/code><\/td>\n<td>Assembly version conflict \/ RAR analysis<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_compiler<\/code><\/td>\n<td>Compiler command-line invocations<\/td>\n<\/tr>\n<tr>\n<td><code>binlog_double_writes<\/code><\/td>\n<td>Files written by more than one task or target &#8211; a classic source of flaky, nondeterministic builds<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Contract<\/h3>\n<p>One housekeeping tool that keeps the others honest across server versions.<\/p>\n<table>\n<thead>\n<tr>\n<th>Tool<\/th>\n<th>What it does<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>binlog_capabilities<\/code><\/td>\n<td>Report the server&#8217;s contract version and tool envelope<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>That is a lot of heavy diagnostic lifting the first post never touched &#8211; whole\nnew capabilities like automated diagnosis (<code>binlog_diagnose<\/code>), per-evaluation\ninspection for multi-targeted builds, dependency and critical-path graphs,\nNuGet restore analysis, assembly-conflict detection, and incremental-build\nintrospection.<\/p>\n<p><div class=\"alert alert-success\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Lightbulb\"><\/i><strong>Tip<\/strong><\/p>To generate a binary log, add <code>\/bl<\/code> to any\n<code>dotnet build<\/code>, <code>dotnet test<\/code>, or <code>dotnet pack<\/code> command &#8211; for example\n<code>dotnet build \/bl<\/code>.<\/div><\/p>\n<h2>Does It Actually Help? The Evaluation Data<\/h2>\n<p>Adding tools to an AI assistant is only worthwhile if it makes the assistant\n<em>better<\/em> and <em>cheaper<\/em>, not just busier. To measure that, the team runs a public\nevaluation harness that scores different configurations on the same set of\nreal-world MSBuild diagnosis scenarios &#8211; identifying a build failure, tracing a\nproperty, doing a full autonomous root-cause investigation &#8211; on a 0-5 quality\nscale, while recording wall-clock time, tool calls, and token usage. The results\nare published at the\n<a href=\"https:\/\/jankrivanek.github.io\/binlog-evals-results\/\">binlog evals dashboard<\/a>.<\/p>\n<p>Across the 102 runs available at the time of writing, the picture is consistent.\nThe dashboard includes several experimental and alternative configurations; the\ntable below selects the no-tools baseline plus the two configurations this post\nis about. Input tokens roughly track compute cost, so on that column lower is\ncheaper. Results vary by run and scenario, so check the dashboard for the full\ncomparison.<\/p>\n<table>\n<thead>\n<tr>\n<th>Configuration<\/th>\n<th>Avg score (0-5)<\/th>\n<th>Avg wall time<\/th>\n<th>Avg input tokens<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>plain<\/code> (no tools)<\/td>\n<td>3.25<\/td>\n<td>349.8 s<\/td>\n<td>1,268,501<\/td>\n<\/tr>\n<tr>\n<td><code>binlog-mcp<\/code> (Binlog MCP Server)<\/td>\n<td>3.68<\/td>\n<td>196.1 s<\/td>\n<td>1,141,426<\/td>\n<\/tr>\n<tr>\n<td><code>skill-mcp<\/code> (skills + MCP)<\/td>\n<td>3.60<\/td>\n<td>166.7 s<\/td>\n<td>879,205<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>In other words, against the no-tools baseline the Binlog MCP Server raised the\naverage score from <strong>3.25 to 3.68<\/strong> while finishing roughly <strong>44% faster<\/strong>\n(196 s vs 350 s). The skills-plus-MCP configuration was the fastest and cheapest\nof the three &#8211; about <strong>52% faster<\/strong> and roughly <strong>30% fewer input tokens<\/strong> than\nbaseline &#8211; while scoring <strong>3.60<\/strong>, just below Binlog MCP alone but still well\nabove the no-tools baseline. One likely reason both tool-based configurations\ncome out ahead is that purpose-built tools let the model query structured binlog\ndata directly instead of reconstructing it from raw text logs, so it spends\nfewer turns and tokens to reach the same answer.<\/p>\n<p><div class=\"alert alert-primary\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>About the numbers<\/strong><\/p>These figures come from a preview\nevaluation harness over a small, evolving set of scenarios; the dashboard flags\nruns with incomplete data. Treat them as directional evidence of the efficiency\ntrend, not as a benchmark guarantee. Re-check the live dashboard for the latest\nresults.<\/div><\/p>\n<h2>Try It Yourself<\/h2>\n<p>Everything above is built on the same foundation you can adopt today:<\/p>\n<ol>\n<li>Install the <code>dotnet-msbuild<\/code> plugin from the\n<a href=\"https:\/\/github.com\/dotnet\/skills\">dotnet\/skills<\/a> marketplace in Visual\nStudio, VS Code, or the Copilot CLI. (That is the build-diagnostics plugin\nthis post uses; the marketplace has others for different jobs.)<\/li>\n<li>Build with <code>\/bl<\/code> to capture a binlog, then ask your assistant to investigate\nit &#8211; now with the full toolset, not just the original 15.<\/li>\n<li>To take it into CI, follow the <code>microsoft\/testfx<\/code> pattern: wire the\ncontainerized Binlog MCP Server into a GitHub Agentic Workflow so build\nfailures get analyzed automatically. (These agentic workflows are still\nevolving; the testfx workflows are the public reference to copy from.)<\/li>\n<\/ol>\n<p>The Model Context Protocol turns out to be far more than a chat convenience. It\nis a portable contract that lets the same diagnostic tools\nrun wherever your code does &#8211; in your editor, in your terminal, and in your\npipelines. We&#8217;d love your feedback; file issues in the\n<a href=\"https:\/\/github.com\/dotnet\/skills\/issues\">dotnet\/skills<\/a> repository.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A practical tour of the Model Context Protocol tools for .NET build diagnostics &#8211; the full Binlog MCP toolset, how those tools run inside a GitHub Actions workflow, and what the evaluation data says about the efficiency gains.<\/p>\n","protected":false},"author":92848,"featured_media":60362,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7781],"tags":[568,8182,8181,7608,7869,8032,8192,8053,98],"class_list":["post-60361","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-ai","tag-ai","tag-binlog","tag-build-diagnostics","tag-github-actions","tag-github-copilot","tag-mcp","tag-microsoft-binlog-mcp","tag-model-context-protocol","tag-msbuild"],"acf":[],"blog_post_summary":"<p>A practical tour of the Model Context Protocol tools for .NET build diagnostics &#8211; the full Binlog MCP toolset, how those tools run inside a GitHub Actions workflow, and what the evaluation data says about the efficiency gains.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/60361","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/92848"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=60361"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/60361\/revisions"}],"predecessor-version":[{"id":60363,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/60361\/revisions\/60363"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/60362"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=60361"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=60361"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=60361"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}