Skip to main content
Glama

akij-hr-data-mcp

Готовый к продакшену, только для чтения, удалённый Model Context Protocol (MCP) сервер, который открывает доступ к одной папке Google Drive — репозиторию AKIJ HR DATA — для MCP-совместимых клиентов через современный транспорт Streamable HTTP.

Это универсальный 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).

  • Работает как стандартный HTTP-сервер на Node/Express с единственной конечной точкой POST /mcp (транспорт Streamable HTTP) и конечной точкой GET /health, разворачивается на Render (или любом Node-хостинге), чтобы продолжать работать, когда ваш ПК выключен.

  • Требует аутентификацию по API-ключу для каждого MCP-запроса.

  • Является строго только для чтения — в коде нет путей, которые могут загружать, редактировать, удалять, переименовывать, перемещать или открывать доступ к файлам 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 Cloud с включённым Google Drive API

  • Google сервисный аккаунт с доступом Viewer, предоставленным на папку AKIJ HR DATA в Drive

  • Аккаунт GitHub (для развёртывания на Render из репозитория)

  • Аккаунт Render

4. Установка

npm install

5. Переменные окружения

Переменная

Обязательная

Описание

PORT

нет (по умолчанию 10000)

Порт, на котором слушает HTTP-сервер. Render устанавливает его автоматически.

GOOGLE_DRIVE_FOLDER_ID

да

Идентификатор папки Drive, к которой ограничен этот MCP.

GCP_KEY_BASE64

да

JSON-ключ сервисного аккаунта в кодировке Base64.

API_KEYS

да

Список допустимых API-ключей для POST /mcp, разделённый запятыми.

См. .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. Запишите email-адрес сервисного аккаунта (выглядит как akij-hr-data-mcp@your-project.iam.gserviceaccount.com).

7. Права доступа в Google Drive

  1. Откройте папку AKIJ HR DATA в Google Drive (ID папки 1oxYLPcC9MPVuxsbeP0kGgYhLmkxt0w2o).

  2. Нажмите Share, вставьте email сервисного аккаунта и предоставьте доступ 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 запускает TypeScript-сервер напрямую через tsx watch (для локальной разработки шаг сборки не нужен).

9. Генерация GCP_KEY_BASE64

Никогда не вставляйте сырой JSON сервисного аккаунта в чат, исходный код или .env.example. Сгенерируйте значение base64 локально из скачанного gcp-key.json и поместите его только в локальный .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 не находится в вашей папке Downloads.

Если вы предпочитаете вывести её в терминал, а не в буфер обмена:

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

10. Локальное тестирование

Запустите сервер:

npm run dev

Проверьте работоспособность:

curl http://localhost:10000/health

Вызовите MCP-инструмент (например, list_files) с помощью curl, используя последовательность initialize → tools/call, или укажите любому MCP-клиенту, поддерживающему Streamable HTTP, адрес http://localhost:10000/mcp с заголовком X-Api-Key: <один из ваших API_KEYS>.

11. Сборка

npm run build

Компилирует src/ (TypeScript, NodeNext ESM) в dist/. Запустите npm run typecheck для проверки типов без создания файлов.

Запустите набор тестов:

npm test

Это запускает Jest в одном процессе (46 тестов в 10 наборах: config, auth, Google auth, проверка области папки Drive, все 11 инструментов и HTTP-эндпоинты /health//mcp).

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) или настройте вручную:

    • Build Command: npm install && npm run build

    • Start Command: npm start

    • Health Check Path: /health

  4. Добавьте переменные окружения (раздел 14) на панели Render — никогда не коммитьте их.

  5. Разверните. Render соберёт и запустит сервис, и он будет работать независимо от вашего ПК.

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. Эндпоинт Health

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

Для MCP-клиентов, поддерживающих удалённые/HTTP-серверы, добавьте запись сервера с:

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

  • Транспорт: Streamable HTTP

  • Заголовки: X-Api-Key: <один из ваших 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 проверяется по API_KEYS с помощью сравнения, безопасного по времени (crypto.timingSafeEqual). Отсутствующие/недействительные ключи получают 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 или ролей мог добавлять более богатые утверждения без изменения каждого места вызова.

  • Известное предупреждение о зависимости: пакет xlsx (SheetJS), используемый для разбора устаревших .xls-файлов, имеет опубликованное предупреждение высокой степени серьёзности (prototype pollution / ReDoS). Он используется только для внутренних файлов с контролируемым доступом из вашей собственной папки Drive (не для произвольных интернет-загрузок), а файлы ограничиваются по размеру перед разбором. Периодически запускайте npm audit и рассмотрите замену пакета, когда появится исправленная версия.

Контрольный список безопасности

  • gcp-key.json никогда не коммитится в git

  • .env никогда не коммитится в git

  • API_KEYS заданы надёжными случайными значениями в Render (не локальным dev-значением)

  • Сервисный аккаунт имеет доступ только Viewer к папке Drive

  • GOOGLE_DRIVE_FOLDER_ID соответствует целевой папке репозитория

  • Переменные окружения Render задаются напрямую на панели, а не в закоммиченных значениях render.yaml

19. Устранение неполадок

Симптом

Причина

Исправление

Сервер сразу завершает работу с ConfigError

Отсутствует/недействительна переменная окружения

Проверьте точное имя переменной из сообщения об ошибке по разделу 5

GCP_KEY_BASE64 is not valid base64

Закодирован не тот файл, или при копировании/вставке строка была обрезана

Перегенерируйте с помощью команды PowerShell из раздела 9

403 Forbidden от Drive API

Сервисный аккаунт не предоставлен к папке или предоставлен на неправильный email

Перепроверьте раздел 7; убедитесь, что client_email в вашем ключе совпадает

File ... is outside the configured repository folder

Вы передали file_id, который не находится внутри дерева GOOGLE_DRIVE_FOLDER_ID

Используйте list_supported_files или search_repository, чтобы получить допустимые ID

401 при каждом вызове /mcp

Отсутствует/неправильный API-ключ

Отправьте X-Api-Key или Authorization: Bearer <key>, совпадающий с одной из записей в API_KEYS

Ошибка FILE_TOO_LARGE

Файл превышает настроенный лимит байт

Это намеренно; большие файлы отклоняются, а не загружаются полностью в память (см. src/utils/limits.ts)

Сервис Render засыпает / медленно холодно стартует

Бесплатные/стартовые планы Render простаивают после бездействия

Перейдите на более дорогой план Render или примите задержку холодного старта при первом запросе

Тесты локально зависают на минуты

ts-jest проверяет типы полного googleapis при параллельных воркерах

Уже устранено: npm test запускает Jest с --runInBand; не удаляйте этот флаг


Оставшиеся ручные шаги (выполнить можете только вы)

  1. Сгенерируйте GCP_KEY_BASE64 из загруженного gcp-key.json (раздел 9) и поместите его в ваш локальный .env для тестирования.

  2. Поделитесь папкой AKIJ HR DATA Drive с адресом электронной почты вашего сервисного аккаунта с правами просмотра (раздел 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