docs: add Starlight docs site for mcilspy.warehack.ing

Follows the warehack.ing cookie-cutter pattern (Caddy + multi-stage Docker).
34 content pages covering Getting Started, 7 Guides, 16 Tool Reference pages,
MCP Prompts, Data Models, Changelog, and Development docs. Steel blue + amber
theme with Pagefind search and Mermaid diagram support.
This commit is contained in:
Ryan Malloy 2026-03-02 18:18:43 -07:00
parent ff365b0c44
commit 643576111c
48 changed files with 13297 additions and 0 deletions

6
docs-site/.dockerignore Normal file
View File

@ -0,0 +1,6 @@
node_modules
dist
.astro
.env
*.log
.git

2
docs-site/.env.example Normal file
View File

@ -0,0 +1,2 @@
COMPOSE_PROJECT_NAME=mcilspy-docs
DOMAIN=mcilspy.l.warehack.ing

49
docs-site/Dockerfile Normal file
View File

@ -0,0 +1,49 @@
FROM node:22-slim AS base
ENV ASTRO_TELEMETRY_DISABLED=1
WORKDIR /app
# Install dependencies
FROM base AS deps
COPY package.json package-lock.json* ./
RUN npm ci
# Build static site
FROM deps AS build
COPY . .
RUN npm run build
# Production: serve from Caddy
FROM caddy:2-alpine AS prod
COPY --from=build /app/dist /srv
COPY <<'CADDYFILE' /etc/caddy/Caddyfile
:80 {
root * /srv
file_server
encode gzip
@hashed path /_astro/*
header @hashed Cache-Control "public, max-age=31536000, immutable"
@unhashed not path /_astro/*
header @unhashed Cache-Control "public, max-age=3600"
handle_errors {
@404 expression {err.status_code} == 404
handle @404 {
rewrite * /404.html
file_server
}
}
try_files {path} {path}/ /index.html
}
CADDYFILE
EXPOSE 80
# Development: Node with HMR
FROM deps AS dev
ENV ASTRO_TELEMETRY_DISABLED=1
COPY . .
EXPOSE 4321
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]

11
docs-site/Makefile Normal file
View File

@ -0,0 +1,11 @@
prod:
docker compose up -d --build
dev:
docker compose --profile dev up --build
down:
docker compose down
logs:
docker compose logs -f

182
docs-site/astro.config.mjs Normal file
View File

@ -0,0 +1,182 @@
import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
import mermaid from "astro-mermaid";
import tailwindcss from "@tailwindcss/vite";
import sitemap from "@astrojs/sitemap";
export default defineConfig({
site: "https://mcilspy.warehack.ing",
telemetry: false,
devToolbar: { enabled: false },
integrations: [
mermaid({ autoTheme: true }),
starlight({
title: "mcilspy",
description:
"Decompile, search, and analyze .NET assemblies with AI assistance via the Model Context Protocol",
favicon: "/favicon.svg",
social: [
{
icon: "seti:git",
label: "Source",
href: "https://git.supported.systems/MCP/mcilspy",
},
],
customCss: ["./src/styles/global.css", "./src/styles/tool-pages.css"],
sidebar: [
{
label: "Getting Started",
items: [
{ label: "Overview", slug: "getting-started/overview" },
{ label: "Installation", slug: "getting-started/installation" },
{ label: "Quick Start", slug: "getting-started/quick-start" },
],
},
{
label: "Guides",
items: [
{
label: "Finding Hardcoded Secrets",
slug: "guides/finding-secrets",
},
{
label: "Reverse Engineering Assemblies",
slug: "guides/reverse-engineering",
},
{
label: "Recovering Lost Source Code",
slug: "guides/recovering-source",
},
{
label: "Analyzing Malware Samples",
slug: "guides/malware-analysis",
},
{
label: "Understanding Libraries",
slug: "guides/understanding-libraries",
},
{
label: "Working with Large Types",
slug: "guides/working-with-large-types",
},
{ label: "Configuration", slug: "guides/configuration" },
],
},
{
label: "Reference",
items: [
{ label: "Tools Overview", slug: "reference/tools-overview" },
{
label: "Decompilation Tools",
collapsed: true,
items: [
{
label: "decompile_assembly",
slug: "reference/tools/decompile-assembly",
},
{
label: "decompile_method",
slug: "reference/tools/decompile-method",
},
{
label: "list_types",
slug: "reference/tools/list-types",
},
{
label: "search_types",
slug: "reference/tools/search-types",
},
{
label: "search_strings",
slug: "reference/tools/search-strings",
},
{
label: "generate_diagrammer",
slug: "reference/tools/generate-diagrammer",
},
{
label: "dump_package",
slug: "reference/tools/dump-package",
},
{
label: "get_assembly_info",
slug: "reference/tools/get-assembly-info",
},
],
},
{
label: "Metadata Tools",
collapsed: true,
items: [
{
label: "search_methods",
slug: "reference/tools/search-methods",
},
{
label: "search_fields",
slug: "reference/tools/search-fields",
},
{
label: "search_properties",
slug: "reference/tools/search-properties",
},
{
label: "list_events",
slug: "reference/tools/list-events",
},
{
label: "list_resources",
slug: "reference/tools/list-resources",
},
{
label: "get_metadata_summary",
slug: "reference/tools/get-metadata-summary",
},
],
},
{
label: "Diagnostics Tools",
collapsed: true,
items: [
{
label: "check_ilspy_installation",
slug: "reference/tools/check-ilspy-installation",
},
{
label: "install_ilspy",
slug: "reference/tools/install-ilspy",
},
],
},
{ label: "MCP Prompts", slug: "reference/prompts" },
{ label: "Data Models", slug: "reference/data-models" },
{ label: "Changelog", slug: "reference/changelog" },
],
},
{
label: "Development",
collapsed: true,
items: [
{ label: "Architecture", slug: "development/architecture" },
{ label: "Contributing", slug: "development/contributing" },
{ label: "Release Guide", slug: "development/release-guide" },
],
},
],
}),
sitemap(),
],
vite: {
plugins: [tailwindcss()],
server: {
host: "0.0.0.0",
...(process.env.VITE_HMR_HOST && {
hmr: {
host: process.env.VITE_HMR_HOST,
protocol: "wss",
clientPort: 443,
},
}),
},
},
});

View File

@ -0,0 +1,41 @@
services:
docs:
build:
context: .
target: prod
restart: unless-stopped
networks:
- caddy
labels:
caddy: ${DOMAIN}
caddy.reverse_proxy: "{{upstreams 80}}"
docs-dev:
build:
context: .
target: dev
profiles:
- dev
volumes:
- ./src:/app/src
- ./public:/app/public
- ./astro.config.mjs:/app/astro.config.mjs
networks:
- caddy
environment:
- VITE_HMR_HOST=${DOMAIN}
labels:
caddy: ${DOMAIN}
caddy.reverse_proxy: "{{upstreams 4321}}"
caddy.reverse_proxy.flush_interval: "-1"
caddy.reverse_proxy.transport: "http"
caddy.reverse_proxy.transport.read_timeout: "0"
caddy.reverse_proxy.transport.write_timeout: "0"
caddy.reverse_proxy.transport.keepalive: "5m"
caddy.reverse_proxy.transport.keepalive_idle_conns: "10"
caddy.reverse_proxy.stream_timeout: "24h"
caddy.reverse_proxy.stream_close_delay: "5s"
networks:
caddy:
external: true

9712
docs-site/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

22
docs-site/package.json Normal file
View File

@ -0,0 +1,22 @@
{
"name": "mcilspy-docs",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/sitemap": "^3.3.1",
"@astrojs/starlight": "^0.37.6",
"@tailwindcss/vite": "^4.1.3",
"astro": "^5.7.10",
"astro-icon": "^1.1.5",
"astro-mermaid": "^1.3.1",
"mermaid": "^11.12.3",
"sharp": "^0.33.0",
"tailwindcss": "^4.1.3"
}
}

View File

@ -0,0 +1,30 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<!-- Binary background circle -->
<circle cx="16" cy="16" r="15" fill="#0f172a" stroke="#334155" stroke-width="1"/>
<!-- Binary digits (faded) -->
<text x="5" y="10" font-family="monospace" font-size="4" fill="#334155" opacity="0.6">01</text>
<text x="14" y="10" font-family="monospace" font-size="4" fill="#334155" opacity="0.6">10</text>
<text x="23" y="10" font-family="monospace" font-size="4" fill="#334155" opacity="0.5">01</text>
<text x="5" y="15" font-family="monospace" font-size="4" fill="#334155" opacity="0.5">11</text>
<text x="14" y="15" font-family="monospace" font-size="4" fill="#334155" opacity="0.4">00</text>
<text x="23" y="15" font-family="monospace" font-size="4" fill="#334155" opacity="0.6">10</text>
<text x="5" y="20" font-family="monospace" font-size="4" fill="#334155" opacity="0.4">10</text>
<text x="14" y="20" font-family="monospace" font-size="4" fill="#334155" opacity="0.5">01</text>
<text x="23" y="20" font-family="monospace" font-size="4" fill="#334155" opacity="0.4">11</text>
<text x="5" y="25" font-family="monospace" font-size="4" fill="#334155" opacity="0.5">01</text>
<text x="14" y="25" font-family="monospace" font-size="4" fill="#334155" opacity="0.6">10</text>
<text x="23" y="25" font-family="monospace" font-size="4" fill="#334155" opacity="0.5">00</text>
<!-- Magnifying glass body -->
<circle cx="14" cy="14" r="7" fill="none" stroke="#f59e0b" stroke-width="2"/>
<!-- Glass lens highlight -->
<circle cx="14" cy="14" r="5" fill="#f59e0b" opacity="0.1"/>
<!-- Magnifying glass handle -->
<line x1="19.5" y1="19.5" x2="26" y2="26" stroke="#f59e0b" stroke-width="2.5" stroke-linecap="round"/>
<!-- C# symbol inside lens -->
<text x="14" y="16.5" font-family="sans-serif" font-size="8" font-weight="bold" fill="#f59e0b" text-anchor="middle">C#</text>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,68 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 240">
<defs>
<linearGradient id="arrowGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#f59e0b" stop-opacity="0.3"/>
<stop offset="50%" stop-color="#f59e0b" stop-opacity="1"/>
<stop offset="100%" stop-color="#f59e0b" stop-opacity="0.3"/>
</linearGradient>
</defs>
<!-- Left: .dll binary block -->
<rect x="20" y="40" width="160" height="160" rx="8" fill="#0f172a" stroke="#334155" stroke-width="1.5"/>
<text x="100" y="72" font-family="monospace" font-size="12" fill="#64748b" text-anchor="middle">4D 5A 90 00 03 00</text>
<text x="100" y="88" font-family="monospace" font-size="12" fill="#64748b" text-anchor="middle">00 00 04 00 00 00</text>
<text x="100" y="104" font-family="monospace" font-size="12" fill="#64748b" text-anchor="middle">FF FF 00 00 B8 00</text>
<text x="100" y="120" font-family="monospace" font-size="12" fill="#475569" text-anchor="middle">PE Header</text>
<text x="100" y="136" font-family="monospace" font-size="12" fill="#64748b" text-anchor="middle">00 00 00 00 00 00</text>
<text x="100" y="152" font-family="monospace" font-size="12" fill="#64748b" text-anchor="middle">40 00 00 00 00 00</text>
<text x="100" y="168" font-family="monospace" font-size="12" fill="#64748b" text-anchor="middle">0E 1F BA 0E 00 B4</text>
<text x="100" y="184" font-family="monospace" font-size="12" fill="#64748b" text-anchor="middle">09 CD 21 B8 01 4C</text>
<!-- .dll label -->
<rect x="60" y="205" width="80" height="24" rx="4" fill="#1e293b" stroke="#475569" stroke-width="1"/>
<text x="100" y="221" font-family="monospace" font-size="13" font-weight="bold" fill="#94a3b8" text-anchor="middle">.dll</text>
<!-- Center: transformation arrow -->
<path d="M 210 120 L 390 120" stroke="url(#arrowGrad)" stroke-width="3" fill="none" stroke-dasharray="8 4"/>
<polygon points="385,110 405,120 385,130" fill="#f59e0b"/>
<!-- mcilspy label on arrow -->
<rect x="255" y="94" width="90" height="24" rx="12" fill="#451a03" stroke="#f59e0b" stroke-width="1"/>
<text x="300" y="110" font-family="monospace" font-size="11" font-weight="bold" fill="#f59e0b" text-anchor="middle">mcilspy</text>
<!-- Right: C# source code block -->
<rect x="420" y="40" width="160" height="160" rx="8" fill="#0f172a" stroke="#334155" stroke-width="1.5"/>
<!-- Syntax-highlighted C# code -->
<text x="432" y="64" font-family="monospace" font-size="10.5">
<tspan fill="#f59e0b">using</tspan><tspan fill="#94a3b8"> System;</tspan>
</text>
<text x="432" y="80" font-family="monospace" font-size="10.5">
<tspan fill="#94a3b8"> </tspan>
</text>
<text x="432" y="96" font-family="monospace" font-size="10.5">
<tspan fill="#f59e0b">public class</tspan><tspan fill="#e2e8f0"> Auth</tspan>
</text>
<text x="432" y="112" font-family="monospace" font-size="10.5">
<tspan fill="#94a3b8">{</tspan>
</text>
<text x="432" y="128" font-family="monospace" font-size="10.5">
<tspan fill="#94a3b8"> </tspan><tspan fill="#f59e0b">string</tspan><tspan fill="#e2e8f0"> _key</tspan>
</text>
<text x="432" y="144" font-family="monospace" font-size="10.5">
<tspan fill="#94a3b8"> = </tspan><tspan fill="#86efac">"sk-..."</tspan><tspan fill="#94a3b8">;</tspan>
</text>
<text x="432" y="160" font-family="monospace" font-size="10.5">
<tspan fill="#94a3b8"> </tspan><tspan fill="#f59e0b">bool</tspan><tspan fill="#e2e8f0"> Login()</tspan>
</text>
<text x="432" y="176" font-family="monospace" font-size="10.5">
<tspan fill="#94a3b8"> { ... }</tspan>
</text>
<text x="432" y="192" font-family="monospace" font-size="10.5">
<tspan fill="#94a3b8">}</tspan>
</text>
<!-- C# label -->
<rect x="460" y="205" width="80" height="24" rx="4" fill="#1e293b" stroke="#475569" stroke-width="1"/>
<text x="500" y="221" font-family="monospace" font-size="13" font-weight="bold" fill="#f59e0b" text-anchor="middle">C#</text>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,6 @@
import { defineCollection } from "astro:content";
import { docsSchema } from "@astrojs/starlight/schema";
export const collections = {
docs: defineCollection({ schema: docsSchema() }),
};

View File

@ -0,0 +1,109 @@
---
title: Architecture
description: Internal architecture of mcilspy -- modules, data flow, and key design patterns.
---
import { Aside } from "@astrojs/starlight/components";
mcilspy is structured as a thin MCP layer over two independent backends: `ilspycmd` for full decompilation and `dnfile` for direct metadata parsing. The design keeps the FastMCP tool definitions separate from the backend logic, so either engine can be used (or replaced) independently.
## Data Flow
```mermaid
flowchart LR
Client["MCP Client"]
Server["server.py\n(FastMCP tools)"]
Wrapper["ilspy_wrapper.py\n(async subprocess)"]
ILSpy["ilspycmd CLI"]
MetaReader["metadata_reader.py\n(dnfile parser)"]
PE["PE/.NET binary"]
Client -->|"JSON-RPC"| Server
Server -->|"decompilation tools"| Wrapper
Wrapper -->|"create_subprocess_exec"| ILSpy
ILSpy -->|"reads"| PE
Server -->|"metadata tools"| MetaReader
MetaReader -->|"dnfile.dnPE"| PE
```
Decompilation tools flow through the `ILSpyWrapper`, which manages `ilspycmd` as an async subprocess. Metadata tools bypass `ilspycmd` entirely and read PE metadata tables through `dnfile`. Both paths share the same Pydantic models for type-safe data exchange.
## Module Map
| Module | Lines | Responsibility |
|--------|------:|----------------|
| `server.py` | 2,022 | FastMCP tool definitions for all 16 tools, 2 prompts, lifespan management, input validation, and error formatting |
| `ilspy_wrapper.py` | 767 | Async subprocess wrapper around `ilspycmd` -- builds CLI arguments, runs the process, parses stdout/stderr, enforces timeouts |
| `metadata_reader.py` | 684 | dnfile-based PE metadata parsing -- reads MethodDef, Field, Property, Event, ManifestResource, and Assembly tables directly |
| `models.py` | 263 | Pydantic `BaseModel` classes for all request/response types, plus `LanguageVersion` and `EntityType` enums |
| `il_parser.py` | 147 | Post-processing extraction of individual methods from type-level IL or C# output (used by `decompile_method`) |
| `constants.py` | 54 | Shared configuration values -- timeouts, output limits, search limits, entity type lists |
| `utils.py` | 50 | Helper for locating the `ilspycmd` binary across platforms (PATH, `~/.dotnet/tools`, Windows USERPROFILE) |
## Key Design Patterns
### Lazy Initialization
The `ILSpyWrapper` singleton is not created at server startup. It is lazily initialized on the first call to a decompilation tool via `get_wrapper()`. This means the server starts successfully even if `ilspycmd` is not installed -- the metadata tools work fine, and the diagnostics tools (`check_ilspy_installation`, `install_ilspy`) remain available.
```python
_cached_wrapper: ILSpyWrapper | None = None
def get_wrapper(ctx: Context | None = None) -> ILSpyWrapper:
global _cached_wrapper
if _cached_wrapper is None:
_cached_wrapper = ILSpyWrapper()
return _cached_wrapper
```
### 5-Minute Subprocess Timeout
Every `ilspycmd` invocation is wrapped with `asyncio.wait_for(..., timeout=300.0)`. This prevents runaway processes from corrupted or adversarial assemblies. The timeout constant lives in `constants.py`:
```python
DECOMPILE_TIMEOUT_SECONDS: float = 300.0 # 5 minutes
```
If a process exceeds this limit, it is killed and a clear error message is returned to the MCP client.
### PATH Auto-Discovery
MCP servers often run in restricted environments where `~/.dotnet/tools` is not in PATH. The `find_ilspycmd_path()` utility in `utils.py` checks three locations:
1. Standard PATH (via `shutil.which`)
2. `~/.dotnet/tools/ilspycmd` (default for `dotnet tool install --global`)
3. Windows `%USERPROFILE%\.dotnet\tools\` when it differs from `~`
### Secure Subprocess Execution
All subprocess calls use `asyncio.create_subprocess_exec` (not `create_subprocess_shell`). Assembly paths are passed as individual arguments, never interpolated into shell strings. This eliminates shell injection as an attack vector -- important because assembly paths come from untrusted MCP client input.
### Output Truncation Guard
The `decompile_assembly` tool accepts a `max_output_chars` parameter (default 100,000). When decompiled output exceeds this limit, the full text is written to a temp file and the tool returns a truncated preview with the file path. This prevents large assemblies from overwhelming the MCP client's context window. Setting `max_output_chars=0` disables truncation.
### Standardized Error Format
All tools use a consistent `_format_error()` helper that produces messages in the format:
```
**Error** (context): description
```
This makes errors easy to parse in both conversational and programmatic contexts.
## Entry Points
The package defines two entry points:
- **CLI**: `mcilspy` command (via `[project.scripts]` in pyproject.toml) calls `server:main()`, which starts the FastMCP server on stdio transport.
- **Module**: `python -m mcilspy` triggers `__main__.py`, which also calls `main()`.
Both paths print a startup banner to stderr (stdout is reserved for the MCP JSON-RPC protocol) and then enter the FastMCP event loop.
<Aside type="note">
The module-level `_cached_wrapper` global is intentionally used instead of
FastMCP's lifespan context. This avoids complex context-threading through
every tool function while still providing lazy initialization and clean
shutdown (the lifespan clears the cache on exit).
</Aside>

View File

@ -0,0 +1,155 @@
---
title: Contributing
description: How to set up a development environment and contribute to mcilspy.
---
import { Steps, Tabs, TabItem, Aside } from "@astrojs/starlight/components";
## Prerequisites
- **Python 3.10+** -- mcilspy uses `str | None` union syntax and other 3.10+ features
- **uv** -- for dependency management and running the project ([install uv](https://docs.astral.sh/uv/getting-started/installation/))
- **ilspycmd** (optional) -- only needed if you are working on decompilation tools. Metadata tools and tests that mock the subprocess work without it.
## Development Setup
<Steps>
1. **Clone the repository**
```bash
git clone https://git.supported.systems/MCP/mcilspy.git
cd mcilspy
```
2. **Install in development mode**
```bash
uv pip install -e ".[dev]"
```
This installs mcilspy in editable mode along with dev dependencies: `pytest`, `pytest-asyncio`, and `ruff`.
3. **Verify the install**
```bash
mcilspy --help
```
Or run directly:
```bash
uv run mcilspy
```
</Steps>
## Running Tests
The test suite uses pytest with async support via pytest-asyncio.
```bash
# Run all tests
pytest
# Run with verbose output
pytest -v
# Run a specific test file
pytest tests/test_models.py
# Run tests matching a pattern
pytest -k "test_decompile"
```
Tests are configured in `pyproject.toml`:
```toml
[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
```
The `asyncio_mode = "auto"` setting means you do not need to decorate async test functions with `@pytest.mark.asyncio` -- pytest-asyncio detects them automatically.
## Code Quality
mcilspy uses [ruff](https://docs.astral.sh/ruff/) for both linting and formatting.
```bash
# Check for lint issues
ruff check src/
# Auto-fix what can be fixed
ruff check --fix src/
# Format code
ruff format src/
```
The ruff configuration in `pyproject.toml`:
```toml
[tool.ruff]
target-version = "py310"
line-length = 100
src = ["src"]
[tool.ruff.lint]
select = ["E", "F", "W", "I", "UP", "B", "SIM"]
ignore = ["E501"]
[tool.ruff.format]
quote-style = "double"
```
## Project Structure
```
mcilspy/
src/mcilspy/
__init__.py # Package version
__main__.py # python -m mcilspy entry point
server.py # FastMCP tool definitions (16 tools, 2 prompts)
ilspy_wrapper.py # Async subprocess wrapper for ilspycmd
metadata_reader.py # dnfile-based PE metadata parsing
il_parser.py # Method extraction from IL/C# output
models.py # Pydantic request/response models
constants.py # Timeouts, limits, configuration
utils.py # PATH discovery helpers
tests/
test_models.py
test_il_parser.py
test_ilspy_wrapper.py
test_server.py
...
pyproject.toml
README.md
LICENSE
```
## Coding Conventions
**Async by default.** All tool functions in `server.py` are `async`. The ilspy_wrapper uses `asyncio.create_subprocess_exec` for non-blocking subprocess management.
**Pydantic for validation.** Request parameters are validated through Pydantic models in `models.py`. Add new fields with sensible defaults to maintain backward compatibility.
**No stdout prints.** MCP uses stdin/stdout for the JSON-RPC transport. Any `print()` to stdout corrupts the protocol stream. Use `logger` (which writes to stderr) for diagnostics. The `main()` function should only call `mcp.run()`.
**Error consistency.** Use the `_format_error()` helper in `server.py` for all error responses. The format is `**Error** (context): description`.
**Constants centralized.** Timeouts, output limits, and search limits live in `constants.py`. Do not hardcode magic numbers in tool functions.
## Testing with Claude Code
You can test your local changes with Claude Code without publishing:
```bash
claude mcp add mcilspy-local -- uv run --directory /path/to/mcilspy mcilspy
```
This starts the MCP server from your local source tree. Changes to the source are picked up on the next server restart.
<Aside type="tip">
For headless automated testing, use `claude -p` with `--mcp-config` and
`--allowedTools` flags. See the project CLAUDE.md for the full pattern.
</Aside>

View File

@ -0,0 +1,100 @@
---
title: Release Guide
description: How to build and publish mcilspy to PyPI.
---
import { Steps, Aside } from "@astrojs/starlight/components";
## Publishing to PyPI
<Steps>
1. **Update the version**
Edit `pyproject.toml` and bump the version number:
```toml
[project]
name = "mcilspy"
version = "0.6.0"
```
mcilspy uses date-aware versioning. Patch versions within a date are fine for same-day fixes.
2. **Clean and build**
Always clean `dist/` before building. Stale files from previous builds cause duplicate upload attempts -- PyPI rejects already-published versions.
```bash
rm -rf dist/ && uv build
```
This produces both a `.tar.gz` source distribution and a `.whl` wheel in `dist/`.
3. **Check the package**
Verify the package metadata and structure before uploading:
```bash
twine check dist/*
```
4. **Upload to PyPI**
```bash
uv publish --token $(grep password ~/.pypirc | head -1 | awk '{print $3}')
```
5. **Verify the release**
```bash
pip index versions mcilspy
```
Or install it fresh:
```bash
pip install mcilspy==0.6.0
```
</Steps>
## Important Notes
<Aside type="caution">
**PyPI is immutable per version.** You cannot re-upload or fix metadata for a published version. If you need to fix something after publishing, bump to a new version. For same-day fixes, use incremental patch versions (e.g., `0.5.1`, `0.5.2`).
</Aside>
<Aside type="caution">
**`uv publish` does not read `~/.pypirc`** by default. You must pass the API token explicitly via `--token`. The command above extracts it from your existing `.pypirc` file.
</Aside>
## Pre-Release Checklist
Before publishing, verify:
- [ ] All tests pass: `pytest`
- [ ] Linting is clean: `ruff check src/`
- [ ] Version in `pyproject.toml` is updated
- [ ] Changelog is updated in the docs site
- [ ] The package installs and runs locally: `uv pip install -e . && mcilspy`
## Build System
mcilspy uses [Hatch](https://hatch.pypa.io/) as its build backend:
```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/mcilspy"]
```
The `src` layout means the package source lives in `src/mcilspy/` and the wheel maps it to `mcilspy/` at install time. The entry point is defined as:
```toml
[project.scripts]
mcilspy = "mcilspy.server:main"
```
This creates the `mcilspy` CLI command that users invoke directly or through `uvx mcilspy`.

View File

@ -0,0 +1,129 @@
---
title: Installation
description: Three ways to install mcilspy — from metadata-only to full decompilation power.
---
import { Tabs, TabItem, Aside, Steps } from "@astrojs/starlight/components";
## Choose Your Path
mcilspy has three installation tiers, depending on how much capability you need.
### Option 1: Metadata Tools Only
Install just the MCP server. Seven tools work immediately by parsing PE metadata directly — no .NET SDK required.
<Tabs>
<TabItem label="pip">
```bash
pip install mcilspy
```
</TabItem>
<TabItem label="uv">
```bash
uv pip install mcilspy
```
</TabItem>
<TabItem label="pipx">
```bash
pipx install mcilspy
```
</TabItem>
</Tabs>
**Available tools:** `search_methods`, `search_fields`, `search_properties`, `list_events`, `list_resources`, `get_metadata_summary`, `search_strings`
### Option 2: Full Power with Auto-Install
Install the MCP server, then let it install `ilspycmd` for you. The `install_ilspy` tool detects your platform and package manager automatically.
```bash
pip install mcilspy
```
Then ask your AI assistant:
> *"Install ilspycmd for me"*
Or call `install_ilspy` with `install_dotnet_sdk: true` to install the .NET SDK first.
**Auto-detected package managers:**
- Arch Linux / Manjaro (`pacman`)
- Ubuntu / Debian / Mint (`apt`)
- Fedora / RHEL / CentOS (`dnf`)
- openSUSE (`zypper`)
- macOS (`homebrew`)
- Windows (`winget` / `chocolatey`)
### Option 3: Manual Setup
Install the .NET SDK and `ilspycmd` yourself:
<Steps>
1. Install the .NET SDK from [dotnet.microsoft.com/download](https://dotnet.microsoft.com/download)
2. Install ilspycmd as a global .NET tool:
```bash
dotnet tool install --global ilspycmd
```
3. Ensure the tools directory is in your PATH:
```bash
export PATH="$PATH:$HOME/.dotnet/tools"
```
4. Install the MCP server:
```bash
pip install mcilspy
```
</Steps>
## Configure Your MCP Client
<Tabs>
<TabItem label="Claude Code">
```bash
claude mcp add ilspy -- mcilspy
```
</TabItem>
<TabItem label="Claude Desktop">
Add to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"ilspy": {
"command": "mcilspy"
}
}
}
```
</TabItem>
<TabItem label="Other MCP Clients">
Point your MCP client at the `mcilspy` command. The server communicates over
stdin/stdout using JSON-RPC.
```json
{
"command": "mcilspy",
"args": []
}
```
</TabItem>
</Tabs>
## Verify Installation
Ask your AI assistant to run the installation check:
> *"Check if ilspycmd is installed correctly"*
This calls `check_ilspy_installation`, which reports:
- Whether the `dotnet` CLI is available and its version
- Whether `ilspycmd` is installed, its version, and its path
- Troubleshooting instructions if anything is missing
<Aside type="note">
The metadata-based tools (`search_methods`, `search_fields`, etc.) work even
if `ilspycmd` is not installed. You only need `ilspycmd` for decompilation,
diagrams, and project generation.
</Aside>

View File

@ -0,0 +1,45 @@
---
title: Overview
description: What mcilspy is, how it works, and who it's for.
---
import { Aside } from "@astrojs/starlight/components";
mcilspy is a [Model Context Protocol](https://modelcontextprotocol.io/) server that gives AI assistants the power to reverse-engineer .NET binaries. It wraps the [ILSpy](https://github.com/icsharpcode/ILSpy) decompiler and [dnfile](https://github.com/malwarefrank/dnfile) metadata parser behind a clean tool interface, letting Claude (or any MCP client) decompile assemblies, search for hardcoded secrets, explore type hierarchies, and recover lost source code.
## Two Engines, One Interface
mcilspy operates with two complementary backends:
**dnfile (metadata engine)** parses PE headers and .NET metadata tables directly in Python. This gives you 7 tools that work immediately — no .NET SDK required. These tools read the MethodDef, Field, Property, Event, and ManifestResource tables to let you search and explore assembly structure without decompiling anything.
**ilspycmd (decompilation engine)** is the command-line interface to ILSpy, the open-source .NET decompiler. When installed, it unlocks 9 more tools for full C# source recovery, IL bytecode output, interactive HTML diagrams, NuGet package extraction, and PDB generation.
## Who Is It For?
- **Security researchers** finding hardcoded credentials, API keys, and connection strings in compiled binaries
- **Reverse engineers** analyzing .NET malware or understanding obfuscated commercial software
- **Developers** recovering source code from legacy assemblies when the original source has been lost
- **Library consumers** reading actual implementations when documentation falls short
## What Is MCP?
The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard for connecting AI assistants to external tools and data sources. Instead of copying output between terminals, you describe what you want in natural language and the AI calls the right tools automatically.
mcilspy exposes 16 tools and 2 prompts through MCP, making .NET reverse engineering a conversational workflow:
> *"Search for any hardcoded API keys in MyApp.dll"*
The AI calls `search_strings` and `search_fields` with the right parameters, aggregates the results, and explains what it found — no manual CLI invocation needed.
## Supported Formats
- .NET Framework assemblies (2.0 through 4.8)
- .NET Core / .NET 5 through 9+ assemblies
- Any PE file with .NET metadata
- NuGet packages (via `dump_package` extraction)
<Aside type="tip">
C# language versions from CSharp1 through CSharp12 are supported for
decompilation output, plus `Preview` and `Latest` options.
</Aside>

View File

@ -0,0 +1,83 @@
---
title: Quick Start
description: Your first .NET assembly analysis in under a minute.
---
import { Steps, Tabs, TabItem, Aside } from "@astrojs/starlight/components";
## First Analysis
Once mcilspy is installed and configured with your MCP client, you're ready to analyze .NET assemblies.
<Steps>
1. **Point at an assembly**
Give your AI assistant a path to any `.dll` or `.exe`:
> *"Analyze the assembly at /path/to/MyApp.dll"*
The assistant will call `get_metadata_summary` to get a quick overview — type counts, method counts, referenced assemblies, and target framework.
2. **Explore the types**
> *"List all the classes and interfaces in MyApp.dll"*
This calls `list_types` to enumerate everything in the assembly, organized by namespace.
3. **Search for something specific**
> *"Find all methods with 'Login' in the name"*
The assistant uses `search_methods` to find matching methods across all types, showing you their declaring types and visibility.
4. **Decompile what interests you**
> *"Decompile the AuthService class and explain what it does"*
This calls `decompile_assembly` with the specific type name, returning full C# source code. The assistant reads and explains the implementation.
5. **Go deeper**
> *"Search for any hardcoded API keys or connection strings"*
The assistant combines `search_strings` and `search_fields` to find embedded secrets — URLs, keys, passwords, and configuration values.
</Steps>
## Recommended Workflow
When analyzing an unknown assembly, this sequence covers the most ground:
| Step | Tool | Purpose |
|------|------|---------|
| 1 | `get_metadata_summary` | Quick reconnaissance — how big is it? What does it reference? |
| 2 | `list_types` | Discover what types exist |
| 3 | `search_types` / `search_methods` | Find specific types or methods by pattern |
| 4 | `search_strings` / `search_fields` | Find hardcoded strings and constants |
| 5 | `decompile_assembly` | Deep dive into specific types |
| 6 | `generate_diagrammer` | Visualize type relationships |
| 7 | `list_resources` | Check for embedded files |
<Aside type="tip">
Steps 14 use metadata tools and work without `ilspycmd`. Steps 57 require
it for full decompilation. You can always start with metadata exploration and
install `ilspycmd` later when you need deeper analysis.
</Aside>
## Example Prompts
Here are natural language prompts that work well with mcilspy:
**Security analysis:**
> *"Search for any URLs, API keys, or connection strings in MyApp.dll"*
**Architecture exploration:**
> *"List all interfaces in this assembly and show me the dependency structure"*
**Source recovery:**
> *"Decompile the entire assembly to a project I can build"*
**Targeted investigation:**
> *"Find all methods that handle HTTP requests and decompile them"*
**Library understanding:**
> *"Show me how Newtonsoft.Json handles circular references"*

View File

@ -0,0 +1,148 @@
---
title: Configuration
description: Environment variables, MCP client setup, and development configuration for mcilspy.
---
import { Tabs, TabItem, Aside } from "@astrojs/starlight/components";
mcilspy follows a zero-configuration philosophy -- it works out of the box with sensible defaults. The configuration surface is intentionally small: one environment variable for logging and the standard MCP client configuration for connecting to the server.
## MCP Client Configuration
<Tabs>
<TabItem label="Claude Code">
The simplest setup. One command registers mcilspy as an MCP server:
```bash
claude mcp add ilspy -- mcilspy
```
For development against a local checkout:
```bash
claude mcp add ilspy -- uv run --directory /path/to/mcilspy mcilspy
```
</TabItem>
<TabItem label="Claude Desktop">
Add to your `claude_desktop_config.json` (typically at `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS or `%APPDATA%\Claude\claude_desktop_config.json` on Windows):
```json
{
"mcpServers": {
"ilspy": {
"command": "mcilspy"
}
}
}
```
To enable debug logging:
```json
{
"mcpServers": {
"ilspy": {
"command": "mcilspy",
"env": {
"LOGLEVEL": "DEBUG"
}
}
}
}
```
</TabItem>
<TabItem label="Generic MCP Client">
mcilspy communicates over stdin/stdout using JSON-RPC. Point any MCP-compatible client at the `mcilspy` command:
```json
{
"command": "mcilspy",
"args": [],
"transport": "stdio"
}
```
If installed via `uvx`, use:
```json
{
"command": "uvx",
"args": ["mcilspy"],
"transport": "stdio"
}
```
</TabItem>
</Tabs>
## Environment Variables
mcilspy reads one environment variable:
| Variable | Default | Values | Purpose |
|----------|---------|--------|---------|
| `LOGLEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` | Controls log verbosity on stderr |
Logs are written to stderr exclusively -- stdout is reserved for the MCP JSON-RPC protocol. You will never see log output mixed into tool responses.
## Debug Mode
Set `LOGLEVEL=DEBUG` to see detailed information about tool invocations, subprocess commands, and metadata parsing:
```bash
LOGLEVEL=DEBUG mcilspy
```
In Claude Code, you can set environment variables in the MCP configuration:
```bash
claude mcp add ilspy -e LOGLEVEL=DEBUG -- mcilspy
```
Debug output includes:
- Every `ilspycmd` subprocess command and its arguments
- Metadata reader operations and timing
- Search pattern compilation and match counts
- Output truncation decisions and temp file paths
<Aside type="tip">
Debug logs are useful for reporting issues. If a tool returns unexpected results, re-run with `LOGLEVEL=DEBUG` and include the stderr output in your bug report.
</Aside>
## Development Setup
For working on mcilspy itself, install in development mode and run directly:
```bash
git clone https://git.supported.systems/MCP/mcilspy.git
cd mcilspy
uv pip install -e .
mcilspy
```
Or run without installing:
```bash
uv run --directory /path/to/mcilspy mcilspy
```
To test with Claude Code using a local development copy:
```bash
claude mcp add ilspy-dev -- uv run --directory /path/to/mcilspy mcilspy
```
This registers a separate `ilspy-dev` server alongside any production installation, so you can compare behavior between versions.
## Tool Defaults
These defaults are built into mcilspy and cannot be changed via configuration. They can be overridden per tool call:
| Parameter | Default | Tool |
|-----------|---------|------|
| `max_output_chars` | 100,000 | `decompile_assembly` |
| `max_results` | 100 | `search_strings` |
| `max_results` | 1,000 | `search_methods`, `search_fields`, `list_types`, `search_types` |
| `language_version` | `Latest` | `decompile_assembly`, `decompile_method` |
| `show_il_code` | `false` | `decompile_assembly` |
| `show_il_code` | `true` | `decompile_method` |

View File

@ -0,0 +1,82 @@
---
title: Finding Hardcoded Secrets
description: How to locate credentials, API keys, connection strings, and other sensitive values embedded in .NET assemblies.
---
import { Aside, Steps } from "@astrojs/starlight/components";
Compiled .NET assemblies frequently contain hardcoded secrets that developers intended to keep private. Connection strings, API keys, bearer tokens, and internal URLs all survive compilation and are readable without source code access. mcilspy provides two complementary approaches for finding them.
<Aside type="caution">
If you discover credentials in a production assembly, treat them as compromised. Rotate the secrets immediately, then fix the code. Hardcoded secrets in compiled binaries are trivially extractable by anyone with access to the file.
</Aside>
## Start with String Literals
The `search_strings` tool reads the .NET User Strings heap directly from metadata -- no decompilation required. This is the fastest way to find embedded text.
Search for common secret patterns:
```
"Search for any URLs in MyApp.dll"
```
The tool supports regex, so you can cast a wider net:
```
"Search MyApp.dll for strings matching the regex https?://|api[_-]?key|password|secret|bearer|connectionstring"
```
Useful regex patterns for common secret formats:
| Pattern | Finds |
|---------|-------|
| `https?://` | URLs and API endpoints |
| `[A-Za-z0-9]{32,}` | Long alphanumeric tokens (API keys, hashes) |
| `(?i)password\|pwd\|passwd` | Password field references |
| `Server=.*Database=` | SQL connection strings |
| `mongodb(\+srv)?://` | MongoDB connection URIs |
| `Bearer\s+[A-Za-z0-9\-._~+/]+=*` | Bearer tokens |
| `-----BEGIN` | PEM-encoded certificates or private keys |
## Follow Up with Field Constants
String literals tell you what values exist, but `search_fields` with `constants_only` reveals where they live in the type system. This is especially useful for configuration classes that store secrets as `const` or `static readonly` fields.
```
"Search for constant fields with 'key' or 'secret' in their name in MyApp.dll"
```
The `constants_only` parameter filters to `const` and `static literal` fields, which are the most common places developers store configuration values:
```
"Search fields in MyApp.dll with pattern 'connection' and constants_only enabled"
```
## Practical Workflow
<Steps>
1. **Broad string search** -- Run `search_strings` with a pattern like `https?://|password|key|token|secret` to find raw values.
2. **Identify interesting hits** -- URLs to internal services, anything that looks like a key or token, base64-encoded blobs.
3. **Find the declaring types** -- Use `search_fields` with the field name or value to locate the class that holds the secret.
4. **Decompile the context** -- Call `decompile_assembly` with `type_name` set to the declaring class to see how the secret is used.
5. **Check for obfuscation** -- If strings look encoded, search for base64 decode calls with `search_methods` using pattern `FromBase64` or `Decrypt`.
</Steps>
## Dealing with Obfuscated Secrets
Some assemblies encode or encrypt their secrets at compile time. When `search_strings` returns base64-encoded or otherwise scrambled values, look for the decoding logic:
```
"Search for methods named Decrypt, Decode, FromBase64, or Deobfuscate in MyApp.dll"
```
Then decompile those methods to understand the encoding scheme. Simple XOR or base64 obfuscation is common and easily reversible once you can read the implementation.
<Aside type="note">
The `search_strings` tool reads the #US (User Strings) metadata heap directly, which is typically 10-100x faster than decompilation-based approaches. It works without `ilspycmd` installed.
</Aside>

View File

@ -0,0 +1,100 @@
---
title: Analyzing Malware Samples
description: Safe static analysis of suspicious .NET executables using metadata inspection and decompilation.
---
import { Aside } from "@astrojs/starlight/components";
.NET is a common platform for malware because it is easy to write, runs on most Windows machines, and compiles to intermediate language that can be decompiled back to readable C#. mcilspy enables static analysis of these samples without executing them.
<Aside type="danger">
Never run suspicious executables on your host machine. Perform analysis inside an isolated virtual machine or container with no network access. mcilspy performs static analysis only -- it reads file bytes but never executes the assembly. The danger comes from accidental execution, not from mcilspy itself.
</Aside>
## Metadata-First Approach
The safest starting point uses only the metadata engine (dnfile), which parses PE headers and .NET metadata tables without invoking any .NET runtime code.
Start with `get_metadata_summary` to understand the binary's structure:
```
"Get metadata summary of suspicious.exe"
```
Pay attention to:
- **Referenced assemblies** -- `System.Net.Http`, `System.Net.Sockets`, or `System.Net.WebClient` indicate network communication. `Microsoft.Win32` suggests registry manipulation. `System.Diagnostics.Process` means it spawns child processes.
- **Type and method counts** -- A legitimate utility with 5,000 methods is very different from a dropper with 12.
- **Target framework** -- Malware targeting .NET Framework 2.0 can run on virtually any Windows machine without additional installs.
## Finding Command and Control Infrastructure
Search for hardcoded URLs, IP addresses, and domain names:
```
"Search for strings matching https?://|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ in suspicious.exe"
```
Then look for connection-related methods:
```
"Search for methods containing 'Download', 'Upload', 'Socket', 'Connect', or 'Request' in suspicious.exe"
```
These searches work without `ilspycmd` and give you a rapid triage of network behavior.
## Identifying Persistence Mechanisms
.NET malware commonly achieves persistence through registry keys, scheduled tasks, or startup folder manipulation. Search for the telltale strings and method calls:
```
"Search strings for 'CurrentVersion\\Run' or 'TaskScheduler' in suspicious.exe"
"Search methods for 'Registry' or 'SetValue' in suspicious.exe"
```
Also check `list_resources` for embedded payloads. Malware frequently carries secondary executables or scripts as embedded resources:
```
"List all embedded resources in suspicious.exe"
```
Resource names like `payload`, `stage2`, or obfuscated names (random characters) deserve closer inspection.
## Decompiling Suspicious Methods
Once you have identified interesting types through metadata search, decompile them to read the actual logic:
```
"Decompile the Loader class from suspicious.exe"
```
For obfuscated samples where type and method names are garbled, `list_types` with all entity types reveals the full structure even when names are meaningless:
```
"List all classes, interfaces, and structs in suspicious.exe"
```
<Aside type="tip">
Obfuscated assemblies often rename types to unprintable characters or single letters. The types still appear in `list_types` output -- they just have unusual names like `a`, `b`, or Unicode characters. The decompiled C# is still readable because IL preserves the program structure regardless of naming.
</Aside>
## Checking for Anti-Analysis
Some .NET malware includes anti-analysis techniques. Look for:
- **Environment detection** -- Methods checking for `IsDebuggerPresent`, sandbox artifacts, or VM-specific registry keys.
- **Sleep calls** -- `Thread.Sleep` with large values to outlast sandbox timeouts.
- **Encrypted strings** -- If `search_strings` returns mostly gibberish, the sample likely decrypts strings at runtime. Search for `Decrypt`, `FromBase64String`, or `XOR` methods.
- **Reflection loading** -- `Assembly.Load` or `Assembly.LoadFrom` calls that load additional code at runtime from embedded resources or downloaded payloads.
```
"Search methods for 'IsDebuggerPresent|Sleep|Decrypt|Assembly.Load' in suspicious.exe using regex"
```
## Generating a Visual Overview
For complex samples with many types, `generate_diagrammer` creates an interactive HTML view of the type hierarchy. This helps identify which classes are central to the malware's operation versus which are support code or decoys:
```
"Generate a type diagram for suspicious.exe"
```

View File

@ -0,0 +1,93 @@
---
title: Recovering Lost Source Code
description: How to decompile .NET assemblies into compilable C# projects, with PDB generation and readable variable names.
---
import { Aside, Steps } from "@astrojs/starlight/components";
Sometimes the source code is gone. The repository was deleted, the developer left, the backup failed. If you still have the compiled `.dll` or `.exe`, mcilspy can reconstruct C# source that is often close to the original.
## The Recovery Workflow
<Steps>
1. **Assess the assembly**
Start with `get_assembly_info` to check the target framework and whether debug information exists:
```
"Get assembly info for LegacyApp.dll"
```
If `has_debug_info` is true, a PDB file may be alongside the assembly. This significantly improves output quality.
2. **Generate a project structure**
Use `decompile_assembly` with `create_project` to produce a `.csproj` file and organized source files:
```
"Decompile LegacyApp.dll into a project structure at ./recovered-source"
```
The `create_project` flag tells ILSpy to generate a buildable project rather than a single concatenated output. Combined with `nested_directories`, source files are organized into namespace-based folder hierarchies.
3. **Enable PDB generation**
Set `generate_pdb` to produce a portable PDB file alongside the decompiled source. This lets you attach a debugger to the decompiled code:
```
"Decompile LegacyApp.dll to ./recovered with create_project, generate_pdb, and nested_directories enabled"
```
4. **Recover original variable names**
If the assembly ships with its original PDB (or an embedded portable PDB), enable `use_pdb_variable_names` to replace ILSpy's generated names (`num`, `text`, `flag`) with the originals:
```
"Decompile with use_pdb_variable_names enabled"
```
Without this flag, local variables get generic names based on their types. With it, you get `connectionTimeout` instead of `num2`.
5. **Build and fix**
The decompiled project usually needs minor adjustments before it compiles. Common issues include missing NuGet package references, unresolved `extern` methods, and resource files that need regenerating. But the structural recovery is typically complete.
</Steps>
## Choosing a Language Version
ILSpy decompiles using modern C# syntax by default (`Latest`). If the original code targeted an older framework, you may want to match the language version for authenticity:
| Original Framework | Suggested Version |
|---|---|
| .NET Framework 2.0-3.5 | `CSharp3` |
| .NET Framework 4.0 | `CSharp4` |
| .NET Framework 4.5 | `CSharp5` |
| .NET Framework 4.6+ | `CSharp6` or `CSharp7` |
| .NET Core 3.x | `CSharp8_0` |
| .NET 5-6 | `CSharp9_0` or `CSharp10_0` |
| .NET 7-8 | `CSharp11_0` or `CSharp12_0` |
Pass the version via the `language_version` parameter on `decompile_assembly`.
## Cleaning Up the Output
ILSpy produces clean output, but two optional flags can tighten it further:
- **`remove_dead_code`** strips unreachable code paths that the compiler left in the IL. This is common with debug builds.
- **`remove_dead_stores`** removes variable assignments whose values are never read.
Both flags are safe for source recovery -- they remove only provably unreachable code.
<Aside type="note">
Decompiled C# is not identical to the original source. Comments, formatting preferences, and some syntactic sugar are lost during compilation. The logic and structure are preserved, but the result is ILSpy's best reconstruction from the IL bytecode.
</Aside>
## Single-Type Recovery
If you only need one class, skip the project generation and decompile just that type:
```
"Decompile the MyApp.Data.CustomerRepository class from LegacyApp.dll"
```
This returns the C# source for that single type, which you can paste directly into a new project.

View File

@ -0,0 +1,73 @@
---
title: Reverse Engineering Assemblies
description: A systematic approach to understanding unknown .NET binaries, from metadata reconnaissance to full decompilation.
---
import { Aside } from "@astrojs/starlight/components";
When you receive an unfamiliar .NET assembly, the temptation is to decompile everything at once. That works for small libraries, but for anything substantial you will drown in output. A structured approach yields better results with less effort.
## Reconnaissance First
Start with `get_metadata_summary` to understand the scale of what you are dealing with. This reads PE headers and .NET metadata tables directly and returns type, method, field, and event counts alongside referenced assemblies and target framework.
```
"Give me a metadata summary of MyApp.dll"
```
The referenced assemblies list is particularly revealing. References to `System.Net.Http` suggest network operations. `EntityFramework` means database access. `Newtonsoft.Json` or `System.Text.Json` indicates serialization. These clues guide where to focus.
## Enumerate the Type Structure
Next, use `list_types` to see what exists. By default it lists classes, but you can include interfaces, structs, enums, and delegates:
```
"List all classes and interfaces in MyApp.dll"
```
Results are grouped by namespace, which reveals the application's architecture at a glance. Most .NET projects organize namespaces by concern -- `MyApp.Services`, `MyApp.Models`, `MyApp.Controllers`, and so on.
## Search Before You Decompile
Rather than decompiling entire namespaces, use `search_types` and `search_methods` to locate specific areas of interest. These tools support substring matching and regex:
```
"Search for types containing 'Auth' in MyApp.dll"
"Find all methods with 'Handle' in their name, filtered to the Events namespace"
```
The `namespace_filter` parameter is especially useful for large assemblies. If you see 40 namespaces in the type listing, narrow your search to the one that matters.
## Decompile Targeted Types
Once you know which types are interesting, decompile them individually with `decompile_assembly` using the `type_name` parameter:
```
"Decompile the MyApp.Auth.TokenValidator class"
```
This returns just that class, keeping output manageable. For types with complex inheritance, decompile the base classes and interfaces separately to build a full picture.
<Aside type="tip">
When working with large assemblies (1000+ types), always use `type_name` to decompile specific classes rather than the entire assembly. Full decompilation can produce millions of characters of output.
</Aside>
## Visualize Relationships
For understanding how types relate to each other, `generate_diagrammer` creates an interactive HTML diagram showing inheritance hierarchies, interface implementations, and dependencies:
```
"Generate a diagram of MyApp.dll focusing on the Services namespace"
```
Use `include_pattern` to focus on a specific namespace and `exclude_pattern` to hide generated code like `<>c__DisplayClass` compiler artifacts.
## Working with Namespaces
Large enterprise assemblies can have deeply nested namespaces. A few techniques for staying oriented:
- **Filter by namespace** on `search_methods`, `search_fields`, and `search_types` to scope results to a single area.
- **Look for entry points** by searching for `Main`, `Startup`, `Configure`, or `Program` methods to find where execution begins.
- **Trace dependencies** by decompiling a type, noting what other types it references, and following the chain.
The metadata tools (`search_methods`, `search_fields`, `search_properties`, `list_events`) all work without `ilspycmd`, so you can do extensive reconnaissance before installing the decompilation engine.

View File

@ -0,0 +1,98 @@
---
title: Understanding Libraries
description: How to read the actual implementation of third-party .NET libraries when documentation falls short.
---
import { Aside, Steps } from "@astrojs/starlight/components";
Documentation tells you what a library does. Decompilation tells you how it does it. When you need to understand retry behavior, thread safety, serialization edge cases, or error handling that the docs do not cover, reading the implementation is the definitive answer.
## Extracting from NuGet
Most .NET libraries are distributed as NuGet packages. The `dump_package` tool extracts assemblies from a NuGet package directory into a flat folder for analysis:
<Steps>
1. **Locate the package cache**
NuGet packages are cached locally. The default locations are:
- **Windows**: `%USERPROFILE%\.nuget\packages\`
- **Linux/macOS**: `~/.nuget/packages/`
Each package has versioned subdirectories containing the compiled assemblies.
2. **Extract the assemblies**
Point `dump_package` at the package directory:
```
"Dump the package at ~/.nuget/packages/newtonsoft.json/13.0.3/ to ./newtonsoft-extracted"
```
This copies all `.dll` and `.exe` files from the package structure into a single directory.
3. **Analyze the extracted assembly**
Now use the standard tools against the extracted DLL:
```
"Get metadata summary of ./newtonsoft-extracted/Newtonsoft.Json.dll"
```
</Steps>
## Finding Entry Points
When you want to understand how a library handles a specific operation, start by searching for the method you call from your own code:
```
"Search for methods named 'DeserializeObject' in Newtonsoft.Json.dll"
```
This shows you the declaring type and all overloads. Then decompile the type to read the full implementation:
```
"Decompile the JsonConvert class from Newtonsoft.Json.dll"
```
## Tracing Internal Behavior
Library methods often delegate to internal classes that do the real work. Once you have decompiled the public entry point, follow the chain:
```
"Search for types containing 'JsonSerializer' in Newtonsoft.Json.dll"
"Decompile the JsonSerializerInternalReader class"
```
The `search_methods` tool with `type_filter` helps narrow down large internal classes:
```
"Search for methods containing 'Populate' in Newtonsoft.Json.dll, filtered to type JsonSerializerInternalReader"
```
## Understanding Configuration and Defaults
Libraries often have settings objects with defaults that are not fully documented. Use `search_fields` with `constants_only` to find them:
```
"Search for constant fields in Newtonsoft.Json.dll with pattern 'Default'"
```
And `search_properties` to find configuration surfaces:
```
"Search for properties containing 'Setting' or 'Option' in Newtonsoft.Json.dll"
```
<Aside type="tip">
When analyzing framework assemblies from the .NET runtime itself (like `System.Text.Json.dll`), the source code is also available on GitHub. But decompilation is faster for spot-checking behavior, and it shows you the exact code running on your machine, including any patches or version-specific changes.
</Aside>
## Comparing Versions
If you are debugging a version-specific issue, extract both versions and decompile the same type from each. The `language_version` parameter does not affect the comparison -- use `Latest` for both and diff the output.
```
"Decompile HttpClient from System.Net.Http.dll version 4.x"
"Decompile HttpClient from System.Net.Http.dll version 8.x"
```
Side-by-side comparison of the decompiled source reveals behavioral changes between versions that changelogs may not mention.

View File

@ -0,0 +1,94 @@
---
title: Working with Large Types
description: How to handle output truncation and extract specific methods from types that exceed the output limit.
---
import { Aside, Steps } from "@astrojs/starlight/components";
Some .NET types are enormous. God classes with hundreds of methods, auto-generated code from ORMs and serializers, or WinForms designers with thousands of lines of layout code -- these can easily exceed the default output limit when decompiled. mcilspy v0.5.0 introduced output truncation and method-level decompilation to handle this.
## How Truncation Works
The `decompile_assembly` tool has a `max_output_chars` parameter that defaults to 100,000 characters. When the decompiled output exceeds this limit, mcilspy:
1. Saves the **full output** to a temporary file on disk.
2. Returns a **truncated preview** with the first portion of the code.
3. Includes the **temp file path** so you can read the rest.
4. Lists **recovery options** for getting the complete content.
The truncation message looks like this:
```
Output truncated (245,000 chars exceeded 100,000 char limit)
Full output saved to: /tmp/mcilspy_full_output_abc123.cs
```
<Aside type="note">
Truncation protects MCP clients from choking on massive responses. The full output is always preserved on disk -- nothing is lost.
</Aside>
## Extracting Specific Methods
When you know which method you need, `decompile_method` extracts just that method from a type without returning the rest of the class. This is the primary tool for working with large types.
```
"Decompile the ProcessPayment method from MyApp.OrderService"
```
The tool decompiles the full type internally, then extracts and returns only the named method. If multiple overloads exist, all of them are returned.
<Steps>
1. **Find the method name** -- Use `search_methods` to locate methods by name pattern within a specific type:
```
"Search for methods in MyApp.dll filtered to type OrderService"
```
2. **Extract the method** -- Call `decompile_method` with the assembly path, fully qualified type name, and method name:
```
"Decompile the method ProcessPayment from type MyApp.Services.OrderService in MyApp.dll"
```
3. **Choose your output format** -- By default, `decompile_method` returns IL bytecode, which is the most reliable format for extraction. Set `show_il_code` to `false` for C# output instead.
</Steps>
## IL vs C# Extraction
The `decompile_method` tool defaults to IL output (`show_il_code: true`) because IL has standard ECMA-335 delimiters that make method boundaries unambiguous:
```il
.method public hidebysig instance void ProcessPayment(...) cil managed
{
// method body
} // end of method OrderService::ProcessPayment
```
C# extraction uses signature matching with brace-depth counting, which works well but can occasionally trip on unusual formatting. If C# extraction misses a method, try IL mode first.
## Adjusting the Truncation Limit
You can control truncation per-call:
- **Increase the limit** -- Set `max_output_chars` to a larger value (e.g., 500000) when your client can handle more data.
- **Disable truncation** -- Set `max_output_chars` to `0` to return the full output regardless of size. Use with caution on very large types.
- **Decrease the limit** -- Set a smaller value if you only need to see the beginning of a file to orient yourself.
```
"Decompile MyApp.dll with max_output_chars set to 0"
```
## Recovery Options After Truncation
When output is truncated, you have several paths forward:
| Approach | When to use |
|----------|-------------|
| Read the temp file directly | You need the complete output and your client can handle file reads |
| Use `decompile_method` | You only need specific methods from the type |
| Increase `max_output_chars` | The output is just slightly over the limit |
| Use `create_project` with `output_dir` | You want all files saved to disk and organized by namespace |
<Aside type="tip">
For assemblies where you need everything on disk rather than inline, use `decompile_assembly` with an `output_dir`. This writes files directly to disk and returns just the output path, bypassing truncation entirely.
</Aside>

View File

@ -0,0 +1,106 @@
---
title: mcilspy
description: Decompile, search, and analyze .NET assemblies with AI assistance via the Model Context Protocol.
template: splash
hero:
tagline: Decompile, search, and analyze .NET assemblies with AI assistance.
image:
file: ../../assets/hero-decompiler.svg
actions:
- text: Get Started
link: /getting-started/overview/
icon: right-arrow
variant: primary
- text: Tool Reference
link: /reference/tools-overview/
variant: minimal
---
import { Card, CardGrid, Tabs, TabItem } from "@astrojs/starlight/components";
## What Can You Do?
<CardGrid>
<Card title="Find Hardcoded Secrets" icon="warning">
Search for URLs, API keys, connection strings, and credentials embedded in
compiled .NET assemblies.
</Card>
<Card title="Reverse Engineer Binaries" icon="magnifying-glass">
List types, explore namespaces, and understand the structure of any .NET
assembly without source code.
</Card>
<Card title="Recover Lost Source Code" icon="document">
Decompile entire assemblies back to compilable C# projects — with PDB
generation and original variable names.
</Card>
<Card title="Analyze Malware Behavior" icon="shield">
Safe static analysis of suspicious .NET executables. Find network calls,
hardcoded URLs, and obfuscated logic.
</Card>
<Card title="Understand Third-Party Libraries" icon="open-book">
Read the actual implementation of any .NET library when documentation falls
short. Extract assemblies from NuGet packages for bulk analysis.
</Card>
</CardGrid>
## Install
<Tabs>
<TabItem label="pip">
```bash
pip install mcilspy
```
</TabItem>
<TabItem label="uvx">
```bash
uvx mcilspy
```
</TabItem>
<TabItem label="Claude Code">
```bash
claude mcp add ilspy -- mcilspy
```
</TabItem>
<TabItem label="Claude Desktop">
```json
{
"mcpServers": {
"ilspy": {
"command": "mcilspy"
}
}
}
```
</TabItem>
</Tabs>
Then ask your AI assistant:
> *"Decompile the LoginService class from this assembly and explain what it does"*
## 16 Tools, Two Engines
mcilspy ships **7 metadata tools** that work immediately — no .NET SDK required. They parse PE headers and metadata tables directly via [dnfile](https://github.com/malwarefrank/dnfile). Install `ilspycmd` to unlock **9 more tools** for full decompilation, diagrams, and project generation.
<div class="feature-matrix">
| Tool | Purpose | Requires ilspycmd |
|------|---------|:-----------------:|
| `decompile_assembly` | Full C# source recovery with PDB support | Yes |
| `decompile_method` | Extract a specific method from a type | Yes |
| `list_types` | Enumerate classes, interfaces, structs, enums | Yes |
| `search_types` | Find types by name pattern (regex supported) | Yes |
| `search_strings` | Find hardcoded strings in IL code | No |
| `search_methods` | Find methods by name or pattern | No |
| `search_fields` | Find fields and constants | No |
| `search_properties` | Find properties by name | No |
| `list_events` | List all event definitions | No |
| `list_resources` | Find embedded files and images | No |
| `get_metadata_summary` | Assembly statistics and references | No |
| `generate_diagrammer` | Interactive HTML type relationship diagrams | Yes |
| `dump_package` | Extract assemblies from NuGet packages | Yes |
| `get_assembly_info` | Version, framework, signing info | Yes |
| `check_ilspy_installation` | Diagnose setup issues | No |
| `install_ilspy` | Auto-install .NET SDK + ilspycmd | No |
</div>

View File

@ -0,0 +1,75 @@
---
title: Changelog
description: Version history for mcilspy.
---
import { Badge } from "@astrojs/starlight/components";
All notable changes to mcilspy are documented here. This project follows [Keep a Changelog](https://keepachangelog.com/) conventions.
---
## 0.5.0 <Badge text="2026-02-11" variant="note" />
### Added
- **Output truncation guard** -- new `max_output_chars` parameter on `decompile_assembly` (default 100,000 characters). When decompiled output exceeds the limit, the full text is saved to a temp file and the tool returns a truncated preview with the file path. Set to `0` to disable truncation.
- **Method-level decompilation** -- new `decompile_method` tool extracts a single method from a type by name. Supports both C# and IL output, handles overloads, and works via post-processing of ilspycmd's type-level output.
- Tool count increased from 15 to **16**.
---
## 0.4.0 <Badge text="2026-02-11" variant="note" />
### Added
- **PDB generation** -- `generate_pdb` flag on `decompile_assembly` produces a portable PDB file alongside the decompiled source.
- **PDB variable names** -- `use_pdb_variable_names` flag recovers original variable names from an existing PDB when decompiling.
- **dump_package tool** -- extract all assemblies from a NuGet package folder into a target directory for bulk analysis.
- Achieved 100% coverage of ilspycmd CLI flags.
- Tool count increased from 14 to **15**.
---
## 0.3.0 <Badge text="2026-02-10" variant="note" />
### Fixed
- Type parsing regex now correctly handles generic types with nested angle brackets.
- UserStringHeap reading fixed for assemblies with large string tables.
- Decompile-to-stdout path no longer creates unnecessary temp directories.
### Changed
- Merged review fixes from taskmaster audit.
- Test suite expanded to **165 tests** passing.
---
## 0.2.0 <Badge text="2026-02-07" variant="note" />
### Security
- **Fixed shell injection vulnerability** -- switched from `asyncio.create_subprocess_shell` to `asyncio.create_subprocess_exec`. Assembly paths are no longer passed through a shell interpreter.
### Added
- 5-minute subprocess timeout prevents runaway decompilation on corrupted or adversarial assemblies.
- pytest test suite with **35 tests** covering all tools and error paths.
- PATH auto-discovery for ilspycmd (checks `~/.dotnet/tools` when not in PATH).
- `importlib.metadata` versioning -- version is derived from the installed package metadata.
- Standardized error message format across all tools.
- FastMCP lifespan pattern for clean startup/shutdown.
---
## 0.1.1 <Badge text="2026-02-06" variant="note" />
### Added
- **dnfile-based metadata tools** -- 6 new tools (`search_methods`, `search_fields`, `search_properties`, `list_events`, `list_resources`, `get_metadata_summary`) that parse PE metadata directly without ilspycmd.
- Platform-aware installation detection and instructions.
- Improved README with tool matrix and usage examples.
---
## 0.1.0 <Badge text="2026-02-05" variant="note" />
### Added
- Initial release with 4 core tools: `decompile_assembly`, `list_types`, `generate_diagrammer`, `get_assembly_info`.
- ILSpyWrapper async subprocess management.
- Pydantic request/response models.
- MCP prompts for guided analysis workflows.

View File

@ -0,0 +1,306 @@
---
title: Data Models
description: Pydantic models, enums, and dataclasses used by mcilspy for request/response handling and metadata representation.
---
import { Aside } from "@astrojs/starlight/components";
mcilspy uses [Pydantic](https://docs.pydantic.dev/) `BaseModel` classes for type-safe request and response handling. All models live in `src/mcilspy/models.py`. The metadata reader models represent data parsed directly from PE/.NET metadata tables via dnfile.
## Enums
### LanguageVersion
Controls the C# language version used for decompilation output. Maps directly to ilspycmd's `-lv` flag.
```python
class LanguageVersion(str, Enum):
CSHARP1 = "CSharp1"
CSHARP2 = "CSharp2"
CSHARP3 = "CSharp3"
CSHARP4 = "CSharp4"
CSHARP5 = "CSharp5"
CSHARP6 = "CSharp6"
CSHARP7 = "CSharp7"
CSHARP7_1 = "CSharp7_1"
CSHARP7_2 = "CSharp7_2"
CSHARP7_3 = "CSharp7_3"
CSHARP8_0 = "CSharp8_0"
CSHARP9_0 = "CSharp9_0"
CSHARP10_0 = "CSharp10_0"
CSHARP11_0 = "CSharp11_0"
CSHARP12_0 = "CSharp12_0"
PREVIEW = "Preview"
LATEST = "Latest"
```
Default is `LATEST`. Use specific versions when you need output compatible with a particular C# compiler.
### EntityType
Filters which kinds of types to return from `list_types`. Accepts both full names and single-letter shorthand.
```python
class EntityType(str, Enum):
CLASS = "c" # class
INTERFACE = "i" # interface
STRUCT = "s" # struct
DELEGATE = "d" # delegate
ENUM = "e" # enum
@classmethod
def from_string(cls, value: str) -> "EntityType":
"""Convert 'class' or 'c' to EntityType.CLASS, etc."""
```
The `from_string()` class method handles conversion from either format, so `"class"` and `"c"` both resolve to `EntityType.CLASS`.
## Request Models
### DecompileRequest
Parameters for `decompile_assembly`. Only `assembly_path` is required -- everything else has sensible defaults.
```python
class DecompileRequest(BaseModel):
assembly_path: str
output_dir: str | None = None
type_name: str | None = None
language_version: LanguageVersion = LanguageVersion.LATEST
create_project: bool = False
show_il_code: bool = False
reference_paths: list[str] = Field(default_factory=list)
remove_dead_code: bool = False
remove_dead_stores: bool = False
show_il_sequence_points: bool = False
nested_directories: bool = False
generate_pdb: bool = False
use_pdb_variable_names: bool = False
```
| Field | Description |
|-------|-------------|
| `assembly_path` | Path to the `.dll` or `.exe` to decompile |
| `output_dir` | Directory for decompiled output (uses temp dir if omitted) |
| `type_name` | Decompile only this type (full or short name) |
| `language_version` | Target C# version for output syntax |
| `create_project` | Generate a buildable `.csproj` project |
| `show_il_code` | Output IL bytecode instead of C# |
| `reference_paths` | Additional assembly paths for type resolution |
| `remove_dead_code` | Strip unreachable code from output |
| `remove_dead_stores` | Strip dead variable assignments |
| `show_il_sequence_points` | Include source mapping markers in IL output |
| `nested_directories` | Organize output files by namespace hierarchy |
| `generate_pdb` | Generate a portable PDB file alongside decompiled output |
| `use_pdb_variable_names` | Recover original variable names from an existing PDB |
### ListTypesRequest
Parameters for `list_types`. Defaults to listing classes only.
```python
class ListTypesRequest(BaseModel):
assembly_path: str
entity_types: list[EntityType] = Field(
default_factory=lambda: [EntityType.CLASS]
)
reference_paths: list[str] = Field(default_factory=list)
```
### GenerateDiagrammerRequest
Parameters for `generate_diagrammer`. Supports include/exclude patterns to control which types appear in the diagram.
```python
class GenerateDiagrammerRequest(BaseModel):
assembly_path: str
output_dir: str | None = None
include_pattern: str | None = None
exclude_pattern: str | None = None
docs_path: str | None = None
strip_namespaces: list[str] = Field(default_factory=list)
report_excluded: bool = False
```
### DumpPackageRequest
Parameters for `dump_package`. Both fields are required.
```python
class DumpPackageRequest(BaseModel):
assembly_path: str # Path to assembly or NuGet package folder
output_dir: str # Directory to extract assemblies into
```
### AssemblyInfoRequest
Parameters for `get_assembly_info`. Just the path.
```python
class AssemblyInfoRequest(BaseModel):
assembly_path: str
```
## Response Models
### DecompileResponse
Returned by `decompile_assembly` and `decompile_method`.
```python
class DecompileResponse(BaseModel):
success: bool
source_code: str | None = None
output_path: str | None = None
error_message: str | None = None
assembly_name: str
type_name: str | None = None
```
When `output_dir` is provided, `source_code` may be `None` and `output_path` points to the directory containing the files. When decompiling to stdout (no `output_dir`), `source_code` contains the decompiled text.
### ListTypesResponse
Returned by `list_types`.
```python
class ListTypesResponse(BaseModel):
success: bool
types: list[TypeInfo] = Field(default_factory=list)
total_count: int = 0
error_message: str | None = None
```
### DumpPackageResponse
Returned by `dump_package`.
```python
class DumpPackageResponse(BaseModel):
success: bool
output_path: str | None = None
assemblies_dumped: list[str] = Field(default_factory=list)
error_message: str | None = None
```
### TypeInfo
Represents a single type discovered by `list_types`.
```python
class TypeInfo(BaseModel):
name: str
full_name: str
kind: str # "class", "interface", "struct", etc.
namespace: str | None = None
```
### AssemblyInfo
Returned by `get_assembly_info`.
```python
class AssemblyInfo(BaseModel):
name: str
version: str
full_name: str
location: str
target_framework: str | None = None
runtime_version: str | None = None
is_signed: bool = False
has_debug_info: bool = False
```
## Metadata Models (dnfile-based)
These models represent data parsed directly from .NET PE metadata tables. They are used by the metadata tools (`search_methods`, `search_fields`, `search_properties`, `list_events`, `list_resources`, `get_metadata_summary`) which work without ilspycmd.
### MethodInfo
```python
class MethodInfo(BaseModel):
name: str
full_name: str
declaring_type: str
namespace: str | None = None
return_type: str | None = None
is_public: bool = False
is_static: bool = False
is_virtual: bool = False
is_abstract: bool = False
parameters: list[str] = Field(default_factory=list)
```
### FieldInfo
```python
class FieldInfo(BaseModel):
name: str
full_name: str
declaring_type: str
namespace: str | None = None
field_type: str | None = None
is_public: bool = False
is_static: bool = False
is_literal: bool = False # True for constants (const/enum values)
default_value: str | None = None
```
### PropertyInfo
```python
class PropertyInfo(BaseModel):
name: str
full_name: str
declaring_type: str
namespace: str | None = None
property_type: str | None = None
has_getter: bool = False
has_setter: bool = False
```
### EventInfo
```python
class EventInfo(BaseModel):
name: str
full_name: str
declaring_type: str
namespace: str | None = None
event_type: str | None = None
```
### ResourceInfo
```python
class ResourceInfo(BaseModel):
name: str
size: int = 0
is_public: bool = True
```
### AssemblyMetadata
The complete metadata summary returned by `get_metadata_summary`.
```python
class AssemblyMetadata(BaseModel):
name: str
version: str
culture: str | None = None
public_key_token: str | None = None
target_framework: str | None = None
type_count: int = 0
method_count: int = 0
field_count: int = 0
property_count: int = 0
event_count: int = 0
resource_count: int = 0
referenced_assemblies: list[str] = Field(default_factory=list)
```
<Aside type="note">
All models use Python 3.10+ union syntax (`str | None`) rather than
`Optional[str]`. The `Field(default_factory=list)` pattern ensures
mutable defaults are safe across instances.
</Aside>

View File

@ -0,0 +1,145 @@
---
title: MCP Prompts
description: Two MCP prompts for structured assembly analysis workflows.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
mcilspy includes two [MCP prompts](https://modelcontextprotocol.io/docs/concepts/prompts) that provide structured analysis workflows. Prompts are templates that MCP clients can invoke to guide multi-step analysis -- they tell the AI assistant what tools to call and in what order.
## analyze_assembly
A structured prompt for broad assembly analysis. It walks the assistant through discovering the overall structure, key types, namespaces, and architectural patterns.
### Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|:--------:|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Path to the `.dll` or `.exe` to analyze |
| `focus_area` | `string` | No | `"types"` | What to focus on: `types`, `namespaces`, or `dependencies` |
### What It Does
The prompt instructs the assistant to:
1. Examine the overall structure and organization of the assembly
2. Identify key types and their relationships
3. Map out namespaces and their purposes
4. Note architectural patterns and design decisions
The `focus_area` parameter steers the analysis toward types, namespace organization, or dependency relationships.
### Example Request
<Tabs>
<TabItem label="JSON-RPC">
```json
{
"method": "prompts/get",
"params": {
"name": "analyze_assembly_prompt",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"focus_area": "namespaces"
}
}
}
```
</TabItem>
<TabItem label="Natural Language">
> *"Use the analyze_assembly prompt to look at /path/to/MyApp.dll, focusing on dependencies"*
</TabItem>
</Tabs>
### Generated Prompt
```text
I need to analyze the .NET assembly at "/path/to/MyApp.dll".
Please help me understand:
1. The overall structure and organization of the assembly
2. Key types and their relationships
3. Main namespaces and their purposes
4. Any notable patterns or architectural decisions
Focus area: namespaces
Start by listing the types in the assembly, then provide insights
based on what you find.
```
## decompile_and_explain
A targeted prompt for deep-diving into a specific type. It instructs the assistant to decompile the type and provide a thorough explanation of its implementation.
### Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|:--------:|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Path to the `.dll` or `.exe` containing the type |
| `type_name` | `string` | Yes | -- | Fully qualified or short name of the type to analyze |
### What It Does
The prompt instructs the assistant to:
1. Decompile the specified type to C# source code
2. Explain what the type does and its purpose
3. Highlight interesting patterns, design decisions, or potential issues
4. Suggest how the type fits into the overall architecture
### Example Request
<Tabs>
<TabItem label="JSON-RPC">
```json
{
"method": "prompts/get",
"params": {
"name": "decompile_and_explain_prompt",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"type_name": "MyApp.Services.AuthService"
}
}
}
```
</TabItem>
<TabItem label="Natural Language">
> *"Use the decompile_and_explain prompt for AuthService in /path/to/MyApp.dll"*
</TabItem>
</Tabs>
### Generated Prompt
```text
I want to understand the type "MyApp.Services.AuthService" from
the assembly "/path/to/MyApp.dll".
Please:
1. Decompile this specific type
2. Explain what this type does and its purpose
3. Highlight any interesting patterns, design decisions, or
potential issues
4. Suggest how this type fits into the overall architecture
Type to analyze: MyApp.Services.AuthService
Assembly: /path/to/MyApp.dll
```
## Using Prompts
How you invoke MCP prompts depends on your client.
**Claude Code** and **Claude Desktop** surface prompts automatically. You can reference them by name in natural language:
> *"Run the analyze_assembly prompt on /path/to/MyApp.dll"*
**Programmatic clients** use the `prompts/get` JSON-RPC method, passing the prompt name and arguments as shown in the examples above. The client receives the expanded text and can include it as part of a conversation.
<Aside type="note">
Prompts are templates, not tools. They don't execute anything directly -- they
generate structured instructions that guide the assistant to call the right
tools in the right order. The actual work happens through tool calls like
`list_types`, `decompile_assembly`, and `search_methods`.
</Aside>

View File

@ -0,0 +1,113 @@
---
title: Tools Overview
description: Complete feature matrix of all 16 tools across two engines and three categories.
---
import { Aside, LinkCard, CardGrid, Badge } from "@astrojs/starlight/components";
mcilspy exposes 16 tools through the Model Context Protocol, powered by two complementary engines. Seven metadata tools parse PE headers directly via [dnfile](https://github.com/malwarefrank/dnfile) and work immediately with no .NET SDK. Nine decompilation tools use [ilspycmd](https://github.com/icsharpcode/ILSpy) for full source recovery, diagrams, and project generation. Two diagnostics tools help you get set up.
## Feature Matrix
| Tool | Purpose | Engine | Category |
|------|---------|--------|----------|
| `decompile_assembly` | Full C# or IL source recovery with PDB support | ilspycmd | Decompilation |
| `decompile_method` | Extract a single method from a type | ilspycmd | Decompilation |
| `list_types` | Enumerate classes, interfaces, structs, enums, delegates | ilspycmd | Decompilation |
| `search_types` | Find types by name pattern (regex supported) | ilspycmd | Decompilation |
| `search_strings` | Find hardcoded strings in the UserString heap | dnfile | Decompilation |
| `generate_diagrammer` | Interactive HTML type relationship diagram | ilspycmd | Decompilation |
| `dump_package` | Extract assemblies from NuGet packages | ilspycmd | Decompilation |
| `get_assembly_info` | Version, framework, signing, and debug info | ilspycmd | Decompilation |
| `search_methods` | Find methods by name or pattern across all types | dnfile | Metadata |
| `search_fields` | Find fields, constants, and their default values | dnfile | Metadata |
| `search_properties` | Find properties by name pattern | dnfile | Metadata |
| `list_events` | List all event definitions in an assembly | dnfile | Metadata |
| `list_resources` | Find embedded files, images, and resource streams | dnfile | Metadata |
| `get_metadata_summary` | Assembly statistics, references, and framework info | dnfile | Metadata |
| `check_ilspy_installation` | Diagnose dotnet CLI and ilspycmd setup | built-in | Diagnostics |
| `install_ilspy` | Auto-install .NET SDK and ilspycmd for your platform | built-in | Diagnostics |
## Tools by Category
### Decompilation Tools
Eight tools that use `ilspycmd` for deep analysis, plus `search_strings` which reads the UserString heap directly via `dnfile`. These cover full source recovery, type enumeration, diagram generation, and NuGet package extraction.
<CardGrid>
<LinkCard
title="decompile_assembly"
description="Full C# source recovery with PDB, IL code, and project generation options."
href="/reference/tools/decompile-assembly/"
/>
<LinkCard
title="decompile_method"
description="Extract a single method by name from a decompiled type."
href="/reference/tools/decompile-method/"
/>
<LinkCard
title="list_types"
description="Enumerate types filtered by kind -- classes, interfaces, structs, delegates, enums."
href="/reference/tools/list-types/"
/>
<LinkCard
title="search_types"
description="Find types by name pattern with regex support."
href="/reference/tools/search-types/"
/>
</CardGrid>
### Metadata Tools
Six tools that parse PE metadata tables directly. No .NET SDK required -- these work on any machine with Python installed.
<CardGrid>
<LinkCard
title="search_methods"
description="Find methods by name or pattern across all types."
href="/reference/tools/search-methods/"
/>
<LinkCard
title="search_fields"
description="Find fields, constants, and their default values."
href="/reference/tools/search-fields/"
/>
<LinkCard
title="get_metadata_summary"
description="Assembly statistics, type counts, and referenced assemblies."
href="/reference/tools/get-metadata-summary/"
/>
</CardGrid>
### Diagnostics Tools
Two tools for setup and troubleshooting. These detect your platform and package manager automatically.
<CardGrid>
<LinkCard
title="check_ilspy_installation"
description="Verify dotnet CLI and ilspycmd are installed and working."
href="/reference/tools/check-ilspy-installation/"
/>
<LinkCard
title="install_ilspy"
description="Auto-install .NET SDK and ilspycmd for your platform."
href="/reference/tools/install-ilspy/"
/>
</CardGrid>
## Recommended Workflow
When approaching an unknown assembly, start broad and narrow down. The [Quick Start](/getting-started/quick-start/) guide walks through this sequence in detail:
1. **Reconnaissance** -- `get_metadata_summary` for type counts, references, and framework target
2. **Discovery** -- `list_types` or `search_types` to find what exists
3. **Search** -- `search_methods`, `search_fields`, `search_strings` to find specific patterns
4. **Deep dive** -- `decompile_assembly` or `decompile_method` for full source code
5. **Visualization** -- `generate_diagrammer` for type relationship diagrams
6. **Resources** -- `list_resources` to check for embedded files
<Aside type="tip">
Steps 1-3 use metadata tools and work without `ilspycmd`. You can always start
with metadata exploration and install `ilspycmd` later when you need deeper analysis.
</Aside>

View File

@ -0,0 +1,52 @@
---
title: check_ilspy_installation
description: Diagnose ilspycmd and .NET SDK setup issues.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-diagnostics">Diagnostics</span>
Check whether `ilspycmd` and the .NET SDK are installed and accessible. This tool probes the system PATH for both `dotnet` and `ilspycmd`, reports their versions and locations, and provides troubleshooting instructions if anything is missing.
## Parameters
This tool takes no parameters.
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "check_ilspy_installation",
"arguments": {}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("check_ilspy_installation", {})
```
</TabItem>
</Tabs>
## Response
A status report covering:
- **dotnet CLI** -- whether it is available and its version
- **ilspycmd** -- whether it is installed, its version, and its filesystem path
- **Next steps** -- installation instructions if either tool is missing
<Aside type="tip">
Run this first if any decompilation tool returns an error about missing
dependencies. The metadata tools (`search_methods`, `search_fields`, etc.)
work without ilspycmd, so this check only matters for decompilation, diagrams,
and project generation.
</Aside>
## Related Tools
- [`install_ilspy`](/reference/tools/install-ilspy/) -- automatically install ilspycmd
- [`get_metadata_summary`](/reference/tools/get-metadata-summary/) -- works without ilspycmd

View File

@ -0,0 +1,71 @@
---
title: decompile_assembly
description: Decompile a .NET assembly to readable C# source code or IL bytecode.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-decompilation">Decompilation</span>
The primary tool for reverse-engineering .NET binaries. Recovers full C# source code from compiled `.dll` or `.exe` files. Supports targeted decompilation of individual types, compilable project generation, IL output, PDB generation, and output truncation for large assemblies.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Path to the `.dll` or `.exe` file |
| `output_dir` | `string\|null` | No | `null` | Directory to save decompiled files (returns inline if omitted) |
| `type_name` | `string\|null` | No | `null` | Fully qualified type name to decompile a single type |
| `language_version` | `string` | No | `"Latest"` | C# syntax version: `CSharp1`--`CSharp12_0`, `Preview`, `Latest` |
| `create_project` | `bool` | No | `false` | Generate a compilable `.csproj` project structure |
| `show_il_code` | `bool` | No | `false` | Output IL bytecode instead of C# |
| `remove_dead_code` | `bool` | No | `false` | Strip unreachable code paths |
| `remove_dead_stores` | `bool` | No | `false` | Strip unused variable assignments |
| `show_il_sequence_points` | `bool` | No | `false` | Include debug sequence points in IL (implies `show_il_code`) |
| `nested_directories` | `bool` | No | `false` | Organize output in namespace-based directory hierarchy |
| `generate_pdb` | `bool` | No | `false` | Generate a portable PDB file (requires `output_dir`) |
| `use_pdb_variable_names` | `bool` | No | `false` | Use original variable names from an existing PDB |
| `max_output_chars` | `int` | No | `100000` | Max inline characters. Excess is saved to a temp file. `0` disables truncation |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "decompile_assembly",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"type_name": "MyApp.Services.AuthService",
"language_version": "Latest"
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("decompile_assembly", {
"assembly_path": "/path/to/MyApp.dll",
"type_name": "MyApp.Services.AuthService",
"language_version": "Latest",
})
```
</TabItem>
</Tabs>
## Response
Returns decompiled C# source code (or IL bytecode) as formatted text. When `output_dir` is provided, files are written to disk and the response confirms the output path. If the output exceeds `max_output_chars`, the full result is saved to a temporary file and a truncated preview is returned with recovery instructions.
<Aside type="tip" title="Usage tips">
- Use `type_name` for targeted decompilation of specific classes instead of the entire assembly.
- Use `create_project` when you need compilable output with a `.csproj` file.
- `generate_pdb` and `use_pdb_variable_names` require `output_dir` to be set.
- If output is truncated, use `decompile_method` to extract individual methods.
</Aside>
## Related tools
- [decompile_method](/reference/tools/decompile-method/) -- extract a single method from a type
- [list_types](/reference/tools/list-types/) -- discover type names before targeted decompilation
- [get_assembly_info](/reference/tools/get-assembly-info/) -- quick reconnaissance before deep-diving

View File

@ -0,0 +1,65 @@
---
title: decompile_method
description: Extract and decompile a specific method from a .NET type.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-decompilation">Decompilation</span>
Extracts a single method from a type within a .NET assembly. Decompiles the containing type, then isolates the named method from the output. Particularly useful when a type is too large to return in full, or when you only need one method's implementation.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Path to the `.dll` or `.exe` file |
| `type_name` | `string` | Yes | -- | Fully qualified type name (e.g., `MyApp.Services.AuthService`) |
| `method_name` | `string` | Yes | -- | Method name to extract (e.g., `Validate`) |
| `show_il_code` | `bool` | No | `true` | Output IL bytecode instead of C# (more reliable for extraction) |
| `language_version` | `string` | No | `"Latest"` | C# syntax version: `CSharp1`--`CSharp12_0`, `Preview`, `Latest` |
| `use_pdb_variable_names` | `bool` | No | `false` | Use original variable names from an existing PDB |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "decompile_method",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"type_name": "MyApp.Services.AuthService",
"method_name": "ValidateToken",
"show_il_code": false
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("decompile_method", {
"assembly_path": "/path/to/MyApp.dll",
"type_name": "MyApp.Services.AuthService",
"method_name": "ValidateToken",
"show_il_code": False,
})
```
</TabItem>
</Tabs>
## Response
Returns the extracted method body as formatted code. If multiple overloads share the same name, all matching overloads are returned with separate headings. IL mode (default) uses ECMA-335 method delimiters for reliable extraction. C# mode uses signature matching with brace-depth counting.
<Aside type="tip" title="Usage tips">
- IL mode (`show_il_code=true`, the default) is more reliable for method extraction because IL has standardized delimiters.
- All overloads with the matching name are returned automatically.
- Use `search_methods` first to find exact method names when you are unsure of the spelling.
</Aside>
## Related tools
- [decompile_assembly](/reference/tools/decompile-assembly/) -- decompile an entire type or assembly
- [search_methods](/reference/tools/search-methods/) -- find method names by pattern before extracting
- [list_types](/reference/tools/list-types/) -- discover fully qualified type names

View File

@ -0,0 +1,57 @@
---
title: dump_package
description: Extract assemblies from a NuGet package into a flat directory for analysis.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-decompilation">Decompilation</span>
Extracts all `.dll` and `.exe` files from a NuGet package folder structure into a single flat directory. This simplifies bulk analysis by collecting assemblies scattered across framework-specific subdirectories into one location where other mcilspy tools can operate on them directly.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Path to the assembly or NuGet package folder to extract from |
| `output_dir` | `string` | Yes | -- | Directory to dump extracted assemblies into (created if needed) |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "dump_package",
"arguments": {
"assembly_path": "/path/to/packages/Newtonsoft.Json/13.0.3",
"output_dir": "/tmp/newtonsoft-dump"
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("dump_package", {
"assembly_path": "/path/to/packages/Newtonsoft.Json/13.0.3",
"output_dir": "/tmp/newtonsoft-dump",
})
```
</TabItem>
</Tabs>
## Response
Returns a summary with the output directory path and a list of all extracted assembly filenames. If no assemblies are found in the package structure, the response indicates that.
<Aside type="tip" title="Usage tips">
- After dumping, use `list_types` or `decompile_assembly` on any of the extracted assemblies.
- Useful for analyzing third-party NuGet dependencies when you need to understand their internals.
- The output directory is created automatically if it does not already exist.
</Aside>
## Related tools
- [list_types](/reference/tools/list-types/) -- explore the types in extracted assemblies
- [decompile_assembly](/reference/tools/decompile-assembly/) -- decompile extracted assemblies
- [get_assembly_info](/reference/tools/get-assembly-info/) -- check metadata of extracted assemblies

View File

@ -0,0 +1,61 @@
---
title: generate_diagrammer
description: Generate an interactive HTML diagram of type relationships in a .NET assembly.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-decompilation">Decompilation</span>
Creates an interactive HTML visualization of type relationships within a .NET assembly. The diagram shows inheritance hierarchies, interface implementations, and namespace organization. Open the generated file in any browser to explore the type graph.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Path to the `.dll` or `.exe` file |
| `output_dir` | `string\|null` | No | `null` | Where to save the HTML file (defaults to a `diagrammer` folder next to the assembly) |
| `include_pattern` | `string\|null` | No | `null` | Regex to include only matching types (e.g., `"MyApp\\.Services\\..+"`) |
| `exclude_pattern` | `string\|null` | No | `null` | Regex to exclude matching types (e.g., `".*Generated.*"`) |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "generate_diagrammer",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"include_pattern": "MyApp\\.Core\\..+",
"exclude_pattern": ".*Tests.*"
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("generate_diagrammer", {
"assembly_path": "/path/to/MyApp.dll",
"include_pattern": r"MyApp\.Core\..+",
"exclude_pattern": r".*Tests.*",
})
```
</TabItem>
</Tabs>
## Response
Returns the path to the generated HTML file along with the output directory. Open the HTML file in a web browser to interactively explore type inheritance, interface implementation, and namespace structure.
<Aside type="tip" title="Usage tips">
- Use `include_pattern` to focus on a specific namespace and keep the diagram readable.
- Use `exclude_pattern` to hide compiler-generated types or test fixtures.
- For very large assemblies, combine both patterns to produce a focused diagram rather than an overwhelming one.
</Aside>
## Related tools
- [list_types](/reference/tools/list-types/) -- discover namespaces before choosing diagram filters
- [search_types](/reference/tools/search-types/) -- find specific types to include or exclude
- [decompile_assembly](/reference/tools/decompile-assembly/) -- deep dive into types visible in the diagram

View File

@ -0,0 +1,63 @@
---
title: get_assembly_info
description: Retrieve metadata and version information from a .NET assembly.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-decompilation">Decompilation</span>
Returns key metadata about a .NET assembly including its name, version, target framework, runtime version, signing status, and debug information availability. A lightweight reconnaissance tool for understanding what kind of binary you are working with before committing to a full decompilation.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Path to the `.dll` or `.exe` file |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "get_assembly_info",
"arguments": {
"assembly_path": "/path/to/MyApp.dll"
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("get_assembly_info", {
"assembly_path": "/path/to/MyApp.dll",
})
```
</TabItem>
</Tabs>
## Response
Returns a structured summary with:
- **Name** and **Full Name** -- assembly identity
- **Version** -- assembly version number
- **Location** -- resolved file path
- **Target Framework** -- .NET Framework, .NET Core, .NET 5+, etc.
- **Runtime Version** -- CLR version the assembly was built against
- **Is Signed** -- whether the assembly has a strong name signature
- **Has Debug Info** -- whether PDB debugging information is available
<Aside type="tip" title="Usage tips">
- Use this as a quick first step before diving into `list_types` or `decompile_assembly`.
- The target framework tells you which .NET runtime the assembly expects, which affects API availability.
- Check `is_signed` for trust verification in security-sensitive contexts.
- If `has_debug_info` is true, consider using `use_pdb_variable_names` in decompilation for better readability.
</Aside>
## Related tools
- [get_metadata_summary](/reference/tools/get-metadata-summary/) -- deeper metadata with type/method counts (uses `dnfile`, no `ilspycmd` needed)
- [list_types](/reference/tools/list-types/) -- explore the assembly's type structure
- [decompile_assembly](/reference/tools/decompile-assembly/) -- full source code recovery

View File

@ -0,0 +1,59 @@
---
title: get_metadata_summary
description: Get assembly statistics and references via comprehensive dnfile analysis.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-metadata">Metadata</span>
Get a comprehensive metadata summary of an assembly. This tool performs a full dnfile analysis of the PE headers and .NET metadata tables -- no ilspycmd required. It returns the assembly identity, statistics across all metadata tables, and a complete list of referenced assemblies.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Full path to the .NET assembly (.dll or .exe) |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "get_metadata_summary",
"arguments": {
"assembly_path": "/path/to/MyApp.dll"
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("get_metadata_summary", {
"assembly_path": "/path/to/MyApp.dll",
})
```
</TabItem>
</Tabs>
## Response
The response includes three sections:
- **Identity** -- assembly name, version, culture, public key token, and target framework
- **Statistics** -- counts for types, methods, fields, properties, events, and resources in a table
- **Referenced Assemblies** -- sorted list of all assemblies this binary depends on
<Aside type="tip">
This is usually the first tool to run when investigating an unknown assembly.
The statistics give you a quick sense of scope (a 5-type library vs. a
2000-type application), and the referenced assemblies reveal which frameworks
and libraries are in play.
</Aside>
## Related Tools
- [`get_assembly_info`](/reference/tools/get-assembly-info/) -- ilspycmd-based metadata (signing, debug info)
- [`list_types`](/reference/tools/list-types/) -- enumerate individual types
- [`list_resources`](/reference/tools/list-resources/) -- list embedded resources

View File

@ -0,0 +1,66 @@
---
title: install_ilspy
description: Automatically install the .NET SDK and ilspycmd across platforms.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-diagnostics">Diagnostics</span>
Install or update `ilspycmd`, the ILSpy command-line decompiler. This tool detects your platform and package manager, optionally installs the .NET SDK if it is missing, and then installs `ilspycmd` as a global .NET tool.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `update` | `bool` | No | `false` | Update ilspycmd to the latest version even if already installed |
| `install_dotnet_sdk` | `bool` | No | `false` | Attempt to install the .NET SDK if it is missing (may require sudo) |
## Supported Platforms
| Platform | Package Manager |
|----------|-----------------|
| Arch / Manjaro / EndeavourOS | `pacman` |
| Ubuntu / Debian / Mint | `apt` |
| Fedora / RHEL / CentOS | `dnf` |
| openSUSE | `zypper` |
| macOS | `homebrew` |
| Windows | `winget` / `chocolatey` |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "install_ilspy",
"arguments": {
"install_dotnet_sdk": true
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("install_ilspy", {
"install_dotnet_sdk": True,
})
```
</TabItem>
</Tabs>
## Response
On success, reports the installed version and path. On failure, returns platform-specific instructions for manual installation. If the .NET SDK is missing and `install_dotnet_sdk` is not set, the response includes the recommended install command for your detected platform.
<Aside type="tip">
For first-time setup, pass `install_dotnet_sdk: true` to handle everything in
one call. After installation, you may need to restart your terminal for PATH
changes to take effect. Run `check_ilspy_installation` to verify.
</Aside>
## Related Tools
- [`check_ilspy_installation`](/reference/tools/check-ilspy-installation/) -- verify installation status
- [`decompile_assembly`](/reference/tools/decompile-assembly/) -- requires ilspycmd
- [`generate_diagrammer`](/reference/tools/generate-diagrammer/) -- requires ilspycmd

View File

@ -0,0 +1,58 @@
---
title: list_events
description: List all events defined in an assembly using direct PE metadata parsing.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-metadata">Metadata</span>
List all events defined in an assembly. This tool reads the Event metadata table directly using dnfile -- no ilspycmd required. Results include the event name, declaring type, and namespace, grouped by fully qualified type name.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Full path to the .NET assembly (.dll or .exe) |
| `type_filter` | `string \| null` | No | `null` | Only list events in types containing this string |
| `namespace_filter` | `string \| null` | No | `null` | Only list events in namespaces containing this string |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "list_events",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"namespace_filter": "MyApp.UI"
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("list_events", {
"assembly_path": "/path/to/MyApp.dll",
"namespace_filter": "MyApp.UI",
})
```
</TabItem>
</Tabs>
## Response
Events grouped by declaring type, each listed with the `event` keyword and name. Results support pagination via `max_results` and `offset` parameters.
<Aside type="tip">
Events reveal the communication patterns within an assembly. Look for them to
understand event-driven architectures, observer patterns, and UI event handlers.
Pair with `search_methods` to find the corresponding `On*` or `Handle*` methods.
</Aside>
## Related Tools
- [`search_methods`](/reference/tools/search-methods/) -- find event handler methods
- [`search_properties`](/reference/tools/search-properties/) -- find related properties
- [`get_metadata_summary`](/reference/tools/get-metadata-summary/) -- see total event count

View File

@ -0,0 +1,55 @@
---
title: list_resources
description: Find embedded resources in an assembly using direct PE metadata parsing.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-metadata">Metadata</span>
List all embedded resources in an assembly. This tool reads the ManifestResource metadata table directly using dnfile -- no ilspycmd required. Results include the resource name and visibility (public or private).
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Full path to the .NET assembly (.dll or .exe) |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "list_resources",
"arguments": {
"assembly_path": "/path/to/MyApp.dll"
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("list_resources", {
"assembly_path": "/path/to/MyApp.dll",
})
```
</TabItem>
</Tabs>
## Response
A sorted list of embedded resources, each showing the resource name and its visibility. Results support pagination via `max_results` and `offset` parameters.
<Aside type="tip">
Embedded resources can contain images, configuration files, localization data,
embedded assemblies, or arbitrary binary data. Look for `.resx` suffixes
(localization), `.resources` (compiled resources), and known file extensions
to understand what the assembly bundles.
</Aside>
## Related Tools
- [`get_metadata_summary`](/reference/tools/get-metadata-summary/) -- see total resource count
- [`search_strings`](/reference/tools/search-strings/) -- find string literals that may reference resources
- [`decompile_assembly`](/reference/tools/decompile-assembly/) -- decompile code that loads resources

View File

@ -0,0 +1,59 @@
---
title: list_types
description: Enumerate all types in a .NET assembly, organized by namespace.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-decompilation">Decompilation</span>
Lists classes, interfaces, structs, delegates, and enums defined in a .NET assembly. Results are grouped by namespace with each type's name, fully qualified name, and kind. This is typically the first tool to reach for when analyzing an unfamiliar assembly.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Path to the `.dll` or `.exe` file |
| `entity_types` | `string[]` | No | `["class"]` | Types to include. Accepts full names or single-letter shortcuts |
**Entity type values:** `class` / `c`, `interface` / `i`, `struct` / `s`, `delegate` / `d`, `enum` / `e`
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "list_types",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"entity_types": ["class", "interface"]
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("list_types", {
"assembly_path": "/path/to/MyApp.dll",
"entity_types": ["class", "interface"],
})
```
</TabItem>
</Tabs>
## Response
Returns types organized by namespace. Each entry includes the type's short name, fully qualified name (e.g., `MyApp.Services.AuthService`), and kind (class, interface, struct, etc.). Results support pagination with `max_results` and `offset` parameters.
<Aside type="tip" title="Usage tips">
- Start here when analyzing an unknown assembly -- the namespace structure reveals the application's architecture.
- Use single-letter shortcuts for brevity: `["c", "i"]` instead of `["class", "interface"]`.
- Pipe the fully qualified names from this tool into `decompile_assembly` with `type_name` for targeted decompilation.
</Aside>
## Related tools
- [search_types](/reference/tools/search-types/) -- find types by name pattern instead of listing all
- [decompile_assembly](/reference/tools/decompile-assembly/) -- decompile types discovered here
- [get_assembly_info](/reference/tools/get-assembly-info/) -- quick metadata before listing types

View File

@ -0,0 +1,65 @@
---
title: search_fields
description: Find fields and constants using direct PE metadata parsing.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-metadata">Metadata</span>
Search for fields in an assembly by name pattern. This tool reads the Field metadata table directly using dnfile -- no ilspycmd required. Results include type information, visibility modifiers, and literal values for constants.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Full path to the .NET assembly (.dll or .exe) |
| `pattern` | `string` | Yes | -- | Search pattern to match against field names |
| `type_filter` | `string \| null` | No | `null` | Only search fields in types containing this string |
| `namespace_filter` | `string \| null` | No | `null` | Only search in namespaces containing this string |
| `public_only` | `bool` | No | `false` | Only return public fields |
| `constants_only` | `bool` | No | `false` | Only return constant (literal) fields |
| `case_sensitive` | `bool` | No | `false` | Whether pattern matching is case-sensitive |
| `use_regex` | `bool` | No | `false` | Treat pattern as a regular expression |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "search_fields",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"pattern": "Key",
"constants_only": true
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("search_fields", {
"assembly_path": "/path/to/MyApp.dll",
"pattern": "Key",
"constants_only": True,
})
```
</TabItem>
</Tabs>
## Response
Fields grouped by declaring type, each showing modifiers (`public`, `static`, `const`) and field name. Results support pagination via `max_results` and `offset` parameters.
<Aside type="tip">
Enable `constants_only` to surface configuration values, magic numbers, API keys,
and hardcoded connection strings. This pairs well with `search_strings` for a
thorough secrets audit.
</Aside>
## Related Tools
- [`search_methods`](/reference/tools/search-methods/) -- find methods by name pattern
- [`search_strings`](/reference/tools/search-strings/) -- search string literals in the #US heap
- [`get_metadata_summary`](/reference/tools/get-metadata-summary/) -- assembly-level statistics

View File

@ -0,0 +1,66 @@
---
title: search_methods
description: Find methods by name pattern using direct PE metadata parsing.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-metadata">Metadata</span>
Search for methods in an assembly by name pattern. This tool reads the MethodDef metadata table directly using dnfile -- no ilspycmd required. Results are grouped by declaring type and include visibility modifiers such as `public`, `static`, `virtual`, and `abstract`.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Full path to the .NET assembly (.dll or .exe) |
| `pattern` | `string` | Yes | -- | Search pattern to match against method names |
| `type_filter` | `string \| null` | No | `null` | Only search methods in types containing this string |
| `namespace_filter` | `string \| null` | No | `null` | Only search in namespaces containing this string |
| `public_only` | `bool` | No | `false` | Only return public methods |
| `case_sensitive` | `bool` | No | `false` | Whether pattern matching is case-sensitive |
| `use_regex` | `bool` | No | `false` | Treat pattern as a regular expression |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "search_methods",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"pattern": "Handle",
"namespace_filter": "MyApp.Services",
"public_only": true
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("search_methods", {
"assembly_path": "/path/to/MyApp.dll",
"pattern": "Handle",
"namespace_filter": "MyApp.Services",
"public_only": True,
})
```
</TabItem>
</Tabs>
## Response
Methods grouped by their declaring type (fully qualified), each showing visibility modifiers. Results support pagination via `max_results` and `offset` parameters.
<Aside type="tip">
Use this tool to find entry points (`Main`), event handlers (`OnClick`, `Handle*`),
lifecycle methods (`Initialize`, `Dispose`), or API endpoints. Pair with
`decompile_method` to extract the full implementation of any match.
</Aside>
## Related Tools
- [`search_fields`](/reference/tools/search-fields/) -- find fields and constants
- [`search_properties`](/reference/tools/search-properties/) -- find properties
- [`decompile_method`](/reference/tools/decompile-method/) -- extract a specific method body

View File

@ -0,0 +1,63 @@
---
title: search_properties
description: Find properties by name pattern using direct PE metadata parsing.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-metadata">Metadata</span>
Search for properties in an assembly by name pattern. This tool reads the Property metadata table directly using dnfile -- no ilspycmd required. Results include the property name and its declaring type, grouped by fully qualified type name.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Full path to the .NET assembly (.dll or .exe) |
| `pattern` | `string` | Yes | -- | Search pattern to match against property names |
| `type_filter` | `string \| null` | No | `null` | Only search properties in types containing this string |
| `namespace_filter` | `string \| null` | No | `null` | Only search in namespaces containing this string |
| `case_sensitive` | `bool` | No | `false` | Whether pattern matching is case-sensitive |
| `use_regex` | `bool` | No | `false` | Treat pattern as a regular expression |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "search_properties",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"pattern": "ConnectionString",
"namespace_filter": "MyApp.Data"
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("search_properties", {
"assembly_path": "/path/to/MyApp.dll",
"pattern": "ConnectionString",
"namespace_filter": "MyApp.Data",
})
```
</TabItem>
</Tabs>
## Response
Properties grouped by declaring type, listing each property name. Results support pagination via `max_results` and `offset` parameters.
<Aside type="tip">
Use this to find configuration properties, data model fields, and API response
shapes. Search for patterns like `Config`, `Settings`, `Options`, or `Url` to
quickly map an application's configurable surface area.
</Aside>
## Related Tools
- [`search_fields`](/reference/tools/search-fields/) -- find fields and constants
- [`search_methods`](/reference/tools/search-methods/) -- find methods by name pattern
- [`decompile_assembly`](/reference/tools/decompile-assembly/) -- decompile a type to see property implementations

View File

@ -0,0 +1,63 @@
---
title: search_strings
description: Find hardcoded string literals embedded in a .NET assembly.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-decompilation">Decompilation</span>
Searches the User Strings (`#US`) heap in the assembly metadata for string literals matching a pattern. This reads directly from metadata without decompilation, making it significantly faster than IL-based approaches. Essential for security audits, finding configuration values, and locating embedded URLs or credentials.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Path to the `.dll` or `.exe` file |
| `pattern` | `string` | Yes | -- | String pattern to search for |
| `case_sensitive` | `bool` | No | `false` | Case-sensitive matching |
| `use_regex` | `bool` | No | `false` | Treat pattern as a regular expression |
| `max_results` | `int` | No | `100` | Maximum number of matches to return |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "search_strings",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"pattern": "https://",
"use_regex": false,
"max_results": 50
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("search_strings", {
"assembly_path": "/path/to/MyApp.dll",
"pattern": "https://",
"max_results": 50,
})
```
</TabItem>
</Tabs>
## Response
Returns a list of matching string literals found in the assembly. Long strings are truncated to 200 characters for display. The total match count is shown, with a note when results are capped at `max_results`.
<Aside type="tip" title="Usage tips">
- This tool uses `dnfile` for direct metadata access -- it does not require `ilspycmd` to be installed.
- Use regex patterns like `"https?://"` or `"password|secret|key"` for broader security sweeps.
- Pair with `decompile_assembly` using `show_il_code` to find which methods reference the strings you discover.
</Aside>
## Related tools
- [search_fields](/reference/tools/search-fields/) -- find constant fields and configuration values
- [decompile_assembly](/reference/tools/decompile-assembly/) -- trace string usage in decompiled code
- [get_metadata_summary](/reference/tools/get-metadata-summary/) -- assembly overview before string searching

View File

@ -0,0 +1,65 @@
---
title: search_types
description: Find types in a .NET assembly by name pattern, with optional namespace and entity type filtering.
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
<span class="tool-badge tool-badge-decompilation">Decompilation</span>
Searches for types whose names match a given pattern. Faster than listing all types when you know what you are looking for. Supports substring matching, regex, namespace filtering, and entity type filtering. Results are grouped by namespace.
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `assembly_path` | `string` | Yes | -- | Path to the `.dll` or `.exe` file |
| `pattern` | `string` | Yes | -- | Search pattern to match against type names |
| `namespace_filter` | `string\|null` | No | `null` | Only return types in namespaces containing this string |
| `entity_types` | `string[]` | No | all | Types to search: `class`, `interface`, `struct`, `delegate`, `enum` |
| `case_sensitive` | `bool` | No | `false` | Case-sensitive pattern matching |
| `use_regex` | `bool` | No | `false` | Treat pattern as a regular expression |
## Example
<Tabs>
<TabItem label="MCP JSON">
```json
{
"tool": "search_types",
"arguments": {
"assembly_path": "/path/to/MyApp.dll",
"pattern": "Service",
"namespace_filter": "MyApp.Core",
"entity_types": ["class", "interface"]
}
}
```
</TabItem>
<TabItem label="Python">
```python
result = await client.call_tool("search_types", {
"assembly_path": "/path/to/MyApp.dll",
"pattern": "Service",
"namespace_filter": "MyApp.Core",
"entity_types": ["class", "interface"],
})
```
</TabItem>
</Tabs>
## Response
Returns matching types grouped by namespace. Each entry shows the type name, fully qualified name, and kind. Supports pagination via `max_results` and `offset`.
<Aside type="tip" title="Usage tips">
- Common search patterns: `"Service"`, `"Controller"`, `"Handler"`, `"Exception"`.
- Enable `use_regex` for patterns like `"I.*Service"` to find service interfaces.
- Combine `namespace_filter` with `pattern` to narrow results in large assemblies.
</Aside>
## Related tools
- [list_types](/reference/tools/list-types/) -- list all types without filtering
- [decompile_assembly](/reference/tools/decompile-assembly/) -- decompile the types you find
- [search_methods](/reference/tools/search-methods/) -- search for methods instead of types

View File

@ -0,0 +1,52 @@
@import "tailwindcss";
/* Steel blue + amber on dark slate — hex editor / debug output aesthetic */
:root {
--sl-color-accent-low: #451a03;
--sl-color-accent: #f59e0b;
--sl-color-accent-high: #fef3c7;
--sl-color-white: #f1f5f9;
--sl-color-gray-1: #cbd5e1;
--sl-color-gray-2: #94a3b8;
--sl-color-gray-3: #64748b;
--sl-color-gray-4: #475569;
--sl-color-gray-5: #1e293b;
--sl-color-gray-6: #0f172a;
--sl-color-black: #020617;
}
:root[data-theme="light"] {
--sl-color-accent-low: #fef3c7;
--sl-color-accent: #d97706;
--sl-color-accent-high: #78350f;
--sl-color-white: #0f172a;
--sl-color-gray-1: #1e293b;
--sl-color-gray-2: #334155;
--sl-color-gray-3: #64748b;
--sl-color-gray-4: #94a3b8;
--sl-color-gray-5: #e2e8f0;
--sl-color-gray-6: #f1f5f9;
--sl-color-black: #f8fafc;
}
/* Splash page hero adjustments */
.hero .hero-html img,
.hero .hero-html svg {
max-height: 280px;
width: auto;
}
/* Feature matrix table on splash/overview pages */
.feature-matrix table {
font-size: 0.875rem;
}
.feature-matrix th {
white-space: nowrap;
}
.feature-matrix td code {
font-size: 0.8rem;
}

View File

@ -0,0 +1,71 @@
/* Tool category badges */
.tool-badge {
display: inline-block;
padding: 0.125rem 0.625rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.025em;
margin-bottom: 0.75rem;
}
.tool-badge-decompilation {
background: #fef3c7;
color: #92400e;
}
.tool-badge-metadata {
background: #dbeafe;
color: #1e40af;
}
.tool-badge-diagnostics {
background: #dcfce7;
color: #166534;
}
:root[data-theme="dark"] .tool-badge-decompilation {
background: #78350f;
color: #fde68a;
}
:root[data-theme="dark"] .tool-badge-metadata {
background: #1e3a5f;
color: #93c5fd;
}
:root[data-theme="dark"] .tool-badge-diagnostics {
background: #14532d;
color: #86efac;
}
/* Tool overview feature matrix cards */
.tool-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0.75rem;
margin: 1rem 0;
}
.tool-card {
padding: 0.75rem 1rem;
border-radius: 0.5rem;
border: 1px solid var(--sl-color-gray-5);
background: var(--sl-color-gray-6);
}
.tool-card h4 {
margin: 0 0 0.25rem;
font-size: 0.875rem;
}
.tool-card p {
margin: 0;
font-size: 0.8rem;
color: var(--sl-color-gray-3);
}
/* Parameter tables on tool reference pages */
.sl-markdown-content table code {
white-space: nowrap;
}

3
docs-site/tsconfig.json Normal file
View File

@ -0,0 +1,3 @@
{
"extends": "astro/tsconfigs/strict"
}