Repository navigation
Description
Category
Documentation
Problem
Description
Following the standard .NET MCP integration pattern sends both content and structuredContent to the model when a server returns the same JSON payload in both fields.
Python Agent Framework provides [tool_result_content](https://github.com/microsoft/agent-framework/pull/8274) to choose whether content, structuredContent, or both are sent to the model. Is there an equivalent option in .NET? The default .NET flow sends both even when they contain identical data, unnecessarily increasing token usage.
Evidence
Minimal reproduction
ASP.NET Core project with the packages listed below. The MCP server returns a typed object; the client passes the discovered tools directly to Agent Framework.
// Program.cs
using Microsoft.Agents.AI;
using ModelContextProtocol.Client;
using OpenAI;
using OpenAI.Responses;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseUrls("http://127.0.0.1:5017");
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithTools<MyTools>();
await using var app = builder.Build();
app.MapMcp("/mcp");
await app.StartAsync();
try
{
await using var mcpClient = await McpClient.CreateAsync(new HttpClientTransport(new()
{
Endpoint = new Uri("http://127.0.0.1:5017/mcp"),
}));
var tools = await mcpClient.ListToolsAsync();
var openAi = new OpenAIClient(Environment.GetEnvironmentVariable("OPENAI_API_KEY")!);
AIAgent agent = openAi.GetResponsesClient().AsAIAgent(
model: "gpt-5.4",
instructions: "Call get_report once and report its marker.",
tools: [.. tools]);
Console.WriteLine(await agent.RunAsync("Get the report."));
}
finally
{
await app.StopAsync();
}
// MyTools.cs
using System.ComponentModel;
using ModelContextProtocol.Server;
[McpServerToolType]
public sealed class MyTools
{
[McpServerTool(Name = "get_report", UseStructuredContent = true)]
[Description("Returns a sample report.")]
public Report GetReport() => new("PROBE_MARKER", 3);
}
public sealed record Report(string Marker, int Count);
Actual behavior
The next LLM request contains one function_call_output whose output string includes both representations. For the simplified report above, the shape is:
{
"content": [
{ "type": "text", "text": "{\"marker\":\"PROBE_MARKER\",\"count\":3}" }
],
"structuredContent": {
"marker": "PROBE_MARKER",
"count": 3
}
}
Desired Outcome
Expected behavior / documentation request
Could the .NET MCP integration provide or document an explicit model-visible result policy, analogous to Python's structured_first, content_first, content_only, structured_only, and both?
At minimum, the .NET MCP sample/docs should explain:
- Which fields are forwarded by default, including the full-envelope fallback and its token implications.
- The supported way to choose the model-facing representation before the next request in the function-calling loop.
- How that choice affects errors, metadata, images/audio, embedded resources, and resource links.
I am not asking for an unconditional return structuredContent: that would drop useful content for tools whose fields are complementary. A documented, explicit policy would be preferable to silently inheriting a fixed conversion behavior.
The generic FICC FunctionInvoker hook exists, but that is different from a documented MCP-specific policy and still requires the application to implement the projection correctly.
Possible Workaround
ficc.FunctionInvoker = async (context, cancellationToken) =>
{
var result = await context.Function.InvokeAsync(
context.Arguments, cancellationToken);
if (context.Function.GetService<McpClientTool>() is not null &&
result is JsonElement { ValueKind: JsonValueKind.Object } json)
{
if (json.TryGetProperty("isError", out var error) &&
error.ValueKind == JsonValueKind.True)
{
return result;
}
// Example policy: `structured-first.`
if (json.TryGetProperty("structuredContent", out var structured) &&
structured.ValueKind is not (JsonValueKind.Null or JsonValueKind.Undefined))
{
return structured.Clone();
}
}
return result;
};
Language
.NET
Acknowledgements
- I searched existing issues and did not find a duplicate.
- I will wait for explicit maintainer agreement before starting implementation of a non-trivial change.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
[-][Issue]:[/-][+].NET: [Issue]:[/+][-].NET: [Issue]:[/-][+].NET: [Issue]:MCP content + structuredContent duplicate model input without a selection policy[/+]Manish-1kumar commentedon Oct 31, 2026
Hi team,
I noticed this discussion regarding token duplication when an MCP server returns both
contentandstructuredContent.I would be interested in helping contribute a fix or sample once the preferred direction is established. Could maintainers provide guidance on whether the preferred approach is:
structuredContentover rawcontentwhen both exist)?Happy to help implement or document this once the team decides on the approach.