命令行AI聊天工具

MCP Chat是一个基于OpenAI模型的命令行交互式AI聊天应用,支持文档检索、命令提示和可扩展工具集成。

  • by AlleninTaipei
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 AlleninTaipei/MCPChat

使用说明

MCP聊天

本项目基于并修改自 人类学在线学习课程原版通过Google Vertex AI使用了Anthropic的Claude;此版本已迁移为使用OpenAI API。

MCP Chat是一个用于交互式AI聊天的命令行界面应用程序,由OpenAI模型提供支持。它支持通过以下方式进行文档检索 @mentions,基于命令的提示通过 /commands,以及通过MCP(模型上下文协议)架构的可扩展工具集成。

先决条件

设置

步骤1:配置环境变量

创建或编辑 .env 项目根目录中的文件:

OPENAI_API_KEY="sk-..."       # Your OpenAI API key
OPENAI_MODEL="gpt-4o-mini"    # Or any other OpenAI model (e.g. gpt-4o)
USE_UV=1                       # Set to 0 if not using uv

步骤2:安装依赖项

选项1:使用紫外线(推荐)

紫外线 是一个快速的Python包安装程序和解析器。

  1. 如果尚未安装,请安装uv:
pip install uv
  1. 安装依赖项:
uv sync
  1. 运行项目:
uv run main.py

选项2:使用普通pip

  1. 创建并激活虚拟环境:
python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
  1. 安装依赖项:
pip install openai python-dotenv prompt-toolkit "mcp[cli]>=1.8.0"
  1. 运行项目:
python main.py

用法

基本聊天

键入您的信息,然后按Enter键:

> What is the capital of France?

文献检索

使用 @ 后面是文档ID,以便在查询中包含文档的内容:

> Summarize @deposition.md

文档直接注入到提示符中,不需要额外的工具调用。

命令

使用 / 运行MCP服务器中定义的预定义提示命令:

> /summarize deposition.md

按 Tab 自动完成可用命令和文档ID。

加载其他MCP服务器

启动应用程序时,将额外的服务器脚本作为参数传递:

uv run main.py my_custom_server.py

MCP 检查员

MCP Inspector是一个基于浏览器的工具,用于检查和测试您的MCP服务器——您可以浏览可用的工具、资源和提示,并在不运行完整应用程序的情况下以交互方式调用它们。

要启动它:

uv run mcp dev mcp_server.py

然后打开终端中显示的URL(通常 http://localhost:5173)在您的浏览器中。

使用检查器的提示

  • 通话时 read_doc_contents,使用包括扩展名在内的完整文件名作为 doc_id例如。 deposition.md.
  • 可用的文档ID包括: deposition.md, report.pdf, financials.docx, outlook.pdf, plan.md, spec.txt.

为什么编辑不会出现在 mcp_server.py

你可能会注意到,打电话后 edit_document 在检查员中 docs 里面的字典 mcp_server.py 不会改变。这是意料之中的,理解为什么是一个有用的教训。

这 docs 迪克住在 存储器(RAM),不在文件中。当服务器启动时,Python读取 mcp_server.py 和负载 docs 进入记忆。 edit_document 修改内存中的副本,这就是为什么后续 read_doc_contents 调用返回更新的内容。但源文件本身从未被触及——它只是食谱书。厨师在记事本上写字,而不是回到书上。

重新启动服务器时,记事本会被丢弃 docs 从原始源文件重新加载,因此所有编辑都消失了。

这是当前设计的一个已知局限性。如果您希望编辑在重新启动后仍然有效, docs 需要由真实的存储(JSON文件、SQLite等)而不是内存中的字典来支持。

端到端测试

验证整个系统是否正常工作的最快方法是按顺序运行以下五种情况:

1.基本聊天 --确认OpenAI连接

> What is 1 + 1?

2. @ 文件注入 --确认MCP服务器正在运行,文档内容已注入提示

> What is @deposition.md about?

3.工具使用 --确认代理循环、ToolManager和MCP工具执行均正常工作

> Use the read_doc_contents tool to read report.pdf and tell me what it says.

4.工具使用+编辑 --确认多回转刀具的使用和内存编辑

> Use edit_document to change the word "condenser" to "cooling" in report.pdf, then read it back to confirm.

5. / 命令 --确认MCP提示检索和完整的命令管道

> /format financials.docx

每个案例都练习堆栈的不同层。如果所有五个都通过,则验证整个端到端流。

期间会发生什么 /format

这 /format 命令很好地说明了所有层是如何协同工作的:

  1. _process_command() 在 core/cli_chat.py 检测 / 前缀并获取 format 来自MCP服务器的提示
  2. 提示指示模型使用Markdown重新格式化文档并使用 edit_document 保存结果的工具
  3. 模型调用 edit_document --代理循环 core/chat.py 检测 finish_reason == "tool_calls" 并执行该工具
  4. 结果被添加回消息历史记录中,循环再次运行,模型输出最终格式化的文档

有一件事需要注意: 如果原始文档很短(如 financials.docx,这只是一句话),该模型可能会发明听起来合理的内容——预算数字、类别等。--来源中不存在。这是LLM的正常行为:当信息稀疏时,模型会填充看似合理的内容,而不是说“我不知道”

在实际应用中,通过在提示符中添加显式指令来防止这种情况: 仅使用文档中已有的信息,不要添加任何新内容。

为什么你只需要跑 main.py

你可能会想知道为什么 mcp_server.py 和 mcp_client.py 不需要单独启动。答案就在 main.py --它发射 mcp_server.py 自动作为a 子进程:

command, args = ("uv", ["run", "mcp_server.py"])

doc_client = await stack.enter_async_context(
    MCPClient(command=command, args=args)
)

MCPClient.connect() 将此命令交给操作系统,操作系统将启动 mcp_server.py 作为背景过程。然后,这两个过程会相互讨论 stdin/stdout --这是MCP的stdio传输。

You run: uv run main.py
              │
              ├── spawns subprocess ──→ mcp_server.py (background process)
              │                               ↑ ↓  stdin / stdout
              └── MCPClient ─────────────────┘
                  (mcp_client.py, imported as a class)
  • mcp_server.py 是 由...推出 main.py --你从不手动启动它
  • mcp_client.py 是 作为类导入 --这不是你运行的脚本
  • 当 main.py 退出后,子流程将通过以下方式自动清理 AsyncExitStack

使用stdin/stdout作为传输的原因是,它使MCP服务器与语言无关——服务器可以用Python、Node.js或Rust编写。只要它在标准I/O上讲MCP协议,客户端就不在乎。


发展

添加新文档

编辑 docs 字典在 mcp_server.py 添加新文档。

添加新的MCP服务器

任何实现MCP协议的Python脚本都可以作为参数传递给 main.py每个服务器都作为自己的子进程运行,并将其工具自动暴露给模型。

过梁和类型检查

当前未配置棉绒或类型检查。


奖金:什么是紫外线和紫外线?

让我们从类比开始

想象一下,你是一位有很多食谱(项目)的厨师,每个食谱都需要不同的食材(包装)。

问题是:配方A要求“酱油v1.0”,配方B要求“酱油v2.0”,这两个版本不兼容,它们的API不匹配。如果你的厨房(你的电脑)只有一瓶酱油,你就卡住了。

venv和uv都是为了解决这个问题而存在的。

什么是venv?

venv 是Python内置的用于创建“虚拟环境”的工具。

虚拟环境背后的想法很简单:它在项目文件夹中创建Python运行时的独立副本,因此为此项目安装的包与其他项目完全隔离,不会相互干扰。

python -m venv .venv        # Create a virtual environment (creates the .venv folder)
source .venv/bin/activate   # "Enter" this environment
pip install openai          # Now openai is installed only for this project

这 openai 您在此项目中安装的包不会影响计算机上的任何其他项目。这就是“隔离”的意思。

这 .venv 文件夹包含Python及其所有包的独立副本,这就是为什么它的大小通常是几百MB:它确实是一个完整的运行时环境。

紫外线是什么?

uv 是一种更现代的工具,取代了以下组合 pip 和 venv.

把它看作是 venv + pip +包版本锁定,所有这些都捆绑在一个更快、更智能的工具中。

# The old way (three steps)
python -m venv .venv
source .venv/bin/activate
pip install openai

# The uv way (one step)
uv add openai

是什么让紫外线更好?

1.快得离谱

pip 一次安装一个软件包,按顺序下载和安装。 uv 它是用Rust编写的,几乎完全并行工作,速度提高了10到100倍。

2.自动 .venv 管理

您不需要手动运行 python -m venv .venv 然后激活它。运行 uv run main.py 自动找到(或创建)正确的虚拟环境,并在其中运行脚本。

3.锁定文件(版本锁定)

这 uv.lock 项目中的文件记录了每个包的确切版本。这意味着,即使你几个月后换了电脑,或者把项目交给同事,运行 uv sync 恢复完全相同的环境,避免了经典的“在我的机器上工作”问题。

背后到底发生了什么 uv run python -c?

uv 是Astral团队开发的Python包和项目管理器,最近在Python生态系统中非常流行。Astral也是著名的Python linter背后的团队 Ruff. uv 它本身是用Rust编写的,因此它的核心特征是速度、简单性和可重复性。

核心工具: uv

uv的目标是取代像 pip, pip-tools, venv,以及 pyenv它最显著的特点是速度极快,通常比传统的Python包管理工具快10到100倍。

  • 由Rust提供支持:它利用了Rust的并发性和高效的内存管理,使包解析和安装非常快。
  • 一个二进制: uv 是一个独立的工具,因此在使用之前不需要预先配置Python环境。
  • 全局缓存: uv 使用内容寻址存储。如果多个项目使用同一个包,则只需要在磁盘上保留一个副本;当构建环境时, uv 通过硬链接将其链接到项目中,这样可以快速安装并节省磁盘空间。

分解命令: uv run

uv run 是其中之一 uv的最强大的功能,您可以将其视为“按需环境管理”。

  • 自动创建虚拟环境:运行时 uv run, uv 检查当前目录中是否已存在可用的虚拟环境。如果没有,它会自动创建 .venv 并确保依赖关系与项目配置相匹配。
  • 无缝的脚本依赖集成:如果Python脚本在顶部包含PEP 723之后的元数据, uv run 可以根据该元数据自动准备脚本所需的包。一旦脚本完成,就不需要手动清理任何临时环境。

分解命令: python -c

python -c 是一个标准的Python功能,意思是“将以下字符串作为Python代码执行”。

uv run python -c "print('hello from uv')"

在这里, -c 代表命令,它通常用于快速测试、单行脚本或在shell脚本中嵌入一小段Python逻辑。

把它放在一起: uv run python -c "..."

以下是运行此命令时发生的情况:

uv run python -c "..."

它触发了现代Python执行工作流:

  1. 环境准备: uv 快速确认当前项目具有正确的Python虚拟环境。
  2. 依赖解析:如果代码或脚本元数据需要特定的包, uv 确保它们已安装。
  3. 代码执行: uv 在之后运行代码 python -c 在孤立的项目环境中。
  4. 一致性:只要 uv 如果在计算机上可用,则同一命令更有可能在不同计算机上产生一致的结果,而无需手动运行 pip install 或者首先激活虚拟环境。

视觉摘要

Your computer
│
├── Project A/
│   └── .venv/          ← Project A's independent environment
│       └── openai 1.0
│
├── Project B/
│   └── .venv/          ← Project B's independent environment
│       └── openai 2.0
│
└── System Python        ← Best to avoid installing anything here

每 .venv 它是一个独立的泡沫,与其他泡沫隔绝。 uv 是为您管理这些泡沫的现代工具。

你真正需要记住的命令

场景 命令
首次设置项目 uv sync
添加包 uv add openai
删除包 uv remove anthropic
运行程序 uv run main.py

无需手动激活。不要摆弄pip。紫外线处理一切。