MCP tools

connectMcpTools connects remote HTTP or SSE MCP servers, merges their tools into a turn, and returns cleanup for the handler to run when the request settles. Local stdio subprocess transport is not supported.

code
import { connectMcpTools }
  from '@mordn/chat-widget/server/mcp';
 
createChatHandler({
  getUserId: getChatUserId,
  model,
  store,
  buildTools: async (ctx) =>
    connectMcpTools(await resolveAgentMcpServers(ctx)),
});

Server configuration

code
const servers = [
  {
    id: 'linear',
    label: 'Linear',
    url: 'https://mcp.linear.app/sse',
    transport: 'sse',
    headers: { Authorization: `Bearer ${developerToken}` },
    namespaceTools: true,
  },
];

Connections are isolated per server. Failures appear in results and do not block healthy servers. Namespacing avoids collisions, and cleanup is idempotent.

Hosted management API

@mordn/chat-api exposes tenant-key-authenticated endpoints:

EndpointPurpose
GET /v1/mcpList servers with credential values redacted
GET /v1/mcp/connectServer-to-server read of enabled connection details
POST /v1/mcpAdd a server with a read-write key
PATCH /v1/mcp/:idUpdate a server with a read-write key
DELETE /v1/mcp/:idRemove a server with a read-write key

The API key fixes tenant and agent scope. Credentials stay on the server.

Warning

The shipped hosted surface is developer-managed and agent-wide. One workspace developer connects a provider for the agent, and enabled tools are shared by that agent's users. Per-end-user OAuth/provider accounts are a separate future trust boundary and are not implemented by these endpoints. Do not store an end user's token in the agent-wide record.

The dashboard's current Integrations manager reflects this developer-owned surface. Custom MCP remains an advanced path; catalog-managed providers must not allow the browser to override backend-owned endpoints or header names.