MCP Server Integration#
Decant ingests and displays MCP (Model Context Protocol) tool calls from both Claude Code and Codex sessions, giving them first-class treatment in the archive database and transcript UI. The system classifies every tool call by inspecting its name, populates dedicated mcp_server and tool_base_name columns in the tool_call table, and renders MCP invocations distinctly from built-in tools.
Naming Convention: mcp__<server>__<base>#
All MCP tool names follow the pattern mcp__<server>__<base>, where the mcp__ prefix identifies the kind, the next __-delimited segment is the server name, and the remainder is the base tool name. The base name may itself contain __ or dots (e.g., mcp__codex_apps__slack.slack_read_thread).
Examples:
mcp__dosu__read_knowledgeβ serverdosu, baseread_knowledgemcp__dosu__whoamiβ serverdosu, basewhoamimcp__codex_apps__slack.slack_read_threadβ servercodex_apps, baseslack.slack_read_thread
During Codex ingest, the parser normalizes names: if the server segment does not already start with mcp__, the prefix is prepended automatically .
Classification: classifyTool()#
classifyTool(name) in src/tools.ts is the single authority for splitting a tool name into its three components:
kind:"mcp"if the name starts withmcp__; otherwise"builtin".mcpServer: the server segment (between the first and second__), ornullif absent.baseName: everything after the server segment (or the full name minusmcp__if there is no server__).
The returned ClassifiedTool object drives two downstream consumers:
-
Ingest (
src/ingest.ts):classifyTool()is called for everytool_useblock. The resolvedkind,mcpServer, andbaseNameare written into thetool_calltable astool_kind,mcp_server, andtool_base_name. This makes MCP server and tool identity queryable without parsing raw tool names. -
UI rendering (
src/ui/transcript-rendering.ts):presentationForTool()callsclassifyTool()to determine how to render a tool block. Ifkind === "mcp", it returns a{ kind: "json", language: "json", source: "mcp" }presentation, rendering the tool input as highlighted JSON labeled as an MCP call .
Database Schema#
The tool_call table stores three MCP-specific columns :
| Column | Description |
|---|---|
tool_kind | "mcp" or "builtin" |
mcp_server | Server name extracted from the mcp__<server>__ prefix, or NULL for built-ins |
tool_base_name | Base tool name (post-server segment) |
To query all MCP calls programmatically, filter on tool_kind = 'mcp' or mcp_server IS NOT NULL.
UI Display#
Tools table (src/ui/tool-table-layout.ts): The "tools" table layout includes a col-tool-server column that shows the MCP server name alongside the tool name and kind.
MCP server summary table: A dedicated "mcp" table layout aggregates MCP calls per server with columns for server name, distinct tools used, call count, error count, and last invocation time (with optional elapsed-time column).
Transcript rendering: MCP tool input is rendered as pretty-printed JSON with source: "mcp" via presentationForTool() . This is the first branch checked β before shell, file read/write, edit, or grep patterns β so any mcp__-prefixed tool gets the MCP path regardless of its base name.
Dosu-specific tools: isDosuToolName() and dosuToolDisplayName() in src/ui/dosu-tool.ts wrap classifyTool() to detect and label tools from the dosu MCP server, showing the base name (e.g., read_knowledge) rather than the full prefixed name.
MCP server display names: Raw server slugs like claude_ai_Dosu, plugin_posthog_posthog, and dosu are transformed into readable display names for UI presentation. Namespace prefixes (claude_ai_, plugin_*_) are stripped, segments are split on delimiters (-, _) and title-cased, and camelCase slugs gain initial capitals while keeping internal ones. formatMcpServer() produces the short name for a single slug, but the same logical server may reach the archive under three different slug namespaces (bare id, connector, plugin). Simply prettifying each slug independently is lossy: distinct registrations collapse onto identical display names and read as duplicated rows rather than the two real registrations they are.
To address this, mcpServerLabels() builds a context-aware map across a whole set of servers. It keeps the short name where unambiguous and appends an origin suffix only where two or more slugs format to the same name (e.g., "Dosu (local)" vs "Dosu (connector)"). The UI constructs the label map from the union of both the Tools and MCP tables (since each is paginated independently), ensuring consistent naming across tables, filters, Insights cards, and the standalone HTML report. Display names appear in all UI text, but filter values, drilldown URLs, API payloads, and database rows preserve the raw slug, which remains the canonical identity.
Legacy: Exec-Wrapped MCP Calls#
Older Codex logs routed some MCP calls through a functions.exec wrapper, producing a function_call with name = "exec". These are classified as kind: "builtin" with mcp_server = NULL and appear in the UI as generic exec tool rows. The nested mcp__<server>__<base> name and arguments survive only in the raw input column .
Key Source Files#
| File | Role |
|---|---|
src/tools.ts | classifyTool() β naming convention parser |
src/ingest.ts | Writes tool_kind, mcp_server, tool_base_name to DB |
src/ui/transcript-rendering.ts | presentationForTool() β MCP rendering path |
src/ui/dosu-tool.ts | Dosu-server detection and display name helpers |
src/ui/tool-table-layout.ts | "mcp" and "tools" table column definitions |
src/mcp-names.ts | Display name formatting, namespace stripping, and disambiguation logic for MCP server slugs |
src/ui/mcp-server.ts | UI wrapper for the MCP names module |