npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

weeek-mcp

v0.1.0-rc.1

Published

Local read-only MCP server for Weeek (stdio transport).

Readme

weeek-mcp

Локальный read-only MCP-сервер для Weeek, общается с AI-клиентами (Claude Desktop, Claude Code, Cursor, MCP Inspector) по stdio.

English README · docs/reviews/roadmap.md (полная мета-roadmap)

Статус: I-pub — публикация в npm (0.1.0-rc.1 под --tag next), RU README, публичный ROADMAP.md. Закрывает захват namespace weeek-mcp и DX-разрыв для русскоязычной аудитории. Ноль правок в src/** за пределами одного строкового литерала версии. Поверхность поведения не меняется: те же семь read-only тулов (ping, weeek_get_me, weeek_list_projects, weeek_list_tasks, weeek_get_task, weeek_list_members, weeek_list_tags) за теми же тремя композирующимися server-side гейтами (READ_ONLY, ENABLED_TOOLS, MAX_RESPONSE_CHARS), та же протокольная цель MCP 2025-06-18. Следом — I7 (read-side parity + многозначные assignee + live-integration harness). Mutating tools приземляются в I8. Полная мета-roadmap: docs/reviews/roadmap.md.

Quickstart

npm install
npm run build
npm run inspect   # запускает MCP Inspector против dist/index.js

Для smoke-теста без MCP-клиента см. docs/smoke.md (на английском).

Что сервер делает сегодня

  • Целится в MCP-протокол 2025-06-18 поверх stdio через @modelcontextprotocol/sdk@^1.29.

  • Обрабатывает: initialize, notifications/initialized, tools/list, tools/call (все — собственность SDK).

  • Регистрирует семь тулов; у каждого выставлены annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) и outputSchema, поэтому клиенты получают structuredContent:

    • ping { msg: string } → { reply: "pong: <msg>" } — health-check, openWorldHint: false.
    • weeek_get_me {} → { id, email, name } — обращается к Weeek /user/me, чтобы подтвердить выданный токен. name собирается из firstName + lastName; если оба пусты — fallback на email.
    • weeek_list_projects {} → { projects: [{ id, title, color, isPrivate }], truncated } — все проекты, видимые токену.
    • weeek_list_tasks { projectId?, completed?, offset?, perPage? } → { tasks: […], hasMore, truncated } — одна страница задач с offset/perPage-пагинацией; следуйте hasMore. truncated независим: пагинация = «есть ещё страницы»; truncation = «сервер обрезал текущую страницу под byte-budget».
    • weeek_get_task { id } → { id, title, description, completed, projectId, priority, type, truncated } — одна задача по id; неизвестный id всплывает как weeek_get_task failed: weeek_not_found. Если ответ превышает MAX_RESPONSE_CHARS, сервер обрезает description и добавляет маркер …[truncated].
    • weeek_list_members {} → { members: [{ id, email, firstName, lastName }], truncated } — все участники workspace.
    • weeek_list_tags {} → { tags: [{ id, title, color }], truncated } — все теги.

    Все Weeek-тулы (weeek_*) помечены openWorldHint: true (они ходят в api.weeek.net); ошибки апстрима всплывают как isError: true со стабильным текстом weeek_<code> и никогда как MCP-протокольные ошибки.

  • Логирует структурированный JSON только в stderr; stdout зарезервирован за JSON-RPC. Логгер рекурсивно редактирует ключи accessToken, authorization, password, secret, token перед записью в stderr.

Скрипты

| Команда | Назначение | |---|---| | npm run dev | Запуск напрямую из TS через tsx (без сборки) | | npm run build | Компиляция в dist/ | | npm start | Запуск собранного dist/index.js | | npm run typecheck | tsc --noEmit по src/** (production) | | npm run typecheck:tests | tsc -p tsconfig.test.json --noEmit по src/** + tests/** (noEmit; npm run build не затрагивается) | | npm run lint | eslint src tests --max-warnings 0 | | npm test | Один прогон unit-тестов (vitest) | | npm run test:watch | Vitest watch-режим | | npm run coverage | Тесты с V8-coverage отчётом | | npm run inspect | MCP Inspector против собранного бинарника |

Конфигурация

Вся runtime-конфигурация читается из окружения на старте и валидируется через zod (см. src/config/env.ts). Невалидные значения прерывают старт: сообщение в stderr и ненулевой exit-code.

| Переменная | Обязательная | Значение по умолчанию | Назначение | |---|---|---|---| | WEEEK_ACCESS_TOKEN | да | — | Персональный API-токен Weeek. Минимум 20 символов; пустые строки, whitespace/control-символы и документированные плейсхолдеры отклоняются на старте. | | WEEEK_BASE_URL | нет | https://api.weeek.net/public/v1 | Базовый URL Weeek HTTP-клиента. Меняйте только под self-hosted прокси. | | WEEEK_TIMEOUT_MS | нет | 30000 | Per-request таймаут (мс) для Weeek HTTP-клиента. Положительное целое. | | READ_ONLY | нет | true | Server-side гейт поверх annotations.readOnlyHint. Когда true, любой тул, у которого readOnlyHint !== true, пропускается на этапе регистрации и не попадает в tools/list. Принимает true / false / 1 / 0 (нечувствительно к регистру); любое другое значение прерывает старт. На сегодня no-op (все 7 тулов read-only); secure-by-default установлен заранее, на момент прихода mutating tools (I8). | | ENABLED_TOOLS | нет | (не задана = все включены) | Список имён тулов через запятую. Когда задан, ограничивает tools/list перечисленными именами (всё ещё пересекается с READ_ONLY). Пробелы обрезаются; дубликаты схлопываются; неизвестные имена дают WARN на старте. Пустые / только-пробельные значения, либо список, в результате которого зарегистрировано ноль тулов, прерывают старт ещё до открытия stdio. | | MAX_RESPONSE_CHARS | нет | 65536 | Верхняя граница на JSON.stringify(structuredContent).length per tool response. Пять тулов (weeek_list_projects, weeek_list_tasks, weeek_list_members, weeek_list_tags, weeek_get_task) обрезают payload под бюджет и возвращают truncated: boolean в outputSchema; списки роняют trailing items, weeek_get_task обрезает description маркером …[truncated]. Минимум 1024, максимум 1000000; нечисловые / out-of-range значения прерывают старт. ping и weeek_get_me не затрагиваются (их payload меньше минимума бюджета). | | LOG_LEVEL | нет | info | Порог логгера: debug, info, warn, error. Неизвестные значения откатываются на info. |

Гейт READ_ONLY работает на стороне сервера: скрытый тул не регистрируется, не появляется в tools/list, и агент не может попытаться его вызвать. Когда гейт пропускает регистрацию, в stderr выводится строка tool gated by READ_ONLY с именем тула. Невалидные значения (например, READ_ONLY=maybe) прерывают старт сообщением invalid env: READ_ONLY: must be 'true' | 'false' | '1' | '0'.

ENABLED_TOOLS работает по той же модели: тул, чьё имя не в списке, не регистрируется, и для каждого пропущенного тула логируется tool gated by ENABLED_TOOLS. Неизвестные имена логируются как unknown tool in ENABLED_TOOLS ровно один раз каждое — без прерывания (allowlist часто ссылается на тулы из ещё не смерженной ветки). Если после применения и READ_ONLY, и ENABLED_TOOLS зарегистрировано ноль тулов, старт прерывается сообщением no tools registered: combination of READ_ONLY and ENABLED_TOOLS hides every tool — сервер не открывает stdio в таком состоянии.

MAX_RESPONSE_CHARS отрабатывает после возврата тула: если итоговый structuredContent превышает бюджет, сервер роняет trailing items из списка (или клипает weeek_get_task.description маркером …[truncated]), выставляет truncated: true и эмитит ровно одну строку response truncated в stderr с полями tool, maxResponseChars, originalChars, truncatedChars (никаких заголовков / id / описаний). При успешном ответе пяти gated-тулов возвращается truncated: false, поэтому агент может рассматривать поле как стабильный сигнал.

См. .env.example — копипастабельный шаблон. Сервер не читает .env-файл сам: пробрасывайте переменные через env-блок MCP-клиента (см. пример ниже) или через свой shell.

Подключение к Claude Desktop

Скопируйте examples/claude_desktop.mcp.json в конфиг Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json на macOS), заменив оба плейсхолдера /ABSOLUTE/PATH/TO/... на вывод which node и абсолютный путь до dist/index.js этого репозитория. Реальный WEEEK_ACCESS_TOKEN обязателен начиная с I3 — без него сервер отказывается стартовать.

Подключение к Cursor

Cursor использует тот же JSON-формат, что и Claude Desktop. Откройте ~/.cursor/mcp.json (создайте, если его нет) и добавьте:

{
  "mcpServers": {
    "weeek": {
      "command": "/ABSOLUTE/PATH/TO/node",
      "args": ["/ABSOLUTE/PATH/TO/weeek-mcp/dist/index.js"],
      "env": {
        "LOG_LEVEL": "info",
        "WEEEK_ACCESS_TOKEN": "YOUR_WEEEK_TOKEN_HERE",
        "WEEEK_BASE_URL": "https://api.weeek.net/public/v1",
        "WEEEK_TIMEOUT_MS": "30000",
        "READ_ONLY": "true",
        "MAX_RESPONSE_CHARS": "65536"
      }
    }
  }
}

Перезапустите Cursor. Замените оба плейсхолдера /ABSOLUTE/PATH/TO/... на which node и абсолютный путь до dist/index.js этого репозитория.

Готовый файл лежит в examples/cursor.mcp.json. Аналог для Cline — examples/cline.mcp.json (тот же shape).

Чтобы ограничить агента подмножеством тулов, добавьте "ENABLED_TOOLS": "weeek_get_me,weeek_list_projects" в env-блок. Оставьте переменную незаданной — будут видны все тулы, прошедшие READ_ONLY-гейт.

Troubleshooting

| Симптом | Вероятная причина | Решение | |---|---|---| | Сервер не появляется в клиенте | command указывает на node, который клиент не находит, или dist/index.js отсутствует / без exec-bit | Запустите npm run build и убедитесь, что ls -la dist/index.js показывает 0755. Используйте абсолютный путь из which node (см. Workaround для NVM ниже). | | MCP server failed to start сразу при запуске | То же, плюс отсутствует node_modules | npm install && npm run build из корня репозитория. | | invalid env: WEEEK_ACCESS_TOKEN: ... в stderr | Токен содержит пробелы / control-символы или совпадает с плейсхолдером your-weeek-token-here | Сгенерируйте реальный токен на https://app.weeek.net/ws/_/settings/apps/api и вставьте без обрамляющих пробелов / переводов строки. | | invalid env: WEEEK_BASE_URL: ... | URL с не-http(s)-схемой или содержит user:pass@ | Используйте обычный https://api.weeek.net/public/v1; пробрасывайте креды через WEEEK_ACCESS_TOKEN. | | EACCES / permission denied при запуске dist/index.js | postbuild-chmod не отработал (например, при копировании на другой хост) | chmod +x dist/index.js. | | npm start работает, но клиент всё ещё не запускается | Клиент стартует под другим PATH, чем ваш shell | См. Workaround для NVM. |

Чтобы воспроизвести сервер вне клиента, запустите npm start напрямую и наблюдайте stderr — те же JSON-логи появятся там.

Workaround для NVM

Claude Desktop и Cursor стартуют свой MCP-subprocess в неинтерактивном shell, который не делает source ~/.nvm/nvm.sh, поэтому голый "command": "node" молча валится, если Node стоит через nvm. Два варианта:

  1. Зашить абсолютный путь (рекомендуется). Запустите which node в терминале и вставьте результат — обычно вида /Users/<you>/.nvm/versions/node/v20.18.0/bin/node. Обновляйте при переключении активной nvm-версии.

  2. Использовать wrapper-скрипт, делающий source nvm:

    #!/usr/bin/env bash
    export NVM_DIR="$HOME/.nvm"
    # shellcheck disable=SC1091
    . "$NVM_DIR/nvm.sh"
    exec node "$@"

    Сохраните как /usr/local/bin/node-via-nvm, chmod +x, и укажите путь в command. Переживёт смену nvm-версий.

Симптом этой проблемы: лог клиента говорит spawn node ENOENT или MCP server failed to start, при том что npm start в shell работает.

Design notes

  • Wire-уровень (JSON-RPC framing, handshake, zod → JSON Schema, version negotiation) живёт в @modelcontextprotocol/sdk; мы только собираем McpServer + StdioServerTransport в src/index.ts и регистрируем тулы. См. docs/mcp-spec-sync.md про целевую версию протокола, отслеживание SDK/spec drift и resync-процесс.
  • Прежняя hand-rolled-реализация сохранена в ветке explainer/no-sdk-implementation для справки.
  • Каждый тул обязан декларировать annotations (чтобы MCP-клиенты не скатывались на destructive-default) и — для всего, возвращающего структурные данные — outputSchema. Гейт READ_ONLY фильтрует на этапе регистрации поверх annotations.readOnlyHint: скрытые тулы не регистрируются вообще и не появляются в tools/list; SDK отклоняет вызов как Tool not found, а не запускает с isError-маркером.

Roadmap (короткий)

  • I2 — env/config loader (zod-validated) ✅
  • I3 — Weeek HTTP-клиент + weeek_get_me; WEEEK_ACCESS_TOKEN обязателен ✅
  • I4weeek_list_projects, weeek_list_tasks, weeek_get_task, weeek_list_members, weeek_list_tags
  • I5a — server-side READ_ONLY гейт ✅
  • I5bENABLED_TOOLS allowlist ✅
  • I5cMAX_RESPONSE_CHARS truncation gate ✅
  • I6a — Vitest + unit-тесты на pure modules ✅
  • I6b — handler-тесты на mocked Weeek client + client.ts тесты ✅
  • I6c — GitHub Actions CI на Node 20 + 22 + ESLint расширен на tests/**
  • I-pub — npm publish (0.1.0-rc.1), RU README, публичный ROADMAP.md
  • I7 — read-side parity (get_project, list_boards, list_board_columns), многозначный assignee, live-integration harness, проход по описаниям тулов
  • I7.5 — tolerant inner-field shaping для всех 10 endpoints (envelope всё ещё strict)
  • I8 — write tools (create_task, update_task, move_task, complete_task); первое live-упражнение I5a READ_ONLY
  • I9 — release maturity (1.0.0): автоматический publish, MCP Registry, Dependabot, CodeQL, полная двуязычная документация

Полная мета-roadmap со scope, out-of-scope, acceptance gates, рисками и open questions блокирующими каждый инкремент: docs/reviews/roadmap.md (на английском).