首页
看点啥
插画图片
首页 看点啥 MCP + npm:为五年前的老系统接上AI

MCP + npm:为五年前的老系统接上AI

2026-07-22 0

前言

那套 Web 系统,当年立项时 PPT 写得天花乱坠,如今打开后台——日活两位数的,一位是测试,一位是你自己刷新页面。

同事嘴上说「早该重构了」,手上却在问 ChatGPT:「帮我把这个文件夹里的报表下下来。」AI 能聊、能写、能画图,就是进不了你们内网那扇登录页的门——不是 AI 不行,是老系统没给它发工牌。

所谓「赋能」,听起来像董事会词汇,落地就一件事:别让 Agent 重新发明一套登录和下载,而是让它走你们现成的 API。 用户还是在浏览器里扫码登录;Token 进 MCP 进程内存;Agent 说「列一下文件」「下这个附件」,和你们页面点按钮,打的是同一批接口。

本文不讲微服务改造、不上 Kubernetes,只讲怎么用 Node + npm + MCP,给「没人用但还不能关」的老系统,挂一条 AI 能走的旁路。老系统负责活着,AI 负责干活——分工明确,各得其所。


你已经有一套 web 系统:用户登录后就能列文件、下载文件。目标不是改业务栈,而是:

  1. npm 把 MCP Server 做成可安装、可发布的包;
  2. 在任意支持 MCP 的 Agent 客户端里用 npx / node 拉起它;
  3. Agent 带上登录态,调用和页面相同的 文件列表 / 下载 API

MCP 是开放协议,不限于 Cursor。同一 npm 包可接入 Cursor、Claude Desktop、VS Code(MCP 扩展)、Windsurf 等;下文以 mcp.json 为例,各客户端配置路径不同,stdio 启动命令相同


需要做些什么?

步骤做什么
1确认列表/下载 API;配置 LOGIN_URLTOKEN_SOURCE
2写 MCP tools:login_with_browser / list_files / download_file
3npm install(含 playwright,执行 playwright install
4npm publish --registry=
5在 Agent 客户端配 mcp.jsonnpx -y --registry=... [email protected]
6Agent 先 login_with_browser(本机 Chrome)→ Token 进内存 → 再列文件/下载

一、和现有系统怎么对齐

页面能力MCP Tool典型 API
登录login_with_browserPlaywright channel: chrome,凭证存内存
文件列表list_filesGET /api/files?path=
下载download_fileGET /api/files/download?id=
退出logout / clear_authPOST /api/logout(可选)

补充 tools:auth_statusclear_authlogout(退出见 §3.4)。

鉴权走 login_with_browser 写入的进程内存,不必配 API_TOKEN。内网只在本机访问,不做内网穿透或公网暴露。


二、npm 在这条链路里干什么

npm 能力用途
npm install装 sdk、playwright、zod
package.json + binMCP 可执行入口
npm publish发到
npx -y --registry=... 包@版本Agent 客户端拉起 MCP(stdio)

业务系统继续跑;MCP 是旁路独立包。配置见第四节。

常见 Agent 客户端与配置文件

客户端配置文件位置(Windows)
Cursor项目:<仓库>.cursormcp.json;全局:%USERPROFILE%.cursormcp.json
Claude Desktop%APPDATA%Claudeclaude_desktop_config.json
VS Code用户/工作区 MCP 配置(扩展提供,结构同为 mcpServers
Windsurf同 Cursor,.windsurf/mcp.json 或设置面板

各客户端 UI 不同,但 MCP Server 段结构一致command + args + env


三、从零做一个 MCP npm 包

3.1 目录

 复制代码your-files-mcp/
  package.json
  src/server.mjs          # stdio 入口
  .gitignore              # 含 .env

可参考:mcp-download-sidecar/

3.2 package.json

 复制代码{
  "name": "files-mcp-client",
  "version": "0.2.0",
  "type": "module",
  "bin": { "files-mcp-client": "./src/server.mjs" },
  "files": ["src"],
  "publishConfig": { "registry": "https://admin.npm.xxxxer.me/" },
  "scripts": { "start": "node src/server.mjs" },
  "engines": { "node": ">=18" },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.12.1",
    "playwright": "^1.52.0",
    "zod": "^3.25.28"
  }
}

playwright 必在 dependencies 里;启动时用 channel: "chrome" 调本机浏览器,不要 playwright install chromium

3.3 登录与浏览器:Token 获取并写入内存(关键代码)

完整实现见 mcp-download-sidecar/download-server.mjs。核心分四步:

① 进程内会话对象(不落盘)

 复制代码const session = { token: "", cookie: "", obtainedAt: null };function getToken() {
  return session.token; // 后续 list_files / download_file 从这里读
}

② 开本机 Chrome,等用户登录

 复制代码const { chromium } = await import("playwright");
const { context } = await chromium.launchPersistentContext(userDataDir, {
  headless: false,
  channel: "chrome", // 本机 Chrome,不下载 Chromium
});const page = context.pages()[0] ?? (await context.newPage());
await page.goto(LOGIN_URL, { waitUntil: "domcontentloaded" });// 轮询:直到 localStorage / Cookie / 请求头里出现凭证
await waitForLoginCredentials(page, context, { source: TOKEN_SOURCE, timeout });

③ 从页面取出 Token(按 TOKEN_SOURCE 配置)

 复制代码// TOKEN_SOURCE 格式:类型:键名
// 例:cookie:ACCESS_TOKEN | localStorage:token | header:Authorization
async function extractTokenFromPage(page, source) {
  const [kind, key] = source.split(":");
  if (kind === "localStorage") {
    return page.evaluate((k) => localStorage.getItem(k) || "", key);
  }
  if (kind === "cookie") {
    const hit = (await page.context().cookies()).find((c) => c.name === key);
    return hit?.value || ""; // key=ACCESS_TOKEN 时取该 Cookie 的值
  }
  return "";
}

示例:登录后 Cookie 名为 ACCESS_TOKEN

 复制代码TOKEN_SOURCE=cookie:ACCESS_TOKEN
 复制代码"env": {
  "TOKEN_SOURCE": "cookie:ACCESS_TOKEN"
}

登录成功后代码会:

  1. 从浏览器读到名为 ACCESS_TOKEN 的 Cookie 值 → 写入 session.token
  2. 同时把所有 Cookie 拼成 session.cookie → 后续请求带 Cookie
  3. session.token 有值,还会带 Authorization: Bearer

若你们后端只认 Cookie: ACCESS_TOKEN=xxx、不认 Bearer,可只依赖 session.cookie(实现里会整串带上)。

 复制代码// 也可拦截页面发出的 Authorization 头(TOKEN_SOURCE=header:Authorization 时用)
let bearer = "";
context.on("request", (req) => {
  const m = /^Bearers+(.+)$/i.exec(req.headers()["authorization"] || "");
  if (m) bearer = m[1];
});const token = (await extractTokenFromPage(page, TOKEN_SOURCE)) || bearer;
const cookieHeader = (await context.cookies())
  .map((c) => `${c.name}=${c.value}`)
  .join("; ");

④ 写入内存,供后续 API 使用

 复制代码session.token = token || "";
session.cookie = cookieHeader || "";
session.obtainedAt = new Date().toISOString();await context.close(); // 关浏览器;凭证留在 session 里// 之后 list_files / download_file 自动带鉴权头
function buildHeaders() {
  const headers = { Accept: "application/json, */*" };
  if (session.token) headers.Authorization = `Bearer ${session.token}`;
  if (session.cookie) headers.Cookie = session.cookie;
  return headers;
}await fetch(`${API_BASE}/api/files`, { headers: buildHeaders() });

要点:

常用环境变量:

 复制代码API_BASE=
LOGIN_URL=
TOKEN_SOURCE=cookie:ACCESS_TOKEN   # Cookie 名 ACCESS_TOKEN;或 localStorage:token / header:Authorization
PLAYWRIGHT_CHANNEL=chrome
DOWNLOAD_DIR=F:/downloads/app-files
LIST_API_PATH=/api/files
DOWNLOAD_API_PATH=/api/files/download
LOGOUT_API_PATH=/api/logout

3.4 退出登录

退出分三层:

层级做什么怎么调
MCP 内存清空 session,后续 API 不再带凭证clear_auth
后端会话(推荐)服务端 ACCESS_TOKEN 失效logout(配 LOGOUT_API_PATH
浏览器 Cookie(可选)本机 Chrome 里 Cookie 可能还在用户在浏览器点「退出」

对 Agent 说「退出登录」 → 调 logout

 复制代码"env": { "LOGOUT_API_PATH": "/api/logout" }

logout 流程:先带当前 Cookie/Token 调后端 logout(默认 POST)→ 再清空内存(后端失败也会清内存)。

Tool调后端清内存
clear_auth
logout

验证:auth_statusready 应为 false。流程见图下半部分 「二、退出登录」


四、发布与接入 Agent 客户端

4.1 publish

 复制代码npm login --registry=
npm publish --registry=

4.2 MCP 配置(通用)

在所用 Agent 的 MCP 配置里加入(Cursor 放 .cursor/mcp.json,Claude Desktop 放 claude_desktop_config.json,其余见上表):

 复制代码{
  "mcpServers": {
    "files": {
      "command": "npx",
      "args": [
        "-y",
        "--registry=/",
        "[email protected]"
      ],
      "env": {
        "API_BASE": "https://你的系统域名",
        "LOGIN_URL": "https://你的系统域名/login",
        "TOKEN_SOURCE": "cookie:ACCESS_TOKEN",
        "PLAYWRIGHT_CHANNEL": "chrome",
        "DOWNLOAD_DIR": "F:/downloads/app-files"
      }
    }
  }
}

注意:--registry=... 写成一个 args 项;pin 版本;不要API_TOKEN

4.3 开发期(未 publish)

command 改为 nodeargs 指向本地 server.mjsenv 同上。跑通后再切回 npx

4.4 使用

  1. 保存配置并重启 Agent 客户端(或 Reload MCP)→ Server 显示已连接
  2. Agent 调 login_with_browser → 本机 Chrome 登录
  3. list_files / download_file
  4. MCP 进程重启后需重新登录

五、边界与验收

做 / 不做

不做
调已有登录后的 API开无鉴权后门
Token 仅存进程内存Token 写进 mcp.json / Git
本机访问内网内网穿透、公网暴露

验收


六、常见坑

现象处理
MCP 未连接 / 红灯npx 不在客户端进程的 PATH;开发期用 node 绝对路径
npx 拉包失败检查 --registry=
401 / 下到登录页 HTMLToken 过期或未登录;重新 login_with_browser
浏览器起不来装本机 Chrome/Edge;不要依赖下载 Chromium
喜欢(0)

上一篇

用Spring AI实现多轮对话记忆:别再让AI每次都失忆

用Spring AI实现多轮对话记忆:别再让AI每次都失忆

下一篇

Agent 工程实习复盘 03-从 Pickle 到 PostgreSQL:LangGraph Checkpoint 迁移、内存治理与可回滚发布

Agent 工程实习复盘 03-从 Pickle 到 PostgreSQL:LangGraph Checkpoint 迁移、内存治理与可回滚发布
猜你喜欢