Azure News - 2026-08-08

2026-08-08
最終更新: 2026-08-27 21:13:50 JST

Azure Updates

[In preview] Public Preview: Azure ExpressRoute resiliency guard

Azure ExpressRoute resiliency guard is now available in public preview for ExpressRoute virtual network gateways. The new resiliency model property lets you specify whether a gateway is intended for a single-homed or multi-homed configuration, helping ali

Apps on Azure Blog

Build Durable, Long-Running MCP Tasks on Azure App Service

詳細を表示

Not every tool call finishes in a few seconds.

A compliance scan might inspect hundreds of resources. A deployment might wait for an approval. A batch import might run for an hour. Holding an HTTP connection open for that entire operation is fragile: clients restart, proxies time out, networks drop, and the App Service instance that accepted the request might recycle or scale in.

The 2026-07-28 Model Context Protocol release addresses this with the official MCP Tasks extension. Instead of blocking until the final result is ready, an MCP server can return a task handle immediately. The client can disconnect, reconnect later, poll for progress, provide input when required, cancel the operation, and retrieve the result when it is complete.

That is the protocol story. The infrastructure story needs one more step:

A durable task ID does not automatically make the underlying work durable.

I built a complete .NET sample for durable MCP Tasks on Azure App Service to make that distinction concrete.

MCP Tasks in about 60 seconds

A Tasks-capable client advertises io.modelcontextprotocol/tasks in its per-request capabilities. For a long-running tool call, the server can then return a CreateTaskResult containing:

  • a stable task ID;
  • the current status;
  • a time-to-live;
  • and a suggested polling interval.

The lifecycle looks like this:

tools/call    -> taskId, status=working
tasks/get     -> status=working, progress message
tasks/get     -> status=input_required
tasks/update  -> approval or other requested input
tasks/get     -> status=completed, final result

Tasks can move through working, input_required, completed, failed, and cancelled. The client does not need to maintain the original connection. Polling from a new process with the same task ID is part of the design.

The client also does not force every call to become asynchronous. It declares support for Tasks, and the server decides whether a particular operation should return a task handle. If the client does not support the extension, a server can fall back to an ordinary synchronous tool result.

The durability trap

The official MCP C# SDK includes ModelContextProtocol.Extensions.Tasks and a convenient WithTasks() registration path. In version 2.1.0, that default is a good fit for a single-process server: the SDK creates the task and runs the tool body in an in-process Task.Run.

For a horizontally scaled App Service deployment, however, that is not the durability guarantee I wanted for this sample.

If the instance running that Task.Run recycles, crashes, or scales in, the task record might still exist while the work itself disappears. Another instance can answer tasks/get, but nothing tells it that the underlying operation still needs to run.

So I used the SDK for the protocol surface and replaced only the execution dispatch:

  • Azure Table Storage stores task status, progress, pending input requests, resolved input, final results, errors, and TTL.
  • Azure Service Bus stores the work item that still needs to execute.
  • A worker running in every App Service instance receives queued work, executes the tool, and updates the shared task row.
  • clientAffinityEnabled=false allows any App Service instance to serve tasks/get, tasks/update, or tasks/cancel.

The important distinction is that both halves are durable:

ConcernDurable home
What state is this task in?Azure Table Storage
Does this work still need to run?Azure Service Bus

If an instance disappears after receiving a message but before completing it, Service Bus can redeliver the work to another available instance. The task is not tied to the HTTP connection or the process that accepted the original call.

Architecture

The sample uses a system-assigned managed identity for both Azure Storage and Service Bus. Storage shared-key access is disabled, Service Bus local authentication is disabled, and there are no storage or broker connection strings in App Service configuration.

The App Service identity receives only:

  • Storage Table Data Contributor on the storage account; and
  • Azure Service Bus Data Owner on the Service Bus namespace.

Keeping the SDK protocol handlers

The server still registers WithTasks() because it provides the extension advertisement and the standard tasks/get, tasks/update, and tasks/cancel handlers.

The custom durable filter is registered before it. The SDK's automatic execution mode is forced to synchronous so it cannot start the in-process background path:

builder.Services
    .AddMcpServer(options =>
    {
        options.ServerInfo = new()
        {
            Name = "mcp-tasks-app-service-sample",
            Version = "1.0.0"
        };
    })
    .WithHttpTransport(options => options.Stateless = true)
    .WithDurableTaskDispatch()
    .WithTasks(tasksHandlerStore, options =>
    {
        options.ExecutionModeSelector =
            _ => McpTaskExecutionMode.Synchronous;
    })
    .WithToolsFromAssembly(typeof(EchoTool).Assembly);

For a Tasks-capable client calling a durable tool, WithDurableTaskDispatch():

  1. creates the task row;
  2. serializes the tool name and arguments;
  3. sends a Service Bus message whose ID is the task ID;
  4. returns CreateTaskResult immediately.

For a client that did not advertise Tasks support, the filter falls through and the same tool executes synchronously. The companion client demonstrates both paths.

Cross-instance approvals need durable input too

Long-running operations often need a decision in the middle of execution. The sample's generate_compliance_report tool pauses after identifying a high-severity finding and moves to input_required.

The original client is deliberately disconnected before that happens. A completely new client connection polls the task, sees the input request, submits approval through tasks/update, and continues polling until completion.

This uncovered another distributed-systems detail: an in-memory event can wake an awaiter only in the process where that event exists. If tasks/update lands on a different App Service instance than the worker awaiting approval, an in-memory callback is not enough.

The sample therefore persists both pending and resolved input in Table Storage. The worker reads the resolved response from the shared store, regardless of which instance received tasks/update.

The same terminal-state guards apply to every update. Once a task is completed, failed, or cancelled, a stale approval or redelivered message cannot move it back to working.

Cancellation, retries, and duplicate delivery

MCP cancellation is cooperative. tasks/cancel records the terminal state, and the running tool checks that state between stages. When it observes cancellation, the worker completes the queue message cleanly rather than treating the expected cancellation as a failure.

Unexpected failures follow the Service Bus retry policy:

  • transient failures abandon the message for redelivery;
  • the queue enforces maxDeliveryCount;
  • exhausted messages move to the dead-letter queue;
  • and the durable task records a failed result.

The design assumes at-least-once delivery. Duplicate work is handled at two levels:

  • Service Bus duplicate detection uses MessageId = TaskId;
  • Table Storage uses optimistic ETag concurrency and refuses to overwrite terminal task states.

That second guard matters even after the broker has accepted a message. A process could complete the work and lose its message lock before acknowledging completion. If Service Bus redelivers, the next worker sees the terminal task state and treats the delivery as a duplicate instead of running the operation again.

App Service, Durable Functions, or Container Apps Jobs?

MCP Tasks defines how a client and server talk about long-running work. It does not prescribe where that work must execute.

App Service, Durable Functions, and Azure Container Apps Jobs are all good options. The right choice depends on the workload you already have and the execution model you want.

 App ServiceDurable FunctionsContainer Apps / Jobs
Strong fitAdding MCP to an existing always-on web app or API and sharing its deployment, networking, scaling, authentication, domains, and operational lifecycleOrchestration-first workflows with checkpoints, durable timers, fan-out/fan-in, retries, sub-orchestrations, and human interactionContainer-native or isolated workers, custom runtimes and dependencies, event-driven scaling, scale-to-zero, or workers that should scale independently from the MCP endpoint
DurabilityYou connect external state and queue services explicitly, as this sample doesDurable orchestration state and replay are framework capabilitiesYou bring the state/queue; Jobs provides an execution and scaling model around it
Operational modelAlways-on web processes; background workers can run beside the MCP endpointServerless functions and orchestrator/activity codeIndependently versioned containers or job executions, often scaled through KEDA rules
Trade-offMore durability plumbing to own, but direct control over storage, queue, latency, and cost choicesLess custom plumbing for workflows, with deterministic orchestrator/replay constraintsMore separation and container flexibility, but a different operational model from an existing App Service application

My practical rule:

  • If MCP is another capability inside an App Service application you already operate, this pattern is a natural extension of that app.
  • If the task is fundamentally a durable orchestration, I would look closely at Durable Functions before writing the plumbing myself.
  • If the workers are naturally container-shaped or should scale independently from the MCP endpoint, Azure Container Apps Jobs is likely the cleaner fit.

This is not a ranking. MCP Tasks is the protocol abstraction; Azure gives you multiple execution backends so you can match the workload.

Deploy the sample

The sample includes an azd project and Bicep infrastructure for:

  • a Linux App Service plan and .NET web app;
  • Azure Table Storage;
  • Azure Service Bus Standard;
  • Log Analytics and Application Insights;
  • managed identity and scoped RBAC.
git clone https://github.com/seligj95/app-service-mcp-tasks-dotnet
cd app-service-mcp-tasks-dotnet

azd auth login
azd env new <your-environment-name>
azd up

Then run the companion client against the deployed endpoint:

dotnet run --project src/McpTasksApp.Client -- \
  https://<your-app-name>.azurewebsites.net

The harness takes you through synchronous fallback, durable reconnect and approval, and cancellation.

The sample intentionally focuses on durable execution. Its public demo endpoint is not a replacement for production authorization. Before exposing a real tool surface, add App Service Authentication, authorize individual tools with scopes or roles, validate inputs, and review the security guidance for the data and actions your tools expose.

The takeaway

MCP Tasks solves an important protocol problem: long-running work no longer has to stay attached to one fragile request or one client connection.

On a scaled cloud service, the implementation still has to answer two separate questions:

  1. Where does the task's state live?
  2. What guarantees that unfinished work will run again if the current process disappears?

For this App Service sample, the answers are Table Storage and Service Bus. The MCP endpoint stays stateless, any instance can answer task requests, clients can reconnect safely, approvals work across instances, and queued execution survives process boundaries.

That is the difference between returning a task ID and actually running a durable task.

Resources

Announcing Grafana 13 Support in Azure Managed Grafana

詳細を表示

Enhanced Dashboarding and Visualization Experience

Grafana 13 introduces a number of improvements that make dashboards easier to build, reuse, and manage at scale. Teams can create richer observability experiences while reducing duplication and improving consistency across environments. These improvements include Dynamic Dashboards, Saved Queries, enhanced filtering and grouping experiences, dashboard templates, and additional usability enhancements that streamline dashboard authoring and discovery. From enhanced dashboard authoring experiences and reusable queries to Git-based dashboard lifecycle management, Grafana 13 helps teams build and operate observability solutions more efficiently at scale. 

Git Sync: Manage Dashboards as Code

One of the most anticipated capabilities associated with Grafana 13 is Git Sync: enabling organizations to manage Grafana dashboards using Git-based workflows. Dashboards can be stored as JSON files in a Git repository, making it easier to version, review, and automate dashboard changes using existing engineering practices.

With Git Sync, teams can:

  • Track dashboard changes through source control.
  • Review updates through pull requests.
  • Integrate dashboard deployments into CI/CD pipelines.
  • Collaborate on dashboard development using familiar Git workflows.

Git Sync supports bidirectional synchronization. Changes made in Grafana can be committed back to a repository, while changes committed to the repository are automatically synchronized to Grafana.

Configuration is managed directly from the Grafana UI, with authentication supported through either a GitHub App or a Personal Access Token. For customers managing large observability estates, Git Sync helps bring dashboards into existing infrastructure-as-code and platform engineering workflows. Visit MSLearn to check out Git Sync on Azure Managed Grafana.

Prometheus Authentication Changes in Grafana 13

One of the most important changes in Grafana 13: using Prometheus with Azure authentication. Starting with Grafana 13, Azure authentication is no longer supported in the standard open-source Prometheus data source. Instead, Azure authentication is exclusively available through the Azure Monitor Managed Service for Prometheus plugin. This change aligns with Grafana Labs' updated Prometheus data source strategy and deprecation guidance.

Customers do not need to modify existing dashboards as part of this transition. Dashboards remain compatible across both plugin versions, and existing visualizations, imports, exports, and dashboard definitions continue to work as expected. Connectivity and query execution against Azure Monitor Workspaces and Azure Monitor Managed Service for Prometheus endpoints will use the Azure-specific plugin that now owns Azure authentication support.

Prometheus data sources configured with non-Azure authentication methods are unaffected by this change and continue to operate without modification. 

We Recommend:

You can start using Grafana 13 today by creating a new Azure Managed Grafana workspace and selecting Grafana 13. We encourage customers to explore the new dashboarding experiences introduced in Grafana 13 and review their Prometheus configurations to understand how Azure-authenticated data sources are transitioned to the Azure Monitor Managed Service for Prometheus plugin.

Existing dashboards continue to work without changes. Customers do not need to:

  • Recreate dashboards.
  • Update visualizations.
  • Modify dashboard JSON definitions.
  • Reconfigure imports or exports.

For additional guidance, see the Azure Managed Grafana documentation:

For additional details about Grafana 13, refer to the official Grafana Labs release announcement and release notes.