Skip to content

Add agent resource support - #17757

Closed
Tommaso Stocchi (tommasodotNET) wants to merge 39 commits into
microsoft:mainfrom
tommasodotNET:feature/agent-awareness-17752
Closed

Tommaso Stocchi (tommasodotNET) wants to merge 39 commits into
microsoft:mainfrom
tommasodotNET:feature/agent-awareness-17752

Conversation

@tommasodotNET

@tommasodotNET Tommaso Stocchi (tommasodotNET) commented May 31, 2026 •

Copy link
Copy Markdown
Contributor

Description

Adds Aspire.Hosting.Agents, a developer-productivity integration for identifying endpoint-backed agents and invoking them during local development. It supports A2A, OpenAI Responses, AG-UI, and ACP message commands, plus an explicit opt-in for MCP tool commands.

Fixes #17752

Scope

  • All new invocation implementation lives in Aspire.Hosting.Agents.
  • No production changes to Aspire.Hosting: existing WithReference, HTTP commands, and MCP discovery/proxying retain their behavior.
  • No generic reference dispatcher or reference-annotation extension point is introduced.
  • Agent-card URLs are passed explicitly with WithEnvironment and endpoint expressions.
  • Commands and diagnostic URLs are run-mode developer tools, not deployed agent clients.

User-facing usage

var a2aAgent = builder.AddUvicornApp("a2a-jsonrpc-agent", "../weather-agent-python", "weather_agent_python.main:app")
    .WithUv()
    .AsAgent(AgentProtocol.A2A);

builder.AddProject<Projects.ResponsesAgent>("responses-agent")
    .WithHttpEndpoint(env: "PORT")
    .AsAgent(AgentProtocol.Responses, agentName: "responses-agent")
    .WithMcpServer()
    .WithMcpToolCommands();

builder.AddUvicornApp("agui-acp-agent", "../agui-acp-agent-python", "agui_acp_agent.main:app")
    .WithUv()
    .AsAgent(AgentProtocol.AgUi)
    .AsAgent(AgentProtocol.Acp, agentName: "agui-acp-agent");

builder.AddProject<Projects.AgentEnvDump>("agent-env-dump")
    .WithEnvironment("A2A_JSONRPC_AGENT_AGENTCARD_URL",
        ReferenceExpression.Create($"{a2aAgent.GetEndpoint("http")}/.well-known/agent-card.json"))
    .WaitFor(a2aAgent);

Call AsAgent once per protocol/path pair. The A2A resource receives A2A_AGENT_BASE_URL for its advertised agent-card base URL; consumer wiring remains explicit. Standard WithReference can still be used independently for service discovery or connection strings.

A2A invocation reads the agent card and selects a supported JSON-RPC or HTTP+JSON binding, with v0.3 and v1.0 support. It defaults to non-streaming and can opt into streaming with A2AInvocationMode.Streaming.

The existing core WithMcpServer API only configures discovery/proxying. The experimental WithMcpToolCommands API in the Agents package opts into interactive and argument-driven tool commands using that configured endpoint resolver. Tool invocation handles initialization, session termination, cancellation, JSON/SSE responses, and protocol errors.

The APIs are exported for generated TypeScript, Python, Go, Java, and Rust AppHosts.

Authentication boundary

Commands issue requests from the AppHost process to endpoints reachable by it. This integration does not implement interactive sign-in, token acquisition/refresh, or forwarding the dashboard user's identity.

For application-specific authentication or user-interactive flows, use a driver application that owns the interaction and authentication; Aspire can orchestrate and observe it. Endpoint authentication should not be disabled to accommodate these commands. Authentication from an agent to a model provider such as Foundry remains the agent application's responsibility.

Playground

playground/AspireAgents contains Foundry-backed examples:

  • a2a-jsonrpc-agent: Python A2A SDK with a LangChain-backed agent.
  • responses-agent: .NET OpenAI Responses agent, also exposing MCP weather tools.
  • vercel-ai-responses-agent: Vercel AI SDK Responses implementation.
  • mcp-agent: .NET MCP server with a model-backed answer_question tool.
  • agui-acp-agent: Python application exposing AG-UI and ACP.
  • agent-env-dump: verifies explicitly configured agent-card environment wiring.

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented May 31, 2026 •

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17757

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17757"

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds generic agent-resource support to Aspire Hosting so endpoint-backed compute resources can be marked as A2A/OpenAI Responses agents, surfaced in the dashboard, and referenced by consumers via agent-card environment variables.

Changes:

  • Adds Aspire.Hosting.Agents public APIs for agent protocols, invocation mode, annotations, and AsAgent(...) extensions.
  • Extends WithReference(...) to inject A2A agent-card URLs into consumers.
  • Adds tests, code-generation coverage, and a new playground/AspireAgents sample.

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/Aspire.Hosting/Agents/AgentResourceBuilderExtensions.cs Adds agent configuration, dashboard commands, URLs, and request preparation helpers.
src/Aspire.Hosting/Agents/AgentResourceAnnotation.cs Adds metadata annotation for agent protocols and paths.
src/Aspire.Hosting/Agents/AgentProtocol.cs Adds supported agent protocol enum.
src/Aspire.Hosting/Agents/A2AInvocationMode.cs Adds A2A dashboard invocation mode enum.
src/Aspire.Hosting/ResourceBuilderExtensions.cs Adds A2A agent-card env-var injection during references.
src/Aspire.Hosting/api/Aspire.Hosting.cs Updates public API surface for new agent APIs.
tests/Aspire.Hosting.Tests/AgentResourceBuilderExtensionsTests.cs Adds hosting tests for annotations, commands, and reference injection.
tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/AtsTypeScriptCodeGeneratorTests.cs Adds ATS capability and enum coverage for TypeScript.
tests/Aspire.Hosting.CodeGeneration.Python.Tests/AtsPythonCodeGeneratorTests.cs Adds ATS capability coverage for Python.
tests/Aspire.Hosting.CodeGeneration.Java.Tests/AtsJavaCodeGeneratorTests.cs Adds ATS capability coverage for Java.
tests/Aspire.Hosting.CodeGeneration.Go.Tests/AtsGoCodeGeneratorTests.cs Adds ATS capability coverage for Go.
playground/AspireAgents/AspireAgents.AppHost/AppHost.cs Adds sample AppHost wiring for A2A and Responses agents.
playground/AspireAgents/AspireAgents.AppHost/AspireAgents.AppHost.csproj Adds sample AppHost project configuration.
playground/AspireAgents/AspireAgents.AppHost/Properties/launchSettings.json Pins local dashboard/resource-service endpoints for the sample.
playground/AspireAgents/ResponsesAgent/ResponsesAgent.csproj Adds Responses agent project dependencies.
playground/AspireAgents/ResponsesAgent/Program.cs Implements sample OpenAI Responses weather agent.
playground/AspireAgents/weather-agent-python/weather_agent_python/main.py Implements sample Python A2A weather agent.
playground/AspireAgents/weather-agent-python/weather_agent_python/__init__.py Adds Python package marker/docstring.
playground/AspireAgents/weather-agent-python/pyproject.toml Adds Python sample package metadata and dependencies.
playground/AspireAgents/weather-agent-python/.python-version Pins Python version for the sample.
playground/AspireAgents/aspire.config.json Points Aspire CLI/config tooling at the sample AppHost.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidfowl

Copy link
Copy Markdown
Collaborator

Definitely don’t want this in Aspire.Hosting. Also this needs to be proven across more than just MAF since it’s a general abstraction. Make this PR a draft until we do more research

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommasodotNET
Tommaso Stocchi (tommasodotNET) marked this pull request as draft May 31, 2026 21:44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 45 out of 47 changed files in this pull request and generated 2 comments.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommasodotNET
Tommaso Stocchi (tommasodotNET) marked this pull request as ready for review June 4, 2026 10:22
@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Validate custom agent paths and A2A stream completion, terminate MCP sessions across invocation outcomes, and dispose invalid protocol responses. Update the Azure connector reflection caller and enable integration analyzers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved protocol-response validation and cancellation-race defects can report failures as successes or complete cancelled work.

Get a fresh assessment by requesting another Copilot review.

Review details

Files not reviewed (1)

  • playground/AspireAgents/vercel-ai-responses-agent/package-lock.json: Generated file
  • Files reviewed: 55/59 changed files
  • Comments generated: 4
  • Review effort level: Balanced

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Reject malformed A2A and MCP responses, handle A2A media types case-insensitively, and stop Python task execution before publishing cancellation. Add focused protocol and cancellation regression coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Agent configuration currently mishandles case-insensitive endpoint schemes and undefined enum values.

Review details

Files not reviewed (1)

  • playground/AspireAgents/vercel-ai-responses-agent/package-lock.json: Generated file

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

src/Aspire.Hosting.Agents/AgentResourceBuilderExtensions.cs:195

  • Undefined enum values are accepted silently. An unknown AgentProtocol adds metadata and an icon but configures no protocol, while an unknown A2AInvocationMode is treated as non-streaming. Validate both enum arguments so invalid configuration fails at the public API boundary instead of producing a partially configured resource.
    src/Aspire.Hosting.Agents/AgentResourceBuilderExtensions.cs:276
  • URI schemes are case-insensitive, but this filter rejects otherwise valid endpoints whose scheme is HTTP or HTTPS. The following ordering already compares schemes case-insensitively, so endpoint eligibility should do the same; otherwise AsAgent can fail with “no ... endpoint was found” for a valid endpoint.
  • Files reviewed: 56/60 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@mitchdenny

Copy link
Copy Markdown
Member

My main concern is the scope of the changes in Aspire.Hosting. This looks primarily like a developer-productivity feature for sending a message to an agent and displaying the response. I think we should keep that functionality in Aspire.Hosting.Agents and constrain changes to Aspire.Hosting unless there is a compelling reason they are needed.

In particular, exposing the generic WithReference(...) dispatcher seems broader than this feature requires. We already have WithEnvironment(...) and endpoint expressions to pass an agent-card URL to another resource. If we are missing general-purpose behavior in WithReference(...), that change should stand on its own, with its own justification and API review, rather than being introduced as plumbing for agent invocation.

I also think there is a natural limit to how useful this interaction can be once these endpoints require authentication. For scenarios involving sign-in, token acquisition/refresh, or other application-specific auth requirements, an interactive driver program that manages those requirements may be a more natural fit. How quickly we reach that limit depends on whether and how people secure these endpoints, but it is worth being explicit about the intended scope here.

Remove generic reference dispatch and all production core Hosting changes. Move MCP tool commands into an explicit Agents opt-in, keep deferred agent HTTP execution local, and use endpoint expressions for agent-card wiring. Document authentication boundaries and validate run/publish behavior and generated SDKs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommasodotNET

Tommaso Stocchi (tommasodotNET) commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks Mitch Denny (@mitchdenny) — agreed, and I have narrowed the implementation in 590d39e rather than retaining the broader core changes.

  • There is now zero production diff under src/Aspire.Hosting against the PR merge base. The generic public WithReference dispatcher/reference-annotation extension point and the HTTP command behavior changes are removed.
  • Agent invocation stays in Aspire.Hosting.Agents. MCP discovery/proxying keeps its existing core behavior; interactive tool invocation is now an explicit .WithMcpServer(...).WithMcpToolCommands() opt-in from the Agents package, using the existing endpoint resolver.
  • The playground and README use explicit WithEnvironment/endpoint expressions for agent-card URLs. AsAgent no longer changes reference injection.
  • Commands and diagnostic URLs are run-only. The README and PR description explicitly bound authentication: no interactive sign-in, token acquisition/refresh, or dashboard-user identity forwarding. A driver application is the recommendation for application-specific authentication; endpoint authentication should not be disabled for these commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Protocol validation, malformed response handling, TypeScript documentation, and the ATS baseline need correction.

Get a fresh assessment by requesting another Copilot review.

Review details

Files not reviewed (1)

  • playground/AspireAgents/vercel-ai-responses-agent/package-lock.json: Generated file

Suppressed comments (1)

src/Aspire.Hosting.Agents/AgentResourceBuilderExtensions.cs:767

  • The ACP command uses mode: "sync", but this validation treats every 2xx JSON response except failed/cancelled as success. A malformed {} or a nonterminal created/in-progress run therefore appears successful even though a synchronous run must return status: "completed". Require a present completed status and fail every other status while preserving the response for diagnostics.
        if (validateAcpRunStatus && TryGetAcpTerminalFailureStatus(responseJson, out var runStatus))
        {
            return CommandResults.Failure(
                $"Agent run ended in the '{runStatus}' state.",
                JsonSerializer.Serialize(responseJson["error"] ?? responseJson, s_indentedJsonOptions),
                CommandResultFormat.Json);
        }
  • Files reviewed: 49/53 changed files
  • Comments generated: 4
  • Review effort level: Balanced

Comment thread src/Aspire.Hosting.Agents/README.md Resolved
Reject undefined protocols and invocation modes before changing resource state, require the MCP CallToolResult content array, and fix the README enum import. Cover invalid enum inputs, malformed content, and valid empty content arrays.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Valid endpoint casing and several protocol-compliant A2A and AG-UI configurations currently produce failed or incompatible invocations.

Review details

Files not reviewed (1)

  • playground/AspireAgents/vercel-ai-responses-agent/package-lock.json: Generated file

Suppressed comments (5)

Previously missed (5) — in code that hasn't changed since the last review.

src/Aspire.Hosting.Agents/AgentResourceBuilderExtensions.cs:269

  • HTTP URI schemes are case-insensitive, but this pattern only accepts lowercase values. Because EndpointAnnotation.UriScheme preserves the supplied casing, a valid endpoint configured as HTTP or HTTPS reaches the “no endpoint found” exception. Compare both schemes with OrdinalIgnoreCase.
    src/Aspire.Hosting.Agents/AgentResourceBuilderExtensions.cs:507
  • The first JSONRPC/HTTP+JSON interface is accepted without checking its protocol version. Since IsA2AProtocolVersionV03 treats every 0.* value as v0.3 and every other value as v1, a card advertising 0.2 or 2.0 before a supported interface is invoked with an incompatible request shape instead of continuing negotiation. Restrict selection to the advertised v0.3/v1.0 versions and continue past unsupported versions.
    src/Aspire.Hosting.Agents/AgentResourceBuilderExtensions.cs:552
  • Legacy v0.3 cards can advertise alternate bindings in additionalInterfaces, but this fallback yields only the primary url/preferredTransport. If the primary binding is unsupported (for example gRPC) and an additional interface provides JSONRPC or HTTP+JSON, the dashboard command incorrectly reports that no invokable binding exists. Normalize and append each additionalInterfaces entry (url plus transport) using the card's protocol version.
    src/Aspire.Hosting.Agents/AgentResourceBuilderExtensions.cs:553
  • For a legacy card with a top-level url but no protocolVersion, this stores null; request preparation then classifies it as v1 and sends v1 method names and an A2A-Version: 1.0 header. A2A's backward-compatibility mapping defaults this legacy shape to 0.3.0, so such v0.3 agents cannot be invoked unless the same default is applied here.
    src/Aspire.Hosting.Agents/AgentResourceBuilderExtensions.cs:661
  • The AG-UI RunAgentInput contract requires tools, context, and forwardedProps, but this request sends only IDs and messages. Tolerant endpoints may supply defaults, while protocol-conforming validators reject the dashboard invocation before the agent runs. Send empty collections/object for these required fields when the command has none to provide.
  • Files reviewed: 49/53 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@tommasodotNET

Copy link
Copy Markdown
Contributor Author

This implementation has moved to the Aspire Community Toolkit: CommunityToolkit/Aspire#2249 (CommunityToolkit/Aspire#2249), tracking CommunityToolkit/Aspire#2248 (CommunityToolkit/Aspire#2248). The replacement preserves the agent invocation feature, tests, and examples in CommunityToolkit.Aspire.Hosting.Agents without production changes to core Aspire.Hosting. Closing this PR in favor of the Toolkit PR; further implementation discussion and review should continue there. Thanks for the review and guidance here.

Tommaso Stocchi (tommasodotNET) added a commit to CommunityToolkit/Aspire that referenced this pull request Oct 28, 2026
Port microsoft/aspire#17757 via standalone source 8d93031b42666b353aee4a8370a8b5349703ad98. Preserve all protocols, MCP invocation, 277 tests and six examples, adapting Toolkit naming, packaging and test infrastructure.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Tommaso Stocchi (tommasodotNET) added a commit to CommunityToolkit/Aspire that referenced this pull request Nov 3, 2026
Port microsoft/aspire#17757 via standalone source 8d93031b42666b353aee4a8370a8b5349703ad98. Preserve all protocols, MCP invocation, 277 tests and six examples, adapting Toolkit naming, packaging and test infrastructure.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Aaron Powell (aaronpowell) pushed a commit to CommunityToolkit/Aspire that referenced this pull request Nov 5, 2026
* Add agent hosting integration from upstream Aspire proposal

Port microsoft/aspire#17757 via standalone source 8d93031b42666b353aee4a8370a8b5349703ad98. Preserve all protocols, MCP invocation, 277 tests and six examples, adapting Toolkit naming, packaging and test infrastructure.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Fix agent invocation issues identified in Copilot review

Complete AG-UI inputs, preserve distinct protocol paths, correlate MCP tool responses, handle dialog cancellation and fall back to raw JSON for complex parameter schemas. Add regression coverage for all five review findings.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Address agent integration maintainer review

Reuse shared test helpers, centralize sample package versions, use application configuration, and document Toolkit diagnostics and the dashboard workflow. Preserve publish assertions without a local xUnit override and add safe agent-card failure diagnostics.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Align agent examples and tests with Aspire 17

Use the shared test project's runtime setup, migrate sample .NET resources to AddDotnetProject, and retain explicit legacy ProjectResource regression coverage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Adopt official MCP SDK for agent tool commands

Replace handwritten protocol handling with ModelContextProtocol.Core while preserving dashboard inputs, endpoint resolution, authentication boundaries, and bounded cleanup. Align MCP versions centrally and document accepted SDK failure-path limitations and actual dashboard diagnostics.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Aspire Agent Awarness

5 participants