{"id":49992837,"url":"https://github.com/pedrosakuma/dotnet-assembly-mcp","last_synced_at":"2026-06-03T22:00:23.623Z","repository":{"id":358758169,"uuid":"1242922219","full_name":"pedrosakuma/dotnet-assembly-mcp","owner":"pedrosakuma","description":"MCP server for static navigation of .NET assemblies — types, methods, attributes, decompilation. Companion to dotnet-diagnostics-mcp.","archived":false,"fork":false,"pushed_at":"2026-05-22T17:25:14.000Z","size":700,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-31T18:33:29.060Z","etag":null,"topics":["ai-agents","assembly","decompiler","dotnet","ilspy","llm","mcp","mcp-server","reflection","static-analysis"],"latest_commit_sha":null,"homepage":"https://github.com/pedrosakuma/dotnet-diagnostics-mcp","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pedrosakuma.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-18T22:14:55.000Z","updated_at":"2026-05-22T17:25:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pedrosakuma/dotnet-assembly-mcp","commit_stats":null,"previous_names":["pedrosakuma/dotnet-assembly-mcp"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/pedrosakuma/dotnet-assembly-mcp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrosakuma%2Fdotnet-assembly-mcp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrosakuma%2Fdotnet-assembly-mcp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrosakuma%2Fdotnet-assembly-mcp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrosakuma%2Fdotnet-assembly-mcp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pedrosakuma","download_url":"https://codeload.github.com/pedrosakuma/dotnet-assembly-mcp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrosakuma%2Fdotnet-assembly-mcp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33876330,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","assembly","decompiler","dotnet","ilspy","llm","mcp","mcp-server","reflection","static-analysis"],"created_at":"2026-05-19T06:01:03.972Z","updated_at":"2026-06-03T22:00:23.616Z","avatar_url":"https://github.com/pedrosakuma.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dotnet-assembly-mcp\n\n\u003e **Status:** 22 tools shipped, dual transport (stdio + HTTP), packaged as `dotnet tool`, Docker image, and self-contained single-file binaries. Latest release: [`v0.14.0`](https://github.com/pedrosakuma/dotnet-assembly-mcp/releases) — collapsed `find_member_references` (field/property/event in one tool) and `get_method_il(format=raw|text|scan)` (issue #83, breaking).\n\nAn **MCP server** for *static* navigation of compiled .NET assemblies — types, methods, attributes, signatures, IL, cross-references, and on-demand decompilation — designed as a **token-efficient alternative to feeding source code into an LLM context**.\n\n## Why\n\nWhen an AI agent needs to understand what a method does, the default today is to read the source file. For a 1,000-LOC class that's ~4–8k tokens, and most of it is irrelevant.\n\nThis server lets the agent **drill down**:\n\n```\nload_assembly(path)                  →  moduleVersionId + method count   (~30 tokens)\nget_method(mvid, token)              →  signature, attributes, IL size   (~30 tokens)\nget_method_il(mvid, token, format='raw')   →  raw IL hex, instruction count    (~80 tokens)\nget_method_il(mvid, token, format='scan')  →  outbound calls / fields / types  (~150 tokens)\ndecompile_method(mvid, token)        →  C# body, hard-capped             (~200–500 tokens)\nfind_callers(mvid, token)            →  reverse call graph (intra+cross) (~100 tokens)\nget_method_source(mvid, token)       →  PDB file/lines + SourceLink URL  (~40 tokens)\n```\n\nClosed generic instantiations are first-class: `get_method` / `find_callers` accept `genericTypeArguments` so the agent gets `int Echo(int)` instead of `T Echo(T)` and `find_callers` narrows to callers whose `MethodSpec` matches the requested instantiation. Producers that already have a `MethodSpec` row in the caller's module can skip the string-rendering step and supply `methodSpecModuleVersionId` + `methodSpecMetadataToken` as a fast-path; when both forms are present they are cross-checked and a mismatch yields `generic_instantiation_mismatch`. See [`docs/handoff-contract.md §3.5`](./docs/handoff-contract.md#35-generic-instantiations).\n\nThe agent pays only for what it actually needs to see.\n\n## Install\n\nFor the full guide (single-file binaries, systemd / launchd / Scheduled Task supervisors, Kubernetes manifest), see [`docs/consumer-install.md`](./docs/consumer-install.md).\n\n### As a global `dotnet tool` (stdio — local MCP clients)\n\n```bash\ndotnet tool install -g dotnet-assembly-mcp\ndotnet-assembly-mcp --stdio    # speak MCP over STDIN/STDOUT\n```\n\nRequires the .NET 10 runtime. Logs go to STDERR so STDOUT stays a clean JSON-RPC channel.\n\n### As a Docker image (HTTP — sidecar / multi-client)\n\n```bash\ndocker run --rm -p 8788:8080 \\\n  -v /path/to/assemblies:/assemblies:ro \\\n  ghcr.io/pedrosakuma/dotnet-assembly-mcp:latest\n# MCP endpoint: http://localhost:8788/mcp\n# Health:       http://localhost:8788/health\n```\n\nOr build locally: `docker build -t dotnet-assembly-mcp:dev -f deploy/Dockerfile .`.\n\n### Joint with `dotnet-diagnostics-mcp` (recommended, optional)\n\nThe diagnostics server emits `MethodIdentity` / `TypeIdentity` handles. As of\n[`dotnet-diagnostics-mcp` #28](https://github.com/pedrosakuma/dotnet-diagnostics-mcp/issues/28),\nthe diagnostics server already resolves PDBs locally and stamps `SourceLocation` directly\nonto every CPU-sample hotspot identity — so for dev workflows where the source tree is open\nin your editor, the diagnostics server is sufficient on its own.\n\nPairing **this** server with diagnostics is recommended when you also want:\n\n- Stripped binaries / NativeAOT (no PDB, no inline source).\n- Third-party assemblies you don't have source for.\n- Decompilation (`decompile_method`), reverse cross-reference (`find_callers`, `find_type_references`, …).\n\nRun both together:\n\n```bash\nexport ASSEMBLIES_DIR=/abs/path/to/your/published/binaries\ndocker compose -f deploy/docker-compose.yml up -d\n# diagnostics: http://localhost:8787/mcp\n# assembly:    http://localhost:8788/mcp\n```\n\nThe same `docker-compose.yml` ships in\n[`pedrosakuma/dotnet-diagnostics-mcp:deploy/docker-compose.yml`](https://github.com/pedrosakuma/dotnet-diagnostics-mcp/blob/main/deploy/docker-compose.yml)\n— bring it up from either checkout. Set `MCP_BEARER_TOKEN` on the host to\ngate both servers with one shared token.\n\n## Verifying releases\n\nEvery release artifact (NuGet package, self-contained binary archive, GHCR\ncontainer image) is published with a **SLSA build provenance attestation**\ngenerated by [`actions/attest-build-provenance`](https://github.com/actions/attest-build-provenance)\nand signed by Sigstore via GitHub's OIDC issuer. The attestation proves the\nartifact was built by this repository on a specific commit by GitHub-hosted\nrunners — no separate cert to install, no key to rotate.\n\nVerify with the GitHub CLI:\n\n```bash\n# NuGet package\ngh attestation verify dotnet-assembly-mcp.0.18.0.nupkg \\\n  --repo pedrosakuma/dotnet-assembly-mcp\n\n# Self-contained binary tarball / zip\ngh attestation verify dotnet-assembly-mcp-0.18.0-linux-x64.tar.gz \\\n  --repo pedrosakuma/dotnet-assembly-mcp\n\n# Container image (attestation is published to the registry alongside the image)\ngh attestation verify oci://ghcr.io/pedrosakuma/dotnet-assembly-mcp:0.18.0 \\\n  --repo pedrosakuma/dotnet-assembly-mcp\n```\n\nA passing verification confirms the build came from `pedrosakuma/dotnet-assembly-mcp`\non the expected commit and tag.\n\n## Client configuration\n\n### Claude Desktop / Cursor / VS Code / Copilot CLI (stdio)\n\n`mcp.json` (Claude Desktop: `~/Library/Application Support/Claude/claude_desktop_config.json`):\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"dotnet-assembly-mcp\": {\n      \"command\": \"dotnet-assembly-mcp\",\n      \"args\": [\"--stdio\"]\n    }\n  }\n}\n```\n\nIf the tool isn't on `PATH`, point `command` at the absolute path (e.g. `~/.dotnet/tools/dotnet-assembly-mcp`).\n\n### Streamable HTTP\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"dotnet-assembly-mcp\": {\n      \"url\": \"http://localhost:8788/mcp\"\n    }\n  }\n}\n```\n\n## Tools\n\nAll tools share the same response envelope (`summary`, `data`, `hints`, `error`); `hints` advertise the suggested next tool so an agent can chain without rediscovering the API. Cross-module xref tools (`find_callers`, `find_type_references`, `find_member_references`, `find_string_references`, `find_attribute_targets`, `list_derived_types`) all use the same matching convention: same-module hits by metadata token, cross-module hits by `(assembly simple name, type full name, member signature)` against the child module's `TypeRef` / `MemberRef` rows.\n\n### Discovery \u0026 loading\n| Tool | Purpose |\n|---|---|\n| `load_assembly` | Load a `.dll`/`.exe` from disk (idempotent by MVID) |\n| `list_assemblies` | List currently loaded modules |\n| `list_assembly_references` | Outbound `AssemblyRef` rows for one module |\n| `list_resources` | `ManifestResource` rows (embedded resources) for one module |\n| `import_assembly_manifest` | Bulk-register a list of paths under configured roots |\n\n### Type \u0026 method enumeration (Tier-1)\n| Tool | Purpose |\n|---|---|\n| `list_types` | Paginated TypeDef listing, filterable by namespace / name / kind |\n| `get_type` | Resolve `(mvid, token)` to a type summary (base type, interfaces, kind) |\n| `list_derived_types` | Walk subclasses **and** interface implementers across every loaded module (`directOnly` / transitive) |\n| `list_members` | Enumerate fields / properties / events of a type |\n| `list_methods` | Paginated MethodDef listing, filterable by declaring type |\n| `find_method` | Module-wide MethodDef search by regex on name / signature |\n| `list_attributes` | Custom attributes on a module / type / method / parameter / field / property / event |\n\n### Single-method resolution (Tier-2 / Tier-3)\n| Tool | Purpose |\n|---|---|\n| `get_method` | Resolve `(mvid, token)` to a method summary; accepts `genericTypeArguments` / `genericMethodArguments` for a closed signature view |\n| `get_method_il` | IL reader for a method, dispatched by `format`: `raw` (hex IL bytes + max-stack + counts), `text` (ildasm-style textual dump, capped + LRU-cached), `scan` (structured outbound references — calls, fields, types, strings) |\n| `decompile_method` | C# body via ICSharpCode.Decompiler (hard-capped, LRU-cached) |\n| `decompile_type` | C# decompilation of a whole TypeDef — members in declaration order (hard-capped, LRU-cached) |\n| `get_method_source` | PDB-resolved file/lines plus SourceLink URL (embedded PDB or sibling `.pdb`) |\n\n### Reverse cross-reference (Tier-4)\n| Tool | Purpose |\n|---|---|\n| `find_callers` | Every method whose IL calls a given method; narrows by instantiation when `genericMethodArguments` is supplied |\n| `find_type_references` | Every site referencing a TypeDef (field/parameter/return/local types + `newobj` / `castclass` / `isinst` / `box` / `ldtoken` / generic args) |\n| `find_member_references` | Inbound xref for a field, property, or event — dispatched by handle prefix (`f:` / `p:` / `e:`); `accessor` narrows property to getter/setter and event to add/remove/raise |\n| `find_string_references` | Every method whose IL emits `ldstr` for a given literal (exact / contains / regex) |\n| `find_attribute_targets` | Reverse custom-attribute index: every assembly/type/method/parameter/field/property/event bearing a given attribute |\n\n## CLI (human-driven front-end)\n\nThe same engine ships as a standalone terminal tool, **`dotnet-assembly-cli`**, for when *you*\n(not an agent) want to navigate an assembly. It is a thin shell over the same orchestration the\nMCP server uses — every MCP tool has a matching subcommand — but renders human-readable text by\ndefault instead of an MCP envelope.\n\n```bash\ndotnet tool install -g dotnet-assembly-cli\ndotnet-assembly-cli --help        # list every subcommand\ndotnet-assembly-cli list-types --help\n```\n\n### A worked walkthrough\n\nStart from a path, drill down to a method, then pivot through the call graph — the same\nloop an agent runs, but readable in your terminal. (Paths must be **absolute**; the index\nkeys modules by MVID, not by relative path.)\n\n```bash\nDLL=$(realpath ./bin/Release/net10.0/MyLib.dll)\n\n# 1. What's in here? (a path-taking command loads the module for you)\ndotnet-assembly-cli list-types \"$DLL\"\n#   25 type(s).\n#   ...\n#     FullName: SampleLib.OrderService\n#     Handle:   t:b613bdf8-…:0x02000007\n\n# 2. Find a method by name regex — gives you its (mvid, token) + handle\ndotnet-assembly-cli find-method \"$DLL\" \"Process\"\n#   3 match(es) for /Process/.\n#     Handle:    m:b613bdf8-…:0x0600000D\n#     Signature: int SampleLib.OrderService.Process(int)\n\n# 3. Decompile it (--assembly loads the module before resolving the token)\ndotnet-assembly-cli decompile-method b613bdf8-… 0x0600000D --assembly \"$DLL\"\n#   SampleLib.OrderService.Process — 240 chars of C#.\n#   Source:\n#     public int Process(int orderId) { _counter++; … }\n\n# 4. Who calls it? --load primes the index so the handle resolves\ndotnet-assembly-cli --load \"$DLL\" find-callers b613bdf8-… 0x0600000D\n#   1 caller(s) in 1 module (built).\n#     Display: SampleLib.OrderService+\u003cProcessAsync\u003ed__6.MoveNext\n\n# Pipe any command through --json for the full MCP-shaped envelope\ndotnet-assembly-cli --load \"$DLL\" find-callers b613bdf8-… 0x0600000D --json | jq '.Data.Callers'\n```\n\n### Shortcut: `explain-type` / `explain-method`\n\nSteps 1–3 above chase a handle and a token by hand — fine for an agent, tedious for a human.\nThe two **composed** commands collapse that loop: give them an assembly plus a **type name**\n(and optionally a **method name**) and they resolve everything internally.\n\n```bash\n# Whole-type overview in one shot: summary, attributes, members and methods grouped.\ndotnet-assembly-cli explain-type \"$DLL\" SampleLib.OrderService\n\n# A method by name — every overload, each with its source location (file:line via PDB).\ndotnet-assembly-cli explain-method \"$DLL\" SampleLib.OrderService Process\n\n# Add --decompile to print the C# body under each overload.\ndotnet-assembly-cli explain-method \"$DLL\" SampleLib.OrderService Compute --decompile\n\n# Who transitively calls a method? A recursive caller tree, resolved by name.\ndotnet-assembly-cli callgraph \"$DLL\" SampleLib.OrderService Compute --depth 3\n\n# What changed in the public surface between two builds of an assembly?\ndotnet-assembly-cli diff-assemblies \"$OLD_DLL\" \"$NEW_DLL\"\n```\n\n`explain-method` matches the method name **exactly** by default (and lists near-misses if there\nis none); pass `--contains` for substring matching. Both honour the global `--json` flag, which\nemits the full `AssemblyResult` envelope instead of the human text view.\n\n`callgraph` builds one tree per matched overload, drawing each method's (transitive) callers\nacross all loaded modules. Bound it with `--depth` (caller levels, default 3) and `--max-nodes`\n(total nodes, default 200); nodes are marked `[cycle]` for recursion and `[more callers not\nshown]` when the depth limit is reached. It is a MethodDef/IL call-path tree, so generic methods\nappear once (not per closed instantiation).\n\n`diff-assemblies` compares the **externally-visible public surface** of two assemblies (a type is\nvisible only when its whole declaring chain is public): types added / removed, and, for types in\nboth, public / protected members added / removed / signature-changed plus type-shape changes\n(kind / base / interfaces). Member identity is name + generic arity + parameter list, so a\nreturn-type, visibility or modifier (`static` / `virtual` / `abstract` / `sealed` / `readonly` /\n`const`) change on the same signature is reported as a change rather than an add + remove.\nProperty / event accessors appear as their `get_` / `set_` / `add_` / `remove_` methods. Finding\ndifferences still exits 0 (a diff is not an error); only an unreadable input assembly exits 1.\nType identity is compared by full name (signatures render type references by full name without\nassembly identity), so a type that keeps its full name but moves to a different assembly — e.g. a\ndependency version swap or type forward — is not flagged as a change.\n\n### Subcommands\n\nThe 22 MCP tools each have a matching 1:1 subcommand, plus four human-oriented composed commands:\n\n| Group | Commands |\n|---|---|\n| **Lifecycle** | `load`, `list-assemblies`, `import-manifest` |\n| **Methods** | `get-method`, `decompile-method`, `decompile-type`, `get-method-il`, `list-methods`, `find-method`, `find-callers`, `get-method-source` |\n| **Types** | `list-types`, `list-assembly-references`, `list-resources`, `list-attributes`, `get-type`, `list-derived-types`, `list-members` |\n| **References** | `find-string-references`, `find-attribute-targets`, `find-member-references`, `find-type-references` |\n| **Analysis (composed)** | `explain-type`, `explain-method`, `callgraph`, `diff-assemblies` |\n\nRun `dotnet-assembly-cli \u003ccommand\u003e --help` for each command's arguments and options.\n\n### Global options \u0026 exit codes\n\nTwo options are honoured by every subcommand:\n\n| Option | Effect |\n|---|---|\n| `--json` | Emit the full `AssemblyResult` envelope as indented JSON (scriptable; identical to the MCP `data`). Without it, you get a human-readable rendering of the result. |\n| `--load \u003cpath\u003e` | Load an assembly into the index before the command runs. Repeatable. Because the CLI is one-shot, a handle (`m:\u003cmvid\u003e:0x…`) only resolves once its module is loaded — `--load` (or a path-taking subcommand such as `find-method`, or a token command's `--assembly`) is how you do that. |\n\n| Exit code | Meaning |\n|---|---|\n| `0` | Success. |\n| `1` | The operation returned an error result (e.g. unknown MVID, absolute-path violation), or no command/an unknown command was given. The error message is printed to **stderr**. |\n| `2` | Invalid argument value (e.g. an unparseable `--kind` / `--mode`). |\n\nThe architecture: a shared **`DotnetAssemblyMcp.Application`** project holds the tool orchestration;\nthe MCP `Server` and the `Cli` are both thin hosts over it, so the two never drift.\n\n## Companion project\n\nScope-disjoint from [`pedrosakuma/dotnet-diagnostics-mcp`](https://github.com/pedrosakuma/dotnet-diagnostics-mcp), which performs **dynamic** diagnostics (attach, EventPipe sampling, GC, exceptions) on a running .NET process. Together they form a closed loop:\n\n```\n[dotnet-diagnostics-mcp]            [dotnet-assembly-mcp]\n   ──────────────────────             ──────────────────────\n   list_dotnet_processes              load_assembly\n   collect_cpu_sample        ──┐  ┌─→ get_method\n   collect_exceptions          │  │   get_method_il (format='scan')\n                               │  │   decompile_method\n                               ▼  │   find_callers\n                        (MethodIdentity)\n```\n\nThe handoff contract — `MethodIdentity = (moduleVersionId, metadataToken)` plus optional `genericTypeArguments` (§3.5) — lives in [`docs/handoff-contract.md`](./docs/handoff-contract.md) and is also served at `assembly://contract/method-identity` as an MCP resource.\n\n### MCP resources\n\nIn addition to the tool surface, the server publishes a small set of read-only **resources** that MCP clients can subscribe to or fetch directly. None of them require a tool call:\n\n| URI                                 | Content |\n|-------------------------------------|---------|\n| `assembly://contract/method-identity` | Full text of [`docs/handoff-contract.md`](./docs/handoff-contract.md) — the producer/consumer wire contract for `MethodIdentity`. |\n| `assembly://manifest/loaded`        | JSON array of every currently-loaded module (`mvid`, `path`, `methodCount`). Mirrors `list_assemblies` without consuming a tool slot. |\n| `assembly://manifest/loaded/{mvid}` | JSON object for one module by MVID. Returns 404-style empty body when the MVID isn't loaded. |\n\nClients that support resource subscriptions get a notification whenever the loaded-module set changes (e.g. after `load_assembly` or a file-watcher reload).\n\n## Where it complements SourceLink\n\nThis server **does not** replace SourceLink / TraceLog source resolution. It is what the agent reaches for when:\n\n- the deployed binary has no PDB or no SourceLink,\n- the target is a third-party NuGet dependency,\n- the runtime is NativeAOT-trimmed and metadata at runtime is sparse,\n- or the agent just wants a structural overview without pulling 8 KB of source.\n\n`get_method_source` is the second-chance source resolver: it reads the on-disk PDB (embedded portable PDB first, then sibling `.pdb`) so the agent doesn't need a separate SourceLink fetch when one is available locally.\n\n## Building blocks\n\n- [`System.Reflection.Metadata`](https://learn.microsoft.com/dotnet/standard/metadata-and-self-describing-components) — metadata-only reads, never `Assembly.Load`\n- [`ICSharpCode.Decompiler`](https://github.com/icsharpcode/ILSpy) — full decompiler engine used by ILSpy\n- [`ModelContextProtocol`](https://github.com/modelcontextprotocol/csharp-sdk) C# SDK 1.3.0\n- [`System.CommandLine`](https://github.com/dotnet/command-line-api) — argument parsing for the `dotnet-assembly-cli` front-end\n\n## License\n\nMIT — see [`LICENSE`](./LICENSE).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpedrosakuma%2Fdotnet-assembly-mcp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpedrosakuma%2Fdotnet-assembly-mcp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpedrosakuma%2Fdotnet-assembly-mcp/lists"}