@vitalyostanin/youtrack-mcp 0.7.0 → 0.7.3
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.
- package/README-ru.md +44 -24
- package/README.md +19 -4
- package/dist/package.json +1 -1
- package/dist/src/config.js +2 -0
- package/dist/src/server.js +5 -4
- package/dist/src/tools/article-search-tools.d.ts +101 -2
- package/dist/src/tools/article-search-tools.js +33 -24
- package/dist/src/tools/article-tools.js +10 -4
- package/dist/src/tools/attachment-tools.js +2 -2
- package/dist/src/tools/issue-link-tools.js +5 -16
- package/dist/src/tools/issue-search-tools.d.ts +93 -2
- package/dist/src/tools/issue-search-tools.js +20 -57
- package/dist/src/tools/issue-star-tools.js +4 -4
- package/dist/src/tools/issue-tools.js +26 -8
- package/dist/src/tools/workitem-tools.js +5 -5
- package/dist/src/types.d.ts +90 -11
- package/dist/src/utils/issue-query.d.ts +13 -0
- package/dist/src/utils/issue-query.js +68 -0
- package/dist/src/utils/mappers.js +17 -1
- package/dist/src/youtrack-client.d.ts +18 -2
- package/dist/src/youtrack-client.js +379 -42
- package/package.json +1 -1
package/README-ru.md
CHANGED
|
@@ -19,29 +19,33 @@ MCP сервер для полноценной интеграции с YouTrack
|
|
|
19
19
|
|
|
20
20
|
## Содержание
|
|
21
21
|
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
|
|
27
|
-
- [
|
|
28
|
-
|
|
29
|
-
- [
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- [
|
|
33
|
-
- [
|
|
34
|
-
- [
|
|
35
|
-
- [
|
|
36
|
-
- [
|
|
37
|
-
- [
|
|
38
|
-
- [
|
|
39
|
-
- [
|
|
40
|
-
- [
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
22
|
+
- [YouTrack MCP Server](#youtrack-mcp-server)
|
|
23
|
+
- [Содержание](#содержание)
|
|
24
|
+
- [Требования](#требования)
|
|
25
|
+
- [Установка](#установка)
|
|
26
|
+
- [Используя npx (Рекомендуется)](#используя-npx-рекомендуется)
|
|
27
|
+
- [Используя Claude MCP CLI](#используя-claude-mcp-cli)
|
|
28
|
+
- [Ручная установка (Для разработки)](#ручная-установка-для-разработки)
|
|
29
|
+
- [Разработка и релиз](#разработка-и-релиз)
|
|
30
|
+
- [GitHub Actions Workflows](#github-actions-workflows)
|
|
31
|
+
- [CI Workflow (`.github/workflows/ci.yml`)](#ci-workflow-githubworkflowsciyml)
|
|
32
|
+
- [Publish Workflow (`.github/workflows/publish.yml`)](#publish-workflow-githubworkflowspublishyml)
|
|
33
|
+
- [Настройка NPM\_TOKEN](#настройка-npm_token)
|
|
34
|
+
- [Процесс релиза](#процесс-релиза)
|
|
35
|
+
- [Ручная сборка и тестирование](#ручная-сборка-и-тестирование)
|
|
36
|
+
- [Запуск сервера (stdio)](#запуск-сервера-stdio)
|
|
37
|
+
- [Конфигурация для Code (Рекомендуется)](#конфигурация-для-code-рекомендуется)
|
|
38
|
+
- [Конфигурация для Claude Code CLI](#конфигурация-для-claude-code-cli)
|
|
39
|
+
- [Конфигурация для VS Code Cline](#конфигурация-для-vs-code-cline)
|
|
40
|
+
- [Инструменты MCP](#инструменты-mcp)
|
|
41
|
+
- [Сервис](#сервис)
|
|
42
|
+
- [Задачи](#задачи)
|
|
43
|
+
- [Связи задач](#связи-задач)
|
|
44
|
+
- [Звездочки задач](#звездочки-задач)
|
|
45
|
+
- [Трудозатраты](#трудозатраты)
|
|
46
|
+
- [Пользователи и проекты](#пользователи-и-проекты)
|
|
47
|
+
- [Статьи](#статьи)
|
|
48
|
+
- [Вложения](#вложения)
|
|
45
49
|
|
|
46
50
|
## Требования
|
|
47
51
|
|
|
@@ -53,6 +57,7 @@ MCP сервер для полноценной интеграции с YouTrack
|
|
|
53
57
|
- `YOUTRACK_HOLIDAYS` — опциональный список праздничных дат через запятую (формат `YYYY-MM-DD`), исключаемых из отчётов и массовых операций
|
|
54
58
|
- `YOUTRACK_PRE_HOLIDAYS` — опциональный список предпраздничных дат через запятую, для которых норма времени уменьшается автоматически
|
|
55
59
|
- `YOUTRACK_USER_ALIASES` — опциональный список соответствий `alias:login` через запятую (например, `me:vyt,petya:p.petrov`), используется при автоматическом выборе исполнителей
|
|
60
|
+
- `YOUTRACK_DEFAULT_PROJECT` — опциональный код проекта (shortName или ID), используемый по умолчанию при создании задач/статей и для преобразования коротких идентификаторов (например, `1234` → `PROJ-1234`)
|
|
56
61
|
- `YOUTRACK_USE_STRUCTURED_CONTENT` — опциональный, управляет форматом ответа (по умолчанию: `true`). При `true` инструменты возвращают только узел MCP `structuredContent` с полными данными. При `false` инструменты возвращают только узел MCP `content` (один текстовый элемент с JSON-строкой)
|
|
57
62
|
|
|
58
63
|
## Установка
|
|
@@ -64,6 +69,7 @@ MCP сервер для полноценной интеграции с YouTrack
|
|
|
64
69
|
```bash
|
|
65
70
|
YOUTRACK_URL="https://youtrack.example.com" \
|
|
66
71
|
YOUTRACK_TOKEN="perm:your-token-here" \
|
|
72
|
+
YOUTRACK_DEFAULT_PROJECT="PROJ" \
|
|
67
73
|
npx -y @vitalyostanin/youtrack-mcp@latest
|
|
68
74
|
```
|
|
69
75
|
|
|
@@ -281,7 +287,7 @@ YOUTRACK_TOKEN = "perm:your-token-here"
|
|
|
281
287
|
| `issues_details` | Режимы краткий/полный для множества задач (макс 50). **Краткий:** предопределённые поля. **Полный (`briefOutput=false`):** добавляет `customFields` для каждой задачи. **Замечание:** объём ответа может быть большим, поэтому по умолчанию используется краткий режим. **Ограничение:** максимум 50 задач за запрос | `issueIds[]` — массив кодов задач; `briefOutput` — опционально (по умолчанию `true`) |
|
|
282
288
|
| `issue_comments` | Комментарии задачи. **Использование:** Просмотр всех комментариев к задаче. **Возвращает:** предопределенные поля - id, text, textPreview, usesMarkdown, author (id, login, name), created, updated | `issueId` — код задачи |
|
|
283
289
|
| `issues_comments` | Комментарии для нескольких задач (пакетный режим, макс 50). **Использование:** Эффективное получение комментариев для множества задач одновременно. **Ограничение:** максимум 50 задач за запрос | `issueIds[]` — массив кодов задач |
|
|
284
|
-
| `issue_create` | Создание новой задачи в YouTrack. **Использование:** Создание задач, подзадач (через `parentIssueId`), назначение исполнителя при
|
|
290
|
+
| `issue_create` | Создание новой задачи в YouTrack. **Использование:** Создание задач, подзадач (через `parentIssueId`), назначение исполнителя при создании, одновременное создание дополнительных связей. **Возвращает:** стандартные поля созданной задачи (id, idReadable, summary, description, wikifiedDescription, usesMarkdown, project, parent, assignee). Пользовательские поля не включены. | `projectId` — внутренний ID проекта, `summary`, опционально `description`, `parentIssueId`, `assigneeLogin`, `stateName`, `usesMarkdown`, `links[]` — массив объектов связи |
|
|
285
291
|
| `issue_update` | Обновление существующей задачи. **Использование:** Изменение summary, description, родительской задачи. **Примечание:** для изменения исполнителя используйте `issue_assign`. Пустая строка в `parentIssueId` удаляет родителя. **Возвращает:** стандартные поля обновленной задачи | `issueId` — ID или код задачи, опционально `summary`, `description`, `parentIssueId` (пустая строка очищает родителя), `usesMarkdown` |
|
|
286
292
|
| `issue_assign` | Назначение исполнителя для задачи. **Использование:** Изменение исполнителя задачи. Поддерживает алиас `me` для текущего пользователя. **Возвращает:** стандартные поля обновленной задачи | `issueId` — ID или код задачи, `assigneeLogin` — логин исполнителя или `me` |
|
|
287
293
|
| `issue_comment_create` | Добавление комментария к задаче. **Использование:** Оставлять комментарии, заметки, обсуждения в задачах. Поддерживает Markdown. **Возвращает:** поля комментария - id, text, textPreview, usesMarkdown, author, created, updated | `issueId` — ID или код задачи, `text` — текст комментария, опционально `usesMarkdown` |
|
|
@@ -299,6 +305,16 @@ YOUTRACK_TOKEN = "perm:your-token-here"
|
|
|
299
305
|
| `issue_link_add` | Создание связи между двумя задачами | `sourceId` — исходная задача, `targetId` — целевая задача, `linkType` — имя или id типа связи (например, `Relates` или UUID) |
|
|
300
306
|
| `issue_link_delete` | Удаление существующей связи по её id для указанной задачи | `issueId` — код задачи, `linkId` — id связи |
|
|
301
307
|
|
|
308
|
+
**issue_create — дополнительные параметры:**
|
|
309
|
+
|
|
310
|
+
- `parentIssueId` — если указан только числовой идентификатор (`"123"`), автоматически добавляет префикс проекта по умолчанию (например, `BC-123`).
|
|
311
|
+
- `links[]` — массив объектов для создания связей после сохранения задачи. Каждый объект поддерживает поля:
|
|
312
|
+
- `linkType` — имя или id типа связи (например, `Subtask`, `Relates`).
|
|
313
|
+
- `targetId` — idReadable задачи или числовой идентификатор, который также резолвится через проект по умолчанию.
|
|
314
|
+
- `direction` — опционально (`"outbound"` по умолчанию). Используйте `"inbound"`, чтобы инвертировать направление для несимметричных типов.
|
|
315
|
+
- `sourceId` — опционально. Если не указан, исходной считается новая задача; укажите его, чтобы привязать новую задачу как `target` к уже существующей.
|
|
316
|
+
- После создания задачи повторно запросите связи (`issue_links`) для подтверждения, что YouTrack применил все отношения.
|
|
317
|
+
|
|
302
318
|
### Звездочки задач
|
|
303
319
|
|
|
304
320
|
| Tool | Описание | Основные параметры |
|
|
@@ -346,6 +362,10 @@ YOUTRACK_TOKEN = "perm:your-token-here"
|
|
|
346
362
|
| `article_create` | Создание статьи в базе знаний. **Использование:** Создание документации, инструкций, статей поддержки. Поддерживает иерархическую структуру через `parentArticleId`. **Возвращает:** предопределенные поля созданной статьи - id, idReadable, summary, content, contentPreview, usesMarkdown, parentArticle, project | `summary` — заголовок статьи, опционально `content` — содержимое, `parentArticleId` — ID родительской статьи для создания подстатьи, `projectId` — ID проекта, `usesMarkdown` — использовать Markdown форматирование, `returnRendered` — вернуть отрендеренный preview |
|
|
347
363
|
| `article_update` | Обновление существующей статьи. **Использование:** Редактирование содержимого, изменение заголовка статьи. **Возвращает:** предопределенные поля обновленной статьи | `articleId` — ID статьи, опционально `summary` — новый заголовок, `content` — новое содержимое, `usesMarkdown`, `returnRendered` |
|
|
348
364
|
| `article_search` | Поиск статей в базе знаний по тексту. **Использование:** Полнотекстовый поиск по заголовкам и содержимому статей, поиск документации. Поддерживает фильтрацию по проекту и родительской статье. **Возвращает:** предопределенные поля - id, idReadable, summary, usesMarkdown, contentPreview (если `returnRendered=true`), parentArticle, project. Поле content не включено для производительности. **Ограничение:** минимум 2 символа в запросе, максимум 200 результатов | `query` — текст для поиска (минимум 2 символа), опционально `projectId` — фильтр по проекту, `parentArticleId` — фильтр по родительской статье, `limit` — максимум результатов (макс 200), `returnRendered` — вернуть отрендеренный preview содержимого |
|
|
365
|
+
| `articles_search` | Полнотекстовый поиск по статьям базы знаний YouTrack по заголовку и содержимому. Возвращает `webUrl` для прямого перехода. | `query`, `limit`, `skip`, опционально `projectId`, `parentArticleId` |
|
|
366
|
+
| `issues_search` | Полнотекстовый поиск по задачам YouTrack по summary, description и комментариям. | `query`, `limit`, `skip` |
|
|
367
|
+
| `issues_list` | Список задач по фильтрам с поддержкой сортировки. **Использование:** Дашборды, аудит командной загрузки, подготовка батч-операций. Поддерживает фильтрацию по проектам, датам создания/обновления, статусам, типам, исполнителю. **Возвращает:** краткие или полные данные задачи в зависимости от `briefOutput`, а также информацию о сортировке и пагинации. | Фильтры: `projectIds`, `createdAfter/Before`, `updatedAfter/Before`, `statuses`, `assigneeLogin`, `types`; сортировка: `sortField` (`created`/`updated`), `sortDirection` (`asc`/`desc`); пагинация: `limit`, `skip`; формат: `briefOutput` |
|
|
368
|
+
| `issues_count` | Подсчёт задач с теми же фильтрами, что у `issues_list`, с разбивкой по проектам. **Использование:** Быстрая оценка объёмов работ перед загрузкой полного списка, подготовка аналитических отчётов. При запросе одного проекта обращается к `/api/issuesGetter/count`, иначе считает постранично. | Те же фильтры, что и `issues_list`; опциональный `top` ограничивает объём ручной агрегации (при необходимости частичной выборки) |
|
|
349
369
|
|
|
350
370
|
### Вложения
|
|
351
371
|
|
package/README.md
CHANGED
|
@@ -55,9 +55,10 @@ MCP server for comprehensive YouTrack integration with the following capabilitie
|
|
|
55
55
|
- `YOUTRACK_TOKEN` — permanent token with read permissions for issues and work items
|
|
56
56
|
- `YOUTRACK_TIMEZONE` — optional timezone for date operations (default: `Europe/Moscow`), must be a valid IANA timezone identifier (e.g., `Europe/London`, `America/New_York`, `Asia/Tokyo`)
|
|
57
57
|
- `YOUTRACK_HOLIDAYS` — optional comma-separated list of holiday dates (format `YYYY-MM-DD`), excluded from reports and batch operations
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
- `YOUTRACK_PRE_HOLIDAYS` — optional comma-separated list of pre-holiday dates with reduced working hours
|
|
59
|
+
- `YOUTRACK_USER_ALIASES` — optional comma-separated list of `alias:login` mappings (e.g., `me:vyt,petya:p.petrov`), used for automatic assignee selection
|
|
60
|
+
- `YOUTRACK_DEFAULT_PROJECT` — optional project code used for manual verification tasks and default parent issues in docs/examples (use `PROJ` in documentation examples)
|
|
61
|
+
- `YOUTRACK_USE_STRUCTURED_CONTENT` — optional, controls response format (default: `true`). When `true`, tools return only the MCP `structuredContent` node with full data. When `false`, tools return only the MCP `content` node (single text item with JSON string)
|
|
61
62
|
|
|
62
63
|
## Installation
|
|
63
64
|
|
|
@@ -68,6 +69,7 @@ You can run the server directly with npx without installation:
|
|
|
68
69
|
```bash
|
|
69
70
|
YOUTRACK_URL="https://youtrack.example.com" \
|
|
70
71
|
YOUTRACK_TOKEN="perm:your-token-here" \
|
|
72
|
+
YOUTRACK_DEFAULT_PROJECT="PROJ" \
|
|
71
73
|
npx -y @vitalyostanin/youtrack-mcp@latest
|
|
72
74
|
```
|
|
73
75
|
|
|
@@ -282,7 +284,7 @@ Tools return either `structuredContent` (default) or a text `content` item, depe
|
|
|
282
284
|
| `issue_lookup` | Brief issue information | `issueId` — issue code (e.g., PROJ-123) |
|
|
283
285
|
| `issue_details` | Issue details with brief/full modes | `issueId` — issue code; `briefOutput` — optional boolean (default `true`). Brief: predefined fields only. Full (`false`): adds `customFields` including `State` |
|
|
284
286
|
| `issue_comments` | Issue comments | `issueId` — issue code |
|
|
285
|
-
| `issue_create` | Create issue | `projectId`, `summary`,
|
|
287
|
+
| `issue_create` | Create issue | `projectId`, `summary`, optional `description`, `parentIssueId`, `assigneeLogin`, `stateName`, `usesMarkdown`, `links` (array of link objects) |
|
|
286
288
|
| `issue_update` | Update existing issue | `issueId`, optionally `summary`, `description`, `parentIssueId` (empty string clears parent), `usesMarkdown` |
|
|
287
289
|
| `issue_assign` | Assign issue to user | `issueId`, `assigneeLogin` (login or `me`) |
|
|
288
290
|
| `issue_comment_create` | Add comment to issue | `issueId`, `text` — comment text, optionally `usesMarkdown` |
|
|
@@ -352,12 +354,16 @@ Tools return either `structuredContent` (default) or a text `content` item, depe
|
|
|
352
354
|
| `article_create` | Create article in knowledge base | `summary`, optionally `content`, `parentArticleId`, `projectId`, `usesMarkdown`, `returnRendered` |
|
|
353
355
|
| `article_update` | Update article | `articleId`, optionally `summary`, `content`, `usesMarkdown`, `returnRendered` |
|
|
354
356
|
| `article_search` | Search articles in knowledge base | `query`, optionally `projectId`, `parentArticleId`, `limit`, `returnRendered` |
|
|
357
|
+
| `articles_search` | Full-text search across YouTrack knowledge base articles by title and content. Returns `webUrl` for direct access. | `query`, `limit`, `skip`, optionally `projectId`, `parentArticleId` |
|
|
358
|
+
| `issues_search` | Full-text search across YouTrack issues by summary, description, and comments. | `query`, `limit`, `skip` |
|
|
355
359
|
|
|
356
360
|
### Search
|
|
357
361
|
|
|
358
362
|
| Tool | Description | Main Parameters |
|
|
359
363
|
| --- | --- | --- |
|
|
360
364
|
| `article_search` | Search articles in knowledge base | `query`, optionally `projectId`, `parentArticleId`, `limit`, `returnRendered` |
|
|
365
|
+
| `issues_list` | List issues across projects with filtering and sorting | Filters: `projectIds`, `createdAfter/Before`, `updatedAfter/Before`, `statuses`, `assigneeLogin`, `types`; Sorting: `sortField`, `sortDirection`; Pagination: `limit`, `skip`; Output mode: `briefOutput` |
|
|
366
|
+
| `issues_count` | Count issues using same filters as `issues_list`, returns per-project breakdown | Same filters as above, optional `top` to cap manual aggregation when many projects are involved |
|
|
361
367
|
|
|
362
368
|
## Important Notes
|
|
363
369
|
|
|
@@ -366,3 +372,12 @@ Tools return either `structuredContent` (default) or a text `content` item, depe
|
|
|
366
372
|
Some operations cannot be undone and require explicit confirmation:
|
|
367
373
|
|
|
368
374
|
- **`issue_attachment_delete`** - Requires `confirmation: true` parameter. Deleted attachments cannot be recovered.
|
|
375
|
+
**issue_create parameters:**
|
|
376
|
+
|
|
377
|
+
- `parentIssueId` — resolves against `YOUTRACK_DEFAULT_PROJECT` when no project prefix is provided (e.g., `123` → `BC-123` if default project is `BC`).
|
|
378
|
+
- `links[]` — optional array describing additional links to create after the issue is saved. Each item supports:
|
|
379
|
+
- `linkType` — name or id of the link type (e.g., `Subtask`, `Relates`).
|
|
380
|
+
- `targetId` — issue id or readable id. Plain numbers are resolved with the default project, matching `resolveIssueId` behaviour.
|
|
381
|
+
- `direction` — optional (`"outbound"` by default). Use `"inbound"` to flip direction for non-symmetric link types.
|
|
382
|
+
- `sourceId` — optional. When omitted, the new issue is treated as the source. Specify to create links from an existing issue to the new one (useful for complex chains).
|
|
383
|
+
- After creation the tool automatically refreshes the issue and attempts to reopen link caches; always re-fetch links with `issue_links` to confirm the final state.
|
package/dist/package.json
CHANGED
package/dist/src/config.js
CHANGED
|
@@ -6,6 +6,7 @@ const configSchema = z.object({
|
|
|
6
6
|
YOUTRACK_HOLIDAYS: z.string().optional(),
|
|
7
7
|
YOUTRACK_PRE_HOLIDAYS: z.string().optional(),
|
|
8
8
|
YOUTRACK_USER_ALIASES: z.string().optional(),
|
|
9
|
+
YOUTRACK_DEFAULT_PROJECT: z.string().optional(),
|
|
9
10
|
YOUTRACK_USE_STRUCTURED_CONTENT: z
|
|
10
11
|
.string()
|
|
11
12
|
.optional()
|
|
@@ -37,6 +38,7 @@ export function loadConfig(env = process.env) {
|
|
|
37
38
|
userAliases: parsed.data.YOUTRACK_USER_ALIASES
|
|
38
39
|
? parseAliasMap(parsed.data.YOUTRACK_USER_ALIASES)
|
|
39
40
|
: undefined,
|
|
41
|
+
defaultProject: parsed.data.YOUTRACK_DEFAULT_PROJECT,
|
|
40
42
|
useStructuredContent: parsed.data.YOUTRACK_USE_STRUCTURED_CONTENT,
|
|
41
43
|
};
|
|
42
44
|
}
|
package/dist/src/server.js
CHANGED
|
@@ -2,11 +2,11 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { registerServiceInfoTool } from "./tools/service-info.js";
|
|
3
3
|
import { registerIssueTools } from "./tools/issue-tools.js";
|
|
4
4
|
import { registerIssueActivityTools } from "./tools/issue-activity-tools.js";
|
|
5
|
-
import {
|
|
5
|
+
import { issuesSearchArgs, issuesSearchHandler } from "./tools/issue-search-tools.js";
|
|
6
|
+
import { articlesSearchArgs, articlesSearchHandler } from "./tools/article-search-tools.js";
|
|
6
7
|
import { registerWorkitemTools } from "./tools/workitem-tools.js";
|
|
7
8
|
import { registerWorkitemReportTools } from "./tools/workitem-report-tools.js";
|
|
8
9
|
import { registerArticleTools } from "./tools/article-tools.js";
|
|
9
|
-
import { registerArticleSearchTools } from "./tools/article-search-tools.js";
|
|
10
10
|
import { registerUserTools } from "./tools/user-tools.js";
|
|
11
11
|
import { registerProjectTools } from "./tools/project-tools.js";
|
|
12
12
|
import { registerAttachmentTools } from "./tools/attachment-tools.js";
|
|
@@ -39,11 +39,12 @@ export class YoutrackServer {
|
|
|
39
39
|
registerServiceInfoTool(this.server, this.client);
|
|
40
40
|
registerIssueTools(this.server, this.client);
|
|
41
41
|
registerIssueActivityTools(this.server, this.client);
|
|
42
|
-
|
|
42
|
+
this.server.tool("issues_search", "Search YouTrack issues by text in summary, description, and comments.", issuesSearchArgs, async (args) => issuesSearchHandler(this.client, args));
|
|
43
|
+
this.server.tool("articles_search", "Search YouTrack knowledge base articles by title and content.", articlesSearchArgs, async (args) => articlesSearchHandler(this.client, args));
|
|
43
44
|
registerWorkitemTools(this.server, this.client);
|
|
44
45
|
registerWorkitemReportTools(this.server, this.client);
|
|
45
46
|
registerArticleTools(this.server, this.client);
|
|
46
|
-
registerArticleSearchTools(
|
|
47
|
+
// Removed redundant registerArticleSearchTools call (articles_search tool registered manually above)
|
|
47
48
|
registerUserTools(this.server, this.client);
|
|
48
49
|
registerProjectTools(this.server, this.client);
|
|
49
50
|
registerAttachmentTools(this.server, this.client);
|
|
@@ -1,4 +1,103 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from "zod";
|
|
2
2
|
import type { YoutrackClient } from "../youtrack-client.js";
|
|
3
|
-
export declare
|
|
3
|
+
export declare const articlesSearchArgs: {
|
|
4
|
+
query: z.ZodString;
|
|
5
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
6
|
+
skip: z.ZodDefault<z.ZodNumber>;
|
|
7
|
+
projectId: z.ZodOptional<z.ZodString>;
|
|
8
|
+
parentArticleId: z.ZodOptional<z.ZodString>;
|
|
9
|
+
};
|
|
10
|
+
export declare const articlesSearchSchema: z.ZodObject<{
|
|
11
|
+
query: z.ZodString;
|
|
12
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
13
|
+
skip: z.ZodDefault<z.ZodNumber>;
|
|
14
|
+
projectId: z.ZodOptional<z.ZodString>;
|
|
15
|
+
parentArticleId: z.ZodOptional<z.ZodString>;
|
|
16
|
+
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
query: string;
|
|
18
|
+
skip: number;
|
|
19
|
+
limit: number;
|
|
20
|
+
projectId?: string | undefined;
|
|
21
|
+
parentArticleId?: string | undefined;
|
|
22
|
+
}, {
|
|
23
|
+
query: string;
|
|
24
|
+
skip?: number | undefined;
|
|
25
|
+
limit?: number | undefined;
|
|
26
|
+
projectId?: string | undefined;
|
|
27
|
+
parentArticleId?: string | undefined;
|
|
28
|
+
}>;
|
|
29
|
+
export declare function articlesSearchHandler(client: YoutrackClient, rawInput: unknown): Promise<{
|
|
30
|
+
[x: string]: unknown;
|
|
31
|
+
content: ({
|
|
32
|
+
[x: string]: unknown;
|
|
33
|
+
text: string;
|
|
34
|
+
type: "text";
|
|
35
|
+
_meta?: {
|
|
36
|
+
[x: string]: unknown;
|
|
37
|
+
} | undefined;
|
|
38
|
+
} | {
|
|
39
|
+
[x: string]: unknown;
|
|
40
|
+
type: "image";
|
|
41
|
+
data: string;
|
|
42
|
+
mimeType: string;
|
|
43
|
+
_meta?: {
|
|
44
|
+
[x: string]: unknown;
|
|
45
|
+
} | undefined;
|
|
46
|
+
} | {
|
|
47
|
+
[x: string]: unknown;
|
|
48
|
+
type: "audio";
|
|
49
|
+
data: string;
|
|
50
|
+
mimeType: string;
|
|
51
|
+
_meta?: {
|
|
52
|
+
[x: string]: unknown;
|
|
53
|
+
} | undefined;
|
|
54
|
+
} | {
|
|
55
|
+
[x: string]: unknown;
|
|
56
|
+
name: string;
|
|
57
|
+
type: "resource_link";
|
|
58
|
+
uri: string;
|
|
59
|
+
description?: string | undefined;
|
|
60
|
+
_meta?: {
|
|
61
|
+
[x: string]: unknown;
|
|
62
|
+
} | undefined;
|
|
63
|
+
mimeType?: string | undefined;
|
|
64
|
+
title?: string | undefined;
|
|
65
|
+
icons?: {
|
|
66
|
+
[x: string]: unknown;
|
|
67
|
+
src: string;
|
|
68
|
+
mimeType?: string | undefined;
|
|
69
|
+
sizes?: string[] | undefined;
|
|
70
|
+
}[] | undefined;
|
|
71
|
+
} | {
|
|
72
|
+
[x: string]: unknown;
|
|
73
|
+
type: "resource";
|
|
74
|
+
resource: {
|
|
75
|
+
[x: string]: unknown;
|
|
76
|
+
text: string;
|
|
77
|
+
uri: string;
|
|
78
|
+
_meta?: {
|
|
79
|
+
[x: string]: unknown;
|
|
80
|
+
} | undefined;
|
|
81
|
+
mimeType?: string | undefined;
|
|
82
|
+
} | {
|
|
83
|
+
[x: string]: unknown;
|
|
84
|
+
uri: string;
|
|
85
|
+
blob: string;
|
|
86
|
+
_meta?: {
|
|
87
|
+
[x: string]: unknown;
|
|
88
|
+
} | undefined;
|
|
89
|
+
mimeType?: string | undefined;
|
|
90
|
+
};
|
|
91
|
+
_meta?: {
|
|
92
|
+
[x: string]: unknown;
|
|
93
|
+
} | undefined;
|
|
94
|
+
})[];
|
|
95
|
+
_meta?: {
|
|
96
|
+
[x: string]: unknown;
|
|
97
|
+
} | undefined;
|
|
98
|
+
structuredContent?: {
|
|
99
|
+
[x: string]: unknown;
|
|
100
|
+
} | undefined;
|
|
101
|
+
isError?: boolean | undefined;
|
|
102
|
+
}>;
|
|
4
103
|
//# sourceMappingURL=article-search-tools.d.ts.map
|
|
@@ -1,31 +1,40 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
3
|
-
const
|
|
4
|
-
query: z.string().min(2).describe("Search string for
|
|
2
|
+
import { toolSuccess, toolError } from "../utils/tool-response.js";
|
|
3
|
+
export const articlesSearchArgs = {
|
|
4
|
+
query: z.string().min(2).describe("Search string for articles (e.g., 'API token')"),
|
|
5
|
+
limit: z.number().int().positive().max(200).default(50).describe("Max results per page"),
|
|
6
|
+
skip: z.number().int().nonnegative().default(0).describe("Offset for pagination"),
|
|
5
7
|
projectId: z.string().optional().describe("Filter by project ID"),
|
|
6
|
-
parentArticleId: z.string().optional().describe("Filter by parent article"),
|
|
7
|
-
limit: z.number().int().positive().max(200).optional().describe("Maximum number of results"),
|
|
8
|
-
returnRendered: z.boolean().optional().describe("Return rendered content preview"),
|
|
8
|
+
parentArticleId: z.string().optional().describe("Filter by parent article ID"),
|
|
9
9
|
};
|
|
10
|
-
const
|
|
11
|
-
export function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
const response = toolSuccess(articles);
|
|
23
|
-
return response;
|
|
10
|
+
export const articlesSearchSchema = z.object(articlesSearchArgs);
|
|
11
|
+
export async function articlesSearchHandler(client, rawInput) {
|
|
12
|
+
const input = articlesSearchSchema.parse(rawInput);
|
|
13
|
+
try {
|
|
14
|
+
const params = {
|
|
15
|
+
fields: "id,idReadable,summary,parentArticle(id,idReadable),project(id,shortName,name)",
|
|
16
|
+
query: `{${input.query}}`,
|
|
17
|
+
$top: input.limit,
|
|
18
|
+
$skip: input.skip,
|
|
19
|
+
};
|
|
20
|
+
if (input.projectId) {
|
|
21
|
+
params.query += ` and project: {${input.projectId}}`;
|
|
24
22
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return errorResponse;
|
|
23
|
+
if (input.parentArticleId) {
|
|
24
|
+
params.query += ` and parent article: {${input.parentArticleId}}`;
|
|
28
25
|
}
|
|
29
|
-
|
|
26
|
+
const data = await client["getWithFlexibleTop"]("/api/articles", params);
|
|
27
|
+
const baseUrl = client.config?.baseUrl ?? "";
|
|
28
|
+
const articlesWithLinks = Array.isArray(data)
|
|
29
|
+
? data.map((article) => ({
|
|
30
|
+
...article,
|
|
31
|
+
webUrl: `${baseUrl}/articles/${article.idReadable}`,
|
|
32
|
+
}))
|
|
33
|
+
: data;
|
|
34
|
+
return toolSuccess(articlesWithLinks);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
return toolError(error);
|
|
38
|
+
}
|
|
30
39
|
}
|
|
31
40
|
//# sourceMappingURL=article-search-tools.js.map
|
|
@@ -5,7 +5,10 @@ const articleLookupArgs = {
|
|
|
5
5
|
};
|
|
6
6
|
const articleListArgs = {
|
|
7
7
|
parentArticleId: z.string().optional().describe("Parent article ID"),
|
|
8
|
-
projectId: z
|
|
8
|
+
projectId: z
|
|
9
|
+
.string()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe("Project ID (defaults to YOUTRACK_DEFAULT_PROJECT when omitted)"),
|
|
9
12
|
};
|
|
10
13
|
const articleCreateArgs = {
|
|
11
14
|
summary: z.string().min(1).describe("Article title"),
|
|
@@ -14,7 +17,10 @@ const articleCreateArgs = {
|
|
|
14
17
|
.optional()
|
|
15
18
|
.describe("Article content. Supports folded sections: <details> <summary>Title</summary>Content</details>"),
|
|
16
19
|
parentArticleId: z.string().optional().describe("Parent article ID"),
|
|
17
|
-
projectId: z
|
|
20
|
+
projectId: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Project ID (defaults to YOUTRACK_DEFAULT_PROJECT when omitted)"),
|
|
18
24
|
usesMarkdown: z.boolean().optional().describe("Use Markdown formatting"),
|
|
19
25
|
returnRendered: z.boolean().optional().describe("Return rendered content preview"),
|
|
20
26
|
};
|
|
@@ -60,7 +66,7 @@ export function registerArticleTools(server, client) {
|
|
|
60
66
|
return errorResponse;
|
|
61
67
|
}
|
|
62
68
|
});
|
|
63
|
-
server.tool("article_create", "Create article in YouTrack knowledge base. Supports markdown with folded sections (<details>/<summary>) in content. Note: Response includes predefined fields only - id, idReadable, summary, content, contentPreview, usesMarkdown, parentArticle (id, idReadable), project (id, shortName, name).", articleCreateArgs, async (rawInput) => {
|
|
69
|
+
server.tool("article_create", "Create article in YouTrack knowledge base. Supports markdown with folded sections (<details>/<summary>) in content. Note: Response includes predefined fields only - id, idReadable, summary, content, contentPreview, usesMarkdown, parentArticle (id, idReadable), project (id, shortName, name). After creation, fetch the article again to confirm rendered content and hierarchy are correct.", articleCreateArgs, async (rawInput) => {
|
|
64
70
|
try {
|
|
65
71
|
const payload = articleCreateSchema.parse(rawInput);
|
|
66
72
|
const article = await client.createArticle({
|
|
@@ -79,7 +85,7 @@ export function registerArticleTools(server, client) {
|
|
|
79
85
|
return errorResponse;
|
|
80
86
|
}
|
|
81
87
|
});
|
|
82
|
-
server.tool("article_update", "Update existing article. Supports markdown with folded sections (<details>/<summary>) in content. Note: Response includes predefined fields only - id, idReadable, summary, content, contentPreview, usesMarkdown, parentArticle (id, idReadable), project (id, shortName, name).", articleUpdateArgs, async (rawInput) => {
|
|
88
|
+
server.tool("article_update", "Update existing article. Supports markdown with folded sections (<details>/<summary>) in content. Note: Response includes predefined fields only - id, idReadable, summary, content, contentPreview, usesMarkdown, parentArticle (id, idReadable), project (id, shortName, name). After updating, re-fetch the article (optionally with rendered content) to verify formatting and links.", articleUpdateArgs, async (rawInput) => {
|
|
83
89
|
try {
|
|
84
90
|
const payload = articleUpdateSchema.parse(rawInput);
|
|
85
91
|
if (payload.summary === undefined && payload.content === undefined) {
|
|
@@ -64,7 +64,7 @@ export function registerAttachmentTools(server, client) {
|
|
|
64
64
|
return errorResponse;
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
|
-
server.tool("issue_attachment_upload", "Upload one or more files to a YouTrack issue. Files must exist on the local filesystem. Note: Can only attach files to existing issues, not during issue creation.", attachmentUploadArgs, async (rawInput) => {
|
|
67
|
+
server.tool("issue_attachment_upload", "Upload one or more files to a YouTrack issue. Files must exist on the local filesystem. Note: Can only attach files to existing issues, not during issue creation. After uploading, fetch the attachments list to verify each file appears with correct metadata.", attachmentUploadArgs, async (rawInput) => {
|
|
68
68
|
try {
|
|
69
69
|
const payload = attachmentUploadSchema.parse(rawInput);
|
|
70
70
|
const result = await client.uploadAttachments({
|
|
@@ -80,7 +80,7 @@ export function registerAttachmentTools(server, client) {
|
|
|
80
80
|
return errorResponse;
|
|
81
81
|
}
|
|
82
82
|
});
|
|
83
|
-
server.tool("issue_attachment_delete", "Delete an attachment from a YouTrack issue. IMPORTANT: Requires explicit confirmation via the 'confirmation' parameter to prevent accidental deletion. This is a destructive operation that cannot be undone.", attachmentDeleteArgs, async (rawInput) => {
|
|
83
|
+
server.tool("issue_attachment_delete", "Delete an attachment from a YouTrack issue. IMPORTANT: Requires explicit confirmation via the 'confirmation' parameter to prevent accidental deletion. This is a destructive operation that cannot be undone. After deletion, list attachments again to ensure the file no longer appears.", attachmentDeleteArgs, async (rawInput) => {
|
|
84
84
|
try {
|
|
85
85
|
const payload = attachmentDeleteSchema.parse(rawInput);
|
|
86
86
|
const result = await client.deleteAttachment({
|
|
@@ -11,13 +11,12 @@ const linkCreateArgs = {
|
|
|
11
11
|
.string()
|
|
12
12
|
.min(1)
|
|
13
13
|
.describe("Link type name or id (e.g., 'Relates', 'Duplicate', or a type id)"),
|
|
14
|
+
direction: z
|
|
15
|
+
.enum(["inbound", "outbound"])
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Direction relative to the source issue (use 'inbound' to flip the relationship)"),
|
|
14
18
|
};
|
|
15
19
|
const linkCreateSchema = z.object(linkCreateArgs);
|
|
16
|
-
const linkDeleteArgs = {
|
|
17
|
-
issueId: z.string().min(1).describe("Issue code that holds the link (e.g., PROJ-123)"),
|
|
18
|
-
linkId: z.string().min(1).describe("Issue link id (internal youtrack id)"),
|
|
19
|
-
};
|
|
20
|
-
const linkDeleteSchema = z.object(linkDeleteArgs);
|
|
21
20
|
export function registerIssueLinkTools(server, client) {
|
|
22
21
|
server.tool("issue_links", "List issue links for a given YouTrack issue. Use for: inspecting relationships like 'relates to', 'duplicates', 'parent/child'. Response includes link id, direction, linkType, and counterpart issue brief (idReadable, summary, project, assignee).", issueIdArgs, async (rawInput) => {
|
|
23
22
|
try {
|
|
@@ -38,7 +37,7 @@ export function registerIssueLinkTools(server, client) {
|
|
|
38
37
|
return toolError(error);
|
|
39
38
|
}
|
|
40
39
|
});
|
|
41
|
-
server.tool("issue_link_add", "Create a link between two issues. Provide sourceId, targetId and linkType (name or id). Limitations: link type must exist in project context; API may reject invalid combinations.", linkCreateArgs, async (rawInput) => {
|
|
40
|
+
server.tool("issue_link_add", "Create a link between two issues. Provide sourceId, targetId and linkType (name or id). Limitations: link type must exist in project context; API may reject invalid combinations. After linking, fetch the issue links again to confirm the relationship appears as expected.", linkCreateArgs, async (rawInput) => {
|
|
42
41
|
try {
|
|
43
42
|
const input = linkCreateSchema.parse(rawInput);
|
|
44
43
|
const result = await client.addIssueLink(input);
|
|
@@ -48,15 +47,5 @@ export function registerIssueLinkTools(server, client) {
|
|
|
48
47
|
return toolError(error);
|
|
49
48
|
}
|
|
50
49
|
});
|
|
51
|
-
server.tool("issue_link_delete", "Delete an existing issue link by id for a given issue. Use 'issue_links' to discover link ids first.", linkDeleteArgs, async (rawInput) => {
|
|
52
|
-
try {
|
|
53
|
-
const input = linkDeleteSchema.parse(rawInput);
|
|
54
|
-
const result = await client.deleteIssueLink(input);
|
|
55
|
-
return toolSuccess(result);
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
return toolError(error);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
50
|
}
|
|
62
51
|
//# sourceMappingURL=issue-link-tools.js.map
|
|
@@ -1,4 +1,95 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from "zod";
|
|
2
2
|
import type { YoutrackClient } from "../youtrack-client.js";
|
|
3
|
-
export declare
|
|
3
|
+
export declare const issuesSearchArgs: {
|
|
4
|
+
query: z.ZodString;
|
|
5
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
6
|
+
skip: z.ZodDefault<z.ZodNumber>;
|
|
7
|
+
};
|
|
8
|
+
export declare const issuesSearchSchema: z.ZodObject<{
|
|
9
|
+
query: z.ZodString;
|
|
10
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
11
|
+
skip: z.ZodDefault<z.ZodNumber>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
query: string;
|
|
14
|
+
skip: number;
|
|
15
|
+
limit: number;
|
|
16
|
+
}, {
|
|
17
|
+
query: string;
|
|
18
|
+
skip?: number | undefined;
|
|
19
|
+
limit?: number | undefined;
|
|
20
|
+
}>;
|
|
21
|
+
export declare function issuesSearchHandler(client: YoutrackClient, rawInput: unknown): Promise<{
|
|
22
|
+
[x: string]: unknown;
|
|
23
|
+
content: ({
|
|
24
|
+
[x: string]: unknown;
|
|
25
|
+
text: string;
|
|
26
|
+
type: "text";
|
|
27
|
+
_meta?: {
|
|
28
|
+
[x: string]: unknown;
|
|
29
|
+
} | undefined;
|
|
30
|
+
} | {
|
|
31
|
+
[x: string]: unknown;
|
|
32
|
+
type: "image";
|
|
33
|
+
data: string;
|
|
34
|
+
mimeType: string;
|
|
35
|
+
_meta?: {
|
|
36
|
+
[x: string]: unknown;
|
|
37
|
+
} | undefined;
|
|
38
|
+
} | {
|
|
39
|
+
[x: string]: unknown;
|
|
40
|
+
type: "audio";
|
|
41
|
+
data: string;
|
|
42
|
+
mimeType: string;
|
|
43
|
+
_meta?: {
|
|
44
|
+
[x: string]: unknown;
|
|
45
|
+
} | undefined;
|
|
46
|
+
} | {
|
|
47
|
+
[x: string]: unknown;
|
|
48
|
+
name: string;
|
|
49
|
+
type: "resource_link";
|
|
50
|
+
uri: string;
|
|
51
|
+
description?: string | undefined;
|
|
52
|
+
_meta?: {
|
|
53
|
+
[x: string]: unknown;
|
|
54
|
+
} | undefined;
|
|
55
|
+
mimeType?: string | undefined;
|
|
56
|
+
title?: string | undefined;
|
|
57
|
+
icons?: {
|
|
58
|
+
[x: string]: unknown;
|
|
59
|
+
src: string;
|
|
60
|
+
mimeType?: string | undefined;
|
|
61
|
+
sizes?: string[] | undefined;
|
|
62
|
+
}[] | undefined;
|
|
63
|
+
} | {
|
|
64
|
+
[x: string]: unknown;
|
|
65
|
+
type: "resource";
|
|
66
|
+
resource: {
|
|
67
|
+
[x: string]: unknown;
|
|
68
|
+
text: string;
|
|
69
|
+
uri: string;
|
|
70
|
+
_meta?: {
|
|
71
|
+
[x: string]: unknown;
|
|
72
|
+
} | undefined;
|
|
73
|
+
mimeType?: string | undefined;
|
|
74
|
+
} | {
|
|
75
|
+
[x: string]: unknown;
|
|
76
|
+
uri: string;
|
|
77
|
+
blob: string;
|
|
78
|
+
_meta?: {
|
|
79
|
+
[x: string]: unknown;
|
|
80
|
+
} | undefined;
|
|
81
|
+
mimeType?: string | undefined;
|
|
82
|
+
};
|
|
83
|
+
_meta?: {
|
|
84
|
+
[x: string]: unknown;
|
|
85
|
+
} | undefined;
|
|
86
|
+
})[];
|
|
87
|
+
_meta?: {
|
|
88
|
+
[x: string]: unknown;
|
|
89
|
+
} | undefined;
|
|
90
|
+
structuredContent?: {
|
|
91
|
+
[x: string]: unknown;
|
|
92
|
+
} | undefined;
|
|
93
|
+
isError?: boolean | undefined;
|
|
94
|
+
}>;
|
|
4
95
|
//# sourceMappingURL=issue-search-tools.d.ts.map
|