@naparnik/mcp 0.10.52 → 0.10.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,374 @@
1
+ /** Определение ресурса в MCP */
2
+ interface McpResource {
3
+ /** URI ресурса (уникальный идентификатор) */
4
+ uri: string;
5
+ /** Человекочитаемое имя */
6
+ name: string;
7
+ /** Описание ресурса (опционально) */
8
+ description?: string;
9
+ /** MIME-тип содержимого (опционально) */
10
+ mimeType?: string;
11
+ }
12
+ /** Текстовое содержимое ресурса */
13
+ interface McpResourceTextContent {
14
+ uri: string;
15
+ mimeType?: string;
16
+ text: string;
17
+ /** Метаданные расширений: у виджета MCP Apps здесь `ui.csp`, `ui.prefersBorder` */
18
+ _meta?: Record<string, unknown>;
19
+ }
20
+ /** Бинарное содержимое ресурса */
21
+ interface McpResourceBlobContent {
22
+ uri: string;
23
+ mimeType?: string;
24
+ /** Base64-кодированные данные */
25
+ blob: string;
26
+ }
27
+ /** Содержимое ресурса — текст или бинарные данные */
28
+ type McpResourceItemContent = McpResourceTextContent | McpResourceBlobContent;
29
+
30
+ /**
31
+ * Типы и утилиты для инструментов агентного цикла.
32
+ *
33
+ * Порт из packages/agent-core/src/tools/tool.ts с расширениями:
34
+ * - readOnly флаг для параллельного выполнения
35
+ * - group — категория инструмента для фильтрации и UI
36
+ * - emitProgress в ToolContext — стриминг прогресса без возврата из execute
37
+ * - agentId в ToolContext — для мульти-агентных сценариев
38
+ */
39
+ /**
40
+ * Примитивный тип JSON Schema для параметра инструмента.
41
+ * Ограниченное подмножество JSON Schema — только то, что понимают LLM-провайдеры.
42
+ */
43
+ type JSONSchemaType = {
44
+ type: 'string';
45
+ description?: string;
46
+ enum?: string[];
47
+ /** Максимальная длина строки — защита от DoS через гигантский input. */
48
+ maxLength?: number;
49
+ /** Минимальная длина строки. */
50
+ minLength?: number;
51
+ } | {
52
+ type: 'number';
53
+ description?: string;
54
+ } | {
55
+ type: 'integer';
56
+ description?: string;
57
+ } | {
58
+ type: 'boolean';
59
+ description?: string;
60
+ } | {
61
+ type: 'array';
62
+ items: JSONSchemaType;
63
+ description?: string;
64
+ } | {
65
+ type: 'object';
66
+ properties: Record<string, JSONSchemaType>;
67
+ required?: string[];
68
+ description?: string;
69
+ /**
70
+ * Разрешить произвольные ключи в объекте (валидный JSON Schema keyword).
71
+ * Полезно для object-параметров с динамическими полями (params интеграций),
72
+ * где нужно явно подсказать LLM что это словарь произвольных ключей.
73
+ * При использовании совмещать с `properties: {}` для соответствия общему
74
+ * стилю кодовой базы.
75
+ */
76
+ additionalProperties?: boolean;
77
+ };
78
+ /** Схема входных параметров инструмента (JSON Schema объект верхнего уровня) */
79
+ interface ToolInputSchema {
80
+ type: 'object';
81
+ properties: Record<string, JSONSchemaType>;
82
+ required?: string[];
83
+ }
84
+ /**
85
+ * Контекст, передаваемый в каждый вызов инструмента.
86
+ *
87
+ * readFileTimestamps — критически важен для защиты от устаревших записей:
88
+ * перед перезаписью файла инструменты write/edit проверяют, что файл был
89
+ * прочитан в текущей сессии и не изменился с момента чтения.
90
+ */
91
+ interface ToolContext {
92
+ /** Уникальный идентификатор текущей сессии */
93
+ sessionId: string;
94
+ /** Сигнал отмены — инструменты должны проверять его при длительных операциях */
95
+ abortSignal?: AbortSignal;
96
+ /** Среда выполнения — влияет на доступные операции */
97
+ env: 'electron' | 'server' | 'test';
98
+ /** Рабочая директория для файловых операций */
99
+ workingDirectory?: string;
100
+ /**
101
+ * Временные метки последнего чтения файлов (путь → timestamp в мс).
102
+ *
103
+ * Заполняется инструментом чтения при каждом успешном обращении.
104
+ * Инструменты записи и редактирования проверяют этот словарь перед записью,
105
+ * чтобы обнаружить устаревшие правки (stale write detection).
106
+ *
107
+ * Ключ: абсолютный путь к файлу.
108
+ * Значение: Date.now() в момент прочтения.
109
+ */
110
+ readFileTimestamps: Record<string, number>;
111
+ /**
112
+ * Содержимое прочитанных файлов (путь → текст).
113
+ *
114
+ * Опциональный словарь для post-compact restore — заполняется инструментами
115
+ * чтения когда featureGates.postCompactRestore=true.
116
+ * Позволяет postCompactRestore() восстановить содержимое без повторного чтения с диска.
117
+ *
118
+ * Ключ: абсолютный путь к файлу (совпадает с readFileTimestamps).
119
+ * Значение: текстовое содержимое на момент последнего чтения.
120
+ */
121
+ readFileContents?: Record<string, string>;
122
+ /**
123
+ * Функция для эмиссии событий прогресса во время выполнения инструмента.
124
+ * Позволяет стримить промежуточные результаты в UI без завершения execute().
125
+ * Отсутствует, если потребитель не поддерживает стриминг прогресса.
126
+ */
127
+ emitProgress?: (content: string) => void;
128
+ /**
129
+ * Идентификатор агента в мульти-агентных сценариях.
130
+ * Используется для изоляции состояния между агентами и корректного логирования.
131
+ */
132
+ agentId?: string;
133
+ /**
134
+ * Программа, которая нас позвала: `clientInfo` из рукопожатия MCP
135
+ * («claude-ai», «codex-mcp-client»). Нужна отчёту о поломке
136
+ * (`crash-report.ts`): одна и та же беда у Claude Desktop и у Codex — это
137
+ * часто две разные беды. Нет — хост не представился.
138
+ */
139
+ host?: {
140
+ name: string;
141
+ version: string;
142
+ };
143
+ }
144
+ /**
145
+ * Текстовый блок в результате инструмента.
146
+ * Используется внутри mixed-content для аннотаций к изображениям.
147
+ */
148
+ interface ToolTextBlock {
149
+ type: 'text';
150
+ text: string;
151
+ }
152
+ /**
153
+ * Блок изображения в результате инструмента (vision support).
154
+ *
155
+ * Tool возвращает картинку «по-человечески»: base64 + mediaType.
156
+ * Конвертация в нативный формат API провайдера (Anthropic source/Google inlineData/
157
+ * OpenAI image_url) — обязанность нижележащего слоя (tool-dispatch + LLM provider).
158
+ *
159
+ * Используется для:
160
+ * - чтения сканированных документов (vision fallback при отказе OCR)
161
+ * - анализа скриншотов
162
+ * - обработки фото с телефона пользователя
163
+ */
164
+ interface ToolImageBlock {
165
+ type: 'image';
166
+ /** Base64-кодированные данные изображения (без префикса data:...) */
167
+ base64: string;
168
+ /** MIME-тип — модели нужен корректный формат для декодирования */
169
+ mediaType: 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp';
170
+ }
171
+ /**
172
+ * Блок-ссылка на изображение в vision-cache (disk storage).
173
+ *
174
+ * Альтернатива ToolImageBlock когда vision-cache сконфигурирован
175
+ * (`ctx.visionCache` есть). Tool пишет raw bytes в cache и возвращает
176
+ * file_ref вместо inline base64. Это снимает нагрузку с RAM/БД/PHP:
177
+ * tool_result в messages.content становится ~200 байт вместо ~500 KB.
178
+ *
179
+ * Раскрытие в base64 происходит непосредственно перед `provider.send()`
180
+ * через `expandVisionRefs` в `super-agent-core/src/loop/query.ts`.
181
+ *
182
+ * @see super-agent-core/src/loop/vision-cache.ts
183
+ */
184
+ interface ToolImageRefBlock {
185
+ type: 'image_ref';
186
+ /** Относительный путь от rootPath: `<sessionId>/<sha256>.<ext>` */
187
+ pathSuffix: string;
188
+ mediaType: 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp';
189
+ }
190
+ /** Объединённый тип контентного блока в результате инструмента */
191
+ type ToolContentBlock = ToolTextBlock | ToolImageBlock | ToolImageRefBlock;
192
+ /**
193
+ * Успешный результат инструмента.
194
+ *
195
+ * Может быть простой строкой (обычный случай) или массивом блоков text+image
196
+ * для мультимодальных результатов (vision). Image-блоки требуются чтобы
197
+ * модель могла «видеть» картинку, а не получать строку base64 в text-блоке.
198
+ */
199
+ interface ToolResultSuccess {
200
+ type: 'success';
201
+ content: string | ToolContentBlock[];
202
+ /**
203
+ * Данные для ВИДЖЕТА, мимо контекста модели.
204
+ *
205
+ * ⚠ РАЗДЕЛЕНИЕ НЕ РАДИ ПОРЯДКА, А РАДИ ДЕНЕГ И ТОЛКУ. Настоящий кадр ролика
206
+ * в base64 весит восемь килобайт; три кадра — двадцать четыре, и модель
207
+ * перечитывает их каждый ход, ничего в них не видя: base64 в тексте она
208
+ * «посмотреть» не может. Картинки нужны ГЛАЗАМ человека, то есть форме, а
209
+ * модели хватает названий словами. Уезжает как `structuredContent` в ответе
210
+ * `tools/call` — так это и разведено в спеке MCP.
211
+ */
212
+ structured?: Record<string, unknown>;
213
+ }
214
+ /** Результат с ошибкой без машиночитаемого кода */
215
+ interface ToolResultErrorBase {
216
+ type: 'error';
217
+ error: string;
218
+ }
219
+ /** Результат с ошибкой с машиночитаемым кодом */
220
+ interface ToolResultErrorWithCode {
221
+ type: 'error';
222
+ error: string;
223
+ /** Код ошибки для программной обработки (retry logic, UI, логирование) */
224
+ code: string;
225
+ }
226
+ /** Результат с ошибкой — с кодом или без */
227
+ type ToolResultError = ToolResultErrorBase | ToolResultErrorWithCode;
228
+ /** Финальный результат выполнения инструмента */
229
+ type ToolResult = ToolResultSuccess | ToolResultError;
230
+ /**
231
+ * Категория инструмента — для фильтрации, UI-группировки и политик доступа.
232
+ * Аналог group:* из конфигурации OpenClaw.
233
+ */
234
+ type ToolGroup = 'fs' | 'runtime' | 'web' | 'memory' | 'knowledge' | 'ui' | 'system' | 'automation' | 'confirmation' | 'collaboration' | 'integration' | 'skill';
235
+ /**
236
+ * Универсальный интерфейс инструмента агента.
237
+ *
238
+ * Инструменты регистрируются в агентском цикле и вызываются моделью
239
+ * по имени через механизм tool_use. Каждый инструмент описывает себя
240
+ * через JSON Schema и реализует функцию execute.
241
+ *
242
+ * @example
243
+ * ```typescript
244
+ * const readFileTool: Tool = {
245
+ * name: 'read_file',
246
+ * description: 'Читает содержимое файла по указанному пути',
247
+ * inputSchema: {
248
+ * type: 'object',
249
+ * properties: {
250
+ * path: { type: 'string', description: 'Путь к файлу' }
251
+ * },
252
+ * required: ['path']
253
+ * },
254
+ * readOnly: true,
255
+ * group: 'fs',
256
+ * async execute(input, ctx) {
257
+ * // ...
258
+ * }
259
+ * }
260
+ * ```
261
+ */
262
+ interface Tool<TInput = any> {
263
+ /** Уникальное имя инструмента (snake_case) */
264
+ name: string;
265
+ /** Человекочитаемое описание для модели */
266
+ description: string;
267
+ /**
268
+ * Название по-русски — для ЧЕЛОВЕКА, в отличие от `description` для модели.
269
+ * Уезжает хосту как `annotations.title` и показывается в настройках вместо
270
+ * имени из кода: без него человек читает «Choose variant», решая, разрешать
271
+ * ли инструмент.
272
+ */
273
+ title?: string;
274
+ /** JSON Schema входных параметров */
275
+ inputSchema: ToolInputSchema;
276
+ /**
277
+ * Флаг «только чтение».
278
+ * readOnly-инструменты не изменяют внешнее состояние и могут выполняться
279
+ * параллельно с другими readOnly-инструментами без риска конфликтов.
280
+ * Агентский цикл использует этот флаг для параллельного выполнения.
281
+ */
282
+ readOnly?: boolean;
283
+ /**
284
+ * Переписывает то, что у человека уже есть.
285
+ *
286
+ * По умолчанию `false`, и это не оптимизм: монтаж кладёт НОВЫЙ файл рядом с
287
+ * исходником, обновление держит прежнюю версию на диске, установка кладёт
288
+ * недостающее в свою папку — ничего из этого не затирает чужого. `true`
289
+ * ставится там, где вызов переписывает содержимое, которое человек считал
290
+ * своим: например, готовый фильтр цвета в его паке стиля.
291
+ */
292
+ destructive?: boolean;
293
+ /**
294
+ * Виджет инструмента (MCP Apps): адрес `ui://…` ресурса, HTML которого хост
295
+ * рисует в ленте вместо текстового ответа. Ресурс регистрируется на
296
+ * сервере отдельно (`McpServer.addResource`); здесь только ссылка, и в
297
+ * `tools/list` она уезжает как `_meta.ui.resourceUri`.
298
+ */
299
+ ui?: {
300
+ resourceUri: string;
301
+ };
302
+ /**
303
+ * Флаг «обратимое действие» — действие остаётся в рамках текущего диалога
304
+ * с этим пользователем и не выходит наружу.
305
+ *
306
+ * `true` (по умолчанию) — безопасно вызывать без явного человеческого approve:
307
+ * recall, web_search, view, create_file (в workspace), send_file_to_chat,
308
+ * send_task_to_agent (внутреннему агенту), bash_tool (sandbox-изолирован),
309
+ * integration_call с read-методами.
310
+ *
311
+ * `false` — действие выходит наружу и должно сопровождаться явной формулировкой
312
+ * подтверждения от пользователя (через диалог) перед выполнением:
313
+ * отправка наружу (письмо/SMS внешнему адресату), запись в CRM/ERP,
314
+ * финансовые операции, удаление persistent данных.
315
+ *
316
+ * Используется для генерации списков в system prompt и (в будущем)
317
+ * для автоматического enforcement в loop.
318
+ */
319
+ reversible?: boolean;
320
+ /**
321
+ * Группа инструмента — для фильтрации, UI-группировки и политик доступа.
322
+ * Соответствует group:* из конфигурации OpenClaw sandbox.
323
+ */
324
+ group?: ToolGroup;
325
+ /**
326
+ * Флаг «отложенная загрузка схемы» (lazy tool loading).
327
+ *
328
+ * Если `true` — JSON Schema этого tool'а НЕ передаётся в LLM API в каждом
329
+ * запросе. Модель видит только имя + 1-строчное описание в специальном
330
+ * блоке `<deferred_tools>` системного промпта и подгружает полную схему
331
+ * через ToolSearch tool когда нужно её вызвать.
332
+ *
333
+ * Используется для редких/тяжёлых tools чтобы экономить токены input'а:
334
+ * - integration_call (динамический, описание ~жирное)
335
+ * - browse_page (тяжёлый prompt)
336
+ * - observer_*, credential_*, skill_* (admin-flow, редко)
337
+ *
338
+ * НЕ deferr'им: bash, view, read, write, edit, grep, glob, web_*,
339
+ * todo_write, Task, ToolSearch, memory tools — это core.
340
+ *
341
+ * После вызова ToolSearch с `select:<name>` или релевантного keyword-search
342
+ * — схема активируется на оставшийся срок жизни сессии (обычный tools[] payload).
343
+ */
344
+ isDeferred?: boolean;
345
+ /**
346
+ * Максимальный размер `tool_result.content` в символах ДО persistence-cap.
347
+ *
348
+ * Семантика 1-в-1 как у Claude Code 2.1.88 (`Tool.ts:466`):
349
+ * - Эффективный порог = `min(maxResultSizeChars, DEFAULT_MAX_RESULT_SIZE_CHARS=50_000)`.
350
+ * Tool может объявить **БОЛЬШЕ** 50K — глобальный cap всё равно применит 50K.
351
+ * Tool может объявить **МЕНЬШЕ** 50K (например Grep 20K) — будет применён tool-specific лимит.
352
+ * - `Infinity` = hard opt-out, никогда не persist (для FileRead/view —
353
+ * нет смысла записывать файл во второй файл).
354
+ * - `undefined` = поведение как 100_000 (clamp до 50K).
355
+ *
356
+ * Применяется в `maybePersistLargeToolResult` (слой A) сразу после
357
+ * выполнения tool'а в `tool-dispatch.ts`, ДО того как tool_result попадёт
358
+ * в messages history. Большие результаты пишутся на диск
359
+ * `<rootPath>/<sessionId>/<tool_use_id>.{json,txt}`, в messages летит
360
+ * preview ~2000 символов внутри `<persisted-output>` тегов.
361
+ *
362
+ * Подробности — `new-version/docs/claude-code-optimizations.md` (Слой A).
363
+ */
364
+ maxResultSizeChars?: number;
365
+ /**
366
+ * Выполняет инструмент с заданными параметрами.
367
+ * @param input - Валидированные входные параметры
368
+ * @param ctx - Контекст выполнения (сессия, сигнал отмены, среда, временные метки файлов)
369
+ * @returns Результат выполнения или ошибка
370
+ */
371
+ execute(input: TInput, ctx: ToolContext): Promise<ToolResult>;
372
+ }
373
+
374
+ export type { McpResource as M, Tool as T, McpResourceItemContent as a, ToolContext as b, ToolResult as c, ToolInputSchema as d };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naparnik/mcp",
3
- "version": "0.10.52",
3
+ "version": "0.10.53",
4
4
  "description": "MCP-сервер Напарника: монтаж вертикального видео на машине пользователя — паузы, субтитры, герой на новом фоне, звук. Видео никуда не уезжает.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "private": false,