Skip to content

MCP Management

lqdflying edited this page Sep 18, 2026 · 10 revisions

MCP Management

ChatHub provides a settings page for managing MCP plugins at Settings → MCP library. It uses a two-panel layout (list + detail) for browsing installed plugins.

ChatHub supports Streamable HTTP MCP servers only. The application server owns the MCP connection, OAuth credentials, protocol client, and tool-result persistence. It does not start local commands or provide stdio MCP transport.

HTTP MCP tool calls continue after you close the tab, using tokens already stored in PostgreSQL. ChatHub remains HTTP-only; stdio MCP is still unsupported. See Background Conversation Generation.


Access

Navigate to Settings (gear icon) → MCP library. This page lists all installed MCP plugins and lets you add, edit, or remove them.


Two-Panel Layout

The MCP library uses a split layout:

  • Left panel: Scrollable list of installed MCP plugins with a search bar and an Add MCP Plugin action.
  • Right panel: Detail view for the selected plugin showing metadata, configuration, and action buttons (Edit, Uninstall).

When no plugin is selected, the right panel shows an empty state prompting you to select a plugin.


Installing MCP Plugins

From Settings

  1. Click Add MCP Plugin
  2. Enter the plugin name, description, and MCP server URL
  3. Configure authentication:
    • OAuth 2.1: If the server supports auto-discovery, click Authorize to complete the OAuth flow. If not, enter the Client ID manually.
    • API Key: Enter the API key directly.
    • None: No authentication required.
  4. Save

Marketplace entries that provide only a local command are not shown. Custom manifests without an HTTP URL are rejected.


Editing MCP Plugins

Click a plugin in the left panel, then click Edit in the detail panel. This opens PluginDevModal with the plugin's current configuration pre-filled.

Key Prop (Critical for Edit Mode)

PluginDevModal populates its form in a useEffect that runs only on mount. Without a key prop, switching between plugins leaves stale form data.

Always pass key={identifier || 'create'} to PluginDevModal to force React to unmount and remount the component when switching plugins.


PluginDevModal Props Reference

Prop Type Notes
mode 'create' or 'edit' Controls drawer title and footer
open boolean
onOpenChange (open: boolean) => void
value LobeToolCustomPlugin Plugin data to pre-fill (edit mode)
onSave (value: LobeToolCustomPlugin) => Promise<void> Call installCustomPlugin (create) or updateCustomPlugin (edit)
onDelete () => void Edit mode only -- call uninstallCustomPlugin
onValueChange (value: Partial<LobeToolCustomPlugin>) => void Always pass updateNewCustomPlugin from store
key string CRITICAL -- identifier for edit, 'create' for add

Uninstalling MCP Plugins

Select a plugin, then click Uninstall in the detail panel. This removes the plugin from the database and the installed list.

An existing plugin record created by an older desktop edition may still contain a stdio command. ChatHub marks that record unsupported and allows it to be removed, but it cannot connect to or edit it into a runnable local process.


OAuth Authorization Flow

When adding an MCP plugin with OAuth 2.1 authentication:

  1. Paste the MCP server URL and click Discover
  2. The server's OAuth metadata is auto-discovered via RFC 9728 + RFC 8414
  3. If dynamic client registration succeeds, fill in Client ID automatically
  4. If registration fails, enter the Client ID manually
  5. Click Authorize -- a popup window opens to the OAuth provider's authorization page
  6. Complete authorization in the popup
  7. The popup closes and the form is pre-filled with the result

Post-Connection Token Management

OAuth tokens are stored server-side in the mcp_oauth_tokens PostgreSQL table. The MCP client automatically:

  • Injects the access token into MCP requests
  • Refreshes expired tokens proactively
  • Retries on 401 with a fresh token

See the MCP OAuth wiki for full details.


Filtering MCP Plugins

In the codebase, installed plugins live in useToolStore(pluginSelectors.installedPlugins). MCP plugins are those with customParams?.mcp:

const installedPlugins = useToolStore(pluginSelectors.installedPlugins, isEqual);
const mcpPlugins = installedPlugins.filter(p => !!p.customParams?.mcp);

For the list display (with metadata like title, description, avatar), use pluginSelectors.installedPluginMetaList.


Store Operations

const [installCustomPlugin, updateCustomPlugin, uninstallCustomPlugin, updateNewDevPlugin] =
  useToolStore((s) => [
    s.installCustomPlugin,   // create new plugin
    s.updateCustomPlugin,    // update existing (id, value)
    s.uninstallCustomPlugin, // remove by identifier
    s.updateNewCustomPlugin, // update draft state for DevModal
  ]);

Always call useFetchInstalledPlugins() to load the installed plugin list from the database on mount.


Empty State

When no MCP plugins are installed, the page shows an empty state with an Add MCP Plugin button.


Connection Reliability

MCP connections recover automatically from common failures:

  • Expired server sessions: if the MCP server drops the streamable-HTTP session, the tool call fails over to a fresh connection and retries once. Tool-level errors returned by the server are never retried, so a mutating tool is never executed twice. That guarantee is strict: only a raw connection-level failure (the server never saw your request) triggers the retry — an error response the MCP server itself produced is always surfaced to the model as-is, even when its text happens to mention the session.
  • Slow handshakes: connecting to an unresponsive MCP server times out after 30 seconds instead of hanging.
  • Repeatedly failing servers: after 3 consecutive connection-level failures, calls to that server fail fast for 60 seconds (instead of each attempt hanging for the full tool timeout), then a trial request is allowed through.
  • Dead connections: a crashed or unreachable server is dropped from the connection cache immediately, and idle connections are reclaimed automatically.
  • Cancellation: stopping a generation (or closing the browser request) aborts the in-flight MCP call instead of letting it run to the full timeout.

Model-Boundary Hygiene

Tool metadata and results are sanitized before they reach the model:

  • Description scrubbing: MCP tool descriptions are server-controlled text. Classic prompt-injection imperatives (for example "ignore all previous instructions") are redacted and descriptions are capped at 1,200 characters when tools are discovered.
  • Protocol metadata stripped: _meta fields on tool results (reserved for MCP protocol extensions) are removed before the result is shown to the model; the tool's own data payload is passed through untouched.
  • Stable tool ordering: the tool list sent to the model is sorted by tool name, so identical tool sets produce byte-identical requests across turns — this keeps provider prompt caches warm.

Operator environment variables:

Variable Default Purpose
MCP_TOOL_TIMEOUT 60000 Maximum time (ms) for a single MCP tool call
MCP_INITIALIZATION_TIMEOUT 30000 Maximum time (ms) to establish an MCP connection
MCP_CLIENT_IDLE_TTL_MS 1800000 Evict cached MCP connections idle longer than this
MCP_CLIENT_CACHE_MAX_SIZE 100 Maximum cached MCP connections (least-recently-used evicted)

Clone this wiki locally