AI agents — systems where an LLM decides what to do next, not just what to say — are now common enough in production .NET systems that architect-level interviews treat them as a topic of their own, distinct from a single-turn chat integration. The Model Context Protocol has become the standard way to expose tools and context to those agents interoperably, which is why agent and MCP questions increasingly appear together in the same loop. Interviewers use this material to see whether a candidate can reason about an agent as a system with a control loop, a security boundary and real failure modes, not as a black box that "figures things out." This page works through the questions asked at the architect level: the mechanics of the agent loop, tool and MCP design, multi-agent orchestration, memory, human oversight, and what actually goes wrong when an agent runs in production.

Q1 Explain the agent loop in concrete terms. What actually happens on each iteration of an LLM-based agent?#

Short answer: Each iteration sends the model the current conversation plus the available tool definitions; the model either returns a final answer or a request to call one or more tools; the runtime executes those calls against real systems and appends the results back into the conversation; and the loop repeats until the model returns a final answer or a bound — an iteration count, a timeout, a budget — is hit. It's a read-act-observe cycle, not a single inference call.

C#
var messages = new List<ChatMessage> { new(ChatRole.User, userInput) };
for (var iteration = 0; iteration < maxIterations; iteration++)
{
    var response = await chatClient.GetResponseAsync(messages, options, ct);
    messages.AddRange(response.Messages);

    if (!response.Messages.Any(m => m.Contents.OfType<FunctionCallContent>().Any()))
        return response; // a final answer, not another tool call

    // UseFunctionInvocation() normally handles execution and result feedback here;
    // shown explicitly so the loop's termination condition stays visible.
}
throw new InvalidOperationException("Agent exceeded its iteration budget.");

The detail that's easy to gloss over is that every iteration re-sends the entire accumulated conversation, so cost and latency grow with the number of steps, not just the length of the final answer — an agent that takes eight tool-call round trips to answer a simple question is far more expensive than the same answer given directly, which is exactly why tool design and iteration bounds matter operationally, not just for correctness. The termination condition also has to be unambiguous: some implementations look for the absence of a tool call in the model's response, others require an explicit "final answer" tool the model must call — the second is more robust because it doesn't depend on correctly inferring intent from response shape, but it requires the model to use it reliably, which is its own trade-off.

What interviewers look for: the specific read-act-observe framing with a named termination condition and a named cost-growth implication, not just "the agent keeps going until it's done."

Common mistakes: describing the loop without an iteration bound, and not recognizing that context, and therefore cost, accumulates across the whole loop, not just the final response.

Q2 What makes a good tool design for an agent versus a bad one?#

Short answer: Good tools are narrow, purpose-built, idempotent where possible, described precisely enough that the model can pick the right one without ambiguity, and return errors as structured, actionable text; bad tools are broad "do anything" functions with overlapping purposes that return raw exceptions or silent failures the model can't reason about.

Tool-selection accuracy degrades as the number of available tools grows and as their purposes overlap, because the model chooses based on a tool's name and description, not its implementation — two tools that both plausibly "look up a customer" but differ in a way visible only in the code will get confused for each other regularly. Granularity cuts both ways: a single tool that takes a free-form action parameter and dispatches internally hides the real capability surface from the model's selection process and tends to produce more wrong calls than several well-named, single-purpose tools; but too many narrow tools bloats the list the model considers on every call, costing context tokens and sometimes reducing selection accuracy too. The description is not documentation for humans — it's the model's only signal for when and how to call the tool — so it needs to state preconditions, side effects and what a failure means, not just a generic summary. Error handling deserves the same care as a public API's error contract: a stack trace teaches the model nothing useful, while a structured message like "order not found; verify the ID format is ORD-XXXXX" gives it something to act on, including retrying correctly or asking for clarification instead of guessing.

C#
[Description("Cancels a pending order the caller owns. Irreversible once shipped.")]
static async Task<string> CancelOrderAsync(
    [Description("Order ID, format ORD-NNNNN")] string orderId,
    IOrderService orders, ClaimsPrincipal user)
{
    var order = await orders.GetForUserAsync(orderId, user.GetUserId());
    if (order is null) return "Order not found or not accessible.";
    if (order.Status == "Shipped") return "Cannot cancel: order has already shipped.";
    await orders.CancelAsync(order.Id);
    return "Order canceled.";
}

What interviewers look for: treating tool design as API design for a caller that can't read your source code — the same discipline as a public REST endpoint, applied to a non-human, imperfectly reasoning caller.

Common mistakes: exposing one large, multi-purpose tool "to keep things simple," and returning raw exception text instead of an actionable error message.

Q3 What is MCP, and what problem does it solve that ad hoc function calling doesn't?#

Short answer: The Model Context Protocol is a standardized, open protocol for connecting AI applications, "hosts," to external tools, data and prompt templates exposed by independent "servers," so a capability built once as an MCP server works with any compliant host, instead of every application writing its own bespoke integration against every tool it wants to use.

Function calling on its own only defines how a model requests a call within one conversation — it says nothing about how that function got registered, discovered or reused across different applications. Before MCP, connecting an agent to, say, a ticketing system meant writing an integration specific to that agent's framework; connecting a different framework to the same system meant writing it again. MCP separates the concerns: a server exposes tools, resources (readable contextual data) and prompts (reusable templates) over a standard protocol, and any MCP-compliant host can discover and use them without custom integration code, the way any HTTP client can talk to any HTTP server because they share a protocol rather than a bespoke SDK. The official C# SDK ships this as several NuGet packages — ModelContextProtocol.Core for minimal client or low-level server use, ModelContextProtocol as the main package with hosting and dependency-injection integration for most projects, and ModelContextProtocol.AspNetCore for HTTP-hosted servers — which is what makes building either side of this in .NET a normal ASP.NET Core or console-app exercise rather than a protocol implementation from scratch.

What interviewers look for: the reuse-across-hosts framing specifically — write the integration once, use it from any compliant client — rather than describing MCP as just another way to do function calling.

Common mistakes: conflating MCP with function calling itself (MCP is a transport and discovery protocol for tools, resources and prompts; function calling is how a model expresses "call this" within a conversation), and not knowing there's an official, actively maintained C# SDK.

Q4 Walk through MCP's architecture: hosts, clients, servers and transports.#

Short answer: A host is the AI application the user interacts with, which owns one or more clients, each maintaining a one-to-one connection to a single MCP server; servers expose tools, resources and prompts and can run locally as a subprocess communicating over standard input and output, or remotely over an HTTP-based transport — the host decides which servers to connect to and mediates everything the model is allowed to see and call.

The one-client-per-server design matters architecturally: it keeps each connection's capability set, authentication and lifecycle independent, so a host can connect to a local filesystem server over stdio and a remote ticketing server over HTTP in the same session without either integration knowing about the other. A local, subprocess-based server over stdio is the simpler and more common pattern for tools needing direct machine access — a local file system, a local database, developer tooling — because it inherits the host process's trust boundary and needs no network exposure at all. A remote, HTTP-hosted server is what you reach for when the capability lives behind a service, needs to be shared across many hosts or users, or needs independent scaling and deployment; that's exactly what ModelContextProtocol.AspNetCore is for, hosting an MCP server as an ASP.NET Core endpoint like any other web API. Regardless of transport, the protocol standardizes discovery — listing available tools, resources and prompts — and invocation, which is why a well-built server should behave identically from a local stdio connection in development and a hosted HTTP deployment in production, modulo the authentication story.

What interviewers look for: the host/client/server separation stated precisely, including the one-client-per-server detail, and a correct read on when stdio versus HTTP transport is the right choice.

Follow-up questions:

  • Why does MCP use one client per server instead of one client multiplexing several servers?
  • What changes operationally when you move a tool from a local stdio server to a hosted HTTP one?

Q5 What security risks does MCP introduce, and how do you mitigate them?#

Short answer: The main risks are tool poisoning and indirect prompt injection through server-returned content, where a malicious or compromised server smuggles instructions inside a tool's description or a resource's content that the model then "obeys"; the confused-deputy problem, where a server acts with more authority than the calling user actually has; and over-broad permissions granted to a server that only needs a narrow slice of access — mitigated with least-privilege scoping per server, treating server-returned content as untrusted data rather than instructions, and proper delegated authorization instead of one shared credential.

Because tool descriptions and resource content flow into the model's context exactly like any other text, a compromised server can embed instructions inside what looks like ordinary data — text hidden inside a document a resource returns, instructing the model to act against the user's interest — and a model that doesn't reliably separate content to reason about from instructions to follow can act on it. This is the same indirect-injection problem RAG content has, with the added risk that an MCP tool can actually take an action, not just influence text output. The confused-deputy risk shows up when a server holds broad credentials on the caller's behalf and a client fails to scope what it requests through that server for a specific user, letting a user, or a compromised host, exercise more authority than they individually hold. The C# SDK addresses the authorization side with support for an Identity Assertion Authorization Grant flow via IdentityAssertionGrantProvider, which lets a server verify the identity actually making a request rather than trusting the host unconditionally; the underlying principle — narrow, per-user, per-server authorization instead of one shared service credential — applies even outside that specific flow. Treating every server as a third-party dependency with its own trust review, rather than an implicit extension of your own code, catches most of these risks before they ship.

What interviewers look for: naming indirect injection through tool and resource content specifically, since it's the risk unique to this architecture, plus a real authorization answer rather than "use HTTPS."

Common mistakes: treating an MCP server's content as inherently trustworthy because it came from "your own" integration, and granting a server one broad credential instead of scoping access per user or capability.

Q6 When do you design a system as multiple specialized agents instead of one agent with many tools, and how do you orchestrate them?#

Short answer: Split into multiple agents when a single agent's tool list and instructions become too broad to reason about reliably, or when parts of the task genuinely need different context, permissions or models — and orchestrate with an explicit pattern: sequential for a fixed pipeline, concurrent for independent subtasks that merge at the end, handoff for a single active agent passing control as the conversation's needs change, and group-collaboration patterns for tasks that benefit from multiple perspectives converging on one answer.

A single agent with dozens of tools across unrelated domains suffers the same selection-accuracy problem as an overloaded tool list, compounded by instructions that have to cover every domain at once and therefore serve none of them well; splitting into specialized agents narrows each one's tools and instructions to something it can execute reliably, at the cost of needing an explicit routing mechanism between them. Microsoft Agent Framework names these orchestration shapes directly as graph-based workflows — sequential execution for a known pipeline, concurrent execution for independent work that fans back in, handoff for conversational scenarios where control should move to a different specialized agent mid-conversation, and group-collaboration patterns where multiple agents contribute before a result is finalized — with checkpointing support so a long-running multi-agent workflow can persist state and resume rather than restart after a failure. The orchestration choice is a real architectural decision: sequential pipelines are easiest to reason about and debug but slowest, concurrent execution improves latency for genuinely independent subtasks but complicates result merging, and handoff is the most flexible but hardest to test exhaustively, since the routing decision itself is made by a model.

What interviewers look for: matching the orchestration pattern to the actual shape of the task — pipeline, independent, or conversational routing — rather than defaulting to one pattern for everything, and naming checkpointing as a real production concern for long-running workflows.

Follow-up questions:

  • How would you test a handoff-based multi-agent system, where the routing itself is non-deterministic?
  • What would push you back toward a single agent with more tools instead of splitting further?

Q7 How do you give an agent memory across turns and sessions, and what are the trade-offs?#

Short answer: Short-term memory — the current conversation's message history — is state you load and persist per session, the same as any chat application; long-term memory, facts or preferences that should carry across sessions, needs a deliberate extraction and storage step, usually into a structured store or a vector store for semantic recall, and the trade-off in both cases is that more persisted memory means more context to manage, more cost, and a real risk of persisting the wrong thing.

Short-term and long-term memory are different engineering problems, though it's tempting to treat "memory" as one feature. Short-term memory is conversation history plus tool-call results within a session, subject to the same context-window budgeting as any multi-turn chat feature — nothing agent-specific beyond the fact that tool results can be large and need the same truncation discipline as message history. Long-term memory is harder: deciding what is worth remembering across sessions usually requires an explicit extraction step, often a smaller model call summarizing what should be retained, rather than persisting raw transcripts, both for cost and because raw transcripts are a worse retrieval target than distilled facts. Microsoft Agent Framework's durability and restartability features address a related but distinct concern — a workflow's own execution state surviving a process restart — which is not the same as an agent remembering something about a user across unrelated sessions, and candidates sometimes conflate the two. The trade-off worth stating explicitly is that unbounded memory accumulation is a liability, not just a cost line: stale or wrong "remembered" facts actively degrade future interactions, so a memory system needs an expiry or review mechanism, not just a write path.

C#
public sealed record UserMemory(string UserId, string Fact, DateOnly LearnedOn);

// Distilled at the end of a session, not the raw transcript:
var extracted = await chatClient.GetResponseAsync<UserMemory[]>(
    $"List durable facts worth remembering from this session:\n{transcript}");
await memoryStore.UpsertAsync(extracted.Result, ct);

What interviewers look for: the short-term-versus-long-term split, and specifically distinguishing workflow execution-state durability from user-facing memory, which checks whether a candidate understands the framework concepts or is pattern-matching on the word "memory."

Common mistakes: persisting entire raw transcripts as "memory" instead of extracted, distilled facts, and never expiring or revalidating stored memory.

Q8 When and how do you insert human-in-the-loop checkpoints into an agent workflow?#

Short answer: Insert an approval checkpoint before any action with real-world consequences that are costly or hard to reverse — sending an external communication, moving money, deleting data, modifying a production system — and implement it as a genuine pause that waits for an explicit decision, not a fire-and-notify pattern, using the workflow's own state persistence so the pause can last minutes or days without holding a process open.

The judgment call is where to place the checkpoint: too many approval gates and the agent is no faster than a human doing the task manually, defeating the point of automating it; too few and a single bad tool call executes before anyone reviews it. The workable heuristic is gating on consequence and reversibility rather than task type — a read-only lookup never needs approval regardless of data sensitivity, while an irreversible write almost always does, and the interesting design work is in between, for actions that are reversible but costly or embarrassing to undo. This has to be a real pause, not a "do it and notify a human afterward" pattern, which isn't human-in-the-loop at all — it's human-after-the-fact. Because a human might not respond for minutes or days, the workflow needs to persist its paused state rather than block a thread or hold a process open, which is exactly what checkpointing in Microsoft Agent Framework's workflow model is for: a workflow serializes its state at the approval point and resumes from that exact point once a decision returns, potentially on a different process entirely. The channel for that approval is a product decision, but the underlying requirement — durable pause, explicit resume, and a clear record of who approved what — is architectural and needs to be designed in from the start.

What interviewers look for: the consequence-and-reversibility heuristic for where to gate, plus recognizing that human-in-the-loop requires durable pause and resume, not just a notification.

Common mistakes: gating every action regardless of risk, making the agent slower than doing the task by hand, and implementing "approval" as a post-hoc notification instead of an actual blocking checkpoint.

Q9 What are the common failure modes of production agents, and how do you detect and contain them?#

Short answer: The recurring failure modes are unbounded loops, runaway cost from many iterations or a fan-out of sub-agents, wrong tool selection, goal drift over a long conversation, and cascading errors in multi-agent chains where one agent's mistake becomes another agent's trusted input — contained with hard iteration and budget limits, timeouts, structured tool errors the model can act on, and treating inter-agent messages with the same skepticism as external input rather than as ground truth.

An unbounded loop is the most mechanical failure and the easiest to prevent outright with a hard iteration cap and a wall-clock timeout on the whole invocation, but the more interesting failure is a bounded loop that still burns an unreasonable amount of cost before hitting the cap, which is why per-invocation token and dollar budgets, not just iteration counts, belong in the design. Wrong tool selection compounds in multi-step tasks, because a wrong call early in the loop feeds a wrong result into every later step, so error surfaces need to be loud and specific rather than silently returning something plausible-but-wrong the agent builds on. Goal drift shows up in longer conversations or workflows where accumulated context gradually pulls the model from the original instructions; periodically re-asserting the goal, or structuring a task as a sequence of narrower sub-agent calls instead of one long open-ended session, both reduce it. Multi-agent cascades are the failure mode unique to orchestration: agent A's incorrect output becomes agent B's trusted input with no independent verification, and the error compounds silently across the chain — the mitigation is validating the interfaces between agents with structured, checked handoffs rather than free-form text, and for high-stakes chains, a final verification step that isn't just another agent asserting confidence.

C#
public sealed record AgentBudget(int MaxIterations, decimal MaxCostUsd)
{
    public int IterationsUsed { get; private set; }
    public decimal CostUsedUsd { get; private set; }

    public bool TryConsume(decimal stepCostUsd)
    {
        if (IterationsUsed >= MaxIterations || CostUsedUsd + stepCostUsd > MaxCostUsd) return false;
        IterationsUsed++;
        CostUsedUsd += stepCostUsd;
        return true;
    }
}

What interviewers look for: naming cost and cascading multi-agent errors specifically, not just "the model might be wrong" — these are the failure modes that distinguish someone who has run agents in production from someone who has only prototyped one.

Common mistakes: capping iterations without capping cost, and trusting inter-agent handoffs as verified facts instead of validating them at the interface.

Q10 How does Microsoft Agent Framework relate to Semantic Kernel and AutoGen, and when would you reach for it instead of building your own agent loop?#

Short answer: Microsoft Agent Framework is Microsoft's unified, open, multi-language framework for building production-grade agents and multi-agent workflows — distributed as Microsoft.Agents.AI on NuGet for .NET, with Microsoft.Agents.AI.Foundry for cloud-hosted scenarios — positioned to consolidate ideas from both Semantic Kernel (plugins, planning, enterprise integration) and AutoGen (multi-agent conversation patterns), with official migration guides from both; reach for it once you need durable, checkpointed multi-agent workflows with human-in-the-loop support rather than a single-agent tool loop you could reasonably hand-roll.

Before Microsoft Agent Framework, teams choosing between Semantic Kernel and AutoGen were choosing between two frameworks with real overlap and different maturity and target scenarios, which made standardizing on one genuinely hard; the unification is meant to end that split by carrying forward what worked from each. The concrete capabilities worth naming in an interview are the graph-based workflow model with sequential, concurrent, handoff and group-collaboration orchestration, checkpointing for durability and restart, and explicit human-in-the-loop support built into the workflow model rather than bolted on. Building your own agent loop directly on IChatClient and AIFunctionFactory remains entirely reasonable for a single agent with a bounded, well-understood tool set — it's less abstraction to learn and debug, and for a narrow use case the framework's workflow machinery is overhead you don't need. The framework earns its complexity once there's more than one agent that needs to hand off or collaborate, a workflow that has to survive a process restart mid-execution, or approval gates that need first-class support rather than custom plumbing; at that point, reimplementing checkpointing and orchestration by hand is infrastructure work better sourced from a maintained framework than rebuilt per project.

What interviewers look for: naming the specific capabilities — checkpointing, durable human-in-the-loop, multi-language consistency — that justify the framework, rather than a generic "it's Microsoft's agent framework" answer, and a clear-eyed view of when hand-rolling a simple loop is still the right call.

Common mistakes: assuming any agent, however simple, needs a full orchestration framework, and not knowing the framework has official migration paths from both Semantic Kernel and AutoGen.

Quick-Fire Round#

QuestionAnswer
What are the three primitives an MCP server can expose?Tools, resources and prompts.
What connection topology does MCP use between clients and servers?One client per server, owned by a host application.
What C# package hosts an MCP server over HTTP in ASP.NET Core?ModelContextProtocol.AspNetCore.
What's the main risk of treating tool or resource content as trusted?Indirect prompt injection — hidden instructions the model may obey.
What Agent Framework feature lets a paused workflow resume after a restart?Checkpointing.
What orchestration pattern hands control to a different agent mid-conversation?Handoff.
What should gate a human-in-the-loop approval?The action's consequence and reversibility, not its task category.
What NuGet package is Microsoft Agent Framework's .NET entry point?Microsoft.Agents.AI.

How to Prepare#

  • Build a minimal agent loop by hand once, with a hard iteration cap, before relying on a framework's built-in loop — it makes the abstractions concrete.
  • Build or run one real MCP server and connect a client to it; know the difference between a stdio and an HTTP-hosted server firsthand.
  • Rehearse the indirect-injection risk for MCP content specifically; it's the security question most loops ask first.
  • Practice matching orchestration patterns — sequential, concurrent, handoff, group — to task shapes instead of defaulting to one pattern.
  • Have one clear example of a human-in-the-loop gate placed by consequence and reversibility, not by task type.
  • Know Microsoft Agent Framework's relationship to Semantic Kernel and AutoGen well enough to explain why the unification happened.