McpSource.ListMcpToolsAsync
C# · package Toolnexus · SPEC §2 · McpSource.cs
public static Task<McpSource.McpInventory> ListMcpToolsAsync(object input, CancellationToken cancellationToken = default)Connects to every enabled server, lists its tool definitions, and disconnects before returning —
no toolkit, no ExecuteAsync wiring, nothing left running. The result is a plain
McpInventory { Tools, Status }:
Tools—server → IReadOnlyList<ToolInfo>, eachToolInfo(Name, Description, InputSchema)using the original, unprefixed tool name (not theserver_toolname a connectedMcpSourcewould expose).Status—server → "connected" | "disabled" | "failed", same vocabulary asLoadAsync.
The returned inventory is unfiltered by any per-server tools allowlist — it exists to author or
validate that allowlist, so it needs to see everything a server offers.
When to use it
Section titled “When to use it”Building a config UI or a CLI that shows “here’s what mcp.json would give you” without paying for a
live toolkit. Also the right call for authoring a per-server tools allowlist: list first, see the
real names, then write the allowlist against them.
Why this and not the alternative
Section titled “Why this and not the alternative”Examples
Section titled “Examples”1. A disabled server never connects, and reports no tools
Section titled “1. A disabled server never connects, and reports no tools”using Toolnexus;
var config = new Dictionary<string, object?>{ ["mcpServers"] = new Dictionary<string, object?> { ["docs_demo"] = new Dictionary<string, object?> { ["type"] = "local", ["command"] = new[] { "echo", "hi" }, ["enabled"] = false, }, },};
var inventory = await McpSource.ListMcpToolsAsync(config);
if (inventory.Status["docs_demo"] != "disabled") throw new Exception(inventory.Status["docs_demo"]);if (inventory.Tools.ContainsKey("docs_demo")) throw new Exception("a disabled server has no tool list");
Console.WriteLine($"ok: {inventory.Status["docs_demo"]}");2. A server that can’t spawn is “failed”, not fatal
Section titled “2. A server that can’t spawn is “failed”, not fatal”using Toolnexus;
var config = new Dictionary<string, object?>{ ["mcpServers"] = new Dictionary<string, object?> { ["broken"] = new Dictionary<string, object?> { ["type"] = "local", ["command"] = new[] { "toolnexus-docs-nonexistent-binary-xyz" }, ["timeout"] = 2_000, }, },};
var inventory = await McpSource.ListMcpToolsAsync(config);
if (inventory.Status["broken"] != "failed") throw new Exception(inventory.Status["broken"]);if (inventory.Tools.ContainsKey("broken")) throw new Exception("a failed server has no tool list");
Console.WriteLine($"ok: {inventory.Status["broken"]}");3. Inventory the shared fixture, gated for a hermetic run
Section titled “3. Inventory the shared fixture, gated for a hermetic run”using Toolnexus;
var repo = Environment.GetEnvironmentVariable("TOOLNEXUS_REPO") ?? ".";var fixture = Path.Combine(repo, "examples", "mcp.json");
// Parse the real fixture, then gate every server off so this doc example never dials out —// the shape (parse -> gate -> inventory) is what an "author the allowlist" tool would run.var config = McpSource.ParseConfig(fixture);foreach (var (_, value) in config) ((IDictionary<string, object?>)value!)["enabled"] = false;
var inventory = await McpSource.ListMcpToolsAsync(config);
if (inventory.Status.Values.Any(s => s != "disabled")) throw new Exception($"unexpected: {string.Join(",", inventory.Status.Values)}");if (inventory.Tools.Count != 0) throw new Exception("no server connected, so no tool lists");
Console.WriteLine($"ok: {string.Join(", ", inventory.Status.Keys.OrderBy(k => k))} all disabled");Fields
Section titled “Fields”| Field | Type | What it is |
|---|---|---|
McpInventory.Tools |
IReadOnlyDictionary<string, IReadOnlyList<ToolInfo>> |
Per-server tool defs, unfiltered by any allowlist. |
McpInventory.Status |
IReadOnlyDictionary<string, string> |
server → "connected" | "disabled" | "failed". |
ToolInfo.Name |
string |
The original, unprefixed MCP tool name. |
ToolInfo.Description |
string |
|
ToolInfo.InputSchema |
IDictionary<string, object?> |
The built JSON-Schema object (same shape LoadAsync uses). |
See also
Section titled “See also”McpSource.LoadAsync— Read an mcp.json, connect every local stdio and remote streamable-HTTP server, expose each server tool as a Tool.McpSource.LoadAsync— The ctx-aware load: bound connection time and cancel a slow or hung server without leaking a child process.McpSource.ParseConfig— Parse and validate config without connecting — the fast fail for a malformed or misspelled server block.McpSource.ElicitationToRequest— Map an MCP server’s elicitation request onto the §10 suspension contract, and map the answer back.