# Decompile and inspect .NET assemblies from the command line — and from an AI assistant

> Source: <https://dev.to/zero_heartbeat_06a3625d7a/decompile-and-inspect-net-assemblies-from-the-command-line-and-from-an-ai-assistant-3h08>
> Published: 2026-11-12 05:42:22+00:00

Glass.NET is a free .NET decompiler built around *navigation* — you open an assembly and read it like your own source. But plenty of the work you do with a decompiler isn't interactive at all. You want to gate a CI job on whether a dependency changed its public surface, emit a software bill of materials for every binary you ship, or check that the NuGet package you just pulled is really what it claims to be. And increasingly you want your AI coding assistant to answer "what does this dependency actually do?" without you hand-feeding it decompiled snippets.

Glass.NET 1.3.0 covers both. It adds a **headless CLI** — the same ICSharpCode.Decompiler engine as the UI, no window required — and `glass mcp`, a **Model Context Protocol server** that lets an AI assistant open assemblies and read decompiled C# on your behalf. Everything below is strictly **static analysis**: Glass reads metadata and IL and reconstructs C#. It never runs the assembly it inspects. And all of it is **free** — no tiers, no license, no seats.

Four commands do the batch and scripting work, plus the server:

`glass export` — reconstruct a buildable C# project, or dump a single member.`glass sbom` — emit a software bill of materials for an assembly or package.`glass verify` — check a NuGet package's authenticity and strong-name identity.`glass diff` — compare two builds and report what changed in the public surface.`glass mcp` — start the MCP server for an AI assistant.
Run `glass --help` for the full list; every command takes `--json` so you can pipe output into `jq` or a build step.

Point `export` at an assembly and a directory and you get a reconstructed, compilable project back:

``` bash
$ glass export ./Acme.Payments.dll -o ./out/Acme.Payments
Decompiling Acme.Payments.dll (net8.0) …
  142 types, 1,206 members
Wrote ./out/Acme.Payments/Acme.Payments.csproj
Wrote 142 source files
Done in 1.9s — static analysis only, assembly was not executed.
```

That `.csproj` targets the assembly's own TFM and lists its references, so `dotnet build ./out/Acme.Payments` just works — useful when you need to diff against source, patch-and-recompile, or hand a reproducible tree to someone.

When you only care about one method, skip the whole project and ask for the member by its documentation-comment ID:

``` bash
$ glass export ./Acme.Payments.dll --member "M:Acme.Payments.Gateway.Charge(System.Decimal)"
public ChargeResult Charge(decimal amount)
{
    if (amount <= 0m)
        throw new ArgumentOutOfRangeException(nameof(amount));
    var req = new ChargeRequest(amount, _clock.UtcNow);
    return _transport.Send(req);
}
```

You can pass a type ID (`T:Acme.Payments.Gateway`) to dump every member of a type, or `--il` to get the IL view instead of C#. This is the fast path for "show me exactly what this one method does" without opening a UI.

`glass sbom` reads an assembly's metadata and produces a dependency inventory in CycloneDX JSON — the assembly's identity, its target framework, and every `AssemblyRef` it binds against, with versions and public-key tokens:

``` bash
$ glass sbom ./Acme.Payments.dll --format cyclonedx -o payments.sbom.json
$ jq '.components[] | {name, version}' payments.sbom.json
{ "name": "Newtonsoft.Json", "version": "13.0.3" }
{ "name": "System.Text.Json", "version": "8.0.0" }
{ "name": "Acme.Core", "version": "4.2.1" }
```

Because it works from the compiled binary rather than a `packages.lock.json`, it tells you what the shipped artifact *actually* references — including transitive assemblies that a project-file audit can miss. Point it at a `.nupkg` and Glass enumerates the assemblies inside each `lib/<tfm>` folder and merges their references into one document.

Before you trust a package, `glass verify` checks two things statically: the NuGet signature on the `.nupkg`, and the strong-name identity of the assemblies inside it.

``` bash
$ glass verify ./Acme.Payments.4.2.1.nupkg
Package     Acme.Payments 4.2.1
Signature   author-signed, counter-signed (timestamp 2026-10-30)  ✓
Assemblies
  Acme.Payments.dll   strong-named  pkt=b77a5c561934e089   ✓
  Acme.Core.dll       NOT strong-named                     ⚠
Verdict     signature valid; 1 assembly unsigned — review before trusting.
```

It reports whether the package is author- or repository-signed, whether the signature is intact, and which assemblies carry a strong name and which don't. It does **not** vouch for intent — a validly signed package can still do something you dislike — which is why `verify` pairs naturally with `export` to actually read the code. And, as with every command, verification reads bytes; it never runs the package.

Hand `diff` two versions of the same assembly and it reports the delta in the public API surface:

``` bash
$ glass diff ./Acme.Payments-4.2.0.dll ./Acme.Payments-4.2.1.dll
+ public ChargeResult Gateway.Charge(decimal, Idempotency)   added overload
- internal void Gateway.ResetCounters()                       removed
~ public sealed class ChargeResult                            field layout changed
3 changes (1 added, 1 removed, 1 modified)
```

With `--json` this becomes a gate: fail the build when a dependency bump quietly changes a signature you depend on, or flag an internal-to-public promotion in review.

Say a new transitive dependency, `Contoso.Telemetry`, showed up in a lockfile and you want to know what it does before it ships. The whole audit is static — nothing here executes the package:

``` bash
# 1. Download the package without installing it into a project.
$ nuget install Contoso.Telemetry -Version 2.1.0 -OutputDirectory ./pkgs -DependencyVersion Ignore

# 2. Is it signed, and are its assemblies strong-named?
$ glass verify ./pkgs/Contoso.Telemetry.2.1.0/Contoso.Telemetry.2.1.0.nupkg
Signature   author-signed  ✓
Assemblies  Contoso.Telemetry.dll  strong-named  ✓

# 3. What does it reference? (Watch for networking / reflection you didn't expect.)
$ glass sbom ./pkgs/Contoso.Telemetry.2.1.0/lib/net8.0/Contoso.Telemetry.dll --json \
    | jq -r '.components[].name'
System.Net.Http
System.Text.Json

# 4. It binds System.Net.Http — read the code that uses it.
$ glass export ./pkgs/Contoso.Telemetry.2.1.0/lib/net8.0/Contoso.Telemetry.dll \
    --member "M:Contoso.Telemetry.Beacon.Flush"
```

Four commands, no window, nothing executed — and you've gone from "an unknown dependency appeared" to reading the exact method that touches the network.

The flow that ties it together:

The same static inspection is available to an AI coding assistant through the [Model Context Protocol](https://modelcontextprotocol.io). `glass mcp` starts a JSON-RPC server over stdio that exposes a small set of read-only tools:

| Tool | What it does | 
|---|---|
| `glass_open` | Open an assembly or `.nupkg` and return its identity + TFM | 
| `glass_list_types` | Enumerate namespaces, types and members | 
| `glass_decompile` | Return reconstructed C# for a type or member ID | 
| `glass_find_references` | List callers of a member, across the open assembly | 
| `glass_sbom` | Return the dependency inventory as structured JSON | 

Register it with any MCP-capable assistant by pointing `command` at `glass`:

```
{
  "mcpServers": {
    "glass": { "command": "glass", "args": ["mcp"] }
  }
}
```

Now, instead of you decompiling a method and pasting it into chat, the assistant does it itself. A `tools/call` for `glass_decompile` looks like this on the wire:

```
{ "jsonrpc": "2.0", "id": 7, "method": "tools/call",
  "params": { "name": "glass_decompile",
    "arguments": { "member": "M:Contoso.Telemetry.Beacon.Flush" } } }
```

and the server answers with the reconstructed C# as text content:

```
{ "jsonrpc": "2.0", "id": 7,
  "result": { "content": [ { "type": "text",
    "text": "private async Task Flush(CancellationToken ct)\n{\n    using var http = new HttpClient();\n    await http.PostAsync(_endpoint, Serialize(_buffer), ct);\n}" } ] } }
```

So you can ask your assistant, in plain language, *"open Contoso.Telemetry 2.1.0 and tell me what `Beacon.Flush` sends and where"* — and it opens the assembly, reads the decompiled method, and tells you it POSTs a serialized buffer to a configured endpoint. The assistant is reading **static** output: `glass mcp` decompiles, it does not execute, so even an assistant acting on your behalf can inspect an untrusted package without running it.

Glass.NET 1.3.0 turns decompilation from something you do by hand in a window into something you can **script** and **delegate**. Use `glass export` for a buildable tree or a single method, `glass sbom` for a bill of materials, `glass verify` to check a package's signature and strong names, and `glass diff` to gate on public-surface changes in CI. When you'd rather ask a question than run a command, `glass mcp` gives your AI assistant the same read-only, static view. Every one of these reads the binary and reconstructs C# — none of them ever run it — and all of it is free. Grab the latest build from the [Glass.NET download page](https://delta1labs.com/products/glass) and point it at the next dependency you're unsure about.
