Troubleshooting
Find the fix for a common problem when you install, build or run MentorAgent: startup errors, blocked requests, roles, confirmation and local models.
On this page
Use this page when something does not work while you install, build or run MentorAgent. Each section starts from what you see, then gives the cause and the fix.
Find your symptom in this list:
- Install and build: the build cannot find a type of your model provider, the app still runs the old packages, the Azure OpenAI Responses client throws MissingMethodException.
- Startup: the app stops with an InvalidOperationException, the app cannot map the Model Context Protocol (MCP) or Agent-to-Agent (A2A) endpoint.
- Clients and connections: the widget button does nothing, a browser client is blocked by Cross-Origin Resource Sharing (CORS), every request to /mcp answers 500, a client cannot connect to the hub, a confirmation answer gets a 404, restoring a conversation fails.
- What the agent does: it does not call your method, an action with RequiredRoles is always refused, an action runs without a confirmation box, an action that only reads asks for confirmation, a local model ignores the instructions.
- Known issues: the defects of this version, in What's new.
The build cannot find a type of your model provider
Section titled “The build cannot find a type of your model provider”The build stops with error CS0246: the type or namespace OpenAI, AzureOpenAIClient or DefaultAzureCredential could not be found.
Cause. MentorAgent brings no SDK of a model provider. You add the package of your provider, at the version you choose.
Fix. Add the package that your code needs:
| Your code uses | Add the package |
|---|---|
OpenAIClient, or AsIChatClient() on an OpenAI client | Microsoft.Extensions.AI.OpenAI, which brings OpenAI |
AzureOpenAIClient | Azure.AI.OpenAI and Microsoft.Extensions.AI.OpenAI |
DefaultAzureCredential | Azure.Identity |
AIProjectClient | Microsoft.Agents.AI.Foundry |
AnthropicClient | Microsoft.Agents.AI.Anthropic |
With the Responses API of Azure OpenAI, pin the version: see The Azure OpenAI Responses client throws MissingMethodException. If your code uses an Agent Framework hosting package that earlier versions of MentorAgent installed, such as Microsoft.Agents.AI.Hosting.A2A.AspNetCore, add that package to your project yourself.
The application still runs the old MentorAgent packages
Section titled “The application still runs the old MentorAgent packages”After the upgrade to 1.0.0, the build succeeds, but the application still behaves like 1.0.0-rc.15.
Cause. A project still references a package with the old ID, which ends with 1.0.0-rc.15. The old and the new packages build side by side without an error, and using lines with the old namespaces keep reaching the old package.
Fix. Follow Move to the Novior.MentorAgent packages. In every project, dotnet list package --include-transitive must list only Novior.MentorAgent packages.
The widget button does nothing
Section titled “The widget button does nothing”Cause. The widget is on a page or layout that renders statically. It shows its button, but nothing handles the click.
Fix. Make the whole app interactive, with <Routes @rendermode="InteractiveServer" /> in Components/App.razor. Or run the widget on the server: give it its own InteractiveServer render mode in the layout. Place the widget shows both.
The app stops at startup with an InvalidOperationException
Section titled “The app stops at startup with an InvalidOperationException”The app ends before it listens, with an InvalidOperationException. On a Blazor Server app or a worker, the terminal shows "Hosting failed to start" and the reason. Some hosts stop earlier, at the Map… call, with the same message. This happens when the host maps the endpoints of Novior.MentorAgent.Server: the hub and its HTTP endpoints, the Model Context Protocol (MCP) server, or the Agent-to-Agent (A2A) agent.
| The message starts with | Fix |
|---|---|
[MentorAgent] AppName is required. | Set options.AppName |
[MentorAgent] Configure ChatClient or Agent. | Set options.ChatClient, or options.Agent for your own AIAgent |
[MentorAgent] Set ChatClient OR Agent, not both. | Keep only one of them |
[MentorAgent] ScanAssemblies cannot be empty. | List your assemblies, for example options.ScanAssemblies = [typeof(Program).Assembly] |
[MentorAgent] Both ChatHistoryProvider and ChatHistoryProviderFactory are set. | Set only one of them. Prefer ChatHistoryProviderFactory when the app has more than one user |
OpenAI:Key is missing | The key is not in the configuration: see below |
In the Quickstart, the key is in user secrets. In the project folder, run dotnet user-secrets list: it must show OpenAI:Key. If it does not, run dotnet user-secrets set OpenAI:Key <your-key> again. The app reads user secrets only in the Development environment. On a server, supply the key another way: see Keys and configuration in the Production checklist.
A .NET MAUI app has no host start to check the options, so the same messages appear the first time MentorAgent is used.
The app stops at startup: Cannot map the MCP or A2A endpoint
Section titled “The app stops at startup: Cannot map the MCP or A2A endpoint”app.MapMentorAgentMcp() or app.MapMentorAgentA2A() stops the app when the server is off or not registered. The message says which. A call to AddMentorAgentMcp() or AddMentorAgentA2A() in the wrong place also stops the app. It stops at the map call or, if the app maps no endpoint, when the host starts.
| The message starts with | Cause | Fix |
|---|---|---|
[MentorAgent] Cannot map MCP endpoint: McpServerEnabled is false. | The option is off. The A2A message names A2AServerEnabled. | Set options.McpServerEnabled = true (or options.A2AServerEnabled = true) in the AddMentorAgent callback, or remove the call. |
[MentorAgent] Cannot map the MCP endpoint: the MCP server is not registered. | The option is on, but nothing registered the server. The A2A message starts [MentorAgent] Cannot map the A2A endpoint: the A2A server is not registered. | Call builder.Services.AddMentorAgentMcp() (or AddMentorAgentA2A()) after AddMentorAgent(). AddMentorAgentServer() calls both. |
[MentorAgent] McpServerEnabled is true, but AddMentorAgentMcp() ran before AddMentorAgent() | The add method came first, found no options and registered nothing. The A2A message names A2AServerEnabled and AddMentorAgentA2A(). | Move the call after AddMentorAgent(). |
[MentorAgent] McpServerEnabled is true, but it was false when AddMentorAgent() read it | The option was turned on after AddMentorAgent() read it: in a Configure or PostConfigure of MentorOptions, or in configuration bound later. | Set the option in the AddMentorAgent callback. |
AddMentorAgentMcp(),AddMentorAgentA2A()and theMapMentorAgent…methods are in theNovior.MentorAgent.Serverpackage. A Blazor Server app that serves MCP or A2A without the hub must add that package. If the compiler says thatWebApplicationhas noMapMentorAgentMcp, the project does not reference the package.AddMentorAgentMcp()called beforeAddMentorAgent()registers nothing, because it reads the options thatAddMentorAgentstores. The app then stops and says so.
MCP server and A2A server show how to turn each one on.
A browser client is blocked by CORS
Section titled “A browser client is blocked by CORS”The browser console reports a Cross-Origin Resource Sharing (CORS) error for the request to /mcp. Desktop and IDE clients connect without a problem.
Cause. The /mcp endpoint has no CORS policy. Only browsers check for one, so only a browser-based client is blocked.
Fix. Opt in to a policy. Define a policy named MentorAgentMcp that lists your origins and exposes the Mcp-Session-Id header. You can register it before or after AddMentorAgent:
services.AddCors(options => options.AddPolicy("MentorAgentMcp",
policy => policy.WithOrigins("https://tools.example.com")
.AllowAnyHeader()
.AllowAnyMethod()
.WithExposedHeaders("Mcp-Session-Id")));Then call app.UseCors() and require the policy on the endpoint:
app.UseCors();
app.MapMentorAgentMcp(configure: endpoint => endpoint.RequireCors("MentorAgentMcp"));If you register no policy with that name, MentorAgent registers one that allows any origin. In production, list your own origins. MCP server has the complete configuration. With authentication, Secure the endpoints shows the order of the calls.
Every request to /mcp answers 500
Section titled “Every request to /mcp answers 500”Cause. You required a CORS policy on the endpoint, but the app has no CORS middleware. ASP.NET Core refuses to run such an endpoint. The log says that a middleware that supports CORS was not found. A plain MapMentorAgentMcp() does not need the middleware.
Fix. Call app.UseCors() before you map the endpoint, as in A browser client is blocked by CORS. If no browser calls /mcp, remove the RequireCors call instead.
A WebAssembly or JavaScript client cannot connect to the hub
Section titled “A WebAssembly or JavaScript client cannot connect to the hub”Cause. The client runs on a different origin from the server, for example another port during development, and the browser blocks the SignalR handshake. You do not need CORS when the client is served by the same host.
Fix.
- On the server, add a CORS policy that lists every client origin and allows credentials.
- Call
UseCorsbeforeUseAuthentication()andUseAuthorization(), and write those two calls inProgram.csyourself. If you leave them out, ASP.NET Core adds them before CORS. Then authorization can refuse the browser's preflight request. This is a request that the browser sends before the real request, and it carries no credentials. - On the client, use the absolute URL of the hub.
Secure the endpoints and Blazor WebAssembly and Auto show the code.
The answer to a confirmation gets a 404
Section titled “The answer to a confirmation gets a 404”Your own client answers a confirmation with POST /mentor/approve, and the server replies 404.
Cause. No turn waits for the answer any more. The question was answered already, the user pressed Stop, or the connection that raised it has closed. Closing a connection ends its turn.
Fix. Nothing is wrong. Treat 404 as "nothing left to answer" and close the dialog. 200 means that the waiting turn received the answer. The WebAssembly client of Novior.MentorAgent.Blazor already does this. A 401 or 403 has another cause: the request does not carry the identity of the hub connection. See Secure the endpoints.
Restoring a conversation answers 400 or 415
Section titled “Restoring a conversation answers 400 or 415”POST /mentor/session restores a conversation from a snapshot that GET /mentor/session returned. When it refuses the snapshot, the live conversation stays as it is. The body of the answer says why.
| What you see | Cause and fix |
|---|---|
415 | The request is not JSON. Send the snapshot with the content type application/json. |
400: the snapshot is from an earlier version | Save the conversation again with GET /mentor/session. |
400: the snapshot was edited or belongs to another user | The snapshot was edited, or it was saved for another user. Send back exactly what GET /mentor/session returned, for the same user. |
400: the Data Protection keys are gone | The ASP.NET Core Data Protection keys that protected the snapshot are gone. Persist and share the ASP.NET Core Data Protection key ring, as the next paragraph explains, and save the conversation again. |
400: the snapshot comes from a host that stores the history differently | The snapshot comes from a host that keeps the conversation history in another way. For example, one host keeps it on the model service with UseServiceManagedHistory, and the other keeps it in your application. Restore a snapshot only on a host that is set up in the same way. |
404 right after you connect | The server has not registered the connection yet. Restore after the first hub call, or try once more. |
To restore after a restart, or on another instance, persist and share the ASP.NET Core Data Protection key ring (external site), as you do for authentication cookies. Windows and Azure App Service keep the keys by default. A container without a volume does not.
Without sign-in, the owner check of the snapshot sees every visitor as the same anonymous user, so a snapshot opens for any connection of the application.
The agent does not call your method
Section titled “The agent does not call your method”Check these in order:
- The service is registered in dependency injection (DI). If it is not, the log has a warning that the tool was not found in DI, and the method is left out.
- Its assembly is in
ScanAssemblies. - The method is public, not static, and declared on the class itself. Inherited methods are ignored. This rule also applies to the classes listed in the
Toolsof a team member. - The method has
[MentorAction], or[Description]with a text. A[Description]with an empty text is ignored. - The description says what the method is for. The model chooses tools by their name and description, so a vague description is a likely reason for a missed call.
- Tool filtering did not send the action. With
EnableToolFilteringon, the model receives only the actions that match the message. Write each description in the words your users use. The Debug log lists the actions that were sent on each turn.- An action that needs confirmation is sent only when its description scores above
ToolFilterMinScore. - A short answer to a question from the agent, such as "yes, go ahead", carries the actions of the previous message.
- An action that needs confirmation is sent only when its description scores above
- The action asks for confirmation, and the caller cannot confirm. The MCP server and the A2A agent card do not publish an action that asks for confirmation. Tool filtering does not send such an action when a message matches nothing. A
[MentorAction]asks for confirmation by default, unless it declaresReadOnly = trueorRequiresConfirmation = false. SeeRequireConfirmationForWrites.- If it only reads, declare
ReadOnly = true. - If it must run without asking, declare
RequiresConfirmation = false.
- If it only reads, declare
- A team member lists the class in
Tools. The class is the toolbox of that member only. The coordinator does not call its methods, and the MCP server and the A2A card do not publish them. A line in the log, at Information level, names each such class.- Put an action that the coordinator must also offer on a class that no member lists.
- A
[MentorSkill]class keeps its coordinator tools.
An action with RequiredRoles is always refused
Section titled “An action with RequiredRoles is always refused”Check these causes, one by one:
- Nobody is signed in, or MentorAgent cannot see who is. Anonymous users are refused. When the app has no authentication at all, every user is refused: the app has neither
Novior.MentorAgent.Servernor anAuthenticationStateProvider. - The user does not have the role. MentorAgent checks roles with
ClaimsPrincipal.IsInRole(theClaimTypes.Roleclaims, by default). With ASP.NET Core Identity, roles reach the claims only when role support is registered: the Blazor template'sAddIdentityCore<ApplicationUser>()needs.AddRoles<IdentityRole>(). - The roles are in a
rolesclaim, and the identity does not name that claim. Arolesclaim works once the identity names it as itsRoleClaimType. Microsoft.Identity.Web does this for you. With JwtBearer andMapInboundClaims = false, setTokenValidationParameters.RoleClaimType = "roles". OtherwiseIsInRolelooks forClaimTypes.Role, and every action withRequiredRolesstays refused. - The app is a .NET MAUI Blazor Hybrid app. There is no ASP.NET Core user, so actions with
RequiredRolesare refused for everyone until you supply one: see .NET MAUI (Blazor Hybrid). - Your own
AuthenticationStateProvideradds the roles. On the hub, on/mentor/chatand over A2A, MentorAgent reads the user from the request. It does not ask yourAuthenticationStateProviderthere, so a claim that only it adds is not seen. Add the claim with anIClaimsTransformation. ASP.NET Core applies it toHttpContext.User, and so to the user of the hub connection. - The caller is an MCP client or another agent. An MCP client sees an action with
RequiredRolesonly whenMcpCallerPrincipalreturns an authenticated user who holds the role. Other channels withhold gated actions too: see Where nobody can answer.
An action that changes data runs without a confirmation box
Section titled “An action that changes data runs without a confirmation box”Cause. A [MentorAction] that is not read-only asks for confirmation by default, unless it declares RequiresConfirmation = false. A method that changes data runs without asking in these cases:
- it declares
RequiresConfirmation = false; - it declares
ReadOnly = true, orIsReadOnlyActionreturnstruefor its tool name; - it is a method with
[Description]alone:RequireConfirmationForWritescovers[MentorAction]methods only; RequireConfirmationForWritesorRequireConfirmationisfalse;- with
HitlMode.Native, a rule ofAutoApprovalRulesapproves it.
Fix. Remove the declaration that opts out, or mark the method [MentorAction]. For a method that you cannot annotate, use the RequiresApproval predicate.
MentorAgent also writes a warning to the log the first time it reads your actions. The warning lists the writes that run without confirmation: the [MentorAction] methods that opted out, and the methods with only [Description] that are not declared read-only. See RequireConfirmationForWrites.
With tool filtering on, an action without confirmation can reach the model on any message: see Tool filtering and confirmation.
An action asks for confirmation, but it only reads
Section titled “An action asks for confirmation, but it only reads”Cause. A [MentorAction] that declares neither ReadOnly = true nor RequiresConfirmation is treated as an action that changes data. It asks for confirmation, and the MCP server and the A2A card do not publish it.
Fix.
- Declare
ReadOnly = trueon an action that only reads, or list its tool name inIsReadOnlyAction. - Declare
RequiresConfirmation = falseon a write that must run without asking. - To turn the default off for the whole application, set
RequireConfirmationForWritestofalse. An action then asks only when it declaresRequiresConfirmation = true.
The Azure OpenAI Responses client throws MissingMethodException
Section titled “The Azure OpenAI Responses client throws MissingMethodException”The app builds without a warning. When your code calls GetResponsesClient() on an AzureOpenAIClient, it throws:
System.MissingMethodException: Method not found: 'Void OpenAI.Responses.ResponsesClient..ctor(System.ClientModel.Primitives.ClientPipeline, OpenAI.OpenAIClientOptions)'.Cause. Azure.AI.OpenAI 2.9.0-beta.1 calls a constructor that OpenAI 2.11 removed. A package that needs OpenAI 2.11 or later brings the newer version: for example a newer Microsoft.Extensions.AI.OpenAI, Microsoft.Agents.AI.OpenAI or Microsoft.Agents.AI.Foundry.
Fix. Keep OpenAI at 2.10. Give each of these references one exact version, built on OpenAI 2.10:
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="[10.6.0]" />
<PackageReference Include="Microsoft.Agents.AI.Foundry" Version="[1.17.0-preview.260804.1]" />Keep the second line only if you use AIProjectClient or FoundryEvals. The Chat Completions client (GetChatClient), OpenAI direct, and Ollama through its OpenAI-compatible endpoint need no pin. Remove the pin when Azure.AI.OpenAI ships a version built on a newer OpenAI.
A local model ignores the instructions or times out
Section titled “A local model ignores the instructions or times out”Cause: the context window is too short. The context window is the amount of text that the model reads at once. The default window of an Ollama model is shorter than the prompt that MentorAgent builds. Ollama then cuts the start of the prompt, without an error. The model answers without your instructions or tools.
Fix. Create a variant of the model with a larger context, with a Modelfile and ollama create, and use the variant's name as the model name. Ollama and other local models shows the file and the command.
Cause. The model is slow. On a CPU, a long prompt can take minutes.
Fix.
- Raise
NetworkTimeoutin theOpenAIClientOptionsof the client. - If you turned on
EnableSafetyCheck,RequireLookupForRecordQuestionsorRequireActionForChangeRequests, raiseSafetyCheckTimeouttoo. These options make an extra model call on each message. This call is the classifier, andSafetyCheckTimeoutlimits it. - If the classifier call of
RequireLookupForRecordQuestionsorRequireActionForChangeRequeststimes out, the turn runs without that option. - To make the classifiers faster, point them at a faster model with
ClassifierChatClient.
Model providers has the complete Ollama setup.
Also check that the model supports tool calling. MentorAgent needs it to call your methods.
Known issues
Section titled “Known issues”1.0.0 has four known issues. Their causes and workarounds are in Known issues in What's new.
See also
Section titled “See also”- Prerequisites — The .NET version, hosts, Agent Framework and provider package versions MentorAgent is tested with, and how to install it.
- What's new — What changed in the current MentorAgent version, what to do when you upgrade, its known issues and limitations, and how versions are numbered.
- MCP server — Expose your actions to MCP clients such as Claude Desktop or VS Code: authentication, CORS, and the actions that the server does not list.
- Secure the endpoints — Protect the SignalR hub, Server-Sent Events, /mcp and /a2a endpoints with authentication and CORS before you expose them.
