Architecture
Overview
@johannes.latzel/llm-chat-mcp bridges the @johannes.latzel/llm-chat tool
ecosystem with the Model Context Protocol. It takes Tool and
ToolPackage instances, converts their JSON Schema parameter definitions to
Zod schemas for validation, and exposes them over stdio or HTTP through the MCP
SDK.
Class hierarchy
BaseMcpServer (abstract)
├── StdioMcpServer — stdin/stdout transport
└── HttpMcpServer — Streamable HTTP transport (Express)
BaseMcpServer
- Stores the
serverInfometadata and a list of registered items register(item)stores the item and registers its tools on the SDK'sMcpServercreateFreshMcpServer()creates a brand-newMcpServerwith all previously registered tools replayed — used byHttpMcpServerto give each HTTP session its own isolated server instancestop()calls theonStop()lifecycle hook then closes the server- Subclasses implement
start()to connect their transport
StdioMcpServer
start()creates aStdioServerTransportand connects- Suitable for MCP clients that spawn a child process (e.g. VS Code, Claude Desktop)
HttpMcpServer
- Express-based server listening on a configurable port
- Provides a single route
POST /mcp(Streamable HTTP) - Multi-session architecture: each HTTP client gets its own
(StreamableHTTPServerTransport, McpServer)pair, keyed by theMcp-Session-Idheader - Session map access is protected by an
async-mutexMutexto prevent concurrent modification from overlapping requests
Request routing (/mcp)
| Method | Session ID header | Action |
|---|---|---|
| DELETE | present | Disconnect that session |
| DELETE | missing | 404 |
| POST | present | Route to existing session |
| POST | missing | Create a new session |
| GET | present | Route to existing session |
| GET | missing | 400 |
| Other | — | 400 |
Lifecycle
constructor(info)— initialises Express app and wires routesregister(item)— tools must be registered beforestart()(they are copied into each per-sessionMcpServerat creation time)start()— begins listening on the configured port- Client sends
POST /mcp(initialize) →handleCreateSessioncreates a transport, connects a freshMcpServer, stores the session, forwards the response - Subsequent requests include
Mcp-Session-Id→ routed viahandleExistingSession DELETE /mcp→handleDeleteremoves and closes the sessionstop()→onStop()snapshots and clears all sessions, closes each transport, then stops Express
Internal converters
toolSchemaToZod (schema-converter.ts)
Converts the JSON Schema output from Tool.toOpenAI().function.parameters into
a Zod object schema. Supports: string, number, integer, boolean,
array (with nested items), object (with nested properties). Recursively
handles required/optional fields and description annotations.
toolResultsToMcp (result-converter.ts)
Converts an array of llm-chat ToolResult into the MCP CallToolResult shape.
Maps each result to a { type: "text", text: string } content entry. Sets
isError: true when any result has a non-success status.
Public API surface
All public exports come from src/index.ts — the lib/ converters and the
McpSession type are internal.
Dependencies
| Package | Role |
|---|---|
@johannes.latzel/llm-chat |
Tool / ToolPackage framework |
@modelcontextprotocol/sdk |
MCP protocol, transports |
express |
HTTP server |
async-mutex |
Session map synchronisation |
zod |
Runtime schema validation |