Skip to main content
Glama

akij-hr-data-mcp

一个生产就绪、只读、远程的 Model Context Protocol (MCP) 服务器,通过现代 Streamable HTTP 传输,将单个 Google Drive 文件夹(即 AKIJ HR DATA 仓库)开放给兼容 MCP 的客户端。

它是一个通用 Drive MCP:可处理 XLSX、XLS、CSV、PDF、DOCX、TXT、图片以及原生 Google Docs/Sheets/Slides 文件——并非仅限 Excel 的工具。


1. 这个项目做什么

  • 使用服务账号连接 Google Drive(没有用户 OAuth 流程,也不需要浏览器登录)。

  • 将所有操作限制在一个已配置的文件夹(GOOGLE_DRIVE_FOLDER_ID)及其子文件夹内。超出该目录树的文件永远不会被返回,即使服务账号在技术上能够看到它们。

  • 提供 11 个 MCP 工具,用于发现和读取文件(列表、搜索、元数据、内容,以及针对 Excel/CSV/PDF/DOCX 的格式特定提取)。

  • 作为标准的 Node/Express HTTP 服务器运行,带有一个 POST /mcp 端点(Streamable HTTP 传输)和一个 GET /health 端点,可部署到 Render(或任何 Node 主机),以便在您的 PC 关闭时继续运行。

  • 在每一个 MCP 请求上强制实施 API 密钥身份验证。

  • 严格只读——不存在任何能够上传、编辑、删除、重命名、移动、共享 Drive 文件或更改权限的代码路径。

Related MCP server: Google Drive MCP Server

2. 架构

Google Drive (AKIJ HR DATA folder)
        ↓ Drive API v3 (read-only scope)
Google Service Account (GCP_KEY_BASE64)
        ↓
GoogleDriveClient (src/google-drive.ts) — enforces folder-tree scope
        ↓
MCP Server (src/mcp-server.ts) — 11 tools, Zod-validated inputs
        ↓
Express app (src/index.ts) — API-key auth, Streamable HTTP transport
        ↓ POST /mcp  (stateless, one transport per request)
        ↓
Render (always-on host)
        ↓ HTTPS
Remote MCP Clients (Claude, other MCP-compatible clients)

服务器是无状态的:每个 POST /mcp 请求都会获得自己的 McpServer + StreamableHTTPServerTransport 实例(sessionIdGenerator: undefined),因此没有会话亲和性要求,并且可以在 Render 上无需粘性会话地进行水平扩展。

项目结构

src/
  index.ts            Express app: /health, /mcp, startup
  config.ts           Environment variable loading/validation
  auth.ts             API-key authentication middleware
  google-auth.ts      Decodes GCP_KEY_BASE64 → JWT auth client
  google-drive.ts      Drive API client with folder-scope enforcement
  mcp-server.ts        McpServer wiring: registers all 11 tools

  tools/
    files.ts           list_files, get_file_metadata, get_file_content, list_supported_files
    search.ts           search_files, search_repository
    excel.ts            inspect_excel, read_excel_sheet
    csv.ts               read_csv
    pdf.ts               extract_pdf_text
    docx.ts              extract_docx_text

  utils/
    errors.ts            Typed AppError hierarchy + safe error serialization
    limits.ts            Size/row/timeout/pagination limits
    mime-types.ts         MIME → file-category classification

tests/                  Jest test suite (46 tests, 10 suites)
.env.example
.gitignore
render.yaml             Render Blueprint (optional one-click deploy)
README.md
package.json
tsconfig.json
jest.config.cjs

3. 先决条件

  • Node.js 20+ 和 npm

  • 一个已启用 Google Drive API 的 Google Cloud 项目

  • 一个在 AKIJ HR DATA Drive 文件夹上共享了 Viewer 访问权限的 Google 服务账号

  • 一个 GitHub 账号(用于从仓库部署到 Render)

  • 一个 Render 账号

4. 安装

npm install

5. 环境变量

变量

是否必需

描述

PORT

否(默认 10000)

HTTP 服务器监听的端口。Render 会自动设置此项。

GOOGLE_DRIVE_FOLDER_ID

是

此 MCP 被限制访问的 Drive 文件夹 ID。

GCP_KEY_BASE64

是

Base64 编码的服务账号 JSON 密钥。

API_KEYS

是

用于 POST /mcp 的有效 API 密钥列表(逗号分隔)。

模板见 .env.example(没有提交任何真实机密)。

6. Google Cloud 设置

  1. 转到 console.cloud.google.com 并选择/创建一个项目。

  2. APIs & Services → Library → 启用 Google Drive API。

  3. APIs & Services → Credentials → Create Credentials → Service Account。

  4. 为它命名(例如 akij-hr-data-mcp),不需要项目级 IAM 角色。

  5. 打开新的服务账号 → Keys → Add Key → Create new key → JSON。这会下载一个 gcp-key.json 文件——不要提交此文件。

  6. 记下服务账号的电子邮件地址(看起来像 akij-hr-data-mcp@your-project.iam.gserviceaccount.com)。

7. Google Drive 权限

  1. 在 Google Drive 中打开 AKIJ HR DATA 文件夹(文件夹 ID 1oxYLPcC9MPVuxsbeP0kGgYhLmkxt0w2o)。

  2. 点击 Share,粘贴服务账号的电子邮件,并授予 Viewer 访问权。

  3. 不要授予 Editor/Owner——此服务器从不写入 Drive,因此 Viewer 就足够了,而且更安全。

8. 本地设置

npm install
cp .env.example .env
# fill in GOOGLE_DRIVE_FOLDER_ID, GCP_KEY_BASE64, API_KEYS in .env
npm run dev

npm run dev 直接使用 tsx watch 运行 TypeScript 服务器(本地迭代无需构建步骤)。

9. 生成 GCP_KEY_BASE64

切勿将原始服务账号 JSON 粘贴到聊天、源代码或 .env.example 中。请从下载的 gcp-key.json 在本地生成 base64 值,并且只将其放入本地 .env(已被 gitignore)或 Render 的环境变量设置中。

PowerShell:

[Convert]::ToBase64String([IO.File]::ReadAllBytes("$HOME\Downloads\gcp-key.json")) | Set-Clipboard

这会读取密钥文件并将 base64 字符串直接复制到剪贴板——请将其作为 GCP_KEY_BASE64 的值粘贴到 .env(本地)或 Render 仪表板(用于部署)中。如果 gcp-key.json 不在您的下载文件夹中,请调整路径。

如果您更想将其打印到终端而不是剪贴板:

[Convert]::ToBase64String([IO.File]::ReadAllBytes("$HOME\Downloads\gcp-key.json"))

10. 本地测试

启动服务器:

npm run dev

检查健康状态:

curl http://localhost:10000/health

使用 curl 调用某个 MCP 工具(例如:list_files),按 initialize → tools/call 顺序操作,或者将任何支持 Streamable-HTTP 的 MCP 客户端指向 http://localhost:10000/mcp,并带有请求头 X-Api-Key: <one of your API_KEYS>。

11. 构建

npm run build

将 src/(TypeScript,NodeNext ESM)编译到 dist/。运行 npm run typecheck 可在不生成文件的情况下进行类型检查。

运行测试套件:

npm test

这会以 in-band 模式运行 Jest(10 个测试套件共 46 个测试:配置、认证、Google 认证、Drive 文件夹范围强制、全部 11 个工具,以及 /health//mcp HTTP 端点)。

12. GitHub 设置

git init
git add .
git commit -m "Initial commit: akij-hr-data-mcp"
git branch -M main
git remote add origin https://github.com/<your-username>/akij-hr-data-mcp.git
git push -u origin main

.env、gcp-key.json、*.pem 和 *.key 已被 gitignore——在提交之前使用 git status 验证没有暂存任何机密内容。

13. Render 部署

  1. 转到 render.com → New → Web Service。

  2. 连接您的 GitHub 仓库(akij-hr-data-mcp)。

  3. Render 会自动检测 render.yaml(Blueprint),或者手动配置:

    • 构建命令: npm install && npm run build

    • 启动命令: npm start

    • 健康检查路径: /health

  4. 在 Render 仪表板中添加环境变量(第 14 节)——切勿提交它们。

  5. 部署。Render 会构建、启动服务,并使其独立于您的 PC 持续运行。

14. Render 环境变量

在 Render → 您的服务 → Environment 中设置这些变量:

PORT=10000
GOOGLE_DRIVE_FOLDER_ID=1oxYLPcC9MPVuxsbeP0kGgYhLmkxt0w2o
GCP_KEY_BASE64=<paste the base64 string from step 9>
API_KEYS=<comma-separated production keys, e.g. key-abc123,key-def456>

生成强随机 API 密钥,例如:

[Convert]::ToBase64String([Guid]::NewGuid().ToByteArray()) -replace '[+/=]',''

15. 健康端点

GET /health
{ "status": "ok", "timestamp": "2026-08-17T12:00:00.000Z" }

无需认证;不暴露任何机密或内部状态。

16. MCP 端点

POST /mcp
  • 实现 MCP Streamable HTTP 传输(@modelcontextprotocol/sdk 的 StreamableHTTPServerTransport),无状态(sessionIdGenerator: undefined)——没有仅限 SSE 的回退。

  • 需要认证:Authorization: Bearer <API_KEY> 或 X-Api-Key: <API_KEY> 请求头。

  • GET /mcp 和 DELETE /mcp 返回 405——此服务器不维护会话,也不支持可选的 SSE 流。

17. 将远程 MCP 连接到客户端

部署后,您的 MCP 端点为:

https://<your-render-service>.onrender.com/mcp

对于支持远程/HTTP 服务器的 MCP 客户端,添加一个服务器条目,包含:

  • URL: https://<your-render-service>.onrender.com/mcp

  • 传输方式: Streamable HTTP

  • 请求头: X-Api-Key: <one of your API_KEYS>(或 Authorization: Bearer <API_KEY>)

通用客户端配置示例:

{
  "mcpServers": {
    "akij-hr-data": {
      "url": "https://<your-render-service>.onrender.com/mcp",
      "headers": {
        "X-Api-Key": "<API_KEY>"
      }
    }
  }
}

18. 安全性

  • 只读:此代码库中不存在上传/删除/编辑/重命名/移动/共享/权限工具。

  • 文件夹范围:GoogleDriveClient.assertFileInScope 在返回任何元数据或内容之前,会沿着每个文件的 parents 链向上遍历到已配置的根目录;树之外的文件会引发 ForbiddenError。

  • API 密钥认证:每个 POST /mcp 请求都会通过时序安全比较(crypto.timingSafeEqual)对照 API_KEYS 进行检查。缺失/无效的密钥会得到 401。

  • 凭据从不记录或返回:解码后的服务账号 JSON 只保留在 google-auth.ts 内;任何工具、日志行或错误消息都无法将其暴露。错误响应经过 toSafeErrorMessage 处理,该函数会剥离堆栈跟踪和上游原始错误主体。

  • 大小/输出限制:下载有上限(LIMITS.MAX_DOWNLOAD_BYTES / MAX_PARSE_BYTES),文本提取被截断(MAX_TEXT_OUTPUT_CHARS),行数据分页(DEFAULT_ROW_LIMIT/MAX_ROW_LIMIT),并且每次向 Google API 发出的调用都有超时(GOOGLE_API_TIMEOUT_MS)。

  • 可扩展认证:req.identity 是一个小巧、稳定的结构({ keyId }),旨在让未来的按用户密钥、OAuth 或基于角色的授权层能够附加更丰富的声明,而无需更改每个调用点。

  • 已知依赖公告:用于解析旧版 .xls 的 xlsx(SheetJS)包有一个已发布的高严重性公告(原型污染 / ReDoS)。它仅用于处理来自您自己的 Drive 文件夹的内部、受访问控制的文件(不是任意的互联网上传),并且文件在解析前有大小上限。请定期运行 npm audit,如果有已修复的版本可用,请考虑替换它。

安全清单

  • gcp-key.json 永远不会提交到 git

  • .env 永远不会提交到 git

  • API_KEYS 在 Render 中设置为强随机值(不是本地开发值)

  • 服务账号在 Drive 文件夹上只有 Viewer 权限

  • GOOGLE_DRIVE_FOLDER_ID 与预期的仓库文件夹匹配

  • Render 环境变量直接在仪表板中设置,绝不使用 render.yaml 中已提交的值

19. 故障排除

症状

原因

修复

服务器以 ConfigError 立即退出

环境变量缺失或无效

对照第 5 节检查错误消息中指定的确切变量名称

GCP_KEY_BASE64 is not valid base64

编码了错误的文件,或复制/粘贴截断了字符串

使用第 9 节中的 PowerShell 命令重新生成

Drive API 返回 403 Forbidden

服务账号未共享到该文件夹,或共享到了错误的电子邮件

重新检查第 7 节;确认密钥中的 client_email 匹配

File ... is outside the configured repository folder

您传入的 file_id 不在 GOOGLE_DRIVE_FOLDER_ID 的目录树内

使用 list_supported_files 或 search_repository 获取有效的 ID

每次 /mcp 调用都返回 401

API 密钥缺失或不正确

发送与 API_KEYS 中某个条目匹配的 X-Api-Key 或 Authorization: Bearer <key>

FILE_TOO_LARGE 错误

文件超过配置的字节限制

这是有意为之;大文件会被拒绝,而不是完全加载到内存中(参见 src/utils/limits.ts)

Render 服务休眠 / 冷启动缓慢

免费/入门级 Render 套餐在闲置后空闲

升级 Render 套餐,或接受首次请求时的冷启动延迟

测试在本地挂起数分钟

ts-jest 在并行工作进程下对完整的 googleapis 类型进行类型检查

已缓解:npm test 使用 --runInBand 运行 Jest;不要移除该标志


剩余的手动步骤(只有您能完成这些)

  1. 从你下载的 gcp-key.json(第9节)生成 GCP_KEY_BASE64,并将其放入本地 .env 文件用于测试。

  2. 将 AKIJ HR DATA Drive 文件夹以查看者(Viewer)权限共享给你的服务账号邮箱(第7节)。

  3. 本地运行(npm run dev),并确认 GET /health 和真实的 list_files 调用能针对你的真实 Drive 文件夹正常工作。

  4. 推送到 GitHub(第12节)。

  5. 创建 Render Web Service,连接仓库,并在 Render 仪表板中设置四个环境变量(第13–14节)——Render 将自动构建和部署。

  6. 生成生产环境 API_KEYS(与任何本地开发密钥不同),并安全存储以供你的 MCP 客户端使用。

  7. 将你的 MCP 客户端连接到 https://<your-render-service>.onrender.com/mcp(第17节)。

Related MCP Connectors

Related MCP Servers