本地聊天客户端

一个轻量级的本地优先聊天客户端,连接至MCP服务器并流式传输来自OpenAI或Ollama模型的响应。单用户,无云后端,对话存储在本地存储中,OAuth令牌在服务器内存中。

  • by adolfoweloy
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 adolfoweloy/open-mcp-dev

使用说明

MCP聊天

一个轻量级的本地第一聊天客户端,连接到 主控程序 服务器和流式传输来自OpenAI或Ollama模型的响应。单用户,无云后端——对话持久存在于本地存储中,OAuth令牌存在于服务器上的内存中。

MCP工具可以在沙盒iframe中呈现交互式UI小部件。iframe协议与ChatGPT Apps SDK兼容。

入门

# Install dependencies (npm workspaces)
npm install

# Create your config file
cp config.example.yaml config.yaml

编辑 config.yaml 要添加至少一个LLM提供程序,请执行以下操作:

llm:
  openai:
    api_key: "sk-..."
    default_model: "gpt-4o"
  ollama:
    base_url: "http://localhost:11434"  # default

可选择在以下位置添加MCP服务器 mcp_servers: --看 config.example.yaml 用于stdio、HTTP和OAuth示例。

如何跑步

启动Express服务器(端口3000)和Vite-dev服务器(端口5173):

# In separate terminals:
npm run dev:server
npm run dev:client

然后打开 http://localhost:5173Vite-dev服务器代理 /api/* 请求表达。

如何构建

npm run build

这将编译服务器 tsc 并使用Vite构建客户端。在生产中,Express将Vite构建作为静态文件提供。

如何测试

npm test

服务器测试使用Node的内置测试运行器;客户端测试使用Vitest。

如何剥皮

npm run lint        # TypeScript type-checking (both workspaces)
npm run typecheck   # Same as lint

架构概述

图层 技术
服务器 Node.js+Express 4+TypeScript
客户端 React 19+Vite 6+顺风CSS 4
LLM流媒体 Vercel AI SDK(ai v4)
MCP客户端 @modelcontextprotocol/sdk v1
配置 config.yaml (单个文件,gitignored)

目录结构:

server/       Express backend — chat streaming, MCP client management, OAuth
client/       React frontend — chat UI, conversation management, iframe widgets
shared/       Shared TypeScript types
specs/        Feature specs and architecture docs
config.yaml   Runtime config (gitignored, copy from config.example.yaml)

请求流

  1. 用户发送消息;客户端POST到 /api/chat 包含对话历史记录、选定模型和活动MCP服务器列表。
  2. 服务器调用 streamText (Vercel AI SDK, maxSteps: 20)注入了来自连接的MCP服务器的所有工具。
  3. 当LLM调用工具时,执行包装器会调用 client.callTool(...) 关于相关 MCPClientManager 连接,并返回下一LLM步骤的结果。
  4. 该流作为Vercel AI SDK数据流返回给客户端(text/plain, X-Vercel-AI-Data-Stream: v1);调试事件(LLM步骤、工具调用、OAuth流)被复用到同一流中。

MCP连接

MCPClientManager 拥有服务器端的所有MCP客户端连接:

  • STDIO服务器使用 StdioClientTransport;HTTP服务器尝试 StreamableHTTPClientTransport 首先,然后回到 SSEClientTransport
  • 工具名称的命名空间为 {serverId}__{toolName} (工具名称中的连字符变为下划线)
  • OAuth2服务器使用授权码+PKCE和RFC 7591动态客户端注册;令牌刷新和401排队是自动的

MCP UI小部件

当工具结果包括 _meta["ui/resourceUri"],聊天UI呈现沙盒iframe。iframe src 通过代理 /api/mcp/resource/{serverId}?uri=...,它在服务器端获取MCP资源HTML并直接返回。

小部件通过JSON-RPC 2.0与主机通信 postMessage握手是由小部件启动的(ui/initialize);主机响应后,小部件接收工具参数和结果。从那里,小部件可以:

  • 直接调用工具(tools/call)不涉及LLM
  • 发送后续用户消息(ui/message)触发新的LLM转弯
  • 请求全屏(ui/request-display-mode)

模型选择

GET /api/models 返回已配置的OpenAI模型和实时Ollama模型的联合(从Ollama获取 /api/tags 端点)。这两个供应商都是通过以下方式驱动的 @ai-sdk/openai --避免使用Ollama的原生AI SDK提供商,因为它会默默地丢弃工具调用令牌。系统提示在中按提供程序配置 config.yaml.

有关完整的架构详细信息,请参阅 规格/架构.md.

配置

所有配置都存在 config.yaml 在项目的根。不需要环境变量。

第节 目的
llm.openai OpenAI API密钥,默认模型,系统提示
llm.ollama Ollama基本URL,系统提示
mcp_servers MCP服务器定义(stdio、HTTP或HTTP+OAuth)

看 config.example.yaml 以获取完整参考。