Skip to content

Add NativeAOT publish coverage for ModelContextProtocol.Extensions.Apps #1659

@halter73

Description

@halter73

Follow-up from PR #1484 (MCP Apps extension).

Gap

The new ModelContextProtocol.Extensions.Apps package declares IsAotCompatible=true, but nothing exercises it under NativeAOT. tests/ModelContextProtocol.AotCompatibility.TestApp only references ModelContextProtocol.Core, ModelContextProtocol, and ModelContextProtocol.AspNetCore — not Extensions.Apps. So the AOT publish job never sees the Apps code paths.

This is the reason a new { } anonymous-type bug in the capability-advertisement path (fixed during PR #1484 review) was not caught by CI. Our convention is that every shipped src/ package gets AOT publish coverage.

Proposed work

  1. Reference the package and root it in tests/ModelContextProtocol.AotCompatibility.TestApp/ModelContextProtocol.AotCompatibility.TestApp.csproj:

    <ProjectReference Include="..\..\src\ModelContextProtocol.Extensions.Apps\ModelContextProtocol.Extensions.Apps.csproj" />
    <TrimmerRootAssembly Include="ModelContextProtocol.Extensions.Apps" />
  2. Extend the test app's Program.cs to actually exercise the surface, otherwise the trimmer drops the package as unused and the publish passes vacuously. At minimum: register a tool decorated with [McpAppUi], call WithMcpApps(), round-trip ListToolsAsync(), and assert the _meta.ui metadata is present.

Caveat (for expectation-setting)

This coverage would not have surfaced the specific new { } issue as an AOT analyzer warning at publish time — that value flows through IDictionary<string, object> (boxed/polymorphic), which the trimmer can't statically trace; it would only manifest as a runtime serialization fallback (or NotSupportedException in strict AOT). But the coverage still catches a broad class of other AOT problems and matches the convention for new packages.

The broader point — that the IDictionary<string, object> extension surface (MCPEXP001) is an AOT footgun in general, since anything assigned to it bypasses source-gen unless callers use JsonObject or a source-gen-registered type — may warrant its own tracking issue.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions