TabHub MCP Server
by WistRu
README.md
# TabHub
Локальный менеджер вкладок из нескольких Chromium-браузеров с REST, MCP и веб-интерфейсом. Сервер слушает только `127.0.0.1`.
## Требования
- Windows 10/11
- Node.js 22+
- Corepack (`corepack enable`)
## Запуск
```powershell
corepack pnpm install
Copy-Item .env.example .env
corepack pnpm dev
```
### Personal-context local capability
The first-class context routes are fail-closed behind
`TABHUB_FEATURE_CONTEXT=true`. Production `/app` navigation receives an opaque
`HttpOnly; SameSite=Strict` local session. During Vite development, set a random
server-only `TABHUB_DEV_PROXY_SECRET`; the Vite proxy must call
`POST /api/local/session/bootstrap` and inject the matching
`x-tabhub-dev-proxy-secret` header. Never use a `VITE_` variable for this value
or expose it to browser code. The bootstrap secret, bearer credentials, pairing
codes, context bodies, raw search queries, and idempotency keys are excluded
from request logs.
Команда сначала собирает веб-интерфейс, затем запускает сервер. Откройте [http://127.0.0.1:7717/app/](http://127.0.0.1:7717/app/).
Веб-интерфейс доступен на английском и русском языках. Язык можно выбрать в шапке приложения; выбор сохраняется в браузере. Popup и настройки расширения автоматически используют язык интерфейса браузера, если это английский или русский.
Проверка сервера:
```powershell
Invoke-RestMethod http://127.0.0.1:7717/api/health
```
Текущий ожидаемый ответ:
```json
{"status":"ok","database":"ok","schemaVersion":26}
```
База по умолчанию создаётся в `data/tabhub.sqlite` относительно корня репозитория. Путь можно изменить через `TABHUB_DB_PATH` в корневом `.env`.
`TABHUB_FEATURE_LOGICAL_IMPORTANCE=false` сохраняет прежний редактор важности для отдельной физической вкладки и отключает новые logical-page endpoints. Значение `true` включает единую каноническую оценку важности для всех копий одной URL-страницы. После изменения флага перезапустите сервер. Для безопасного отката верните `false`: сохранённые канонические данные не удаляются, но legacy-интерфейс их не читает и не изменяет.
Для разработки UI с hot reload запустите сервер и Vite одной командой, затем откройте адрес Vite из консоли:
```powershell
corepack pnpm dev:web
```
`TABHUB_FEATURE_RESOURCES=true` enables the Resource backend and REST API:
resource list/detail/pages/all-time activity, resource context, commands, user evaluation,
and `resource_id` intersections for tab/instance selections. The Resource UI
facet arrives in W30 and is not enabled by this server flag alone. Set the flag
back to `false` and restart for a safe rollback: stored mappings, context, and
evaluations remain isolated and are neither deleted nor exposed by resource routes.
The exact-copy capture and Drawer Short/Deep page-summary flow is independently
fail-closed behind `TABHUB_FEATURE_PAGE_SUMMARY_CAPTURE=true`. It deliberately
does not reuse the Resource research flag: a deep page summary still analyzes
one captured page, while research has separate corpus, evidence, budget, and
consent semantics. With this flag off (the default), `/api/features` reports
`pageSummaryCapture: false`, the HTTP relay rejects only
`capture-tab-content` before extension dispatch, and the exact-instance ingest
route is absent. Ordinary content ingest, the existing Library short-summary
action for already captured content, and activation/close/workspace relay
commands remain available. Restart the server after changing the flag; set it
back to `false` for the schema-compatible rollback surface.
Captured-only Resource/page research is independently default-off behind
`TABHUB_FEATURE_RESEARCH=true`. Schema 24 is installed unconditionally so
existing research history and privacy redaction remain readable when the flag
is returned to `false`; the disabled flag blocks only new preflight, run and
research-cancel mutations. Execution additionally requires `ANTHROPIC_API_KEY`.
Without a provider, preflight, history, job reads and privacy redaction remain
available, while run/refine fail before writing with
`503 RESEARCH_PROVIDER_UNAVAILABLE`.
The provider uses `ANTHROPIC_RESEARCH_MODEL`, immutable startup prices from
`ANTHROPIC_RESEARCH_INPUT_USD_PER_MTOK` and
`ANTHROPIC_RESEARCH_OUTPUT_USD_PER_MTOK`, and an optional explicit
`ANTHROPIC_RESEARCH_PRICING_VERSION`. When the version is blank, TabHub derives
one from the effective prices. `TABHUB_RESEARCH_MAX_OUTPUT_TOKENS` is capped at
8192 and `TABHUB_RESEARCH_TIMEOUT_MS` bounds one call. The worker permits one
concurrent call, ten attempts and USD 2 of reservation per UTC day, while every
run must also fit its user-approved budget. Research consumes only the captured
approved corpus: it never fetches, opens or navigates to a URL. Restart the
server after changing any research flag or provider setting.
Schema-26 bounded live acquisition is independently default-off behind
`TABHUB_FEATURE_LIVE_ACQUISITION=true`. When enabled, the accepted C90b
coordinator exposes Resource-only preflight/start/status flows, uses the closed
server-internal `SafePublicHttpClient`, materializes bounded public evidence, and
hands an immutable captured/live corpus to the existing research workflow. It
does not expose a generic fetch endpoint and never uses browser navigation,
extension fetches, redirects, retries, scripts, subrequests, or tab/window
mutation. Keep the flag `false` outside an explicitly reviewed rollout.
`TABHUB_FEATURE_PRIVACY_PURGE=true` enables creation of new durable privacy
purges. Existing schema-26 purge status and retry/recovery remain available when
the flag is off so disabling new work cannot strand an active purge.
Daily activity is controlled by two independent, fail-closed flags. Set
`TABHUB_FEATURE_ACTIVITY_DAILY_WRITER=true` to collect accepted activity into
UTC daily buckets and update gap/duplicate/out-of-order metrics. Set
`TABHUB_FEATURE_ACTIVITY_WINDOWS=true` together with
`TABHUB_FEATURE_ACTIVITY_DAILY_WRITER=true` and
`TABHUB_FEATURE_RESOURCES=true` to advertise and expose 7d/30d page/resource
windows and activity metrics to UI/adapters. Both activity flags default to
`false`. Reader-only mode fails closed to G3 all-time activity because daily
coverage would be incomplete; writer-only mode collects buckets without exposing
the new readers and is valid for staged rollout.
The immutable migration availability epoch records when daily tracking became
available. A separate persisted writer lifecycle epoch records only the current
continuous period during which the server-side daily writer was enabled. It does
not claim that the browser extension delivered every possible observation; gaps
and delivery health remain separate telemetry concerns. Disabling and re-enabling
the writer starts a new continuous epoch, and finite readers remain unavailable
unless both activity flags are currently enabled.
Priority assessment rollout uses three independent default-off flags:
`TABHUB_FEATURE_PRIORITY_ASSESSMENT_WRITER` permits staged assessment writes,
`TABHUB_FEATURE_PRIORITY_READERS` permits schema-22 readers, and
`TABHUB_FEATURE_PRIORITY_SHADOW` permits shadow presentation only when readers
are also enabled. C50 only declares and validates these flags; it does not start
collection or expose priority routes. A writer can be staged without readers or
shadow, while every requested capability fails closed on a database older than
schema 22.
### Автозапуск в Windows
Для постоянного локального запуска сначала соберите production-артефакты и проверьте их вручную:
```powershell
corepack pnpm install --frozen-lockfile
corepack pnpm build
corepack pnpm start
```
Сервер по-прежнему принимает соединения только на `127.0.0.1`; другое значение `TABHUB_HOST` отклоняется, потому что в v1 нет авторизации. Для автозапуска откройте **Планировщик заданий → Создать задачу** и задайте:
- триггер **При входе в систему**;
- на вкладке **Общие** выберите «Выполнять только для вошедшего пользователя», потому что перевод фокуса между окнами браузеров требует интерактивного рабочего стола;
- действие **Запуск программы**;
- программа — абсолютный путь из `(Get-Command node).Source`;
- аргументы — абсолютный путь из `(Resolve-Path packages/server/dist/main.js).Path`, заключённый в кавычки;
- рабочая папка — путь из `(Resolve-Path .).Path`.
- на вкладке **Параметры** отключите «Останавливать задачу, выполняемую дольше 3 дней» и включите перезапуск при сбое, например через 1 минуту до 3 раз.
После сохранения запустите задачу вручную и проверьте `Invoke-RestMethod http://127.0.0.1:7717/api/health`. После обновления TabHub снова выполните `corepack pnpm install --frozen-lockfile` и `corepack pnpm build`, затем перезапустите работающий сервер (или задачу в Планировщике), чтобы применились новые миграции, и убедитесь, что health endpoint показывает `schemaVersion: 26`. Перезагрузите TabHub на странице расширений браузера и обновите страницу приложения, чтобы отправить свежий снимок; задачу пересоздавать не нужно.
## Расширение Chromium
Соберите один Manifest V3-билд:
```powershell
corepack pnpm --filter @tabhub/extension build
```
В каждом браузере откройте страницу расширений, включите режим разработчика и загрузите распакованную папку `packages/extension/.output/chrome-mv3`:
- Chrome: `chrome://extensions`
- Edge: `edge://extensions`
- Yandex Browser: `browser://extensions`
Откройте настройки TabHub и отдельно выберите имя текущего браузера. Это обязательно: Chromium API не позволяет надёжно отличить Chrome от Yandex Browser, поэтому до явного выбора автоматическая и ручная отправка вкладок отключена. После обновления со старой версии браузер нужно выбрать ещё раз: это не позволяет прежнему автоматическому значению `chrome` ошибочно пометить Edge или Yandex. При смене уже настроенного значения расширение сначала закрывает старый снимок, затем отправляет полный снимок с новой идентичностью. Каждая установка расширения хранит собственный UUID, а для текущей загруженной сессии расширения в браузере — отдельный сессионный UUID, и передаёт нативный `tabId`; поэтому два профиля одного браузера и две физические вкладки с одинаковым URL больше не сливаются, а устаревший `tabId` после перезапуска или перезагрузки расширения не используется для переключения.
В popup доступны проверка локального сервера, число несинхронизированных физических вкладок и операций, ручной снимок и захват контента текущей либо всех доступных HTTP(S)-вкладок. Полный снимок без жёсткого лимита количества вкладок также отправляется при старте, после изменений вкладок с debounce и каждые пять минут через `chrome.alarms`; транспорт проверяет только фактический размер payload. Если сервер выключен, ожидающие данные сохраняются в `chrome.storage.local`: заменённые снимки и повторный контент компактируются, а очередь ограничена только безопасным размером 32 MiB без лимита количества операций. Постоянные HTTP-ошибки 4xx, кроме 408/425/429, переносятся в ограниченный журнал из 50 записей и не блокируют следующие элементы; временные ошибки сохраняют порядок и повторяются автоматически.
Веб-интерфейс по умолчанию открывает **Library**, а **Graph** остаётся альтернативной визуализацией тех же канонических страниц. Отдельной основной вкладки **Open tabs** больше нет. Library сохраняет первоначальную последовательность появления страниц и постоянный порядок браузеров Chrome → Yandex → Edge → Other; теги, summary и связи не дублируются между физическими копиями. В колонке **Tab** закрытая страница не имеет физической цели, одна открытая копия показана компактной точной вкладкой браузера, а две и более копии раскрываются в список с окном, позицией и нативным `tabId`. Переход и закрытие из этого списка адресуются полной identity `browser / installation / browserSession / browserTabId`, поэтому TabHub фокусирует или закрывает выбранную вкладку в её собственном Chrome, Yandex Browser, Edge либо другом Chromium-профиле и не открывает URL-дубликат. Фильтр **Multiple open copies** оставляет только канонические строки с `openInstanceCount > 1`; он применяется на сервере до подсчёта и пагинации и намеренно отличается от exact-duplicate проверки raw URL. Fragment (`#...`) входит в идентичность канонической страницы, а регистронезависимые `utm_*` по-прежнему удаляются как tracking-параметры.
В обычном состоянии Library checkbox выделяет канонические страницы для изменения статуса и тем. Отдельная кнопка **Manage browser tabs / Управление вкладками** включает массовый выбор физических экземпляров: checkbox родительской строки выбирает все её открытые копии, а раскрытый список позволяет оставить только конкретные. Физический выбор сохраняется при пагинации, но очищается при смене Library-фильтров, выключении управления или уходе в Graph; переход в Graph также возвращает обычный режим страниц. Полный отфильтрованный набор физических вкладок разрешается отдельным непагинированным запросом без лимита SQLite на 999 bind-параметров. В этом режиме доступны Move, Close, Pin/Unpin, Mute/Unmute, Sleep, Reload, Workspaces и экспорт URL/Markdown/JSON, а также пресеты **Extra exact copies**, точного hostname и возраста. Обычная live-команда может относиться только к одной точной browser/install/session; смешанный, устаревший или offline-выбор блокируется целиком. Отдельное явное действие **Close all matching duplicates** пакетирует только безопасные лишние exact raw-URL копии по подключённым профилям, сохраняет keeper в каждой группе, выполняет отдельный строгий live preview для каждого профиля и перед общим подтверждением показывает исключённые профили. Массовое закрытие показывает receipt по профилям и доступный **Reopen closed tabs**; неизвестный результат автоматически не повторяется. Нажатие колёсиком по строке Library закрывает без модального окна только единственную физическую копию; при нескольких копиях сначала нужно выбрать точную строку в раскрытом списке. Вкладка TabHub остаётся защищённой, а live-команды не имеют скрытого лимита целей.
Внутри Library есть персональные коллекции **На разбор** и **Корзина**. На разбор попадают только слабые рекомендации по страницам из Inbox с нулевой важностью: интерфейс всегда показывает причины и предупреждения, но не удаляет ничего автоматически. Для любой страницы — независимо от сайта или темы — можно явно выбрать **Оставить**, **Позже** либо **Закрыть и забыть**. Последнее действие требует подтверждения, адресует каждую известную физическую копию в её собственном браузере, требует полного точного результата закрытия и только затем скрывает каноническую страницу из обычной Library. При offline, изменившейся или неадресуемой копии страница не забывается; если сбой произошёл уже во время закрытия нескольких браузеров, результат сообщает число успевших закрыться копий, а запись остаётся в Library для безопасного повтора. Забытая страница семь дней остаётся в обратимой Корзине; повторное открытие или явное восстановление отменяет удаление, а просроченные закрытые записи очищаются сервером в фоне.
В колонке Library **Activity** TabHub суммирует две исторические оценки для канонической страницы во всех отслеженных сессиях браузера. Эти значения сохраняются после закрытия физической вкладки и перезапуска браузера; при навигации интервалы относятся к URL, на котором они были записаны, поэтому время страниц не смешивается. Даже если короткий переход завершился раньше дебаунсированного snapshot, принятый activity interval сам создаёт закрытую Library-запись, а последующий snapshot открывает и обогащает её без дубликата. **On screen** учитывает только время, когда вкладка выбрана, её окно находится на переднем плане, а компьютер не простаивает и не заблокирован. **Active use** — подмножество этого времени в течение 60 секунд после подтверждённого движения или нажатия мышью, клавиатуры, прокрутки либо касания. Drawer отдельно показывает историческую **Page activity / Активность страницы** и метрики **Open copies / Открытые копии** для конкретных физических вкладок текущей browser session. Расширение сохраняет только интервалы и суммы, без координат указателя, нажатых клавиш и текста. Для защищённых страниц браузера, где content script недоступен, учитывается только On screen. После полного перезапуска браузера счётчики физических вкладок начинают новую сессию, чтобы повторно использованный Chromium `tabId` не получил чужое время, но историческая активность страницы продолжает накапливаться. Точный исторический агрегат начинается со schema 15: прежние физические суммы без сохранённого URL намеренно не переносятся на страницы наугад; schema 16 материализует точные activity-only URL, которые snapshot не успел увидеть.
**Workspaces** сохраняют в SQLite именованный снимок всех выбранных физических экземпляров, включая одинаковые URL, в актуальном серверном порядке browser/window/index. Запрос содержит компактные идентификаторы, а после live-команды расширение сначала синхронизирует новый порядок и флаги; поэтому Save сразу после Move/Pin/Mute не фиксирует старое состояние. **Save & close** сначала подтверждённо сохраняет снимок и лишь затем открывает close preview. Весь сохранённый набор можно открыть в текущем или новом окне, переименовать либо удалить; восстановление последовательно открывает каждый сохранённый элемент без скрытого усечения. Во время восстановления повторный запуск блокируется, а при неизвестном результате по таймауту UI просит сначала проверить браузер. Выбранные вкладки также копируются как список URL, Markdown или JSON.
Контент извлекается только по команде: Readability получает основной текст и HTML статьи, а для страниц без подходящей статьи используется `document.body.innerText`. Автоматического обхода всех вкладок в v1 нет.
После снимков из нескольких браузеров записи появятся в общей таблице с колонкой браузера. Повторный снимок обновляет существующую нормализованную ссылку; исчезнувшая вкладка остаётся в БД с `isOpen=false`.
### REST-проверка без расширения
```powershell
$body = @{
browser = 'chrome'
tabs = @(@{
url = 'https://example.com/?utm_source=test#section'
title = 'Example'
windowId = 1
index = 0
})
} | ConvertTo-Json -Depth 4
Invoke-RestMethod -Method Post -Uri http://127.0.0.1:7717/api/ingest/snapshot -ContentType application/json -Body $body
Invoke-RestMethod http://127.0.0.1:7717/api/tabs
```
`GET /api/tabs` поддерживает глобальную сортировку до пагинации: `sort_by`
принимает `title`, `topics`, `browser`, `activity`, `status`, `importance`,
`state` или `age`, а `sort_direction` — `asc` или `desc`. Сортировка по
столбцам не комбинируется с `search_mode=semantic` и `similar_to`, где порядок
определяется релевантностью.
### Полнотекстовый поиск
Поиск работает по заголовку и полному URL ещё до захвата контента, включая заголовок и исходный URL каждой физической вкладки, объединённой с канонической страницей; после захвата он также учитывает очищенный текст и summary. Частично введённые слова совпадают по префиксу, а буквальные фрагменты заголовка и URL — по регистронезависимой Unicode-подстроке; пунктуация пользовательского запроса не интерпретируется как FTS-синтаксис:
```powershell
Invoke-RestMethod 'http://127.0.0.1:7717/api/tabs?q=local-first'
```
В веб-интерфейсе тот же параметр доступен в строке поиска над таблицей.
### Семантический поиск и кластеры inbox
Эмбеддинги создаются только по явному запросу. По умолчанию TabHub использует локальный Ollama на `http://127.0.0.1:11434`; перед первым индексированием установите модель:
```powershell
ollama pull nomic-embed-text
```
Для Voyage задайте `EMBEDDING_PROVIDER=voyage`, `VOYAGE_API_KEY` и при необходимости `VOYAGE_EMBEDDING_MODEL` в `.env`. `EMBEDDING_PROVIDER=disabled` полностью отключает провайдер. Оба варианта сохраняют 512-мерные векторы в локальной таблице `sqlite-vec`; захваченный текст перед отправкой провайдеру ограничивается 32 000 символами и обрабатывается пакетами по 100 вкладок.
```powershell
Invoke-RestMethod -Method Post `
-Uri http://127.0.0.1:7717/api/embeddings/reindex `
-ContentType application/json `
-Body '{"limit":100}'
Invoke-RestMethod 'http://127.0.0.1:7717/api/tabs?q=compiler&search_mode=semantic'
Invoke-RestMethod 'http://127.0.0.1:7717/api/tabs?similar_to=1'
Invoke-RestMethod -Method Post `
-Uri http://127.0.0.1:7717/api/clusters/inbox `
-ContentType application/json `
-Body '{"maxClusters":8}'
```
Повторный захват текста удаляет устаревший вектор. `cluster_inbox` индексирует только ещё не проиндексированные вкладки со статусом `inbox`, затем детерминированно предлагает именованные кластеры; он не создаёт теги и не меняет пользовательскую разметку.
### Суммаризация по запросу
TabHub никогда не суммаризирует вкладки автоматически. Чтобы включить ручные запросы из UI или MCP, задайте `ANTHROPIC_API_KEY` в `.env` и перезапустите сервер. По умолчанию короткий режим использует `claude-haiku-4-5-20251001`, глубокий — `claude-sonnet-5`; модели и расчётные цены можно переопределить переменными `ANTHROPIC_*` из `.env.example`.
Запрос создаёт надёжное задание в SQLite, а фоновый worker выполняет не более одного вызова Anthropic одновременно. Временные ошибки повторяются с backoff, незавершённые задания восстанавливаются после перезапуска, устаревший результат не записывается поверх повторно захваченного контента. `TABHUB_DAILY_SUMMARY_LIMIT` ограничивает именно попытки вызова провайдера за UTC-день; расход токенов и расчётная стоимость сохраняются для каждой попытки и пишутся в лог успешного задания.
```powershell
$job = Invoke-RestMethod -Method Post `
-Uri http://127.0.0.1:7717/api/tabs/1/summarize `
-ContentType application/json `
-Body '{"depth":"short"}'
Invoke-RestMethod "http://127.0.0.1:7717/api/jobs/$($job.jobId)"
```
Если ключ не настроен, endpoint возвращает `503 SUMMARY_PROVIDER_UNAVAILABLE` и не создаёт задание. В таблице UI у каждой вкладки с захваченным текстом доступно создание или обновление короткого summary; состояние очереди и ошибки показываются рядом с действием.
### Организация вкладок
Таблица поддерживает выбор строк и массовое изменение статуса либо назначение иерархического пути темы, например `Research/AI/Agents`. Поле темы в массовой панели и карточке вкладки предлагает существующие пути с поиском, но остаётся редактируемым для создания нового пути; системная тема `Без темы` в подсказки не входит. Строки текущей страницы виртуализируются с динамическим измерением высоты, поэтому раскрытые summary остаются корректными без монтирования всей страницы в DOM. Сайдбар тем показывает дерево произвольной глубины с накопительными счётчиками: в нём можно создавать корневые и дочерние темы, переименовывать и перемещать их, задавать цвет и после подтверждения удалять темы без подтем. Фильтр по родительскому пути включает вкладки из всех дочерних тем. Клик по строке открывает карточку вкладки с контентом, summary, темами, направленными связями, важностью и произвольными полями.
Защищённая системная тема `Без темы` автоматически содержит все вкладки без пользовательской темы. При назначении первой обычной темы эта связь снимается, а после удаления последней обычной темы восстанавливается. `Без темы` можно использовать как фильтр в Library и Graph, но нельзя переименовывать, перемещать, удалять или назначать вручную. В графе сама системная тема и её структурные связи не отображаются: отфильтрованные вкладки выглядят как обычные вкладки без назначенных тем.
`PATCH /api/tabs/:id` принимает любую непустую комбинацию `status`, `importance` и `customFields`. Строковое значение создаёт или обновляет поле, `null` удаляет его. Массовая важность доступна через `PATCH /api/tabs/importance`. CRUD тем находится под `/api/tags`, назначение пути — `POST /api/tags/assign`. Универсальные связи вкладка-вкладка, вкладка-тема и тема-тема доступны под `/api/relations`; прежний `/api/links` сохранён как совместимая проекция связей между вкладками. Ручные изменения сохраняются с происхождением `user`, изменения MCP — `agent`.
### Граф связей
Раздел **Graph** открывает трёхмерный WebGL-граф, где отдельными типами узлов представлены вкладки и темы. Мышью можно вращать сцену, перемещаться по плоскости, приближать и отдалять её. Клик выбирает узел, переводит к нему камеру и открывает инспектор с метаданными, переходом к существующей вкладке браузера или выбранной теме Library.
Для выбранного узла настраивается глубина фокуса от одного до пяти шагов: все узлы и рёбра в этом неориентированном окружении остаются яркими, остальная сцена становится прозрачной. При активном фильтре сервер сохраняет прямые перекрёстные связи за границей темы, а более глубокое окружение выбранного узла догружает отдельной ограниченной проекцией — полный глобальный граф для этого не требуется. В инспекторе можно создать направленную смысловую связь с любым видимым узлом, указать её тип и заметку либо удалить существующую смысловую связь. Иерархия тем и принадлежность вкладок отображаются как структурные рёбра, но не дублируются в таблице пользовательских связей.
Фильтр в дереве тем загружает только выбранное поддерево. Для плотных графов интерфейс сокращает время симуляции, упрощает геометрию и отключает дорогое перетаскивание отдельных узлов; сам 3D-код загружается отдельным lazy chunk и не утяжеляет первоначальное открытие Library. Канонический типизированный REST-ответ доступен отдельно, а прежний endpoint сохранён для совместимости:
```powershell
Invoke-RestMethod http://127.0.0.1:7717/api/graph/v2
Invoke-RestMethod 'http://127.0.0.1:7717/api/graph/v2?root_topic_id=1'
Invoke-RestMethod 'http://127.0.0.1:7717/api/graph/v2?root_topic_id=1&focus_node_type=topic&focus_node_id=2&focus_depth=3'
Invoke-RestMethod http://127.0.0.1:7717/api/relations
Invoke-RestMethod http://127.0.0.1:7717/api/graph
```
## MCP для Claude Desktop и Codex
Сначала соберите stdio-сервер MCP и оставьте основной TabHub-сервер запущенным на `127.0.0.1:7717`:
```powershell
corepack pnpm --filter @tabhub/mcp build
corepack pnpm dev
```
MCP-процесс использует `TABHUB_API_URL` и остаётся тонким адаптером над REST API. Он предоставляет инструменты `list_tabs`, `get_tab`, `search_tabs`, `summarize_tab`, `cluster_inbox`, `set_status`, `set_importance`, `tag_tabs`, `link_tabs`, `list_tags`, `get_stats`, `review_disposable_pages`, `set_page_retention`, `close_and_forget_page`, `list_retention_trash`, `restore_retention_page` и ресурс `tabhub://tab/{id}`. `list_tabs` принимает те же фильтры, что REST-список, включая `q`, `search_mode` и `similar_to`; `search_tabs` поддерживает режимы `fulltext` и `semantic`. `cluster_inbox` явно индексирует неразобранные вкладки и возвращает предложения с названиями, ключевыми словами и идентификаторами вкладок. Deprecated-инструмент `set_importance` сначала читает `/api/features`: при включённом logical importance сервер фиксирует агентскую запись `on_behalf_of_user`, а при выключенном флаге или старом schema-17 сервере используется прежняя скалярная запись только выбранных вкладок. Некорректный feature contract не приводит к записи. `review_disposable_pages` только показывает персональные предложения и предупреждения; `set_page_retention` сохраняет решения «оставить» или «позже». Разрушающий `close_and_forget_page` требует `confirmed=true`, закрывает все известные физические экземпляры только при точно подтверждённом результате и затем переносит страницу в семидневную корзину; её можно просмотреть и отменить через `list_retention_trash` и `restore_retention_page`. `summarize_tab` помечает запрос как агентский, ставит его в ту же SQLite-очередь и ожидает завершения до 55 секунд; если работа ещё не закончилась, повторный вызов продолжит ожидание того же активного задания. Контент в ответах MCP ограничен примерно 20 000 символами.
### Claude Desktop
Откройте **Settings → Developer → Edit Config**, добавьте сервер в `%APPDATA%\Claude\claude_desktop_config.json` и полностью перезапустите Claude Desktop:
```json
{
"mcpServers": {
"tabhub": {
"command": "C:\\Program Files\\nodejs\\node.exe",
"args": ["D:\\VibeCoding\\TabHub\\packages\\mcp\\dist\\main.js"],
"env": {
"TABHUB_API_URL": "http://127.0.0.1:7717"
}
}
}
}
```
Если Node.js или репозиторий находятся в другом месте, получите абсолютные пути командами `(Get-Command node).Source` и `(Resolve-Path packages/mcp/dist/main.js).Path` и замените значения выше.
### Codex
Добавьте сервер через CLI:
```powershell
codex mcp add tabhub --env TABHUB_API_URL=http://127.0.0.1:7717 -- 'C:\Program Files\nodejs\node.exe' 'D:\VibeCoding\TabHub\packages\mcp\dist\main.js'
codex mcp list
```
Эквивалентная ручная настройка в `%USERPROFILE%\.codex\config.toml`:
```toml
[mcp_servers.tabhub]
command = 'C:\Program Files\nodejs\node.exe'
args = ['D:\VibeCoding\TabHub\packages\mcp\dist\main.js']
cwd = 'D:\VibeCoding\TabHub'
startup_timeout_sec = 10
tool_timeout_sec = 60
[mcp_servers.tabhub.env]
TABHUB_API_URL = "http://127.0.0.1:7717"
```
После подключения откройте `/mcp` в Codex и убедитесь, что `tabhub` и все перечисленные выше инструменты доступны.
## Проверки
```powershell
corepack pnpm test
corepack pnpm typecheck
corepack pnpm build
```
## Резервная копия
При остановленном или работающем сервере SQLite online-backup создаётся командой:
```powershell
corepack pnpm backup
```
Файл появится в корневой папке `backups/`.
## Статус реализации
- Этап 0: каркас монорепозитория, общие схемы, миграция SQLite и healthcheck — готово.
- Этап 1: снимки из Chromium-браузеров, надёжная очередь расширения, REST ingest, дедупликация и общая таблица — готово.
- Этап 2: ручной захват Readability-контента, FTS5 и поиск в UI — готово.
- Этап 3: REST-операции управления, иерархические теги, статистика и MCP-инструменты для Claude Desktop/Codex — готово.
- Этап 4: явная суммаризация через надёжную SQLite-очередь, последовательный Anthropic worker, UI и MCP — готово.
- Этап 5: дерево тем, карточка вкладки, связи, важность, custom fields и массовые операции в UI/MCP — готово.
- Этап 6: `sqlite-vec`, явное индексирование через Ollama/Voyage, семантический поиск, похожие вкладки и именованные кластеры inbox в REST/MCP — готово.
- Этап 7: типизированный 3D-граф вкладок и тем с WebGL-навигацией, произвольными перекрёстными связями, инспектором и фокусом на окружении глубиной 1–5 шагов — готово.
## Keeping the runtime up
The server is an ordinary process: started by hand, it dies with the machine and
does not come back. On 2026-08-24 the host lost power at 04:32 and the runtime
stayed down for eight hours before anyone noticed, which cost a day of the Trial
week (issue #37).
Two things address that, and they are separate concerns.
### Start it, and keep it started
```bash
corepack pnpm --filter @tabhub/server build
```
```powershell
powershell -ExecutionPolicy Bypass -File scripts/install-autostart.ps1
```
The build comes first: the task launches `packages/server/dist/main.js`, and the
installer refuses to register a task that would point at nothing.
Autostart is configured by `pnpm install`, so there is normally nothing to run
by hand. The command above is only for reconfiguring it.
It prefers a per-user scheduled task with two triggers: at logon, so a reboot is
survivable, and every five minutes, so a runtime that dies on its own comes back
without waiting for one. **On some machines that is refused outright** — security
policy or protection software can deny scheduled tasks to an ordinary user, and
this one does. When that happens it falls back to a Startup-folder entry running
the launcher in `-Watch` mode, which needs no privileges and does both jobs:
starts at logon, keeps checking while it runs.
The fallback is weaker in one way worth knowing: if the watcher process is
killed, nothing restores it until the next logon. Both call `scripts/tabhub-runtime.ps1`, which checks two
things before starting anything: whether something is already serving on
`127.0.0.1`, and whether a TabHub process is running at all. The second matters —
a process that is alive but not yet listening still holds the database, and a port
check alone would happily start a second one alongside it.
It needs no elevated privileges. Remove it with `-Remove`.
**It is not proven until the machine has actually been rebooted.** These are shell
scripts, outside the test suite; reasoning that they should work is not the same as
watching them work.
### Tell an outage from an idle stretch
```bash
corepack pnpm --filter @tabhub/server availability
```
The runtime records when it is available, to `data/runtime-availability.jsonl`,
and heartbeats to `data/runtime-heartbeat.json` while it lives. A hard kill writes
nothing on its way out, so a session that never recorded a clean stop is closed by
the next start, bounded by the last heartbeat it managed to write.
The extension also marks its own icon when it cannot reach the server, so an outage
is visible without opening anything — which is how eight hours passed unnoticed the
first time.
This record exists because "TabHub was down" and "nobody used TabHub" are
indistinguishable in the data and mean opposite things. Where no heartbeat survived, the boundary is
reported as unknown rather than guessed, so a reader is never handed a confident
wrong duration.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessResponsive