docs: update docs
This commit is contained in:
+79
-120
@@ -2,19 +2,30 @@
|
||||
|
||||
## Контекст
|
||||
|
||||
Проект **rubber-duck** — интерактивная уточка для дебага. MCP-сервер расширяет концепцию: LLM-модель (Claude, Cursor) может «обращаться к уточке» за кряком и мудростью. Сервер — **отдельный репозиторий**, деплой на **Vercel**, стек: **Express + TypeScript + Streamable HTTP**.
|
||||
Проект **rubber-duck** — интерактивная уточка для дебага. MCP-сервер расширяет концепцию: LLM (Claude, Cursor) может «обращаться к уточке» за кряком и мудростью. Сервер — отдельный репозиторий, деплой на Vercel (Hobby, бесплатно).
|
||||
|
||||
---
|
||||
|
||||
## Стек
|
||||
|
||||
| Что | Пакет | Зачем |
|
||||
| ----------- | ------------------------------------- | ------------------------------------------------- |
|
||||
| Фреймворк | **Next.js 15+** (App Router) | Route Handlers на Vercel, autodeploy из коробки |
|
||||
| MCP-адаптер | **`mcp-handler` ^2.1.1** | HTTP-адаптер от Vercel, stateless Streamable HTTP |
|
||||
| MCP SDK | **`@modelcontextprotocol/server` ^2** | McpServer, registerTool, registerResource |
|
||||
| Валидация | **`zod` ^4** | Schema для input тулзов |
|
||||
|
||||
`@vercel/mcp-adapter` и `@modelcontextprotocol/sdk` v1 — **устарели**. Используем `mcp-handler` v2 + `@modelcontextprotocol/server` v2.
|
||||
|
||||
---
|
||||
|
||||
## Философия сервера
|
||||
|
||||
Сервер не решает задачи за модель. Он — **Explicit Reasoning Buffer** (буфер явных рассуждений). Когда модель застревает в логическом цикле или склонна к галлюцинациям, вызов `quack()` заставляет её:
|
||||
Сервер — **Explicit Reasoning Buffer** (буфер явных рассуждений). Не решает задачи за модель. Когда LLM застревает в логическом цикле, вызов `quack()` заставляет:
|
||||
|
||||
1. **Сформулировать аргументы** — чтобы вызвать инструмент, модель должна выгрузить промежуточные мысли из весов в текст. Неявные рассуждения становятся явными данными.
|
||||
2. **Прервать генерацию** — вместо того чтобы «проскочить» сложный момент, модель делает паузу и структурирует задачу.
|
||||
3. **Создать внешнюю память** — записывая статус в «уточку», модель формирует краткое резюме пройденных этапов.
|
||||
|
||||
Описывается через **Resource** `about://rubber-duck` — текстовый документ, который сервер отдаёт при запросе. Модель читает его и понимает контекст.
|
||||
1. **Сформулировать аргументы** — выгрузить мысли из весов в текст.
|
||||
2. **Прервать генерацию** — сделать паузу и структурировать задачу.
|
||||
3. **Создать внешнюю память** — задокументировать пройденный этап.
|
||||
|
||||
---
|
||||
|
||||
@@ -22,154 +33,102 @@
|
||||
|
||||
```txt
|
||||
rubber-duck-mcp/
|
||||
├── api/mcp.ts — Express handler для Vercel Serverless
|
||||
├── src/
|
||||
│ ├── server.ts — McpServer: регистрация tools + resources
|
||||
│ ├── tools/
|
||||
│ │ ├── quack.ts — Tool: случайный кряк
|
||||
│ │ └── quack-wisdom.ts — Tool: кряк + мудрость программиста (ФАЗА 2)
|
||||
│ ├── data/
|
||||
│ │ └── wisdoms.ts — Массив цитат/мудростей (ФАЗА 2)
|
||||
│ └── index.ts — Express dev-сервер (localhost)
|
||||
├── vercel.json
|
||||
├── app/
|
||||
│ ├── layout.tsx — корневой layout
|
||||
│ ├── page.tsx — заглушка
|
||||
│ └── api/mcp/route.ts — MCP-хендлер (GET + POST)
|
||||
├── lib/
|
||||
│ └── mcp.ts — McpServer + инструменты
|
||||
├── package.json
|
||||
└── tsconfig.json
|
||||
├── tsconfig.json
|
||||
└── next.config.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Зависимости
|
||||
## Инструменты
|
||||
|
||||
- **@modelcontextprotocol/sdk** — McpServer + StreamableHTTPServerTransport
|
||||
- **express** — HTTP-сервер
|
||||
- **@types/express, typescript** — типизация
|
||||
- **tsx** — dev-запуск TypeScript без сборки
|
||||
### Tool #1: `quack` (ФАЗА 1)
|
||||
|
||||
---
|
||||
Заставляет модель остановиться. Аргумент `mood` (опциональный): `"happy" | "confused" | "excited" | "sleepy"`. Без аргумента — случайный кряк из общей пуллы. Возвращает `TextContent` с текстом кряка.
|
||||
|
||||
## Инструменты (Tools)
|
||||
### Tool #2: `quack_wisdom` (ФАЗА 2)
|
||||
|
||||
### Tool #1: `quack` (ФАЗА 1 — полная реализация)
|
||||
Кряк + случайная мудрость программиста. Аргумент `topic` (опциональный): `"debugging" | "life" | "code" | "random"`. База мудростей — массив `{ text, author?, topic? }` в `src/data/wisdoms.ts`.
|
||||
|
||||
- **Назначение**: Заставляет модель остановиться и сформулировать мысль
|
||||
- **Аргументы**: `mood` (опциональный) — `"happy" | "confused" | "excited" | "sleepy"`
|
||||
- **Логика**: Без аргументов — случайный кряк. С `mood` — кряк подбирается по настроению
|
||||
- **Возвращает**: `TextContent` с текстом кряка
|
||||
### Resource: `about://rubber-duck` (ФАЗА 2)
|
||||
|
||||
### Tool #2: `quack_wisdom` (ФАЗА 2 — после проверки Tool #1)
|
||||
|
||||
- **Назначение**: Кряк + случайная мудрость для программиста
|
||||
- **Аргументы**: `topic` (опциональный) — `"debugging" | "life" | "code" | "random"`
|
||||
- **Логика**: Генерирует кряк, выбирает мудрость из базы (фильтр по topic), форматирует
|
||||
- **Возвращает**: `TextContent` — кряк + мудрость + автор
|
||||
|
||||
### База мудростей (`data/wisdoms.ts`) — ФАЗА 2
|
||||
|
||||
Массив `{ text, author?, topic? }`. Классические цитаты (Kernighan, Knuth, Stallman) + юмористические фразы. Каждая запись с полем `topic` для фильтрации.
|
||||
|
||||
---
|
||||
|
||||
## Resource: философия сервера — ФАЗА 2
|
||||
|
||||
- **URI**: `about://rubber-duck`
|
||||
- **Название**: "About Rubber Duck MCP"
|
||||
- **Содержимое**: Текстовый документ (~10-15 строк):
|
||||
- Что это (Explicit Reasoning Buffer)
|
||||
- Зачем (замедление, фиксация контекста, внешняя память)
|
||||
- Как использовать (вызывай quack() когда застрял)
|
||||
|
||||
---
|
||||
|
||||
## Промпты
|
||||
|
||||
**Не используются.** Промпты — шаблоны для пользователя в UI. Для простого сервера из двух тулзов избыточны: модель свободно вызывает инструменты сама.
|
||||
|
||||
---
|
||||
|
||||
## Express-хендлер
|
||||
|
||||
Один эндпоинт `POST /mcp`. На каждый запрос:
|
||||
|
||||
1. Новый `McpServer` (с tools + resources)
|
||||
2. `StreamableHTTPServerTransport` — **stateless** (`sessionIdGenerator: undefined`)
|
||||
3. Подключение + обработка запроса
|
||||
|
||||
Локально: `index.ts` с `app.listen(3000)`.
|
||||
Текстовый документ (~10-15 строк) с описанием философии сервера. Модель читает его и понимает контекст.
|
||||
|
||||
---
|
||||
|
||||
## Деплой на Vercel
|
||||
|
||||
`vercel.json`: маппинг `/mcp` → `api/mcp.ts` через `@vercel/node`.
|
||||
### Вариант A: Vercel CLI (без GitHub)
|
||||
|
||||
```bash
|
||||
npm i -g vercel
|
||||
vercel login # авторизация через браузер
|
||||
vercel --prod # деплой
|
||||
```
|
||||
|
||||
При первом запуске `vercel` задаст вопросы — отвечаем: Yes, наш аккаунт, No (новый проект), текущая директория. URL будет `https://rubber-duck-mcp.vercel.app`.
|
||||
|
||||
### Вариант B: GitHub (автодеплой)
|
||||
|
||||
1. Push в GitHub
|
||||
2. Vercel → Add New Project → выбрать репозиторий
|
||||
3. Deploy
|
||||
4. URL: `https://<project>.vercel.app/mcp`
|
||||
3. Framework: Next.js (автоопределение) → Deploy
|
||||
|
||||
Ограничения: таймаут 10 сек (Hobby), 60 сек (Pro). Stateless — каждый вызов независим.
|
||||
### Лимиты Hobby (бесплатно)
|
||||
|
||||
---
|
||||
|
||||
## Тестирование
|
||||
|
||||
**Локально**: `npm run dev` → MCP Inspector или curl POST на `/mcp`.
|
||||
|
||||
**Удалённо**: `curl -i https://<project>.vercel.app/mcp` → MCP Inspector с удалённым URL.
|
||||
Таймаут функции 300с, деплои 100/день, проектов 200. Для quack ответ за ~1мс — лимиты не актуальны. `vercel.json` не нужен.
|
||||
|
||||
---
|
||||
|
||||
## Подключение к клиентам
|
||||
|
||||
- **Cursor**: Settings → Features → MCP → Streamable HTTP → URL `/mcp`
|
||||
- **Claude Desktop**: `claude_desktop_config.json` → `url: "https://<project>.vercel.app/mcp"`
|
||||
- **VS Code**: `.vscode/mcp.json` → `type: "http"`, url `/mcp`
|
||||
**Cursor:** Settings → Features → MCP → Streamable HTTP → URL `/api/mcp`
|
||||
|
||||
**Claude Desktop:** в `claude_desktop_config.json` прописать `"url": "https://<project>.vercel.app/api/mcp"`. Если клиент не поддерживает Streamable HTTP — через `mcp-remote` как бридж.
|
||||
|
||||
---
|
||||
|
||||
## Чеклист
|
||||
|
||||
| Проверка | Результат |
|
||||
| ------------------------ | --------------------------------- |
|
||||
| `npm run typecheck` | 0 ошибок |
|
||||
| `npm run build` | Сборка OK |
|
||||
| MCP Inspector (локально) | Видит tools + resource |
|
||||
| curl `tools/call` | Возвращает кряк / кряк + мудрость |
|
||||
| Vercel deploy | 200 OK |
|
||||
| MCP Inspector (удалённо) | Работает |
|
||||
| Cursor/Claude | LLM вызывает инструменты |
|
||||
| Проверка | Результат |
|
||||
| ------------------------ | ------------------ |
|
||||
| `npm run typecheck` | 0 ошибок |
|
||||
| `npm run build` | Сборка OK |
|
||||
| MCP Inspector (локально) | Видит tools |
|
||||
| curl `tools/call` | Возвращает кряк |
|
||||
| `vercel --prod` | Деплой OK |
|
||||
| MCP Inspector (удалённо) | Работает |
|
||||
| Cursor / Claude | LLM вызывает quack |
|
||||
|
||||
---
|
||||
|
||||
## Порядок реализации
|
||||
|
||||
### ФАЗА 1: Tool #1 (quack) — полный цикл
|
||||
### ФАЗА 1: quack
|
||||
|
||||
1. Инициализация проекта: `package.json`, `tsconfig.json`, зависимости
|
||||
2. `src/tools/quack.ts` — Tool #1 (quack)
|
||||
3. `src/server.ts` — McpServer + регистрация quack tool (без resource)
|
||||
4. `src/index.ts` — Express dev-сервер
|
||||
5. `api/mcp.ts` + `vercel.json` — Vercel конфигурация
|
||||
6. `npm run typecheck` → исправить ошибки
|
||||
7. `npm run build` → убедиться что компилируется
|
||||
8. **Тест MCP Inspector локально** — вызвать quack, проверить ответ
|
||||
9. **Тест curl локально** — POST запрос, проверить JSON-RPC ответ
|
||||
10. `git init` + `git push` → деплой на Vercel
|
||||
11. **Тест MCP Inspector удалённо** — проверить что работает через Vercel URL
|
||||
12. **Тест curl удалённо** — POST запрос к Vercel endpoint
|
||||
13. **Подключение к Cursor** — проверить что LLM видит и вызывает quack
|
||||
14. **Подключение к Claude Desktop** — проверить что LLM видит и вызывает quack
|
||||
|
||||
### ФАЗА 2: Tool #2 + Philosophy (после проверки ФАЗЫ 1)
|
||||
|
||||
1. `src/data/wisdoms.ts` — наполнить базу мудростей
|
||||
2. `src/tools/quack-wisdom.ts` — Tool #2 (quack_wisdom)
|
||||
3. Добавить регистрацию quack_wisdom в `src/server.ts`
|
||||
4. Зарегистрировать Resource `about://rubber-duck` в `src/server.ts`
|
||||
1. `npx create-next-app@latest rubber-duck-mcp --typescript --app`
|
||||
2. Установить `mcp-handler`, `@modelcontextprotocol/server`, `zod`
|
||||
3. Создать `lib/mcp.ts` — функция `createMcpServer()` с tool `quack`
|
||||
4. Создать `app/api/mcp/route.ts` — хендлер через `createMcpHandler`
|
||||
5. `npm run typecheck` → исправить ошибки
|
||||
6. `npm run build` → проверить
|
||||
7. **Тест MCP Inspector локально** — проверить что видит оба tool + resource
|
||||
8. **Тест curl локально** — вызвать quack_wisdom
|
||||
9. `git push` → автодеплой на Vercel
|
||||
10. **Тест MCP Inspector удалённо** — проверить что оба tool работают
|
||||
11. **Подключение к Cursor/Claude** — проверить что LLM использует quack_wisdom
|
||||
6. `npm run build` → убедиться
|
||||
7. Тест локально: MCP Inspector + curl
|
||||
8. Деплой: `vercel --prod` (или через GitHub)
|
||||
9. Тест удалённо: MCP Inspector + curl к Vercel URL
|
||||
10. Подключение к Cursor и Claude Desktop — проверить что LLM вызывает quack
|
||||
|
||||
### ФАЗА 2: quack_wisdom + Philosophy
|
||||
|
||||
1. Создать `src/data/wisdoms.ts` — база мудростей
|
||||
2. Добавить tool `quack_wisdom` в `lib/mcp.ts`
|
||||
3. Зарегистрировать resource `about://rubber-duck`
|
||||
4. `npm run typecheck` + `npm run build`
|
||||
5. Тест локально: MCP Inspector видит оба tool + resource
|
||||
6. `vercel --prod` → тест удалённо
|
||||
7. Подключение к Cursor/Cude — проверить quack_wisdom
|
||||
|
||||
Reference in New Issue
Block a user