Skip to content

McpSource.listMcpTools

Java · package io.github.muthuishere:toolnexus · SPEC §2 · McpSource.java

public static McpInventory listMcpTools(Object input)
public static McpInventory listMcpTools(Object input, CancelSignal cancel)
public record ToolInfo(String name, String description, Map<String, Object> inputSchema) {}
public record McpInventory(Map<String, List<ToolInfo>> tools, Map<String, String> status) {}

Connects to every enabled server, lists its tool definitions, and disconnects immediately — no Toolkit wiring, no execute() routing, nothing left running afterward. The inventory is keyed by server name and is unfiltered by the per-server tools allowlist: this call exists precisely so you can see the full set and decide what that allowlist should be.

When you want to inspect what a config would expose — for a setup UI, a --dry-run, writing the tools: {...} allowlist for a server config, or a health check — without paying for a live toolkit or leaving a child process / HTTP connection open. Same failure isolation as load: one bad server is "failed", the rest still list.

The ToolInfo names here are the original, unprefixed server tool names — load’s Tool.name() is <server>_<tool> after sanitizing. Use listMcpTools’s names when authoring a server’s tools: {name: bool} allowlist (§2 Gap 7), since that filter is keyed on the original name too.

1. Inventory from a hermetic, all-disabled config

Section titled “1. Inventory from a hermetic, all-disabled config”
import io.github.muthuishere.toolnexus.*;
import java.util.Map;
public class Example {
public static void main(String[] args) throws Exception {
Map<String, Object> config = Map.of(
"mcpServers", Map.of(
"off", Map.of("command", java.util.List.of("x"), "enabled", false)
)
);
McpSource.McpInventory inv = McpSource.listMcpTools(config);
if (!"disabled".equals(inv.status().get("off"))) throw new AssertionError(inv.status());
if (inv.tools().containsKey("off")) throw new AssertionError("disabled server shouldn't list");
System.out.println("ok: " + inv.status());
}
}

2. A failed server reports status but never throws

Section titled “2. A failed server reports status but never throws”
import io.github.muthuishere.toolnexus.*;
import java.util.Map;
public class Example {
public static void main(String[] args) throws Exception {
Map<String, Object> config = Map.of(
"mcpServers", Map.of(
"broken", Map.of(
"command", java.util.List.of("/no/such/binary-toolnexus-docs-example"),
"timeout", 2000
)
)
);
McpSource.McpInventory inv = McpSource.listMcpTools(config);
if (!"failed".equals(inv.status().get("broken"))) throw new AssertionError(inv.status());
if (inv.tools().containsKey("broken")) throw new AssertionError("failed server has no tools entry");
System.out.println("ok: " + inv.status());
}
}

3. Cancelling the whole listing — same CancelSignal idiom as loadWith

Section titled “3. Cancelling the whole listing — same CancelSignal idiom as loadWith”
import io.github.muthuishere.toolnexus.*;
import java.util.Map;
import java.util.concurrent.CancellationException;
public class Example {
public static void main(String[] args) throws Exception {
Map<String, Object> config = Map.of(
"mcpServers", Map.of("never-runs", Map.of("command", java.util.List.of("x")))
);
McpSource.CancelSignal alreadyCancelled = () -> true;
boolean threw = false;
try {
McpSource.listMcpTools(config, alreadyCancelled);
} catch (CancellationException e) {
threw = true;
}
if (!threw) throw new AssertionError("expected CancellationException");
System.out.println("ok: listing aborted via CancelSignal");
}
}
Member Type What it is
ToolInfo.name() String Original, unprefixed server tool name.
ToolInfo.description() String Empty string when the server sent none.
ToolInfo.inputSchema() Map<String,Object> Normalized: type:object, properties:{} default, additionalProperties:false.
McpInventory.tools() Map<String, List<ToolInfo>> Keyed by server name; absent key for disabled/failed servers.
McpInventory.status() Map<String,String> Per server: connected | disabled | failed.