> ## Documentation Index
> Fetch the complete documentation index at: https://si.easyaf.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Analyzers

> Roslyn diagnostics that catch broken MCP forms while you type—unmappable properties, colliding wire names, and invalid lambdas.

MCP form elicitation is easy to get slightly wrong: a nested object on `From<T>()`, two properties that camelCase to the same name, a lambda that isn’t `x => x.Email`. Runtime skips or throws. The analyzers in **McpEssentials.Core** turn those mistakes into IDE squiggles and `dotnet build` diagnostics.

They fire on [`FormElicitation.From<T>()`](https://si.easyaf.dev/mcpessentials/guides/form-elicitation) and on expression starters (`Exclude`, `String`, `Email`, …). String-named `Create()` fields are whatever you add, so they are not analyzed.

> [card] Ships in Core
>
> `dotnet add package McpEssentials.Core` is enough. No extra package for everyday use.

> [card] Six IDs
>
> MCPESS001–006. Warnings, errors, and one info. All in the Usage category.

> [card] Same chain
>
> `.Exclude(x => x.Home)` on the `From` call that seeded `Home` suppresses MCPESS001 for that property.

## Install

> [tab] With Core
>
> Core already packs `CloudNimble.McpEssentials.Analyzers.dll` under `analyzers/dotnet/cs`. Adding Core to a project enables the diagnostics.
>
> ```bash theme={"dark"}
> dotnet add package McpEssentials.Core
> ```

> [tab] Analyzers only
>
> Use `McpEssentials.Analyzers` when you want the analyzer assembly without taking Core as a runtime dependency, or to pin analyzer versions separately.
>
> ```bash theme={"dark"}
> dotnet add package McpEssentials.Analyzers
> ```

> [!TIP]
>
> Rebuild after adding Core. Roslyn loads analyzers from the package; a running IDE may need a restart before squiggles appear.

## What they watch

**1. From a type**

`FormElicitation.From<T>("…")` and `new FormElicitationBuilder<T>("…")`. Public instance properties are checked against the same mapping rules as runtime.

**2. Expression starters**

`Exclude`, `String`, `Email`, `Uri`, `Date`, `DateTime`, `Integer`, `Number`, `Boolean`, `Choice`, and `MultiChoice` when the first argument is a lambda.

**3. The fluent chain**

`Exclude` calls on the same expression as `From` are collected so skipped properties you already excluded do not warn.

> [!NOTE]
>
> `FormElicitation.Create("…").String("filter")` is metadata-driven. There is no CLR property to inspect, so the analyzers stay quiet. That is the path for OData `$metadata` and other runtime catalogs.

## Diagnostics

> [accordion] MCPESS001 — unmappable property
>
> **Warning.** `From<T>()` skips public properties the MCP form schema cannot represent: nested objects, dictionaries, `TimeSpan`, `byte[]`, `string[]`, indexers, write-only and static members.
>
> ```csharp Warns theme={"dark"}
> public class SignupForm
> {
>     public string Name { get; set; }
>     public Address Home { get; set; } // skipped at runtime
> }
>
> FormElicitation.From<SignupForm>("Sign up");
> // MCPESS001: Property 'Home' on 'SignupForm' is skipped by FormElicitation.From.
> ```
>
> ```csharp Fixed theme={"dark"}
> FormElicitation.From<SignupForm>("Sign up")
>     .Exclude(x => x.Home);
> ```
>
> An empty type (no public properties) is a confirm dialog and does **not** warn.

> [accordion] MCPESS002 — colliding wire names
>
> **Error.** Two properties camelCase to the same JSON name. Runtime throws `InvalidOperationException` at `From`. The analyzer fails the build instead.
>
> ```csharp Errors theme={"dark"}
> public class CollisionForm
> {
>     public string EmailAddress { get; set; }
>     public string emailAddress { get; set; } // both become emailAddress
> }
>
> FormElicitation.From<CollisionForm>("m");
> // MCPESS002: Properties 'EmailAddress' and 'emailAddress' on 'CollisionForm'
> // both map to form field 'emailAddress'.
> ```
>
> ```csharp Fixed theme={"dark"}
> FormElicitation.From<CollisionForm>("m")
>     .Exclude(x => x.emailAddress);
> ```

> [accordion] MCPESS003 — nested or invalid lambda
>
> **Error.** Expression starters and `Exclude` require a simple property access on the form type, the same rule as `FormElicitationProperty.From`. Nested members, method calls, and fields fail.
>
> ```csharp Errors theme={"dark"}
> FormElicitation.From<Order>("m")
>     .Exclude(x => x.Address.City);   // nested
>
> FormElicitation.From<Order>("m")
>     .String(x => x.Name.Trim());     // method
> ```
>
> ```csharp Fixed theme={"dark"}
> FormElicitation.From<Order>("m")
>     .Exclude(x => x.Address)
>     .String(x => x.Name);
> ```

> [accordion] MCPESS004 — Exclude of something that was never a field
>
> **Info.** `Exclude` of an unmappable property is a successful no-op at runtime. The analyzer tells you so you do not think you removed a field that was never seeded.
>
> ```csharp theme={"dark"}
> public class Form
> {
>     public string Name { get; set; }
>     public Address Home { get; set; }
> }
>
> FormElicitation.From<Form>("m").Exclude(x => x.Home);
> // MCPESS004: Exclude of 'Home' does nothing because the property is not a supported form field
> // MCPESS001 is suppressed for Home on this From call.
> ```

> [accordion] MCPESS005 — From on a built-in
>
> **Warning.** `From<T>()` expects a class or struct of public properties. `string`, primitives, enums, and arrays are not form DTOs.
>
> ```csharp Warns theme={"dark"}
> FormElicitation.From<string>("m");
> FormElicitation.From<int>("m");
> FormElicitation.From<ColorChoice>("m");
> ```
>
> ```csharp Fixed theme={"dark"}
> FormElicitation.From<SignupForm>("m");
> FormElicitation.Create("m").String("notes");
> ```

> [accordion] MCPESS006 — field added after Build
>
> **Warning.** `Build`, `ToXml`, `ToJson`, `ToDefinition`, and `ToInputRequest` seal the form. A later starter or `Exclude` on that local would throw at runtime.
>
> ```csharp Warns theme={"dark"}
> var form = FormElicitation.Create("m").String("trackingNumber");
> form.Build();
> form.Integer("quantity"); // MCPESS006
> ```
>
> ```csharp Fixed theme={"dark"}
> var form = FormElicitation.Create("m")
>     .String("trackingNumber")
>     .Integer("quantity");
> form.Build();
> ```

## Severity at a glance

| Id | Severity | Default | Typical fix |
| - | - | - | - |
| MCPESS001 | Warning | On | `.Exclude(x => x.Prop)` or change the property type |
| MCPESS002 | Error | On | Rename or Exclude one of the colliding properties |
| MCPESS003 | Error | On | Use `x => x.Email`, not nested access |
| MCPESS004 | Info | On | Drop the `Exclude`, or leave it as documentation |
| MCPESS005 | Warning | On | Pass a form DTO, or use `Create()` |
| MCPESS006 | Warning | On | Add every field before `Build` / `ToXml` / `ToJson` |

## Suppress a diagnostic

Use this when the skip is deliberate and you do not want `.Exclude` on the chain.

> [tab] Inline
>
> ```csharp theme={"dark"}
> #pragma warning disable MCPESS001
> var form = FormElicitation.From<LegacyDto>("Continue");
> #pragma warning restore MCPESS001
> ```

> [tab] EditorConfig
>
> ```ini theme={"dark"}
> [*.cs]
> dotnet_diagnostic.MCPESS001.severity = suggestion
> dotnet_diagnostic.MCPESS004.severity = none
> ```

> [tab] Project
>
> ```xml theme={"dark"}
> <PropertyGroup>
>   <NoWarn>$(NoWarn);MCPESS004</NoWarn>
> </PropertyGroup>
> ```

> [!WARNING]
>
> Do not suppress MCPESS002 or MCPESS003. Those match runtime exceptions. A warning you understand (MCPESS001 on a DTO you do not own) is the usual candidate.

## What maps

The analyzer uses the same rules as [`FormElicitation.From<T>()`](https://si.easyaf.dev/mcpessentials/guides/form-elicitation). If Core would seed a field, MCPESS001 stays quiet.

> [accordion] Seeded
>
> `string`, `Guid`, `char`, `Uri`, `DateOnly`, `DateTime`, `DateTimeOffset`, `bool`, integer types, `float` / `double` / `decimal`, enums, `[Flags]` enums, and sequences of enums (`TEnum[]`, `List<TEnum>`, `IEnumerable<TEnum>`).

> [accordion] Skipped
>
> Nested objects, `Dictionary<,>`, `object`, `TimeSpan`, `byte[]`, `string[]`, `int[]`, indexers, write-only properties, static properties.

## Related

> [card] [Form elicitation](https://si.easyaf.dev/mcpessentials/guides/form-elicitation.md)
>
> Fluent schemas, ElicitAsync, and parking a form on a task.

> [card] [FormElicitation API](https://si.easyaf.dev/mcpessentials/api-reference/CloudNimble/McpEssentials/Core/Tasks/Elicitations/FormElicitation.md)
>
> `Create`, `From<T>`, and `Bind<T>`.

> [card] [Authenticated tasks](https://si.easyaf.dev/mcpessentials/guides/authenticated-tasks.md)
>
> Isolation, identity factory, and the samples.

> [card] [Stores](https://si.easyaf.dev/mcpessentials/guides/stores.md)
>
> Durable providers that persist the parked form.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.