AgentOps.Mcp.Hardening
0.1.0-alpha
dotnet add package AgentOps.Mcp.Hardening --version 0.1.0-alpha
NuGet\Install-Package AgentOps.Mcp.Hardening -Version 0.1.0-alpha
<PackageReference Include="AgentOps.Mcp.Hardening" Version="0.1.0-alpha" />
<PackageVersion Include="AgentOps.Mcp.Hardening" Version="0.1.0-alpha" />
<PackageReference Include="AgentOps.Mcp.Hardening" />
paket add AgentOps.Mcp.Hardening --version 0.1.0-alpha
#r "nuget: AgentOps.Mcp.Hardening, 0.1.0-alpha"
#:package AgentOps.Mcp.Hardening@0.1.0-alpha
#addin nuget:?package=AgentOps.Mcp.Hardening&version=0.1.0-alpha&prerelease
#tool nuget:?package=AgentOps.Mcp.Hardening&version=0.1.0-alpha&prerelease
AgentOps.Mcp.Hardening
Runaway prevention for Microsoft Agent Framework + MCP agents. Stop the unbounded loops, recursive sub-agent storms, and silent budget burns that turn a $5 chat into a $5,000 incident.
What it does
Three middleware layers, sharing one accumulator, watching three distinct boundaries:
| Capability | Boundary watched | Limit type |
|---|---|---|
MaxToolCalls |
Function invocations per agent session | Hard count |
MaxRecursionDepth |
Nested agent invocations within a session | Hard depth |
MaxTokenBudget |
Cumulative input + output tokens across all LLM calls | Hard budget |
When any limit is breached, the responsible middleware emits three signals simultaneously:
- A typed exception (
CallCountExceededException,RecursionDepthExceededException, orTokenBudgetExceededException, all inheriting fromRunawayDetectedException) - An OpenTelemetry span event named
agentops.runaway.{capability}with structured attributescapability,limit,actual— attached to the failing span so operators see exactly where in the trace tree the limit fired - A structured
ILoggerwarning with the same fields
Quickstart
dotnet add package AgentOps.Mcp.Hardening --version 0.1.0-alpha
using AgentOps.Mcp.Hardening;
// 1. Open a scope with limits
using var scope = AgentOpsMcpHardening.BeginScope(new AgentOpsMcpHardeningOptions
{
MaxToolCalls = 50,
MaxRecursionDepth = 5,
MaxTokenBudget = 100_000,
});
// 2. Wire the middleware on your chat client (token budget layer)
var chatClient = baseChatClient
.AsBuilder()
.UseFunctionInvocation()
.UseAgentOpsMcpHardening(loggerFactory) // chat-layer
.Build();
// 3. Wire the middleware on your agent (recursion + call-count layers)
var agent = new ChatClientAgent(chatClient, instructions: "...", name: "...", tools: [...])
.AsBuilder()
.UseAgentOpsMcpHardening(loggerFactory) // agent + function layers
.Build();
// 4. Run normally — limits enforced automatically
var response = await agent.RunAsync("...");
That's it. Three method calls, three layers wired, full coverage.
How it composes with Microsoft Agent Framework
AgentOps.Mcp.Hardening plugs into MAF's existing middleware system at three distinct layers:
- The chat client layer (via
IChatClientbuilder middleware) - The agent layer (via
AIAgentbuilder middleware) - The function invocation layer (composed inside the agent middleware)
It does not replace FunctionInvokingChatClient.MaximumIterationsPerRequest — that built-in MAF setting caps tool calls per LLM turn. AgentOps caps per agent session, which is the boundary that matters for runaway cost.
How it composes with AgentOps.Observability
Designed as a pair. AgentOps.Observability provides the OTel TracerProvider and instrumentation; AgentOps.Mcp.Hardening attaches span events to those traces when limits fire. One service, one trace tree, full story.
using var tracerProvider = AgentOpsObservability.CreateTracerProvider(...);
var chatClient = baseChatClient
.AsBuilder()
.UseFunctionInvocation()
.UseAgentOpsObservability()
.UseAgentOpsMcpHardening(loggerFactory)
.Build();
Together: Observability shows you what happened; Hardening stops what shouldn't.
Important: how breaches are propagated
MAF's FunctionInvokingChatClient catches function- and agent-layer exceptions and converts them into structured tool errors that the LLM sees. This is deliberate framework design — it lets the agent recover gracefully with a partial answer rather than hard-crashing on a single tool failure.
What this means for your code:
| Middleware layer | Limit | Exception propagation |
|---|---|---|
| Function (call count) | MaxToolCalls |
Caught by MAF; agent recovers with partial output. Telemetry + log fire. |
| Agent (recursion) | MaxRecursionDepth |
Caught by MAF; agent recovers. Telemetry + log fire. |
| Chat (token budget) | MaxTokenBudget |
Propagates to your try/catch. Telemetry + log fire. |
The library emits identical telemetry regardless of where the limit fires. Your operators see every breach in the trace tree even when the agent quietly recovers. Most production teams want this behavior — graceful degradation by default, hard abort available where it matters.
For the full runnable demo: samples/02-mcp-hardening-quickstart
Compatibility
| Dependency | Version |
|---|---|
| .NET | 10.0 |
| Microsoft.Agents.AI | [1.3.0, 2.0.0) |
| Microsoft.Extensions.AI | [10.5.0, 11.0.0) |
License
MIT. See LICENSE.
Roadmap
v0.1-alpha → v0.2 directions under consideration:
- Per-tool overrides (different limits for different tools)
- Cost-based USD budget (in addition to token budget)
- Pluggable
IRunawayPolicyinterface for custom escalation AgentOps.Mcp.Hardening.Azurecompanion package (App Insights sink, Azure Monitor metrics, cost dictionaries)
About
Built by Pinusx AI, LLC — production AI systems for .NET teams.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Agents.AI (>= 1.3.0 && < 2.0.0)
- Microsoft.Extensions.AI (>= 10.5.0 && < 11.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Options (>= 10.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-alpha | 79 | 5/15/2026 |