Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

AIContextBuilder

NUGET · AICONTEXTBUILDER · SCANNED SEP 24

Symbol-aware C# and .NET code context for AI coding assistants.

Available components

69 Trust /100
Trust breakdown (7 categories)

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →

Supply Chain Security100
  • No malware found by supply-chain analysis.Pass
  • No known CVEs affecting this package version or its production dependencies.Pass
  • No install/post-install scripts declared.Pass
  • No production dependencies, so there is no dependency health to assess. View diagnostics → Pass
Provenance & Transparency35
Schema Quality & AI Usability76
  • 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
  • AI-judged instruction clarity (excellent).Pass
  • Context-footprint check failed: tool/resource definitions use about 30863 tokens (~523/item across 59 items; 54 tools + 5 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management3
  • Stability observed for 1 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage100
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 100% of tool parameters carry a description.Pass
Tool Safety100
  • No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
  • We read all 54 captured tool definition(s), and no name or description among them implies an irreversible operation.Pass
  • An AI judge read all 56 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
  • Implements a current MCP spec version (2026-07-28).Pass
Install

How do I install the AIContextBuilder MCP server?

AIContextBuilder runs locally as a NuGet package, launched with dnx AIContextBuilder@0.5.464.41 --yes. Ready-made configuration for Claude, Cursor, VS Code, Codex and 3 more is on this page, copied from each client's own documentation.

nuget · AIContextBuilder

# add to Claude Code
claude mcp add gregordadera-aicb -- dnx AIContextBuilder@0.5.464.41 --yes
// .cursor/mcp.json
{
  "mcpServers": {
    "gregordadera-aicb": {
      "command": "dnx",
      "args": [
        "AIContextBuilder@0.5.464.41",
        "--yes"
      ]
    }
  }
}
// .vscode/mcp.json
{
  "servers": {
    "gregordadera-aicb": {
      "command": "dnx",
      "args": [
        "AIContextBuilder@0.5.464.41",
        "--yes"
      ]
    }
  }
}
# add to Codex CLI
codex mcp add gregordadera-aicb -- dnx AIContextBuilder@0.5.464.41 --yes
// opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "gregordadera-aicb": {
      "type": "local",
      "command": [
        "dnx",
        "AIContextBuilder@0.5.464.41",
        "--yes"
      ],
      "enabled": true
    }
  }
}
# ~/.hermes/config.yaml
mcp_servers:
  gregordadera-aicb:
    command: "dnx"
    args: ["AIContextBuilder@0.5.464.41", "--yes"]
// ~/.netclaw/config/netclaw.json
{
  "McpServers": {
    "gregordadera-aicb": {
      "Transport": "stdio",
      "Command": "dnx",
      "Arguments": [
        "AIContextBuilder@0.5.464.41",
        "--yes"
      ]
    }
  }
}
// mcp.json
{
  "mcpServers": {
    "gregordadera-aicb": {
      "command": "dnx",
      "args": [
        "AIContextBuilder@0.5.464.41",
        "--yes"
      ]
    }
  }
}
Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 24 Sept 26 0
    • Tool safety: pass → unverified ▼ security
    • Malware scan: pass → unverified ▼ security
    • Stability: Stability not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet. security
    • Capabilities: pass → unverified ▼ functional
    • Tool coverage: 100 → unverified ▼ functional
    • Schema quality: 100 → unverified ▼ functional
    • Stability: unverified → 0.03 ▲ functional
    • Package version: 0.5.464.36 → 0.5.464.41 functional
    • Package version: 0.5.464.36 → 0.5.464.40 functional
  • 23 Sept 26 69

    First indexed and scored.

Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 24 Sept 2026 · Analysed nuget/AIContextBuilder@0.5.464.41

Provenance No attestation

The registry publishes no build provenance for this version, so there is nothing to verify.

Result No attestation
Ecosystem nuget
Reason Signature malformed

Background: How many MCP packages publish verified provenance →

Dependencies 0 packages
Packages resolved 0
Tree resolution Complete

Background: SBOMs and build attestations, explained →

MCP tools · 54 exposed · ~30,044 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →

Tool Tokens
analyze_solution ~401

Analyze a C#/.NET solution (.sln) with Roslyn and cache it for the session. Returns a session_id used by export_markdown, refresh_session and the insights tools.

NameTypeReqDescription
dbPathstring|null–Optional absolute path to a config/master DB. When given, the DB's active namespace-exclusion list is applied during analysis (same as the GUI/CLI); the DB's active test-detection profile (per-soluti…
layerProfilestring|null–Optional absolute path to a layer-mapping profile JSON. Omit to use the config DB's active layer profile (per-solution > app-global) when a config DB is resolved, else the .aicb.json sidecar's profil…
solutionPathstringyesAbsolute path to the .sln file to analyze.

No output schema declared.

No examples provided.

apply_solution_config ~588

Apply a proposed Layer Profile + Exclude-Namespaces + Test Profile configuration for a solution. Creates a new custom layer profile / exclusion list / test profile (tagged with the source solution for provenance), activates them, and marks each touched slot initialized. proposalJson is a JSON object {"layerRules":[{"pattern":".Application.","matchType":"Contains","layer":"Application"}],"exclusions":[{"pattern":"System.","matchType":"StartsWith"}]}; the test axis is given via testProposalJson {"testProjectRules":[{"pattern":".Tests","matchType":"EndsWith"}],"testAttributeNames":["Fact","Theory"]} (rules match PROJECT names) OR via testPreset = xunit|nunit|mstest|default. At least one axis must be non-empty (empty arrays/slots are skipped). matchType is Contains|StartsWith|EndsWith|Exact (an invalid matchType is rejected, not silently defaulted). Writes to the config/master DB (the given dbPath, or the server's default - the GUI's - if omitted; created if missing) AND to the git-tracked <SolutionName>.aicb.json sidecar next to the .sln (returned as sidecarPath - commit it so the config travels with the repo).

NameTypeReqDescription
dbPathstring|null–Absolute path to the aicb config/master SQLite DB to write the configuration into (created if missing). Omit to use the server's default config DB (the same one the GUI uses), if the server resolved…
exclusionListNamestring|null–Optional display name for the created exclusion list. Omit for an auto-generated name.
layerProfileNamestring|null–Optional display name for the created layer profile. Omit for an auto-generated name.
layeringPolicystring|null–Layer-mapping policy for the new profile: 'Advisory' (default) or 'Strict'.
proposalJsonstring|null–Optional layer/exclusion proposal as a JSON object with 'layerRules' and/or 'exclusions' arrays (see tool description). Omit for a test-only apply.
sessionIdstringyesThe session_id returned by analyze_solution.
testPresetstring|null–Optional shortcut: clone a built-in test profile (xunit|nunit|mstest|default) into a custom per-solution profile. Mutually exclusive with testProposalJson.
testProfileNamestring|null–Optional display name for the created test profile. Omit for an auto-generated name.
testProposalJsonstring|null–Optional test-axis proposal as a JSON object {"testProjectRules":[{"pattern":".Tests","matchType":"EndsWith"}],"testAttributeNames":["Fact","Theory"]}. testProjectRules match PROJECT names. Mutually…

No output schema declared.

No examples provided.

architecture_overview ~550

Orient on a whole solution WITHOUT the firewall of full source. Renders a structural-only AI-Builder-Markdown overview: the macro/architecture graphs (layer map, service & class dependency graphs, role graph, entry points + entry-point flow, architecture flow, interface relations) plus a domain summary and a quality-hotspots section (the most complex methods + most-coupled types) - but NO per-type/per-file source-code blocks, so it stays bounded where export_markdown is a 27-29 MB firehose. BOUNDED AT SCALE: each macro section is capped at 80 entries with a '+N more' truncation note, so even a 200+-project monolith returns a usable orientation instead of overflowing the token cap (use export_markdown for the full set, or find_symbol / call_graph / get_context to drill in). PRODUCTION-FOCUSED: test projects are excluded by default (an architecture overview is otherwise dominated by every test method listed as an entry point + its flow trace, which is not part of the production architecture) - set includeTests=true to include *.Tests/*.Spec projects. Method-level call graphs are deliberately omitted (use call_graph / explain_symbol for a specific symbol). Multi-TFM solutions are deduplicated to one logical project per name, keeping the NEWEST TFM's instance (Roslyn loads a <TargetFrameworks> project once per TFM - without the dedup every hotspot/edge appears xN). Recall-safe: works on live AND recalled sessions (on a recalled session quality-hotspot line counts are unavailable, complexity is still shown). Use this FIRST to understand a codebase's shape, then get_context / explain_symbol to drill into a symbol.

NameTypeReqDescription
includeTestsboolean–Include test projects (default FALSE - production focus: an architecture overview is otherwise flooded by every test method listed as an entry point + its flow trace, bloating the output with scaffol…
leanboolean–Lean mode (default TRUE): drop the <AI_CONTEXT_SPEC>/<AI_CONTEXT_META> format-rules preamble and any empty graph sections. Set false for the full AI-Builder-MD document contract.
sessionIdstringyesThe session_id returned by analyze_solution.
summaryOnlyboolean–Summary mode (default FALSE): collapse each macro-section to a count + top-N entries instead of up to 80. Use on EXTREME/very-large solutions (200+ projects, heavy generics) where even the bounded ov…

No output schema declared.

No examples provided.

assert_absence ~400

Check a NEGATIVE claim against the analyzed model and return confirmed / refuted / indeterminate with evidence. Supported: 'no_tests:<Symbol>' (the symbol has no detected covering test), 'absent:<Symbol>.<axis>' (the semantic axis is verified-absent - developer declared 'none', NOT merely unknown), and 'unknown:<Symbol>.<axis>' (the axis has no provenance entry at all). <Symbol> is a bare name or the qualified Type.Member form - the same strings find_usages / find_tests_for / impact_of_change resolve, so the pre-edit gate's tools accept one vocabulary; a name that resolves to nothing declared says so ('resolves to no declared type or member'), which is a statement about the name, not a claim the code lacks it. axis is e.g. role/layer/domain/context/responsibility; an axis name not recorded anywhere in the solution returns 'indeterminate' with the actual recorded axes as evidence (a typo'd/invented axis is NOT silently 'confirmed'). Conservative in BOTH directions: a claim the model cannot prove is 'indeterminate', never falsely confirmed - and 'refuted' for a no_tests claim requires at least one STRONG covering test (the test INVOKES the symbol - directly or through one method it calls -; the reason states the invokes/name-only split, matching find_tests_for's invokesTotal). Tests that merely carry the symbol in their NAME yield 'indeterminate' with that split disclosed, not a refutation - a test named after a symbol is not proof it exercises it. Use to validate 'this service is untested' or 'role is explicitly unset' before relying on it.

NameTypeReqDescription
claimstringyesThe negative claim: 'no_tests:<Symbol>', 'absent:<Symbol>.<axis>', or 'unknown:<Symbol>.<axis>'.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

batch ~730

Run several READ-ONLY query tools in ONE round-trip - instead of calling find_usages, get_type_hierarchy and find_tests_for (or list_insights then get_insight) as separate turns, batch them. Pass the shared session_id once (all sub-queries reuse the same analysis, so a self-init .sln path is analyzed only once), plus 'queries': an array of {tool, args} where 'tool' is a read-only tool name and 'args' is that tool's own arguments as a JSON object WITHOUT the sessionId. Example: queries=[{"tool":"find_usages","args":{"symbol":"OrderService"}},{"tool":"get_type_hierarchy","args":{"typeName":"OrderService"}},{"tool":"find_tests_for","args":{"symbol":"OrderService"}}]. Returns { results: [{tool, ok, result | error}], count, okCount }: each sub-query is isolated - a failing one reports ok:false + error while the rest still return ok:true (one bad query never fails the batch). Likewise a result too LARGE to fit inline (usually a markdown slice) is omitted with ok:false + a pointer to call that tool directly, so it never blows up the whole response - the others still return. A JSON-returning tool's result is nested as a JSON object (not an escaped string); a Markdown tool's (get_context/explain_symbol) result is the Markdown string. ONLY read-only query tools are dispatchable (find_usages/find_symbol/find_implementations/find_overrides/impact_of_change/get_type_hierarchy/get_context/explain_symbol/symbol_signature/pack_for_task/get_diagnostics/calls_external/symbol_metrics/coverage_gaps/assert_absence/find_by_semantics/find_by_side_effects/find_by_attribute/find_by_event_subscription/architecture_overview/detect_circular_dependencies/describe_api_surface/instantiation_sites/resolve_injection/find_dead_code/list_insights/get_insight/solution_metrics/…) - including the MARKUP fan-in queries (find_binding_usages/find_resource_usages/find_unresolved_bindings), which is the pairing worth knowing: they answer exactly where find_usages reports a structural zero. Tools that MUTATE…

NameTypeReqDescription
queriesarrayyesThe read-only sub-queries: an array of { tool, args } objects. 'tool' is a read-only tool name; 'args' is that tool's argument object (without sessionId), omittable when the tool needs no arguments.…
sessionIdstringyesThe session_id returned by analyze_solution (or an absolute .sln path to self-init once). Shared by ALL sub-queries - do NOT repeat it inside each query's args.

No output schema declared.

No examples provided.

call_graph ~238

Build a depth-limited call graph rooted at a method NAME. direction='callees' follows project-internal calls outward; direction='callers' follows the inverse (who calls this). Returns (caller, callee) edges using method-lookup keys, cycle-safe and capped at 500 edges (truncated flag). Rooted at the name, NOT at one symbol: EVERY same-named declaration in the solution is a root and the graph is their union, so a common name (e.g. 'ExecuteAsync') can pull in unrelated members and inflate the payload. 'rootedAt' lists the declarations actually walked - check it when the result looks too big (then re-query a rarer name) and when it is empty (the name resolved to nothing, which an empty edge list alone does not tell you).

NameTypeReqDescription
depthinteger–Max traversal depth (1-10). Default 2.
directionstring–'callees' (default) or 'callers'.
methodstringyesThe root method's name.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

calls_external ~754

Find which production methods CALL an EXTERNAL (non-solution: BCL / third-party) method whose fully-qualified key contains a pattern (substring, case-insensitive) - the 'who calls the external/risky API X?' query that find_usages (intra-solution only) cannot answer. Backed by two persisted facts (surfaced by no other tool): InvokedExternalMethods for CALLS - a key looks like 'System.IO.File.ReadAllText(string)' - and ReadExternalMembers for external PROPERTY READS, e.g. 'System.DateTime.UtcNow' (the 'global::' prefix is stripped before match + display). Audit value: AOT/trimming readiness, security surface, external dependency footprint (e.g. pattern='Process.Start', 'Assembly.Load', 'File.', 'System.Reflection', 'JsonSerializer', 'DateTime.UtcNow'). Each hit reports the two kinds APART - matchedCalls vs matchedReads - because an invocation executes while a read only observes ambient state, and an AOT / testability / security verdict differs per kind. The pattern is OPEN vocabulary, so an empty result is NOT a misspelling and there is no did-you-mean - and empty is now a strong statement, though not absolute: an external FIELD read ('string.Empty' and other value carriers, deliberately excluded as audit-irrelevant payload noise) and a bare 'new X()' are still not recorded. The scan set includes every property/indexer/event accessor and constructor with a body as a unit of its own (get_X / set_X / .ctor; a member initializer counts toward the constructor that runs it) - an expression-bodied getter `=> DateTime.UtcNow` is therefore a read site under its own name. Cross-check a surprising empty against the declaring type (pattern='DateTime' instead of 'DateTime.UtcNow') or the source. Required, meaningful - use a specific type/namespace; a very broad pattern (e.g. 'System') truncates at 200. Test-project methods are EXCLUDED by default (production focus) - set includeTests=true to include them. When that filter actually removed hits, the response carries 'testMatchesF…

NameTypeReqDescription
includeTestsboolean–Include test-project methods (default false - production focus; test setup/assertions calling external APIs would otherwise drown the signal).
patternstringyesA substring of the external (BCL/third-party) call key to match (case-insensitive), e.g. 'Process.Start', 'File.', 'Assembly.Load', 'System.Reflection', 'JsonSerializer'. Required - a very broad patt…
scopestring–'solution' (default) or a namespace prefix (e.g. 'MyApp.Infrastructure') to narrow scope.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

check_solution_config_drift ~371

Check whether a solution's active Layer Profile, Exclude-Namespaces and Test Profile still FIT the code - has the config drifted since it was set up? Three conservative signals: (1) layer 'unmapped' - declared (own) namespaces that no rule of the active layer profile maps; (2) exclusion 'uncovered' - EXTERNAL referenced namespaces (the solution's own namespaces are excluded from this check) that the active exclusion list does not cover; (3) test 'unmatched' - projects the canonical default heuristic classifies as test projects that the active custom test profile's rules do NOT match (it may be too narrow). ONLY a custom config is evaluated: a built-in preset (e.g. Clean Architecture / BCL default / the default test heuristic) or an empty/role-heuristic config is reported as not-evaluated (a deliberate generic choice, not stale). All three configs (layer/exclusion/test) are DB-active (if dbPath is given) else the .aicb.json sidecar next to the .sln. Each axis reports its source (db/sidecar/none). Requires a live session (call analyze_solution first). dbPath is optional - omit it to check only the .aicb.json sidecar config.

NameTypeReqDescription
dbPathstring|null–Optional absolute path to the aicb config/master DB. If given, the DB's per-solution active layer profile / exclusion list take precedence over the .aicb.json sidecar. Omit to fall back to the server…
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

compare_with_previous ~513

Diff the current session against a previously saved snapshot of the SAME solution - the newest by default, or the N-th previous via snapshotsBack (0=newest saved, 1=the one before, ...). Optionally narrow the diff to a single type and/or method. Returns added/removed types plus, per changed type, added/removed methods and signature changes. Requires a sessionId and at least one earlier save_session; dbPath is optional and defaults to the server's standard config DB when omitted. Name-based, syntactic (no method-body diff).

NameTypeReqDescription
dbPathstring|null–Optional absolute path to the aicb SQLite DB holding the saved snapshots. Omit to use the server's standard config DB.
methodNamestring|null–Optional: within that type, restrict to this method name (case-insensitive). Omit for all methods of the type. Same disclosure rule as typeName: if the type matched and this name matches none of its…
sessionIdstringyesThe current session_id (the 'after' side of the diff).
snapshotsBackinteger–0 = newest saved snapshot, 1 = the one before it, etc. (index into the per-solution history, newest first).
typeNamestring|null–Optional: restrict the diff to this type (simple name, case-insensitive). Omit for the whole-solution diff. A simple name ALSO matches the namespace-qualified form the diff renders for a type whose s…

No output schema declared.

No examples provided.

coverage_gaps ~513

Surface NEGATIVE knowledge for a scope: (a) methods that no test invokes DIRECTLY (Tier-1 call-graph coverage - a weak test-name match does NOT count as coverage here, it's too weak to prove it; abstract/interface method declarations are excluded - they have no body and are not coverable units) and (b) semantic axes that are 'verified-absent' (developer explicitly declared an axis as 'none'). Use this to find untested code and explicitly-blank semantics before claiming coverage. scope is 'solution' (default) or a namespace prefix (e.g. 'MyApp.Domain'). Both lists capped at 200. THE LIST IS ONE HOP, NOT A COVERAGE MEASUREMENT: a method a test reaches THROUGH another method (a CLI verb behind its command builder, a handler behind a dispatcher) is listed as uncovered although it is thoroughly exercised - measured on this server's own solution, that is 52.7 % of the solution-wide list and 97 % of one CLI-handler namespace. So READ THE PER-ENTRY 'testReachDepth': hops to the nearest directly-tested method (1 = one is calling it), ABSENT when no test reaches the method at all. Those absent ones are the real gaps - work them first. The entries are marked rather than filtered out, because a deep transitive path is not the same claim as a test, and silently hiding a genuinely untested method is the worse error for a negative-knowledge tool. A non-empty answer also leads with a 'note' carrying that count for THIS answer (and transitivelyReached beside it). Absence of a detected test is not proof of zero tests. THE POPULATION IS DISCLOSED: judgedUnits = the non-test, non-abstract methods the uncovered list is drawn from, out of symbolsScanned (every unit in scope, methods and types); testProjectsExcluded = the distinct test-classified projects (csproj marker or configured name rules) whose units were excluded; testFixtureTypesExcluded = the distinct types excluded via the attribute-inferred fixture axis (a type declaring a test-attributed method is a test fixture, so its attr…

NameTypeReqDescription
scopestring–'solution' (default) or a namespace prefix to narrow which symbols are checked.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

describe_api_surface ~507

List the PUBLIC API SURFACE of a solution or namespace - every externally-visible type with its externally-visible members (constructors, properties, fields, methods, user-defined operators), each as a compact declaration signature. The "header"/contract view: what a consumer of this assembly can actually reference, WITHOUT the source bodies (like a public-API digest, not a firehose). A type is included when its OWN declared accessibility is externally visible - public or the protected family (reachable by a subclass in another assembly); its members likewise. A property renders only the accessors that are themselves visible (a { get; private set; } shows as { get; }), a const carries its value, an enum is listed as a type (its values are not in the model). includeInternal=true additionally surfaces the internal family. PRODUCTION-FOCUSED: test projects are excluded by default (a shipped API surface is production code) - set includeTests=true to include *.Tests/*.Spec projects. scope='solution' (default) covers everything; a namespace prefix narrows it. The type list is capped (the true total travels in the envelope; narrow by namespace or filter to see the rest); members per type are whole. Recall-safe (reads persisted accessibility + signature facts) → works on live AND recalled sessions. Known v1 simplifications: accessibility is the type's OWN declared modifier (effective accessibility through the nesting chain is not computed - a public member of a type nested in an internal type is still listed); a type declared with NO access modifier is stored as private by the analyzer, so a modifier-omitted (compiler-internal) top-level type is not surfaced even with includeInternal. Use it to review a public contract before changing it, or as the baseline for a contract comparison - save_session then compare_with_previous, or diff_public_contract, which is outside the default profile's pool.

NameTypeReqDescription
includeInternalboolean–Include the internal family (internal / private-protected) types + members too (default FALSE = only the externally-visible public/protected surface).
includeTestsboolean–Include test projects (default FALSE - a shipped API surface is production code). Set true to include *.Tests/*.Spec projects.
scopestring–'solution' (default - the whole solution) or a namespace prefix (e.g. 'MyApp.Contracts') to narrow the surface.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

detect_circular_dependencies ~589

Detect circular NAMESPACE dependencies - groups of namespaces that depend on each other in a cycle (A -> B -> A, or a larger tangle), a modularity smell the C# compiler ALLOWS (unlike project-reference cycles, which it forbids). Each reported cycle is a strongly-connected component of >=2 namespaces, listing the participating namespaces plus example 'witness' type->type edges (one per directed namespace pair) that show WHY each link exists. Read those as EXAMPLES, not as a work list: edgeCount counts directed NAMESPACE pairs, and each witness carries typeEdgeCount - how many distinct type->type references cross that one boundary. Where typeEdgeCount is 1 the example IS the inventory; where it is higher, breaking the shown reference leaves the namespace edge standing and the next reference surfaces. Complements layer-violation analysis (the Clean/Onion inward-dependency rule) with the orthogonal 'who is mutually entangled' question. Namespace edges are derived from FULLY-QUALIFIED facts (member / field / parameter / return / typeof types + base class + implemented interfaces), so a same-named type in two namespaces is never conflated; external (BCL / NuGet) references are ignored (intra-solution cycles only). PRODUCTION-FOCUSED: test projects are excluded by default (a test->production reference is one-way, not an architecture cycle) - set includeTests=true to include *.Tests/*.Spec projects. scope='solution' (default) reports every cycle; a namespace prefix (e.g. 'MyApp.Infrastructure') narrows the REPORT to cycles touching that prefix (the analyzed graph stays the whole solution, so namespacesScanned is unchanged). Cycles that span assemblies are returned first, then largest-first within each kind (capped at 100; witness edges are capped per cycle, but each cycle's namespace list is complete). Each cycle also reports the distinct projects/assemblies its namespaces are declared in (projects) plus spansMultipleProjects: a cycle INSIDE one assembly is pure namespace…

NameTypeReqDescription
includeTestsboolean–Include test projects (default FALSE - production focus: a test->production reference is one-way and not an architecture cycle). Set true to include *.Tests/*.Spec projects.
scopestring–'solution' (default - all cycles) or a namespace prefix to report only cycles whose members include that prefix.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

docs ~341

The aicb operating manual - how to USE this server, as opposed to what it can tell you about your code. Call it with no arguments for the directory (each page with a one-line summary and a token estimate, so you can budget); pass one or more page ids to read them, or the route id 'init' for the whole first run in order. Pages: 'overview' (what aicb is and is not, the three ways to run it), 'install' (getting the dotnet tool, `aicb init`, and what it writes - the client's .mcp.json entry and the agent skill a tool install cannot deliver; for setting aicb up somewhere else, or finishing a half-done setup), 'first-context' (from a .sln to your first context - and why the full export is rarely the right call), 'navigation' (which tool answers which question about the code, the blast-radius call before editing shared code, and where plain text search is still right), 'solution-config' (layers / exclusions / test detection and the .aicb.json sidecar), 'glossary' (session, facet, MCP profile, snapshot, insight, AI-Builder MD). Start here if you have not used aicb before. No session and no solution needed.

NameTypeReqDescription
topicsarray|null–Optional page or route ids. Omit for the directory. A route id ('init') expands to its pages in reading order; repeats collapse, so asking for a route and one of its pages yields one copy. Unknown id…

No output schema declared.

No examples provided.

evaluate_change_set ~620

Advisory policy gate: which code-quality / design-smell / layer-violation findings would this edit INTRODUCE? Ask BEFORE writing it. Cheapest form - the edit you are about to make anyway: changes: [{filePath, oldText, newText}], the snippet being replaced and what it becomes (the shape an editor takes). The full file is rebuilt here from the analyzed document, so the payload is the size of the CHANGE, not of the file, and 'operation' defaults to 'modify'. oldText must occur EXACTLY ONCE - a missing or ambiguous anchor is an error, never a silently different edit; line endings are reconciled for you; an empty newText deletes the snippet. Full-text form still works and is required for add/delete: {filePath, operation: 'modify'|'add'|'delete', newContent}. Findings are a delta against the current session, so pre-existing debt is never blamed. The changeset is applied as an in-memory Roslyn overlay (NO disk write, the session is untouched) and the amended solution is re-analyzed. Verdict: pass / warn / block. Policy: 'block_on_critical' (default) | 'block_on_warning' | 'advisory' (an unknown policy is rejected, not silently treated as advisory). Advisory only - an MCP tool cannot block; the real blocking gate is the CLI '--fail-on'. The findings delta honors the session's explicit layer profile (analyze_solution(layerProfile) / sidecar) and its resolved test-detection profile on both sides; pass dbPath to also use that DB's active QualityProfile (producer thresholds + toggles) and its configured default layer profile (per-solution > app-global; the explicit session profile still wins) - same semantics as list_insights, so the gate judges by the same configured thresholds as the CLI gate. apply_change_set is out of scope. Pass absolute file paths matching the analyzed documents.

NameTypeReqDescription
changesarrayyesThe proposed file changes. Per change: filePath (absolute), plus EITHER the anchor patch oldText + newText (preferred - 'operation' may be omitted, it defaults to 'modify') OR the full new file text…
dbPathstring|null–Optional path to an AIContextBuilder SQLite DB. When set, producer thresholds + toggles come from that DB's active QualityProfile AND its configured default layer profile (per-solution > app-global)…
policystring|null–Policy: 'block_on_critical' (default) | 'block_on_warning' | 'advisory'.
sessionIdstringyesThe session_id returned by analyze_solution (the baseline).

No output schema declared.

No examples provided.

explain_symbol ~749

Explain a symbol: its source PLUS a chosen environment, as ONE dense AI-Builder-Markdown slice - the cold-read in a single call instead of 4-6 (get_context + find_usages + find_implementations + find_tests_for + ...). 'include' selects the environment axes (any combination): callers (the members that reference it, with their bodies, and their owner types as structure - not the calling types whole), callees (what it calls/depends on, depth 1), implementations (the types implementing it, if it's an interface), tests (its covering test cases), siblings (naming/file-convention kin), quality (complexity / efferent-coupling hotspot metrics). A partial type renders as ONE block (its declaration fragments are folded, a leading comment says which files) instead of one identical block per file. An empty include returns just the symbol's source - and then the manifest names the axes you could have asked for, so that answer is a stated choice rather than a silent default; an include token that names no axis is reported as dropped, whether or not a sibling token was valid. A leading manifest comment discloses what each merge axis actually found - so '(none)' is an honest negative (no impl / no caller / no test), not 'not asked'. Pass a type or method simple name (use find_symbol to disambiguate). Recall-safe (reads persisted facts); prefer it over export_markdown for one symbol's world. Multi-TFM solutions are deduplicated to one logical project per name (NEWEST TFM's instance, matching find_symbol's view).

NameTypeReqDescription
budgetinteger|null–Optional token budget (floored at 8000). Compacts/drops method bodies and, when the neighborhood overflows, drops the least-relevant types. The center symbol is always kept - with its full source whe…
includearray|null–Which environment axes to include (any combination, case-insensitive): callers, callees, implementations, tests, siblings, quality. Empty/omitted = just the symbol's source.
leanboolean–Lean slice (default TRUE): drop the <AI_CONTEXT_SPEC>/<AI_CONTEXT_META> format-rules preamble and omit enabled-but-empty graph sections. Set false for the full AI-Builder-MD document with the format…
sessionIdstringyesThe session_id returned by analyze_solution.
symbolstringyesThe type or method simple name to center on (use find_symbol to disambiguate), or the qualified Type.Member form to focus ONE declaration of a shared method name - the same string find_usages / find_…

No output schema declared.

No examples provided.

export_markdown ~468

Render the cached analysis of a session as AI-Builder Markdown. No re-analysis - instant. NOTE: this renders the WHOLE solution - on a large codebase the default render is a multi-MB firehose that can blow the response/token cap. For a bounded view prefer architecture_overview (whole-solution orientation, structural-only, no per-type source) or get_context / explain_symbol (one symbol's world). When the server was started profile-aware (aicb mcp --db-path), the active MCP profile drives the render: the chosen facet's template (detail presets, graphs, line numbers, quality metrics) is used; otherwise the full default render is used. Returns the Markdown; if outputPath is given it writes the file and returns a short confirmation (not the full content), so a large render does not flood the response.

NameTypeReqDescription
facetstring|null–Optional facet to render through - the task axis of this call: General (default), Exploration, Refactoring, Debugging, Review, Testing, Documentation, Architecture, or Performance. The facet picks th…
formatstring|null–Optional inner notation of the rendered Markdown: 'tag' (the established AI-Builder tag format) or 'yaml' (idiomatic YAML - a lossless re-notation, not a different selection of content). Pick whichev…
outputPathstring|null–Optional absolute path to write the Markdown to (UTF-8, no BOM). When given, the tool writes the file and returns a short confirmation (path + size) instead of the full markdown - so a large (whole-s…
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_binding_usages ~783

Binding-path fan-in across the solution's XAML/AXAML markup. The symbol graph records a {Binding} ROOT member against a resolved view-model at symbol granularity (low-confidence, tagged '(xaml)'); this tool adds the markup site list, resolution form, deeper-path split and the forms the fan-in layer skips. With a path: every binding site (file:line) plus what each one resolves AGAINST - dataContext (the view-model, the only form that is a VM member edge), elementName, relativeSource or source - so 'which bindings hang on an ancestor lookup rather than on the DataContext?' is one query. A path matches as the whole path OR as its ROOT segment ('Foo' finds {Binding Foo} and {Binding Foo.Bar}, both of which consume Foo; the 'Bar' in {Binding Foo.Bar} does NOT match - it is a member of Foo's type, and such sites are reported APART as deeperSegmentSites with their own count, because a rename of the same-named member on the nested type goes through exactly them). On an elementName/relativeSource redirect a leading 'DataContext.' is the hop to the element's view-model, not a member: {Binding DataContext.Cmd, RelativeSource={RelativeSource AncestorType=UserControl}} - the ItemTemplate idiom for a command on the page view-model - is a site of 'Cmd' (on a plain or a Source= binding the segment stays the root, because there the source is not an element by construction; a hop that sits MID-path, PlacementTarget.DataContext.Cmd in a ContextMenu, is not followed either - such a site roots at PlacementTarget). Without a path: the inventory - every distinct bound ROOT MEMBER (same grouping rule: {Binding Foo}, {Binding Foo.Bar} and the hop form are one entry) with its site + per-form counts, most-bound first. Case-sensitive. Reads the CURRENT .xaml/.axaml files on disk (bin/obj/.vs excluded, same discovery as the analyzer) - never stale after markup edits, no refresh_session needed, works on recalled sessions. pathlessBindingCount reports the bindings that name no member (an empty {…

NameTypeReqDescription
formstring|null–Optional form filter: 'dataContext', 'elementName', 'relativeSource' or 'source'. Omit for all forms. Applies to both views.
pathstring|null–The exact (case-sensitive) bound member path, e.g. 'GestureLabel' or 'Foo.Bar'. Omit for the inventory view (every bound path with its site counts).
scopestring–'solution' (default) or a view-path substring (e.g. 'AIContextBuilder.UI/Views/Dialogs') to narrow which markup files are reported.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_by_attribute ~401

Find symbols (types, methods, properties or fields) that carry a given ATTRIBUTE - a cross-cutting query that find_symbol (name-only) cannot do. The attribute name is matched format-independently: the last name segment, with an optional 'Attribute' suffix stripped, case-insensitive. So 'Obsolete', 'ObsoleteAttribute' and 'System.ObsoleteAttribute' all match the same symbols (types store the fully-qualified attribute class, methods/properties/fields store the source-syntax name - this reconciles both). The raw stored attribute list travels with each hit so you see the ground truth. kinds = 'all' (default - types + methods + properties + fields) / 'type' / 'method' / 'property' / 'field'. Member scanning surfaces a member-level attribute like a CommunityToolkit '[ObservableProperty]' (on a backing field or a modern partial property) or a '[JsonProperty]' that a type/method-only scan misses. Use it for '[Obsolete]', '[ApiController]', '[Authorize]', test attributes, etc. The 'method' axis includes constructors and accessors with a body (named .ctor / get_X / set_X), so a [JsonConstructor] or an [Obsolete] setter is found. Deterministic from Roslyn - works on recalled sessions. Capped at 200.

NameTypeReqDescription
attributestringyesThe attribute to find (e.g. 'Obsolete', 'ApiController', 'Fact'). Suffix/namespace are normalized away - required.
kindsstring–Which symbol kinds to search: 'all' (default - types + methods + properties + fields), 'type', 'method', 'property', or 'field'.
scopestring–'solution' (default) or a namespace prefix (e.g. 'MyApp.Api') to narrow scope.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_by_event_subscription ~788

Find the TYPES that SUBSCRIBE to a C# event - a `+=` whose left-hand side is an event - anywhere in the type (constructor, method, property accessor, lambda), a deterministic Roslyn fact no other tool surfaces. Event handlers are most often wired in a CONSTRUCTOR (the dominant UI pattern), which this whole-type walk captures. Conservative + no false positives: only a resolved event left-hand side counts, so a `+=` on an int / string / a delegate FIELD (delegate combination, not an event) is skipped; v1 captures subscriptions (`+=`) only. Pass eventName=<name> to filter to types subscribing to that event - matched by the event NAME ('Click') or the qualified 'DeclaringType.EventName' key ('Button.Click'), case-insensitive - or omit it to list every type with any subscription. Each hit carries the subscribed event keys. Test-project types are EXCLUDED by default (production focus) - set includeTests=true to include them. When that filter actually removed hits, the response carries 'testMatchesFiltered: N' - counted over the FILTERED-OUT units, a population the scan count above does NOT include, so the two share no denominator and N may legitimately exceed it; absent means nothing was hidden. Read that count FIRST when a named event comes back empty: a filtered zero arrives beside an availableEvents list that does not contain the queried name, which reads as 'wrong name' when the name was right and only its subscribers were tests. Deterministic from persisted Roslyn facts → works on recalled sessions. On ZERO matches the response lists the subscribed events actually present in scope (availableEvents) - so read an empty FILTERED result as 'no such event IN PRODUCTION', not 'no subscriptions' and not 'wrong name' - testMatchesFiltered settles which. An EMPTY availableEvents means no subscription was RECORDED in a scope that WAS scanned, which is NOT the same as none being present: recognition needs a RESOLVED left-hand side, so in a project whose types do not fully reso…

NameTypeReqDescription
eventNamestring|null–Filter to types subscribing to this event - the event name ('Click') or the qualified 'DeclaringType.EventName' key ('Button.Click'), case-insensitive. Omit to list every type with any subscription.
includeTestsboolean–Include test-project types (default false - production focus; test setup that wires events would drown the signal).
scopestring–'solution' (default) or a namespace prefix (e.g. 'MyApp.UI') to narrow scope.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_by_semantics ~743

Find symbols whose RESOLVED semantics match the given criteria (AND across all provided filters). role and layer are CLOSED vocabularies and match their value EXACTLY (case-insensitive, whole value): role='View' is one view, not every ViewModel. The values that merely CONTAIN the query are counted in nearMisses (value + how many symbols carry it) and named in a leading 'note' - never listed as matches - so the neighbours are visible without flooding the answer; query one of them by its exact value to list it. domain and responsibility are free text and match as a case-insensitive substring; the echoed criteria show the mode ('role=View' vs 'domain~order'). Query any of: layer, role, domain, responsibility (responsibility is type-only - methods have no such axis). Each hit carries, per matched axis, the value AND its provenance ('fact'/'ai'/'inferred'), so you can tell a fact-backed match from a heuristic guess. By default ALL sources match (including 'inferred'); set minConfidence='asserted' to keep only fact/ai matches (exclude guesses). At least one filter is required. Capped at 200. Known vocabularies - layer: Domain / Application / Infrastructure / Presentation / Contracts; inferred TYPE role (closed set): Service, Helper, Model, Record, Interface, Enum, Builder, ViewModel, Converter, Controller, Middleware, Attribute, Exception, EntryPoint, ContractModel, Type (there is NO 'Repository' role - repositories classify as 'Service'); methods carry a method-category role (e.g. Query, Command, Mapping, Validation, Orchestration). domain and responsibility are free text. <ai>-asserted values can differ from these inferred defaults and keep their own spelling ('viewmodel', 'viewmodel-item' next to the inferred 'ViewModel' - each is its own value; the case-insensitive match folds 'viewmodel' into 'ViewModel', the hyphenated refinements stay apart and show up as near misses). On ZERO matches the response returns the axis values actually present in THIS solution (availabl…

NameTypeReqDescription
domainstring|null–Match symbols whose resolved Domain contains this (free text - derived from naming/namespace). Omit to not filter on domain.
layerstring|null–Match symbols whose resolved Layer EQUALS this (whole value, case-insensitive). Clean-Architecture layers: Domain / Application / Infrastructure / Presentation / Contracts. Omit to not filter on laye…
minConfidencestring–Confidence floor: 'any' (default - include inferred guesses) or 'asserted' (only fact/ai). Any other value is rejected (not silently treated as 'any').
responsibilitystring|null–Match TYPES whose resolved Responsibility contains this (types only; free text). Omit to not filter.
rolestring|null–Match symbols whose resolved Role EQUALS this (whole value, case-insensitive). Inferred TYPE roles (closed set): Service, Helper, Model, Record, Interface, Enum, Builder, ViewModel, Converter, Contro…
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_by_side_effects ~763

Find methods by their observable SIDE-EFFECT profile - what they touch in the outside world. Each effect token is one of: io, network, database, serialization, logging, cache, messaging, unknown ('unknown' = an unanalyzable external call). That vocabulary is CLOSED: an 'effect' outside it is REJECTED with an error naming the token you sent and the eight valid ones - never answered with a silent zero. A known token with zero hits carries a 'note' quoting what the token means ('cache' = calls into an external cache API, not a cache a type holds in memory). Effects include transitively propagated ones (a method that calls a project method which hits the DB counts as 'database'). Pass effect=<token> to filter to one effect, and/or purity='pure' (no detected side effects - a good refactor/test-isolation signal) / 'impure' / 'any'. With NO effect and NO purity, only IMPURE methods are listed (a bare 'all methods' dump has no value). Use it to answer 'what hits the DB/network?' or 'is X pure?'. The scan set is every method PLUS every property/indexer/event accessor and constructor with a body, each a unit of its own named by its metadata name (get_X / set_X / .ctor / .cctor; a field or property initializer counts toward the constructor the compiler runs it in) - so a getter touching the filesystem or a constructor opening a connection is listed under its own name; the purity='pure' listing stays methods-only, because a bodied getter is pure by default and would drown it. Test-project methods are EXCLUDED by default (production focus) - set includeTests=true to include them. When that filter actually removed hits, the response carries 'testMatchesFiltered: N' - counted over the FILTERED-OUT units, a population the scan count above does NOT include, so the two share no denominator and N may legitimately exceed it; absent means nothing was hidden. Deterministic from Roslyn - works on recalled sessions. On ZERO matches the response lists the effect tokens actually present in…

NameTypeReqDescription
effectstring|null–Filter to methods carrying this effect token - exactly one of: io, network, database, serialization, logging, cache, messaging, unknown (case-insensitive; any other value is rejected, not answered wi…
includeTestsboolean–Include test-project methods (default false - production focus: a 'what hits the DB?' query is otherwise drowned by Seed*/Migrate_*/*RepositoryTests). Set true to also list methods in *.Tests/*.Spec…
puritystring–'any' (default), 'pure' (only side-effect-free methods), or 'impure' (only methods with at least one effect).
scopestring–'solution' (default) or a namespace prefix (e.g. 'MyApp.Infrastructure') to narrow scope.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_dead_code ~775

Find dead-code suspects as a queryable list (the list_insights producers only give Top-20 aggregates). kinds='method' (default): PRIVATE methods with zero detected callers (UsedBy.Count==0) - limited to private because public/internal have framework escapes (reflection / DI / event handlers / source-generated callers) the call graph can't see; UsedBy unknown is skipped, not guessed. kinds='type': types with no incoming reference in the reliable reverse type fan-in (the same source find_usages and the design-unused-type insight use), minus the structurally-fan-in-invisible forms (interfaces, static + *Extensions classes, framework/DI/reflection-activated, WPF-XAML, MVC controllers). kinds='all': both. Recall-safe (UsedBy / Dependencies are persisted). scope = 'solution' (default) or a namespace prefix. Test-project methods/types are EXCLUDED by default (production dead-code) - set includeTests=true to include them; candidates that filter removed are reported per axis as 'testMethodsFiltered' / 'testTypesFiltered' (omitted when it hid nothing, and likewise for an axis that never ran - methodsScanned/typesScanned tell those two apart), so a zero that is the filter's does not read like a zero that is the code's. Each axis capped at 200. An answer that LISTS candidates leads with a 'note' naming what the zero each candidate rests on does not prove, and how to confirm one before deleting it. An EMPTY answer is qualified too, but only when it was structurally guaranteed: the scanned units the predicate could never judge are reported as methodsIneligible/typesIneligible (omitted when zero); methodsIneligible is split into methodsIneligibleNotPrivate (the deliberate policy - public/internal have framework escapes) and methodsIneligibleUnanalyzedCallers (PRIVATE methods with no analyzed caller list - the blind spot this axis exists to find); typesIneligible is split the same way into typesIneligibleStructural / typesIneligibleTestScaffolding / typesIneligibleFrameworkActivat…

NameTypeReqDescription
includeTestsboolean–Include test-project methods/types (default false - production dead-code; a private test-helper without callers is not production dead code).
kindsstring–'method' (default) private methods with no caller · 'type' types with no incoming reference · 'all' both.
scopestring–'solution' (default) or a namespace prefix (e.g. 'MyApp.Core') to narrow scope.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_implementations ~612

List the types that implement an interface. Unions the interface's ImplementedByTypes with any type whose implemented-interface list contains the name (robust to a missing back-edge). Pass the interface's simple name, e.g. 'ICodeAnalyzer'. Each item carries name + isAbstract + kind (class/struct/record/interface) + isTestProject - so an abstract base (e.g. 'FooBase : IFoo') or a test fake is distinguishable from a concrete production implementer (without it, an agent cannot tell them apart from the bare name). Test-project implementers are EXCLUDED by default (production focus: test fakes/stubs would otherwise drown the real implementers) - set includeTests=true to include them; when that filter actually removed something the response carries 'testImplementationsFiltered: N', so a short list is never silently short (absent = nothing was hidden). The name may be arity-qualified ('IConsumer`1' or 'IConsumer<T>', e.g. copied from a find_symbol signature) - the suffix FILTERS: it selects the implementers of the generic interface of that arity ('IConsumer`0' the non-generic's), while a bare name keeps the merged view of every arity. A generic implementer additionally carries 'declaration' (its arity-qualified form, 'PolicyWrap<TResult>') so a generic/non-generic pair sharing name+namespace stays distinguishable; an item whose only evidence is the interface's back-edge membership (not a declared implemented-interfaces edge) carries via:'back-edge'. Cross-namespace namesakes are membership-checked by full name when the facts carry one (a same-named type from a foreign namespace is no longer listed as an implementer); a candidate without a stored full name keeps the recall-safe name match. Returns a capped envelope (items/count/totalFound/truncated), max 100. If the result is empty because the name is a class (not an interface), the response carries a 'hint' pointing to get_type_hierarchy / find_overrides - and if the name is not DECLARED in the solution at all, the hint s…

NameTypeReqDescription
includeTestsboolean–Include test-project implementers (default false - production focus).
interfaceNamestringyesThe interface's simple name, e.g. 'ICodeAnalyzer'. An arity suffix ('IConsumer`1' / 'IConsumer<T>', or 'IConsumer`0' for the non-generic namesake) filters to that arity; a bare name keeps the merged…
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_overrides ~370

List the override-to-base relationships for methods of a given name - the class-inheritance counterpart to find_implementations (which covers interfaces). Each entry pairs an overriding method with the nearest ancestor (base-class chain) that declares the virtual/abstract method it overrides: 'Derived.M(params) overrides Base'. Container and base render in their DECLARATION FORM ('Strategy<T>.M(...) overrides ResilienceStrategy<TResult>' - the type parameters AS DECLARED, the same render get_type_hierarchy uses, NOT a normalized arity like 'Foo`1'), so a generic and a non-generic namesake no longer collapse into one row; non-generic entries are unchanged. Two same-named types that differ ONLY by namespace (or that declare identical type-parameter names) still render identically and collapse into a single row - the list carries no namespace, so treat a row as the relationship, not as one attributed type. Answers BOTH 'who overrides this virtual/abstract method?' (impact) and 'what does this override?' (comprehension) in one call. When the overridden base is a BCL/framework virtual not in the solution (e.g. object.ToString / Stream.Dispose), the entry reads '... overrides (external base)'. Pass the method's exact (case-sensitive) simple name, e.g. 'ToString'. Recall-safe (reads persisted facts: IsVirtual/IsOverride/IsAbstract + base chain). Returns a capped envelope (items/count/totalFound/truncated), max 100; empty means no overrides of that name were found.

NameTypeReqDescription
methodNamestringyesThe method's exact (case-sensitive) simple name, e.g. 'ToString' or 'Dispose'.
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_resource_usages ~554

Resource-key fan-in across the solution's XAML/AXAML markup AND its C# sources - the question the C# symbol graph cannot answer because resources are wired by string key, not by symbol. With a key: where it is DEFINED (x:Key, file:line), every REFERENCE (file:line + kind - 'static'/'dynamic' for the markup extension, since a theme-swapped brush must be dynamic, and 'code' for a C# string literal equal to the key), and same-file duplicate definitions (in a compiled resource dictionary a duplicate silently shadows a neighboring key; a same-named key in DIFFERENT files is usually a legitimate theme pair, so only same-file counts as a collision). Without a key: the audit view - every never-referenced key (deletion candidates; deleting a still-referenced key compiles clean and throws only at runtime) + all same-file collisions. Reads the CURRENT .xaml/.axaml/.cs files on disk (bin/obj/.vs excluded, same discovery as the analyzer) - never stale after an edit, no refresh_session needed, works on recalled sessions. STRING keys only (a structural x:Key="{x:Type ...}" and the {StaticResource ResourceKey=...} long form are out of scope); XML-commented markup is ignored. Fan-in comes from TWO channels: the solution's markup ({StaticResource}/{DynamicResource}) and C# string literals equal to the key - the TryFindResource channel, reported as kind 'code' with its file:line because a matching literal is not by itself proof of a resource lookup (it may be a test assertion, or a doc-comment cref naming a same-named converter type). Still invisible: a key ASSEMBLED at runtime (interpolated or concatenated), a source file that is not .cs, and a third-party library template resolving the key from ITS OWN dll (e.g. a theme library's DynamicResource re-key) - zero references means 'verify before deleting', not proof. Lists capped at 200.

NameTypeReqDescription
keystring|null–The exact (case-sensitive) resource key, e.g. 'TextPrimaryBrush'. Omit for the audit view (never-referenced keys + same-file collisions).
scopestring–'solution' (default) or a view-path substring (e.g. 'AIContextBuilder.UI/') to narrow which files are reported. In the audit view the scope narrows the DEFINITIONS under audit; references still count…
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_symbol ~453

Find types, methods, properties, fields, events, enum members and operators whose name contains the query (case-insensitive). Returns each match with kind ('type'/'method'/'property'/'field'/'event'/'enum_member'/'operator'), name, declaring type, namespace and a signature. Use this to locate a symbol before calling find_usages / call_graph / get_context - every kind listed here except 'operator' is one find_usages / impact_of_change resolve (an operator is located by its metadata name but carries no fan-in: 'a == b' is no invocation the call index records). Types are listed first, then methods, then properties (handwritten + source-generated - a generated property carries a '// source-generated' note in its signature), then fields, events and enum members (an enum member's signature is its qualified Enum.Member form, the string the fan-in tools take), then user-defined operators + conversions. A user-defined operator is found by its METADATA name (query 'op_Equality' / 'op_Addition' / 'op_Implicit'; 'op_' lists them all). Not indexed, so an empty answer is expected for them: local variables, parameters, labels, namespaces. Results are ranked by match quality FIRST - exact name, then case-insensitive exact, then prefix, then substring - and only within one rank by the kind order above; an exact match is therefore never hidden by the cap behind weaker substring hits (a symbol named 'Type' used to sit at position 1026 of 1102). Returns a capped envelope (items/count/totalFound/truncated), max 100 - if truncated, the exact/prefix matches are the ones you got; narrow the query (a longer substring) to see the weaker rest. If the query matches nothing, the response carries a 'nearest' suggestion - the closest declared symbol name (a likely typo/case-mismatch); a matched symbol never carries one.

NameTypeReqDescription
querystringyesA substring of the symbol name to search for (type, method, property, field, event, enum member or operator).
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_tests_for ~568

Find the test CASES that likely cover a symbol (Tier-1 heuristic). Only a method that itself carries a test attribute (Fact/Theory/Test/TestMethod/TestCase) counts - an actual runnable test, NOT a fixture-builder/helper that merely lives in a test project. A match is reported when the test invokes the target (strong, via call graph - exactly TWO hops: the test itself and one method it calls, its own helper or a production entry point; a deeper chain (helper → helper) or a table-driven sweep is not counted) or its own name / its test class's name mentions the symbol at an identifier-segment boundary (weak - see matchReason; a mid-word substring is not a mention). Pass a type name, or a member name either bare or in the qualified Type.Member form - the same rule find_usages and impact_of_change resolve, so the pre-edit gate's tools all accept the same strings. The qualified form narrows the STRONG tier to the member declared on that type; the weak tier is a name guess and probes the member segment. A 'note' names the three cases where the bare numbers mislead: a qualified query whose TYPE segment names no declared type (matching is case-sensitive, so the strong tier silently collected nothing and every hit is weak name noise); a query that names NOTHING declared at all (same, one level up - a full page of hits then describes the spelling, not this solution's coverage); and an EMPTY answer on a symbol that DOES resolve, where the note names the two-hop limit and the declaring type's own count, because a bare 0 otherwise reads as 'nothing pins this' - the answer the pre-edit gate acts on. matchReason names THREE tiers, ordered by how direct the evidence is: 'invokes' (the test calls the target itself), 'invokes-via' (it reaches the target through one method it calls - still strong, but second-hand) and 'name' (the weak guess). 'invokesTotal' counts BOTH strong tiers, so it means exactly what it did before the tiers were named apart - a split the per-item matchReason ca…

NameTypeReqDescription
sessionIdstringyesThe session_id returned by analyze_solution.
symbolstringyesThe type name, or the member name - bare or in the qualified Type.Member form - to find covering tests for.

No output schema declared.

No examples provided.

find_unresolved_bindings ~599

List silently broken XAML bindings: a {Binding X} whose root member does NOT exist on its confidently resolved DataContext view-model (typo, removed/renamed member, or wrong DataContext) - the defect class that NEITHER the compiler NOR render-smoke tests catch. Covers WPF/WinUI .xaml (VM resolved via d:DesignInstance or a unique FooView->FooViewModel convention) AND Avalonia .axaml ({Binding}/{CompiledBinding}, VM resolved ONLY via x:DataType at scope level; no naming convention). Conservative BY SKIPPING, and the skip is what carries the accuracy claim: a binding whose DataContext scope cannot be typed with certainty (ControlTemplate/Style, runtime DataContext, keyed resources, a DataType-less template - WPF alone recovers an item template's type from the host's pinned ItemsSource; on Avalonia an x:DataType-less template, TreeDataTemplate included, is always skipped) is never flagged - a recall miss, never a false report - and only view-models resolved with certainty and with a verifiable member surface (in-solution base chain or a known MVVM base) are checked; source-generated ([ObservableProperty]/[RelayCommand]) and inherited members count as resolved. The residual exposure is scope TYPING, not member lookup: a markup shape the walk types WRONGLY (confident and wrong, instead of unknown and skipped) produces false reports - the one measured class, a HierarchicalDataTemplate's own ItemsSource mis-pinned onto its content, read 8/8 false on MahApps.Metro and is fixed + fixture-pinned (0 after). So read a hit as high-confidence evidence to verify at its file:LINE, not as proof - each report carries the attribute's 1-based line, and identical reports from multi-TFM analysis instances are deduplicated (one entry per site, not one per TFM). Every answer carries the POPULATION the zero would otherwise hide: markupFilesScanned and bindingSitesInMarkup, both from a live disk walk of the session's project directories - so '0 broken among 1021 sites in 164 markup files' an…

NameTypeReqDescription
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

find_usages ~772

List who uses a symbol (fan-in). For a type name → the types that reference it; for a method name → the methods that call it (union across overloads); for a PROPERTY or FIELD name → the methods that read or write it (resolvedKind 'property'/'field' - a CommunityToolkit [ObservableProperty] BACKING FIELD additionally lists the consumers of its generated property: the two are one symbol pair to a caller, a rename/delete of the field renames/deletes the property with it); for an EVENT → the methods that raise, subscribe to or unsubscribe from it ('event'; the subscriber TYPES are also on find_by_event_subscription, the raiser only here); for an ENUM MEMBER → the methods that reference it - a switch label, a comparison, an assignment ('enum_member'; bare 'Partial' or qualified 'BackupStatus.Partial'). Members accept a bare name (union across all same-named members of any type) or the qualified Type.Member form to disambiguate. Returns the resolved kind and the caller/user list - capped at 100 (response reports usedBy.totalFound + usedBy.truncated). resolvedKind 'not_found' means the name did not resolve to any declared type/method/property/field/event/enum member; a real kind with an EMPTY usedBy means the symbol exists but has no detected intra-solution fan-in - it may be an entry point or reached only via a markup attribute's MEMBER half / DI registration / reflection / a source generator (which static analysis does not see), so empty is 'verify elsewhere', not proof of dead code. That empty answer carries a 'note' ahead of the list naming the escapes and the cross-check to run. Separately, if the analysis run could not resolve every project's references, that 'note' leads ANY answer of this family - empty or not - naming the unresolved projects: such a run is short by ORDINARY references, so even a plausible-looking list is unreliable until you rebuild and refresh_session. On 'not_found' the response carries a 'nearest' suggestion (the closest declared name); when a…

NameTypeReqDescription
sessionIdstringyesThe session_id returned by analyze_solution.
symbolstringyesThe exact (case-sensitive) type, method, property, field, event or enum-member name - the qualified Type.Member form for a member - or 'Type.Type' for a type's CONSTRUCTOR (see the tool description:…

No output schema declared.

No examples provided.

get_context ~586

Return a dense, token-budgeted AI-Builder-Markdown slice of the code around a symbol: the symbol's source plus its expanded neighborhood (direct dependencies + callees, depth 1). Pass a type or method simple name (use find_symbol first to disambiguate). budget caps the output in tokens (floored at 8000); omit for full bodies. The fastest single-symbol retrieval - prefer it over export_markdown (which renders the WHOLE solution) when you only need one symbol's context. Multi-TFM solutions are deduplicated to one logical project per name, keeping the NEWEST TFM's instance (matching find_symbol's view; export_markdown keeps the unfiltered per-TFM render). Need a CHOSEN environment of one symbol (callers / tests / implementations / quality)? use explain_symbol. Bundling a whole task from a natural-language goal? use pack_for_task (read) or prepare_task (edit-ready: + covering tests & siblings).

NameTypeReqDescription
budgetinteger|null–Optional token budget (floored at 8000). Caps the slice TWO ways: it compacts/drops method bodies AND - when the expanded neighborhood still overflows - drops the least-relevant non-seed types entire…
includeQualityMetricsboolean–When true, also emit the <QUALITY_HOTSPOTS> section plus complexity=""/ce="" tag attributes for the sliced symbols (cyclomatic complexity, efferent coupling). Default false (leaner slice). Set true w…
leanboolean–Lean slice (default TRUE): drop the repeated <AI_CONTEXT_SPEC> format-rules preamble and the <AI_CONTEXT_META> block, and omit any enabled-but-empty graph section (the ones that would otherwise rende…
sessionIdstringyesThe session_id returned by analyze_solution.
symbolstringyesThe type or method simple name to center the slice on.

No output schema declared.

No examples provided.

get_diagnostics ~1,179

A FAST PRE-BUILD GATE: after editing .cs, call refresh_session and THEN this, for the compiler errors/warnings in seconds instead of a full 'dotnet build'. THAT ORDER IS NOT COSMETIC: the diagnostics are compiled from the SESSION's document snapshot, not from the files on disk, so under auto-refresh mode 'off' they describe the pre-edit source - measured on a throw-away solution, a freshly written CS0029 answers errorCount:0, and the same call after refresh_session answers 1. Under the shipped 'reactive' mode this tool is refreshed for you before it answers, so the explicit call is redundant rather than wrong - and calling it is the only spelling that is correct in EVERY mode. An answer computed from a graph KNOWN to be behind the disk leads with verdict:'stale' + verdictReason before any count, so reading the pre-edit state deliberately stays possible - it just cannot be mistaken for a clean bill. Surfaces the COMPILER diagnostics (errors / warnings / info) of the session's solution - the real Roslyn build output, the way the C# compiler sees it. Reads each project's Compilation.GetDiagnostics() and returns them filtered by a minimum severity, with per-severity counts, each diagnostic's id (e.g. CS0219), message, file:line location, category and project. Suppressed diagnostics (#pragma / [SuppressMessage]) are excluded; a multi-targeted project that compiles the same source under several TFMs reports each diagnostic once (deduped by id + location + message), not once per TFM. NOTE: compiler diagnostics only - third-party Roslyn ANALYZER diagnostics (which need the project's analyzer references loaded and run) are out of scope. A project whose compilation cannot resolve its core references (System.Object missing - a targeting pack not installed for that TFM, or an unrestored project; common when a foreign solution targets a .NET version this machine lacks) would otherwise flood with thousands of bogus cascade errors (CS0518/CS0234/CS0246) - such projects are NOT li…

NameTypeReqDescription
scopestring–'solution' (default) or a file-path substring (e.g. 'MyApp.Core' or 'Services/') that filters the RESULT. It does not reduce the work: all projects are compiled either way (see the tool description)…
sessionIdstringyesThe session_id returned by analyze_solution.
severityFloorstring–Minimum severity to include: 'error', 'warning' (default), 'info', or 'hidden'.

No output schema declared.

No examples provided.

get_insight ~483

Get the full detail of one insight (incl. the per-item Details list) by its id. Discover ids via list_insights (the producers that found issues). Ids are producer-level. An unknown/typo'd id is rejected with the known producer ids; a registered producer that found nothing this session reports that explicitly (distinct from a typo - list_insights lists only producers WITH findings, so a 0-finding id is not discoverable there). Details default to the top 20 items (a '(... and N more)' marker discloses the rest); pass maxDetails to raise that cap for a full per-item drill-down. Pass dbPath to use the active QualityProfile from that DB (same semantics as list_insights, incl. the explicit-layerProfile precedence). Triage-filtered like list_insights, on BOTH axes: detail lines removed by a suppression ('by design', DB + sidecar) or by a dismissal ('seen', solution record) are gone, and 'suppressedDetailCount' reports the two ADDED TOGETHER (absent = none) - so it is not a count of sidecar entries. A producer silenced outright reports as 'registered but 0 hits'.

NameTypeReqDescription
dbPathstring|null–Optional path to an AIContextBuilder SQLite DB. When set, producer thresholds + toggles come from that DB's active QualityProfile AND the configured default layer profile (DefaultLayerProfileName / p…
insightIdstringyesThe producer-level insight id, e.g. 'quality-long-methods' (discover via list_insights; an unknown id is rejected WITH the known ids).
maxDetailsinteger|null–Optional cap on the returned Details list (default 20). Raise it (e.g. 200) for a full per-item drill-down of this insight; a '(... and N more)' marker still discloses any remainder beyond the value.…
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

get_type_hierarchy ~598

Walk a type's inheritance hierarchy in both directions: the base-class chain upward (nearest base first; when the chain leaves the solution the last entry NAMES the external base, e.g. 'ObservableObject (external)') and the transitively derived types downward (each entry reads 'Derived : DirectBase', so the subtree structure is preserved in the flat list). Also lists the type's implemented interfaces (for an interface query these are its base interfaces). The type-level counterpart to find_overrides (method level); for 'who implements this interface' use find_implementations (interfaces never appear as a base class, so an interface's derivedTypes is empty). Every link is rendered arity-qualified ('Foo<T>' vs 'Foo') so a same-name generic + non-generic type are distinguishable. Pass the type's exact (case-sensitive) simple name; add an arity suffix - 'Foo<T>' (or the metadata form 'Foo`1') - to address a generic type unambiguously when a generic and a non-generic share the name (a bare name keeps the merged view of both). The simple-name index merges NAMESAKES - same simple name, different declared type (a foreign namespace, or a different declaring type for a nested one) - and when the answered view merged such types, 'mergedNamesakes' names them ahead of the lists they may taint (absent = one declared type, nothing merged); an arity suffix separates arities only, namesakes cannot be separated. The opposite case has its own field: derivedTypes lists a type only when its DECLARED base really is the resolved type, so a derivation from a same-named type that is NOT the one you got - typically a framework base shadowed by an in-solution namesake - is excluded and counted in 'separatedNamesakes', which names the resolved type and the foreign bases (absent = nothing was excluded). Without it an empty derivedTypes on a name the solution plainly uses as a base would read as 'nothing derives from this'. Recall-safe (reads persisted facts: base type + full name + interfaces;…

NameTypeReqDescription
sessionIdstringyesThe session_id returned by analyze_solution.
typeNamestringyesThe type's exact (case-sensitive) simple name, e.g. 'GraphSectionRendererBase'. Add an arity suffix ('Repository<T>' or 'Repository`1') to disambiguate a generic from a same-named non-generic type.

No output schema declared.

No examples provided.

impact_of_change ~690

Estimate the blast radius of changing a symbol: the direct and transitive fan-in (who depends on it, directly or via chains). For a type → reverse type fan-in closure (computed from forward dependencies); for a method → UsedBy caller closure; for a PROPERTY or FIELD → the methods that read or write it (resolvedKind 'property'/'field' - a CommunityToolkit [ObservableProperty] BACKING FIELD additionally reports the consumers of its generated property: the two are one symbol pair to a caller, a rename/delete of the field renames/deletes the property with it); for an EVENT → the methods that raise, subscribe to or unsubscribe from it ('event'); for an ENUM MEMBER → the methods that reference it ('enum_member') - a member has no transitive member chain, so transitiveCount == directCount. Every MEMBER - method, property, field, event and enum member alike - accepts a bare name (union across all same-named members) or the qualified Type.Member form; a TYPE takes its simple name only. Returns direct/transitive counts and a risk level (none/low/medium/high). The risk level is calibrated on the PRODUCTION fan-in only - test-project callers/implementers are excluded, because exercising a symbol from tests is its designed fan-in and updating those tests after the change is mechanical, not risk (a method with 50 test callers and 1 production caller is low-risk to change). productionImpactCount discloses the (non-test) transitive count the risk is based on (≤ transitiveCount). Call this before refactoring a symbol to gauge how much you might break. directImpact is a capped envelope (items/count/totalFound/truncated, max 20); directCount/transitiveCount are the true totals (incl. tests, matching find_usages). A resolved symbol with directCount 0 EXISTS but has no detected fan-in - it may be reached only via XAML / DI / reflection / a source generator that static analysis does not see, so it is not proof the symbol is safe to delete; THAT answer carries a 'note' AHEAD of the count…

NameTypeReqDescription
sessionIdstringyesThe session_id returned by analyze_solution.
symbolstringyesThe exact (case-sensitive) type, method, property, field, event or enum-member name to assess - or the qualified Type.Member form for a member.

No output schema declared.

No examples provided.

init_solution_config ~150

Start the guided Layer Profile + Exclude-Namespaces + Test Profile setup for a solution. Returns the solution's declared (own) namespaces - the source for layer-mapping rules - and its referenced (external/framework) namespaces - the source for exclusion rules; plus the test-axis material: the projects the default heuristic classifies as test projects and the test-attribute markers actually present in the code. Walks the warm session workspace (no re-analysis). Propose a mapping from this material, then call apply_solution_config with it. Requires a live session (call analyze_solution first; a recalled-from-memory session has no live workspace).

NameTypeReqDescription
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

install_agent_hooks ~229

Install the aicb symbol guard into this project for an agent harness, so a C#-symbol question is REFUSED on a text search and redirected to the tool that answers it. Writes the guard script plus the harness's wiring entry (.claude/settings.json, .codex/hooks.json or opencode.json) and nothing else - no .mcp.json, no skills, and only inside the directory of the session's own solution. Omit 'harness' to install for the harness that is calling. An existing guard or wiring is kept unless force=true. Restart or reconnect the client afterwards, then call refresh_session so the session stops reporting the guard as missing.

NameTypeReqDescription
forceboolean–Overwrite an existing guard script and rewrite an existing wiring entry.
harnessstring|null–Which harness to install for: claude-code, codex or opencode. Omit to use the harness the calling MCP client belongs to.
sessionIdstringyesSession id, or the absolute .sln/.slnx/.slnf path (self-init).

No output schema declared.

No examples provided.

instantiation_sites ~573

Find who INSTANTIATES a type - the construction + dependency-injection sites of type X, the narrow 'who creates/obtains an instance of X?' answer that find_usages (every reference: field, parameter, generic arg, ...) cannot give. Two edge kinds: 'created' - a method, constructor or accessor that does `new X(...)` (incl. target-typed `new`, `record with`, collection/stackalloc allocation; a field or property initializer `= new X()` is attributed to the constructor the compiler runs it in, the implicit one when none is declared, so such a site is named '.ctor' - and with several non-chaining constructors one initializer line yields one site per constructor, as the compiler runs it in each); 'injected' - a type that receives X as a constructor-injected dependency (the DI container news X and hands it over). Each site carries its member (created: the method + its declaring type; injected: the consuming type, declaringType null) and its kind; the response reports the two true edge counts (createdByCount / injectedIntoCount). The type name is matched on its simple name (namespace + generic args normalized away). Like find_usages this is a discovery/impact tool - test-project sites ARE included (a test that `new`s X breaks when X's ctor changes). Deterministic from persisted Roslyn facts (CreatedTypes / InjectionDependencies) → works on recalled sessions. scope = 'solution' (default) or a namespace prefix. Capped at 200. Both counts zero yields a 'note' ahead of them naming the construction paths this fact cannot see. A CONCRETE type registered in a DI container reports injectedIntoCount 0 correctly - its consumers take the INTERFACE, so the injection edges sit on that name instead; whenever the injected count is zero and the type implements interfaces, the 'note' names them and tells you which query carries the answer, because the honest zero is the one most likely to be misread as 'nothing depends on this'. A typeName matching NO declaration is the OTHER zero and is rep…

NameTypeReqDescription
scopestring–'solution' (default) or a namespace prefix (e.g. 'MyApp.Core') to narrow which sites are scanned.
sessionIdstringyesThe session_id returned by analyze_solution.
typeNamestringyesThe type whose instantiation/injection sites to find (simple name; namespace + generic args are normalized away, e.g. 'OrderService' or 'List').

No output schema declared.

No examples provided.

list_insights ~439

List code-quality / async / design-smell insights for a session (long methods, fat interfaces, unused types, missing async suffixes, many-parameter methods, ...). Runs against the live analyzed solution; each insight is aggregated per producer with a Details list. Pass dbPath to use the active QualityProfile (producer thresholds + toggles) from that DB; omit it for the default profile (DB-free). Honors the session's active test-detection profile (resolved by analyze_solution(dbPath)) for the production-focused producers. An explicit analyze_solution(layerProfile) drives the layer-violation insight and wins over the DB-configured profile (same precedence as solution_metrics and the CLI gate). THIS ANSWER IS TRIAGE-FILTERED, on BOTH triage axes: findings the solution marked intentional (a suppression - in the DB or in the git-tracked <Solution>.aicb.json sidecar) AND findings a user dismissed as seen (in the solution record, NOT in the sidecar) are removed, and an insight whose findings are all gone does not appear at all. Every insight that lost lines carries 'suppressed' with the count of what BOTH axes removed together (absent = nothing filtered), so a shrinking number is never mistaken for a codebase that improved - but do not read that count as a sidecar entry count, because some of it is dismissal. Note 'title' is producer text computed BEFORE filtering, so on a partially filtered insight it still names the pre-filter total - 'detailsCount' + 'suppressed' are the real split.

NameTypeReqDescription
dbPathstring|null–Optional path to an AIContextBuilder SQLite DB. When set, producer thresholds + toggles come from that DB's active QualityProfile AND the configured default layer profile (DefaultLayerProfileName / p…
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

list_mcp_profiles ~195

List the MCP profiles in the server's config DB - each with its id, name, the slots that have a template assigned (General appears exactly when a profile-wide template is set), the profile-wide templateId (null = none), whether it carries a skill, its effective tool-set (toolSelection: the class-level CSV, or a 'methods:'-prefixed function-name list when the profile curates individual tool functions; null = lean core), whether it is the active one, AND the render config it applies (tokenBudget / outputFormat / overflowPolicy - a null tokenBudget/overflowPolicy means inherit: the template then the active PipelineProfile decides). Requires the server to be started with --db-path. Use the ids with 'aicb mcp --mcp-profile <id>' to pin the profile at server start - that is the only way to change it; there is no runtime switch tool.

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

list_skills ~323

The server's capability map: a tools INDEX naming EVERY tool this server has - each exactly once, grouped into three lists by pool state (inPool.core = the tools every profile exposes, in reach-for-them order; inPool.extras = the rest of the active pool, alphabetical; outOfPool = exists but the active tool set does not expose it) - plus the sections that group them by name: the always-on navigation CORE (listed in no menu because it needs none), the task FACETS (id + guidance + template slot + the facet's tool menu), the cross-cutting guidance styles, and the legacy functional skill bundles. Use it to discover specialized long-tail tools (e.g. get_insight, find_by_concurrency_risk, coverage_gaps, find_unresolved_bindings) beyond that core - and to check whether ANY tool you want is merely in outOfPool rather than nonexistent. Tools outside the active pool become reachable via an MCP profile whose facet menu or bundle names them (see list_mcp_profiles / 'aicb mcp --mcp-profile <id>'), or via the AICB_MCP_TOOLS override. By default the answer omits the per-tool descriptions, which is what makes it cheap; pass detail="full" when you need them. No session needed.

NameTypeReqDescription
detailstring|null–How much per-tool text to include: "lean" (default) - bare names in their pool groups; "full" - additionally each tool's one-line description. Case-insensitive.

No output schema declared.

No examples provided.

measure ~485

Report how BIG a read-only query's answer would be - its exact token count - WITHOUT returning the answer. Use it to decide before you pull: whether a call is worth making, what 'budget' to pass a slice tool (get_context/explain_symbol/pack_for_task), or whether to narrow 'scope' first. Same shape as batch: pass the shared session_id once plus 'queries', an array of {tool, args} where 'args' is that tool's own arguments WITHOUT the sessionId. Example: queries=[{"tool":"explain_symbol","args":{"symbol":"OrderService","include":["callees"]}}] → {tool, ok, tokens, chars, returned, totalFound, truncated, budgetNote}. 'tokens' is the real tokenizer count (cl100k_base) of the exact text the tool would return; 'returned/totalFound/truncated' are passed through when the tool answers with a capped envelope, so you also see whether you would be seeing everything. The Markdown slice tools (get_context / explain_symbol / pack_for_task) have no such envelope - they disclose budget pruning in prose, so 'budgetNote' carries that disclosure verbatim: if it says types were dropped, the answer you are pricing is already CUT (an axis you asked for can be missing entirely), and a larger 'budget' is what buys it back. IMPORTANT: measure does NOT make the query cheaper to RUN - the server does the full work either way; it makes the answer cheap to INSPECT (you pay ~50 tokens instead of the answer). So measure to DECIDE, then call once - do not measure every call by reflex. Dispatches the same read-only tools as batch, and refuses the same ones for the same four reasons - mutation is only the first of them; the refusal message names which one applies. Like batch, sub-queries follow the ACTIVE POOL: an out-of-pool tool is refused per item. Max 16 queries per call.

NameTypeReqDescription
queriesarrayyesThe read-only queries to measure: an array of { tool, args } objects, exactly as for batch. Max 16.
sessionIdstringyesThe session_id returned by analyze_solution (or an absolute .sln path to self-init once). Shared by ALL queries - do NOT repeat it inside each query's args.

No output schema declared.

No examples provided.

pack_for_task ~555

Goal-driven context packing: given a natural-language task, seed on every symbol the goal names (type or method), expand the neighborhood, and return a token-budgeted AI-Builder-Markdown bundle - with goal-aware trimming that keeps the most task-relevant methods when the budget is tight. Name the symbols you care about in the goal (e.g. 'refactor OrderService.Cancel and Validate'). budget caps output tokens (floored at 8000). Multi-TFM solutions are deduplicated to one logical project per name (NEWEST TFM's instance, matching find_symbol's view). For an EDIT-ready bundle that also pulls in the covering tests + naming/file siblings (and, on a profile-aware server, renders through the facet's template), use prepare_task instead.

NameTypeReqDescription
budgetinteger|null–Optional token budget (floored at 8000). Caps the slice TWO ways: it compacts/drops method bodies AND - when the expanded neighborhood still overflows - drops the least-relevant non-seed types entire…
facetstring|null–Optional facet - the task axis of this call: General, Exploration, Refactoring, Debugging, Review, Testing, Documentation, Architecture, or Performance. pack_for_task always renders the lean bundle (…
goalstringyesThe task description (name the relevant types/methods in it).
includeQualityMetricsboolean–When true, also emit the <QUALITY_HOTSPOTS> section plus complexity=""/ce="" tag attributes (cyclomatic complexity, efferent coupling) for the packed symbols. Default false. Set true when the task is…
leanboolean–Lean slice (default TRUE): drop the repeated <AI_CONTEXT_SPEC>/<AI_CONTEXT_META> preamble and omit enabled-but-empty graph sections ('- none'). Keeps PATH_LEGEND / COMPRESSION_LEGEND and all non-empt…
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

prepare_task ~658

Prepare a task-ready context bundle for a goal: seed on the symbols the goal names, expand the neighborhood, AND add the test methods that cover those symbols plus 1-2 naming/file-convention siblings (the test, the factory, the validator you'd otherwise miss). Leads with a one-line manifest (seeds / tests / siblings / render) so you can see what was covered - and what was NOT ((none)). Prefer this over pack_for_task when you're about to EDIT, not just read. Multi-TFM solutions are deduplicated to one logical project per name (NEWEST TFM's instance, matching find_symbol's view). When the server is profile-aware (aicb mcp --db-path), the chosen facet's template shapes the render (graphs, detail, line numbers, quality); otherwise a lean default render is used.

NameTypeReqDescription
budgetinteger|null–Optional token budget (floored at 8000). Applies to BOTH the lean and the profile-aware template render path: it compacts/drops method bodies AND drops the least-relevant types when the neighborhood…
facetstring|null–Optional facet to work under - the task axis of this call: General (default), Exploration, Refactoring, Debugging, Review, Testing, Documentation, Architecture, or Performance. On a profile-aware ser…
goalstringyesThe task description - name the relevant types/methods in it (e.g. 'refactor OrderService.Cancel and its validation').
includeQualityMetricsboolean–When true, also emit the <QUALITY_HOTSPOTS> section plus complexity=""/ce="" tag attributes for the bundled symbols (lean path). Default false. Set true for a refactor/quality pass.
includeSiblingsboolean–Include 1-2 naming/file-convention siblings of the seeded types (default true).
includeTestsboolean–Include the test methods that cover the seeded symbols (default true).
leanboolean–Lean slice (default TRUE): on the lean-render path, drop the repeated <AI_CONTEXT_SPEC>/<AI_CONTEXT_META> preamble and omit enabled-but-empty graph sections ('- none'); keeps PATH_LEGEND / COMPRESSIO…
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

refresh_session ~342

Re-analyze the session's solution after YOUR code edits - call it once you have changed .cs files, otherwise find_usages / impact_of_change / list_insights / get_context may keep answering from the STALE pre-edit graph (a silent source of wrong results). Cheap to call speculatively: a W0 file-set-hash check skips the expensive Roslyn re-run when nothing actually changed, and a C# file whose timestamp moved while its text stayed the snapshot's (a save without an edit) does not count as a change either. That check reads SOURCE files, so it cannot see a restore or build - after one of those, an analysis that reported unresolved references retries once by itself, and 'force' is the deterministic way to demand it. Reuses the warm workspace. Returns { changed, reason, session, mode } - 'mode' names the path the re-analysis took ('incremental' = document texts replayed into the warm snapshot without an MSBuild reload, else 'full-reload') and is absent when nothing was re-analyzed. The incremental path can stop engaging without any visible symptom - answers stay correct, calls just get slow again - so 'mode' is how you notice.

NameTypeReqDescription
forceboolean–Re-analyze even when no source file has changed. Use it after a restore/build that was meant to repair unresolved references - those live in build output the file-set hash does not cover, so an ordin…
sessionIdstringyesThe session_id returned by analyze_solution.

No output schema declared.

No examples provided.

resolve_injection ~1,250

Resolve a Microsoft.Extensions.DependencyInjection registration: given an interface (e.g. 'ICodeAnalyzer'), return the concrete implementation(s) registered for it, the lifetime (Singleton/Scoped/Transient) and where - 'location' (the Add* call, file:line), 'project' and 'declaringMethod' (Type.Method; null for top-level statements). Scans Add{Singleton,Scoped,Transient}, their TryAdd* variants and project-local wrappers ending in a lifetime (AddCachedSingleton) in generic, typeof, instance and factory-lambda form - plus ONE data-driven shape: a foreach over a static table of 'new(typeof(Service), typeof(Impl))' rows is expanded into one registration per row (note 'table row File.cs:line'), also when the table lives in another project. NOT expanded, and disclosed instead: a call whose service type is a runtime value (reflection/assembly scans, method results, a deconstructed loop variable), and a factory lambda whose product cannot be named - the response then leads with a 'note' naming those sites and which of the two kinds each is, so an empty list WITH a note means 'not statically visible', never 'not registered'. The three empty answers are distinguishable: a name that resolves to NOTHING (no declaration, no registration) carries resolvedKind:'not_found' and a 'nearest' suggestion (a typo); a REAL name with no registration, on an unfiltered query, carries a 'note' that states the reader's boundary - no Microsoft.Extensions.DependencyInjection (Add*/TryAdd*) registration was found, which is NOT proof that nothing registers it (Autofac, Castle Windsor and other non-Microsoft containers, and keyed, open-generic and Scrutor registrations, stay out of scope) - and when any scanned project REFERENCES a foreign container assembly (Autofac etc.), that note names the sign instead, because its registrations are invisible here. Registrations in TEST projects are EXCLUDED by default - a test's own container stub is not the production binding - set includeTests=true to incl…

NameTypeReqDescription
includeTestsboolean–Include registrations declared in test projects (default false - production focus).
interfacestringyesThe interface simple or fully-qualified name, e.g. 'ICodeAnalyzer'.
sessionIdstringyesThe session_id returned by analyze_solution.
sitestring|null–Optional: narrow to registrations whose file path contains this substring.

No output schema declared.

No examples provided.

review_context ~239

Assemble review context for a set of changed symbols: for each, its fan-in usages, the transitive change-impact + a risk level, the types that implement it (if an interface), and the test methods that likely cover it. Pass the type/method names you touched (e.g. the symbols in a diff). Use this before reviewing or refactoring to see blast radius + test coverage at a glance. 'coveringTests' is find_tests_for's list under find_tests_for's contract: strong 'invokes' matches ordered ahead of weak name guesses, with 'invokesTotal' naming how many of them are strong - so ranking by position is meaningful and you can see where the evidence stops. Unlike find_tests_for it applies NO cap, so a symbol with a hundred covering tests contributes a hundred rows; budget the symbol list accordingly. The response is ordered by symbol NAME, not by the order you passed them - index it by 'symbol', never by request position.

NameTypeReqDescription
sessionIdstringyesThe session_id returned by analyze_solution.
symbolsarrayyesThe changed type/method names to assemble review context for.

No output schema declared.

No examples provided.

save_session ~182

Persist the current session's analyzed model as a named Manual snapshot in an aicb DB, so a later session can diff against it (see compare_with_previous). Returns the snapshot_id. Requires a live (or recalled) sessionId from analyze_solution/recall_codebase and a human-readable name; dbPath is optional and defaults to the server's standard config DB (the same one the GUI uses) when omitted. Note: snapshots lose line numbers (StartLine/EndLine) on the DB round-trip.

NameTypeReqDescription
dbPathstring|null–Optional absolute path to the aicb SQLite DB to persist into. Omit to use the server's standard config DB.
namestringyesHuman-readable name for this snapshot (e.g. 'before refactor').
sessionIdstringyesThe session_id whose current state to snapshot.

No output schema declared.

No examples provided.

server_info ~398

Returns the aicb MCP server name, version and BUILD COMMIT - a reachability smoke-check + the config DB's schema version. The commit answers the question the version number cannot: 'is the binary I am talking to built from the code I just landed?'. Compare it against `git rev-parse HEAD` (the reported sha is the full one, so a short hash is a prefix of it). This matters because a version number can be identical across DIFFERENT builds - a parallel branch that packs the same number first wins, and `dotnet tool update` then skips the newer package as 'already installed'; the commit is the only field that shows it. Also flags two kinds of drift so a stale server reports its own backlog: (1) CONFIG DRIFT - the active MCP profile changed (a GUI edit in the 'MCP Profiles' panel, or another process writing the config DB) since this server started → restart/reconnect to load the current skill pool (tools + instructions); (2) VERSION DRIFT - this binary lags the config DB: the DB schema is newer than this binary's migrations, or the active profile's pool lists tools this binary does not register → rebuild/reinstall the standalone tool. That drift check is tool-NAME level (a new parameter on an existing tool is not detected) - the build commit is the finer-grained signal. A build with no resolvable git revision omits the commit rather than guessing. (3) ANALYZER DRIFT - the axis the other two cannot see: this binary's build commit against the HEAD of the repo holding the analyzed solution, so a fact producer that got smarter since this build shows up even though the tool names and the source files are unchanged. Reports in-sync and ahead too, not only drift. Silent without an analyzed session, and on a repo that does not know this commit (i.e. any foreign solution).

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

Common questions

What is the AIContextBuilder MCP server?

AIContextBuilder is an MCP server listed in the public MCP registry as io.github.gregordadera/aicb. Symbol-aware C# and .NET code context for AI coding assistants. This page covers its NuGet package (AIContextBuilder).

Is the AIContextBuilder MCP server safe to use?

AIContextBuilder scores 69 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 24 September 2026. It declares no install or post-install scripts. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

What tools does the AIContextBuilder MCP server expose?

AIContextBuilder exposes 54 tools: coverage_gaps, impact_of_change, install_agent_hooks, docs, apply_solution_config, and 49 more. Their descriptions and schemas cost roughly 30,044 tokens of context every time the server is loaded.

Is the AIContextBuilder MCP server still maintained?

AIContextBuilder is still listed as active in the MCP registry. We last reached this channel on 24 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.