schemeog-mcp 2.0.0 → 2.2.1
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.md +161 -69
- package/index.js +802 -49
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,129 +1,221 @@
|
|
|
1
|
-
# SchemeOG MCP Server v2.
|
|
1
|
+
# SchemeOG MCP Server v2.2
|
|
2
2
|
|
|
3
|
-
MCP
|
|
3
|
+
MCP server for [SchemeOG Cloud](https://scheme.smartlaunchhub.com) — create diagrams and flowcharts with AI.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 14 Commands
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|---------|----------|
|
|
9
|
-
| `list_schemas` | Список всех схем |
|
|
10
|
-
| `get_schema` | Получить схему с данными |
|
|
11
|
-
| `create_schema` | Создать новую схему |
|
|
12
|
-
| `replace_schema` | Заменить содержимое схемы |
|
|
13
|
-
| `delete_schema` | Удалить схему |
|
|
7
|
+
### Schemas (5 commands)
|
|
14
8
|
|
|
15
|
-
|
|
9
|
+
| Command | Description |
|
|
10
|
+
|---------|-------------|
|
|
11
|
+
| `list_schemas` | List all schemas |
|
|
12
|
+
| `get_schema` | Get schema with data |
|
|
13
|
+
| `create_schema` | Create new schema |
|
|
14
|
+
| `replace_schema` | Replace schema content |
|
|
15
|
+
| `delete_schema` | Delete schema |
|
|
16
16
|
|
|
17
|
-
###
|
|
17
|
+
### Projects (5 commands)
|
|
18
|
+
|
|
19
|
+
| Command | Description |
|
|
20
|
+
|---------|-------------|
|
|
21
|
+
| `list_projects` | List projects (folders) |
|
|
22
|
+
| `create_project` | Create project |
|
|
23
|
+
| `update_project` | Update project |
|
|
24
|
+
| `delete_project` | Delete project |
|
|
25
|
+
| `move_schema_to_project` | Move schema to project |
|
|
26
|
+
|
|
27
|
+
### Tags (4 commands)
|
|
28
|
+
|
|
29
|
+
| Command | Description |
|
|
30
|
+
|---------|-------------|
|
|
31
|
+
| `list_tags` | List schema tags |
|
|
32
|
+
| `add_tag` | Add tag to schema |
|
|
33
|
+
| `remove_tag` | Remove tag from schema |
|
|
34
|
+
| `tag_element` | Assign/remove tag from element |
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
### Via npx (recommended)
|
|
18
39
|
|
|
19
40
|
```bash
|
|
20
|
-
npx schemeog-
|
|
41
|
+
npx schemeog-mcp
|
|
21
42
|
```
|
|
22
43
|
|
|
23
|
-
##
|
|
44
|
+
## Setup
|
|
24
45
|
|
|
25
|
-
### 1.
|
|
46
|
+
### 1. Get your token
|
|
26
47
|
|
|
27
|
-
1.
|
|
28
|
-
2.
|
|
29
|
-
3.
|
|
30
|
-
4.
|
|
48
|
+
1. Open https://scheme.smartlaunchhub.com
|
|
49
|
+
2. Sign in with email
|
|
50
|
+
3. Go to Profile
|
|
51
|
+
4. Copy token from "Claude Code Integration" section
|
|
31
52
|
|
|
32
|
-
### 2.
|
|
53
|
+
### 2. Add to Claude Code / Cline
|
|
33
54
|
|
|
34
|
-
|
|
55
|
+
In `~/.claude.json` (or Cline settings):
|
|
35
56
|
|
|
36
57
|
```json
|
|
37
58
|
{
|
|
38
59
|
"mcpServers": {
|
|
39
60
|
"schemeog": {
|
|
40
61
|
"command": "npx",
|
|
41
|
-
"args": ["-y", "schemeog-
|
|
62
|
+
"args": ["-y", "schemeog-mcp"],
|
|
42
63
|
"env": {
|
|
43
|
-
"SCHEMEOG_TOKEN": "
|
|
64
|
+
"SCHEMEOG_TOKEN": "schog_xxxxx..."
|
|
44
65
|
}
|
|
45
66
|
}
|
|
46
67
|
}
|
|
47
68
|
}
|
|
48
69
|
```
|
|
49
70
|
|
|
50
|
-
##
|
|
51
|
-
|
|
52
|
-
### Создать схему
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
Создай схему "User Registration Flow" с блоками:
|
|
56
|
-
- Форма регистрации
|
|
57
|
-
- Валидация
|
|
58
|
-
- Сохранение в БД
|
|
59
|
-
- Отправка email
|
|
60
|
-
- Успех
|
|
61
|
-
```
|
|
71
|
+
## Schema Data Format
|
|
62
72
|
|
|
63
|
-
|
|
73
|
+
### Full schema example
|
|
64
74
|
|
|
65
75
|
```json
|
|
66
76
|
{
|
|
67
77
|
"name": "User Registration Flow",
|
|
78
|
+
"description": "User registration process",
|
|
68
79
|
"elements": [
|
|
69
|
-
{
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
{
|
|
81
|
+
"id": "start",
|
|
82
|
+
"type": "card",
|
|
83
|
+
"title": "Registration Form",
|
|
84
|
+
"color": "light_green",
|
|
85
|
+
"tags": ["user"],
|
|
86
|
+
"description": "User fills in email and password"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": "validate",
|
|
90
|
+
"type": "condition",
|
|
91
|
+
"title": "Validate Data",
|
|
92
|
+
"color": "light_yellow",
|
|
93
|
+
"tags": ["system", "check"],
|
|
94
|
+
"description": "Check email format and password strength"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"id": "save",
|
|
98
|
+
"type": "card",
|
|
99
|
+
"title": "Save to Database",
|
|
100
|
+
"color": "light_blue",
|
|
101
|
+
"tags": ["system"],
|
|
102
|
+
"description": "Create user record in database"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"id": "error",
|
|
106
|
+
"type": "card",
|
|
107
|
+
"title": "Validation Error",
|
|
108
|
+
"color": "light_red",
|
|
109
|
+
"tags": ["system", "error"],
|
|
110
|
+
"description": "Show validation errors to user"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"id": "success",
|
|
114
|
+
"type": "card",
|
|
115
|
+
"title": "Registration Complete",
|
|
116
|
+
"color": "light_green",
|
|
117
|
+
"tags": ["user"],
|
|
118
|
+
"description": "User successfully registered"
|
|
119
|
+
}
|
|
74
120
|
],
|
|
75
121
|
"connections": [
|
|
76
|
-
{"from": "
|
|
77
|
-
{"from": "
|
|
78
|
-
{"from": "
|
|
79
|
-
{"from": "
|
|
122
|
+
{"from": "start", "to": "validate", "label": "submit"},
|
|
123
|
+
{"from": "validate", "to": "save", "label": "valid"},
|
|
124
|
+
{"from": "validate", "to": "error", "label": "invalid"},
|
|
125
|
+
{"from": "save", "to": "success"},
|
|
126
|
+
{"from": "error", "to": "start", "label": "retry"}
|
|
127
|
+
],
|
|
128
|
+
"tagsDictionary": [
|
|
129
|
+
{"id": "tag-user", "name": "user", "color": "#4CAF50"},
|
|
130
|
+
{"id": "tag-system", "name": "system", "color": "#2196F3"},
|
|
131
|
+
{"id": "tag-check", "name": "check", "color": "#FF9800"},
|
|
132
|
+
{"id": "tag-error", "name": "error", "color": "#F44336"}
|
|
80
133
|
]
|
|
81
134
|
}
|
|
82
135
|
```
|
|
83
136
|
|
|
84
|
-
###
|
|
137
|
+
### Element (card or condition)
|
|
85
138
|
|
|
86
|
-
```
|
|
87
|
-
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"id": "unique_id",
|
|
142
|
+
"type": "card",
|
|
143
|
+
"title": "Card Title",
|
|
144
|
+
"color": "light_blue",
|
|
145
|
+
"tags": ["tag1", "tag2"],
|
|
146
|
+
"description": "Detailed description of the action or process"
|
|
147
|
+
}
|
|
88
148
|
```
|
|
89
149
|
|
|
90
|
-
|
|
150
|
+
**Element types:**
|
|
151
|
+
- `card` — regular process/action card
|
|
152
|
+
- `condition` — decision point (diamond shape)
|
|
91
153
|
|
|
92
|
-
|
|
154
|
+
**Available colors (`color`):**
|
|
155
|
+
| Color | Purpose |
|
|
156
|
+
|-------|---------|
|
|
157
|
+
| `white` | Default white |
|
|
158
|
+
| `light_blue` | Main processes |
|
|
159
|
+
| `light_green` | Start and success |
|
|
160
|
+
| `light_yellow` | Checks and conditions |
|
|
161
|
+
| `light_orange` | Warnings |
|
|
162
|
+
| `light_red` | Errors and critical |
|
|
163
|
+
| `light_purple` | Decisions |
|
|
164
|
+
| `light_gray` | Completion |
|
|
165
|
+
| `light_pink` | Additional processes |
|
|
166
|
+
| `light_teal` | Special operations |
|
|
93
167
|
|
|
94
|
-
|
|
95
|
-
Покажи мои схемы
|
|
96
|
-
```
|
|
168
|
+
**Border colors (`borderColor`):** `default`, `blue`, `green`, `orange`, `purple`, `red`, `teal`, `yellow`, `gray`, `black`
|
|
97
169
|
|
|
98
|
-
|
|
170
|
+
**Important:** Do NOT specify `width`, `height`, `x`, `y` — they are calculated automatically!
|
|
99
171
|
|
|
100
|
-
###
|
|
172
|
+
### Connection
|
|
101
173
|
|
|
102
174
|
```json
|
|
103
175
|
{
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"text": "Текст", // содержимое
|
|
109
|
-
"width": 200, // ширина (опционально)
|
|
110
|
-
"height": 100, // высота (опционально)
|
|
111
|
-
"color": "#E3F2FD" // цвет фона (опционально)
|
|
176
|
+
"from": "source_id",
|
|
177
|
+
"to": "target_id",
|
|
178
|
+
"label": "optional label",
|
|
179
|
+
"style": "solid"
|
|
112
180
|
}
|
|
113
181
|
```
|
|
114
182
|
|
|
115
|
-
|
|
183
|
+
**Line styles (`style`):** `solid`, `dashed`, `dotted`
|
|
184
|
+
|
|
185
|
+
### Tags Dictionary (tagsDictionary)
|
|
116
186
|
|
|
117
187
|
```json
|
|
118
188
|
{
|
|
119
|
-
"
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
189
|
+
"tagsDictionary": [
|
|
190
|
+
{"id": "tag-1", "name": "system", "color": "#2196F3"},
|
|
191
|
+
{"id": "tag-2", "name": "user", "color": "#4CAF50"},
|
|
192
|
+
{"id": "tag-3", "name": "check", "color": "#FF9800"}
|
|
193
|
+
]
|
|
123
194
|
}
|
|
124
195
|
```
|
|
125
196
|
|
|
126
|
-
|
|
197
|
+
**Tags = roles/actors.** Indicate WHO performs the action:
|
|
198
|
+
- `system`, `user`, `admin`
|
|
199
|
+
- `client`, `manager`, `bot`
|
|
200
|
+
|
|
201
|
+
## Schema Methodology
|
|
202
|
+
|
|
203
|
+
Schema = complete tree of **ACTIONS** and **CONSEQUENCES**:
|
|
204
|
+
|
|
205
|
+
1. Each decision → show ALL possible options
|
|
206
|
+
2. Each option → show ALL consequences
|
|
207
|
+
3. Use `condition` for decision points
|
|
208
|
+
4. NOT abstract thoughts — CONCRETE paths
|
|
209
|
+
5. Tags indicate WHO performs the action
|
|
210
|
+
|
|
211
|
+
**Example:**
|
|
212
|
+
```
|
|
213
|
+
"Submit Form" → condition "Validate" →
|
|
214
|
+
├── "Data Valid" → "Save" → "Success"
|
|
215
|
+
└── "Error" → "Show Errors" → "Fix Form"
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Links
|
|
127
219
|
|
|
128
220
|
- [SchemeOG Cloud](https://scheme.smartlaunchhub.com)
|
|
129
221
|
- [GitLab](https://gitlab.com/serter2069/schemeog-cloud)
|
package/index.js
CHANGED
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* SchemeOG
|
|
4
|
+
* SchemeOG MCP Server v2.2
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* 5 команд — максимум мощи, минимум сложности.
|
|
6
|
+
* MCP сервер для работы со схемами, проектами и тегами в SchemeOG Cloud.
|
|
8
7
|
*
|
|
9
|
-
*
|
|
8
|
+
* Команды для схем:
|
|
10
9
|
* - list_schemas: Список всех схем
|
|
11
10
|
* - get_schema: Получить схему с данными
|
|
12
11
|
* - create_schema: Создать схему (с элементами и связями)
|
|
13
12
|
* - replace_schema: Полностью заменить содержимое схемы
|
|
14
13
|
* - delete_schema: Удалить схему
|
|
14
|
+
*
|
|
15
|
+
* Команды для проектов:
|
|
16
|
+
* - list_projects: Список проектов (папок)
|
|
17
|
+
* - create_project: Создать проект
|
|
18
|
+
* - update_project: Обновить проект
|
|
19
|
+
* - delete_project: Удалить проект
|
|
20
|
+
* - move_schema_to_project: Переместить схему в проект
|
|
21
|
+
*
|
|
22
|
+
* Команды для тегов:
|
|
23
|
+
* - list_tags: Список тегов схемы
|
|
24
|
+
* - add_tag: Добавить тег в схему
|
|
25
|
+
* - remove_tag: Удалить тег из схемы
|
|
26
|
+
* - tag_element: Присвоить/убрать тег с элемента
|
|
15
27
|
*/
|
|
16
28
|
|
|
17
29
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -24,16 +36,98 @@ import {
|
|
|
24
36
|
// Конфигурация
|
|
25
37
|
const API_BASE_URL = process.env.SCHEMEOG_API_URL || "https://scheme.smartlaunchhub.com";
|
|
26
38
|
const AUTH_TOKEN = process.env.SCHEMEOG_TOKEN || "";
|
|
39
|
+
const DOCS_URL = "https://scheme.smartlaunchhub.com/docs";
|
|
40
|
+
const PROFILE_URL = "https://scheme.smartlaunchhub.com/profile";
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Коды ошибок MCP
|
|
44
|
+
*/
|
|
45
|
+
const ErrorCodes = {
|
|
46
|
+
AUTH_MISSING: "AUTH_MISSING",
|
|
47
|
+
AUTH_INVALID: "AUTH_INVALID",
|
|
48
|
+
AUTH_EXPIRED: "AUTH_EXPIRED",
|
|
49
|
+
NOT_FOUND: "NOT_FOUND",
|
|
50
|
+
VALIDATION_ERROR: "VALIDATION_ERROR",
|
|
51
|
+
RATE_LIMIT: "RATE_LIMIT",
|
|
52
|
+
SERVER_ERROR: "SERVER_ERROR",
|
|
53
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Создать форматированную ошибку
|
|
58
|
+
*/
|
|
59
|
+
function createError(code, message, details = {}) {
|
|
60
|
+
const errorMessages = {
|
|
61
|
+
[ErrorCodes.AUTH_MISSING]: {
|
|
62
|
+
title: "🔑 Токен не указан",
|
|
63
|
+
hint: `Укажите SCHEMEOG_TOKEN в настройках MCP.\n\nПолучить токен: ${PROFILE_URL}\nДокументация: ${DOCS_URL}`,
|
|
64
|
+
},
|
|
65
|
+
[ErrorCodes.AUTH_INVALID]: {
|
|
66
|
+
title: "🔒 Неверный токен",
|
|
67
|
+
hint: `Токен невалидный или отозван.\n\nСоздайте новый токен: ${PROFILE_URL}`,
|
|
68
|
+
},
|
|
69
|
+
[ErrorCodes.AUTH_EXPIRED]: {
|
|
70
|
+
title: "⏰ Токен истёк",
|
|
71
|
+
hint: `Срок действия токена истёк.\n\nСоздайте новый токен: ${PROFILE_URL}`,
|
|
72
|
+
},
|
|
73
|
+
[ErrorCodes.NOT_FOUND]: {
|
|
74
|
+
title: "🔍 Не найдено",
|
|
75
|
+
hint: `Проверьте правильность ID.\n\nСписок схем: list_schemas\nСписок проектов: list_projects`,
|
|
76
|
+
},
|
|
77
|
+
[ErrorCodes.VALIDATION_ERROR]: {
|
|
78
|
+
title: "⚠️ Ошибка валидации",
|
|
79
|
+
hint: `Проверьте формат данных.\n\nДокументация: ${DOCS_URL}`,
|
|
80
|
+
},
|
|
81
|
+
[ErrorCodes.RATE_LIMIT]: {
|
|
82
|
+
title: "🚫 Превышен лимит запросов",
|
|
83
|
+
hint: "Подождите немного и повторите запрос.",
|
|
84
|
+
},
|
|
85
|
+
[ErrorCodes.SERVER_ERROR]: {
|
|
86
|
+
title: "💥 Ошибка сервера",
|
|
87
|
+
hint: `Попробуйте позже или обратитесь в поддержку.\n\nСтатус: ${API_BASE_URL}/status`,
|
|
88
|
+
},
|
|
89
|
+
[ErrorCodes.NETWORK_ERROR]: {
|
|
90
|
+
title: "🌐 Ошибка сети",
|
|
91
|
+
hint: "Проверьте подключение к интернету.",
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const errorInfo = errorMessages[code] || { title: "Ошибка", hint: "" };
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
code,
|
|
99
|
+
message: `${errorInfo.title}\n\n${message}${errorInfo.hint ? `\n\n${errorInfo.hint}` : ""}`,
|
|
100
|
+
details,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
27
103
|
|
|
28
104
|
/**
|
|
29
105
|
* Выполнить запрос к API SchemeOG
|
|
30
106
|
*/
|
|
31
107
|
async function apiRequest(endpoint, options = {}) {
|
|
108
|
+
// Проверка токена перед запросом
|
|
109
|
+
if (!AUTH_TOKEN) {
|
|
110
|
+
const error = createError(
|
|
111
|
+
ErrorCodes.AUTH_MISSING,
|
|
112
|
+
"Переменная окружения SCHEMEOG_TOKEN не установлена."
|
|
113
|
+
);
|
|
114
|
+
throw new Error(error.message);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Базовая валидация формата токена (schog_ - новый формат)
|
|
118
|
+
if (!AUTH_TOKEN.startsWith("schog_") || AUTH_TOKEN.length < 20) {
|
|
119
|
+
const error = createError(
|
|
120
|
+
ErrorCodes.AUTH_INVALID,
|
|
121
|
+
`Неверный формат токена. Токен должен начинаться с "schog_" и содержать минимум 20 символов.\n\nПолучен: ${AUTH_TOKEN.substring(0, 10)}...`
|
|
122
|
+
);
|
|
123
|
+
throw new Error(error.message);
|
|
124
|
+
}
|
|
125
|
+
|
|
32
126
|
const url = `${API_BASE_URL}/api${endpoint}`;
|
|
33
127
|
|
|
34
128
|
const headers = {
|
|
35
129
|
"Content-Type": "application/json",
|
|
36
|
-
|
|
130
|
+
"Authorization": `Bearer ${AUTH_TOKEN}`,
|
|
37
131
|
...options.headers,
|
|
38
132
|
};
|
|
39
133
|
|
|
@@ -43,15 +137,67 @@ async function apiRequest(endpoint, options = {}) {
|
|
|
43
137
|
headers,
|
|
44
138
|
});
|
|
45
139
|
|
|
46
|
-
|
|
140
|
+
// Попробуем распарсить JSON
|
|
141
|
+
let data;
|
|
142
|
+
try {
|
|
143
|
+
data = await response.json();
|
|
144
|
+
} catch {
|
|
145
|
+
data = { error: "Invalid JSON response" };
|
|
146
|
+
}
|
|
47
147
|
|
|
48
148
|
if (!response.ok) {
|
|
49
|
-
|
|
149
|
+
// Определяем тип ошибки по статусу
|
|
150
|
+
let errorCode;
|
|
151
|
+
let errorMessage = data.message || data.error || `HTTP ${response.status}`;
|
|
152
|
+
|
|
153
|
+
switch (response.status) {
|
|
154
|
+
case 401:
|
|
155
|
+
errorCode = ErrorCodes.AUTH_INVALID;
|
|
156
|
+
errorMessage = "Токен отклонён сервером. Возможно, он отозван или недействителен.";
|
|
157
|
+
break;
|
|
158
|
+
case 403:
|
|
159
|
+
errorCode = ErrorCodes.AUTH_EXPIRED;
|
|
160
|
+
errorMessage = "Доступ запрещён. Проверьте права токена.";
|
|
161
|
+
break;
|
|
162
|
+
case 404:
|
|
163
|
+
errorCode = ErrorCodes.NOT_FOUND;
|
|
164
|
+
errorMessage = data.message || "Ресурс не найден. Проверьте ID схемы или проекта.";
|
|
165
|
+
break;
|
|
166
|
+
case 422:
|
|
167
|
+
errorCode = ErrorCodes.VALIDATION_ERROR;
|
|
168
|
+
errorMessage = data.message || "Неверный формат данных.";
|
|
169
|
+
if (data.errors) {
|
|
170
|
+
errorMessage += "\n\nДетали:\n" + JSON.stringify(data.errors, null, 2);
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
case 429:
|
|
174
|
+
errorCode = ErrorCodes.RATE_LIMIT;
|
|
175
|
+
errorMessage = "Слишком много запросов.";
|
|
176
|
+
break;
|
|
177
|
+
default:
|
|
178
|
+
errorCode = response.status >= 500 ? ErrorCodes.SERVER_ERROR : ErrorCodes.VALIDATION_ERROR;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const error = createError(errorCode, errorMessage);
|
|
182
|
+
throw new Error(error.message);
|
|
50
183
|
}
|
|
51
184
|
|
|
52
185
|
return data;
|
|
53
186
|
} catch (error) {
|
|
54
|
-
|
|
187
|
+
// Если это уже наша форматированная ошибка — пробрасываем
|
|
188
|
+
if (error.message.includes("🔑") || error.message.includes("🔒") ||
|
|
189
|
+
error.message.includes("🔍") || error.message.includes("⚠️") ||
|
|
190
|
+
error.message.includes("🚫") || error.message.includes("💥") ||
|
|
191
|
+
error.message.includes("🌐") || error.message.includes("⏰")) {
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Ошибка сети
|
|
196
|
+
const networkError = createError(
|
|
197
|
+
ErrorCodes.NETWORK_ERROR,
|
|
198
|
+
`Не удалось подключиться к ${API_BASE_URL}\n\nДетали: ${error.message}`
|
|
199
|
+
);
|
|
200
|
+
throw new Error(networkError.message);
|
|
55
201
|
}
|
|
56
202
|
}
|
|
57
203
|
|
|
@@ -69,10 +215,7 @@ function prepareElements(elements) {
|
|
|
69
215
|
if (!elements) return [];
|
|
70
216
|
return elements.map(el => ({
|
|
71
217
|
id: el.id || generateId(),
|
|
72
|
-
type: el.type || "
|
|
73
|
-
x: el.x || 0,
|
|
74
|
-
y: el.y || 0,
|
|
75
|
-
text: el.text || "",
|
|
218
|
+
type: el.type || "card",
|
|
76
219
|
...el
|
|
77
220
|
}));
|
|
78
221
|
}
|
|
@@ -89,14 +232,15 @@ function prepareConnections(connections) {
|
|
|
89
232
|
}
|
|
90
233
|
|
|
91
234
|
/**
|
|
92
|
-
*
|
|
235
|
+
* Инструменты MCP
|
|
93
236
|
*/
|
|
94
237
|
const TOOLS = [
|
|
238
|
+
// ========== СХЕМЫ ==========
|
|
95
239
|
{
|
|
96
240
|
name: "list_schemas",
|
|
97
241
|
description: `Получить список всех схем пользователя.
|
|
98
242
|
|
|
99
|
-
Возвращает: ID, название, описание, дату обновления каждой схемы.
|
|
243
|
+
Возвращает: ID, название, описание, проект, дату обновления каждой схемы.
|
|
100
244
|
|
|
101
245
|
Используй эту команду чтобы узнать какие схемы есть у пользователя.`,
|
|
102
246
|
inputSchema: {
|
|
@@ -132,45 +276,63 @@ const TOOLS = [
|
|
|
132
276
|
name: "create_schema",
|
|
133
277
|
description: `Создать новую схему с элементами и связями.
|
|
134
278
|
|
|
135
|
-
ВАЖНО: Генерируй сразу полную схему с elements и
|
|
279
|
+
ВАЖНО: Генерируй сразу полную схему с elements, connections и tagsDictionary!
|
|
136
280
|
|
|
137
281
|
Параметры:
|
|
138
282
|
- name: название схемы (обязательно)
|
|
139
283
|
- description: описание
|
|
284
|
+
- project_id: ID проекта (опционально)
|
|
140
285
|
- elements: массив элементов
|
|
141
286
|
- connections: массив связей
|
|
287
|
+
- tagsDictionary: справочник тегов (опционально)
|
|
142
288
|
|
|
143
289
|
Формат элемента:
|
|
144
290
|
{
|
|
145
|
-
"id": "
|
|
146
|
-
"type": "
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
"color": "#E3F2FD" // цвет фона (опционально)
|
|
291
|
+
"id": "unique_id", // уникальный ID
|
|
292
|
+
"type": "card", // card (карточка) или condition (ромб решения)
|
|
293
|
+
"title": "Название", // заголовок карточки
|
|
294
|
+
"color": "light_blue", // цвет фона: white, light_blue, light_green, light_yellow, light_orange, light_red, light_purple, light_gray, light_pink, light_teal
|
|
295
|
+
"borderColor": "blue", // цвет обводки: default, blue, green, orange, purple, red, teal, yellow, gray, black
|
|
296
|
+
"tags": ["тег1"], // массив названий тегов (опционально)
|
|
297
|
+
"description": "Описание процесса" // подробное описание (опционально)
|
|
153
298
|
}
|
|
154
299
|
|
|
300
|
+
НЕ указывай x, y, width, height - рассчитываются автоматически!
|
|
301
|
+
|
|
155
302
|
Формат связи:
|
|
156
303
|
{
|
|
157
|
-
"from": "
|
|
158
|
-
"to": "
|
|
304
|
+
"from": "source_id", // ID элемента-источника
|
|
305
|
+
"to": "target_id", // ID элемента-назначения
|
|
159
306
|
"label": "подпись", // текст на связи (опционально)
|
|
160
307
|
"style": "solid" // solid, dashed, dotted (опционально)
|
|
161
308
|
}
|
|
162
309
|
|
|
163
|
-
|
|
310
|
+
Формат тега (tagsDictionary):
|
|
164
311
|
{
|
|
165
|
-
"
|
|
312
|
+
"id": "tag-1", // уникальный ID тега
|
|
313
|
+
"name": "система", // название тега (роль/актор)
|
|
314
|
+
"color": "#2196F3" // цвет в HEX
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
Пример: создать схему регистрации:
|
|
318
|
+
{
|
|
319
|
+
"name": "User Registration",
|
|
166
320
|
"elements": [
|
|
167
|
-
{"id": "
|
|
168
|
-
{"id": "
|
|
169
|
-
{"id": "
|
|
321
|
+
{"id": "start", "type": "card", "title": "Форма регистрации", "color": "light_green", "tags": ["пользователь"]},
|
|
322
|
+
{"id": "validate", "type": "condition", "title": "Валидация", "color": "light_yellow", "tags": ["система"]},
|
|
323
|
+
{"id": "save", "type": "card", "title": "Сохранение в БД", "color": "light_blue", "tags": ["система"]},
|
|
324
|
+
{"id": "error", "type": "card", "title": "Ошибка", "color": "light_red", "tags": ["система"]},
|
|
325
|
+
{"id": "success", "type": "card", "title": "Успех", "color": "light_green", "tags": ["пользователь"]}
|
|
170
326
|
],
|
|
171
327
|
"connections": [
|
|
172
|
-
{"from": "
|
|
173
|
-
{"from": "
|
|
328
|
+
{"from": "start", "to": "validate"},
|
|
329
|
+
{"from": "validate", "to": "save", "label": "OK"},
|
|
330
|
+
{"from": "validate", "to": "error", "label": "ошибка"},
|
|
331
|
+
{"from": "save", "to": "success"}
|
|
332
|
+
],
|
|
333
|
+
"tagsDictionary": [
|
|
334
|
+
{"id": "tag-user", "name": "пользователь", "color": "#4CAF50"},
|
|
335
|
+
{"id": "tag-system", "name": "система", "color": "#2196F3"}
|
|
174
336
|
]
|
|
175
337
|
}`,
|
|
176
338
|
inputSchema: {
|
|
@@ -184,6 +346,10 @@ const TOOLS = [
|
|
|
184
346
|
type: "string",
|
|
185
347
|
description: "Описание схемы",
|
|
186
348
|
},
|
|
349
|
+
project_id: {
|
|
350
|
+
type: "string",
|
|
351
|
+
description: "ID проекта для размещения схемы (опционально)",
|
|
352
|
+
},
|
|
187
353
|
elements: {
|
|
188
354
|
type: "array",
|
|
189
355
|
description: "Массив элементов схемы",
|
|
@@ -191,13 +357,12 @@ const TOOLS = [
|
|
|
191
357
|
type: "object",
|
|
192
358
|
properties: {
|
|
193
359
|
id: { type: "string" },
|
|
194
|
-
type: { type: "string", enum: ["
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
color: { type: "string" },
|
|
360
|
+
type: { type: "string", enum: ["card", "condition"] },
|
|
361
|
+
title: { type: "string" },
|
|
362
|
+
color: { type: "string", enum: ["white", "light_blue", "light_green", "light_yellow", "light_orange", "light_red", "light_purple", "light_gray", "light_pink", "light_teal"] },
|
|
363
|
+
borderColor: { type: "string", enum: ["default", "blue", "green", "orange", "purple", "red", "teal", "yellow", "gray", "black"] },
|
|
364
|
+
tags: { type: "array", items: { type: "string" } },
|
|
365
|
+
description: { type: "string" },
|
|
201
366
|
},
|
|
202
367
|
},
|
|
203
368
|
},
|
|
@@ -215,6 +380,18 @@ const TOOLS = [
|
|
|
215
380
|
required: ["from", "to"],
|
|
216
381
|
},
|
|
217
382
|
},
|
|
383
|
+
tagsDictionary: {
|
|
384
|
+
type: "array",
|
|
385
|
+
description: "Справочник тегов схемы",
|
|
386
|
+
items: {
|
|
387
|
+
type: "object",
|
|
388
|
+
properties: {
|
|
389
|
+
id: { type: "string" },
|
|
390
|
+
name: { type: "string" },
|
|
391
|
+
color: { type: "string" },
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
},
|
|
218
395
|
},
|
|
219
396
|
required: ["name"],
|
|
220
397
|
},
|
|
@@ -285,14 +462,319 @@ const TOOLS = [
|
|
|
285
462
|
required: ["schema_id"],
|
|
286
463
|
},
|
|
287
464
|
},
|
|
465
|
+
|
|
466
|
+
// ========== ПРОЕКТЫ ==========
|
|
467
|
+
{
|
|
468
|
+
name: "list_projects",
|
|
469
|
+
description: `Получить список всех проектов пользователя.
|
|
470
|
+
|
|
471
|
+
Проекты - это папки для группировки схем.
|
|
472
|
+
Возвращает: ID, название, описание, цвет, иконку и количество схем в каждом проекте.`,
|
|
473
|
+
inputSchema: {
|
|
474
|
+
type: "object",
|
|
475
|
+
properties: {},
|
|
476
|
+
required: [],
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
name: "create_project",
|
|
481
|
+
description: `Создать новый проект (папку для схем).
|
|
482
|
+
|
|
483
|
+
Параметры:
|
|
484
|
+
- name: название проекта (обязательно)
|
|
485
|
+
- description: описание проекта
|
|
486
|
+
- color: цвет в формате HEX (например #FF5733)
|
|
487
|
+
- icon: emoji иконка (например 📁, 🚀, 💡)`,
|
|
488
|
+
inputSchema: {
|
|
489
|
+
type: "object",
|
|
490
|
+
properties: {
|
|
491
|
+
name: {
|
|
492
|
+
type: "string",
|
|
493
|
+
description: "Название проекта",
|
|
494
|
+
},
|
|
495
|
+
description: {
|
|
496
|
+
type: "string",
|
|
497
|
+
description: "Описание проекта",
|
|
498
|
+
},
|
|
499
|
+
color: {
|
|
500
|
+
type: "string",
|
|
501
|
+
description: "Цвет проекта в формате HEX",
|
|
502
|
+
},
|
|
503
|
+
icon: {
|
|
504
|
+
type: "string",
|
|
505
|
+
description: "Emoji иконка проекта",
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
required: ["name"],
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
name: "delete_project",
|
|
513
|
+
description: `Удалить проект.
|
|
514
|
+
|
|
515
|
+
ВАЖНО: Схемы внутри проекта НЕ удаляются - они перемещаются в раздел "Общие".`,
|
|
516
|
+
inputSchema: {
|
|
517
|
+
type: "object",
|
|
518
|
+
properties: {
|
|
519
|
+
project_id: {
|
|
520
|
+
type: "string",
|
|
521
|
+
description: "ID проекта для удаления",
|
|
522
|
+
},
|
|
523
|
+
},
|
|
524
|
+
required: ["project_id"],
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
name: "move_schema_to_project",
|
|
529
|
+
description: `Переместить схему в проект или убрать из проекта.
|
|
530
|
+
|
|
531
|
+
Параметры:
|
|
532
|
+
- schema_id: ID схемы (обязательно)
|
|
533
|
+
- project_id: ID проекта. Если не указан или null - схема перемещается в "Общие" (без проекта)`,
|
|
534
|
+
inputSchema: {
|
|
535
|
+
type: "object",
|
|
536
|
+
properties: {
|
|
537
|
+
schema_id: {
|
|
538
|
+
type: "string",
|
|
539
|
+
description: "ID схемы",
|
|
540
|
+
},
|
|
541
|
+
project_id: {
|
|
542
|
+
type: "string",
|
|
543
|
+
description: "ID проекта (или null для перемещения в Общие)",
|
|
544
|
+
},
|
|
545
|
+
},
|
|
546
|
+
required: ["schema_id"],
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
name: "update_project",
|
|
551
|
+
description: `Обновить проект - изменить название, описание, цвет или иконку.
|
|
552
|
+
|
|
553
|
+
Параметры:
|
|
554
|
+
- project_id: ID проекта (обязательно)
|
|
555
|
+
- name: новое название
|
|
556
|
+
- description: новое описание
|
|
557
|
+
- color: новый цвет в формате HEX
|
|
558
|
+
- icon: новая emoji иконка`,
|
|
559
|
+
inputSchema: {
|
|
560
|
+
type: "object",
|
|
561
|
+
properties: {
|
|
562
|
+
project_id: {
|
|
563
|
+
type: "string",
|
|
564
|
+
description: "ID проекта",
|
|
565
|
+
},
|
|
566
|
+
name: {
|
|
567
|
+
type: "string",
|
|
568
|
+
description: "Новое название проекта",
|
|
569
|
+
},
|
|
570
|
+
description: {
|
|
571
|
+
type: "string",
|
|
572
|
+
description: "Новое описание проекта",
|
|
573
|
+
},
|
|
574
|
+
color: {
|
|
575
|
+
type: "string",
|
|
576
|
+
description: "Новый цвет проекта в формате HEX",
|
|
577
|
+
},
|
|
578
|
+
icon: {
|
|
579
|
+
type: "string",
|
|
580
|
+
description: "Новая emoji иконка проекта",
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
required: ["project_id"],
|
|
584
|
+
},
|
|
585
|
+
},
|
|
586
|
+
|
|
587
|
+
// ========== ТЕГИ ==========
|
|
588
|
+
{
|
|
589
|
+
name: "add_tag",
|
|
590
|
+
description: `Добавить новый тег в схему.
|
|
591
|
+
|
|
592
|
+
Теги используются для категоризации элементов схемы.
|
|
593
|
+
|
|
594
|
+
Параметры:
|
|
595
|
+
- schema_id: ID схемы (обязательно)
|
|
596
|
+
- name: название тега (обязательно)
|
|
597
|
+
- color: цвет тега в формате HEX (например #4CAF50)`,
|
|
598
|
+
inputSchema: {
|
|
599
|
+
type: "object",
|
|
600
|
+
properties: {
|
|
601
|
+
schema_id: {
|
|
602
|
+
type: "string",
|
|
603
|
+
description: "ID схемы",
|
|
604
|
+
},
|
|
605
|
+
name: {
|
|
606
|
+
type: "string",
|
|
607
|
+
description: "Название тега",
|
|
608
|
+
},
|
|
609
|
+
color: {
|
|
610
|
+
type: "string",
|
|
611
|
+
description: "Цвет тега в формате HEX",
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
required: ["schema_id", "name"],
|
|
615
|
+
},
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
name: "remove_tag",
|
|
619
|
+
description: `Удалить тег из схемы.
|
|
620
|
+
|
|
621
|
+
Тег будет удалён из tagsDictionary и убран со всех элементов.
|
|
622
|
+
|
|
623
|
+
Параметры:
|
|
624
|
+
- schema_id: ID схемы (обязательно)
|
|
625
|
+
- tag_id: ID тега для удаления (обязательно)`,
|
|
626
|
+
inputSchema: {
|
|
627
|
+
type: "object",
|
|
628
|
+
properties: {
|
|
629
|
+
schema_id: {
|
|
630
|
+
type: "string",
|
|
631
|
+
description: "ID схемы",
|
|
632
|
+
},
|
|
633
|
+
tag_id: {
|
|
634
|
+
type: "string",
|
|
635
|
+
description: "ID тега для удаления",
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
required: ["schema_id", "tag_id"],
|
|
639
|
+
},
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
name: "tag_element",
|
|
643
|
+
description: `Присвоить или убрать тег с элемента.
|
|
644
|
+
|
|
645
|
+
Параметры:
|
|
646
|
+
- schema_id: ID схемы (обязательно)
|
|
647
|
+
- element_id: ID элемента (обязательно)
|
|
648
|
+
- tag_id: ID тега (обязательно)
|
|
649
|
+
- action: "add" или "remove" (по умолчанию "add")`,
|
|
650
|
+
inputSchema: {
|
|
651
|
+
type: "object",
|
|
652
|
+
properties: {
|
|
653
|
+
schema_id: {
|
|
654
|
+
type: "string",
|
|
655
|
+
description: "ID схемы",
|
|
656
|
+
},
|
|
657
|
+
element_id: {
|
|
658
|
+
type: "string",
|
|
659
|
+
description: "ID элемента",
|
|
660
|
+
},
|
|
661
|
+
tag_id: {
|
|
662
|
+
type: "string",
|
|
663
|
+
description: "ID тега",
|
|
664
|
+
},
|
|
665
|
+
action: {
|
|
666
|
+
type: "string",
|
|
667
|
+
enum: ["add", "remove"],
|
|
668
|
+
description: "Действие: add (добавить) или remove (убрать)",
|
|
669
|
+
},
|
|
670
|
+
},
|
|
671
|
+
required: ["schema_id", "element_id", "tag_id"],
|
|
672
|
+
},
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
name: "list_tags",
|
|
676
|
+
description: `Получить список всех тегов схемы.
|
|
677
|
+
|
|
678
|
+
Параметры:
|
|
679
|
+
- schema_id: ID схемы (обязательно)`,
|
|
680
|
+
inputSchema: {
|
|
681
|
+
type: "object",
|
|
682
|
+
properties: {
|
|
683
|
+
schema_id: {
|
|
684
|
+
type: "string",
|
|
685
|
+
description: "ID схемы",
|
|
686
|
+
},
|
|
687
|
+
},
|
|
688
|
+
required: ["schema_id"],
|
|
689
|
+
},
|
|
690
|
+
},
|
|
288
691
|
];
|
|
289
692
|
|
|
693
|
+
/**
|
|
694
|
+
* Валидация UUID формата
|
|
695
|
+
*/
|
|
696
|
+
function isValidUUID(str) {
|
|
697
|
+
if (!str || typeof str !== "string") return false;
|
|
698
|
+
// Принимаем разные форматы ID: UUID и cuid
|
|
699
|
+
return /^[a-zA-Z0-9_-]{10,}$/.test(str);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Валидация параметров команды
|
|
704
|
+
*/
|
|
705
|
+
function validateArgs(name, args) {
|
|
706
|
+
const errors = [];
|
|
707
|
+
|
|
708
|
+
// Валидация schema_id
|
|
709
|
+
if (["get_schema", "replace_schema", "delete_schema", "add_tag", "remove_tag", "tag_element", "list_tags"].includes(name)) {
|
|
710
|
+
if (!args.schema_id) {
|
|
711
|
+
errors.push("schema_id — обязательный параметр");
|
|
712
|
+
} else if (!isValidUUID(args.schema_id)) {
|
|
713
|
+
errors.push(`schema_id "${args.schema_id}" — неверный формат. Используйте ID из list_schemas`);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// Валидация project_id
|
|
718
|
+
if (["delete_project", "update_project"].includes(name)) {
|
|
719
|
+
if (!args.project_id) {
|
|
720
|
+
errors.push("project_id — обязательный параметр");
|
|
721
|
+
} else if (!isValidUUID(args.project_id)) {
|
|
722
|
+
errors.push(`project_id "${args.project_id}" — неверный формат. Используйте ID из list_projects`);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// Валидация name для создания
|
|
727
|
+
if (["create_schema", "create_project"].includes(name)) {
|
|
728
|
+
if (!args.name || typeof args.name !== "string" || args.name.trim().length === 0) {
|
|
729
|
+
errors.push("name — обязательный параметр (название)");
|
|
730
|
+
} else if (args.name.length > 100) {
|
|
731
|
+
errors.push("name — слишком длинное название (макс. 100 символов)");
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// Валидация тегов
|
|
736
|
+
if (name === "add_tag") {
|
|
737
|
+
if (!args.name || typeof args.name !== "string") {
|
|
738
|
+
errors.push("name — обязательный параметр (название тега)");
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
if (name === "remove_tag" || name === "tag_element") {
|
|
743
|
+
if (!args.tag_id) {
|
|
744
|
+
errors.push("tag_id — обязательный параметр");
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
if (name === "tag_element") {
|
|
749
|
+
if (!args.element_id) {
|
|
750
|
+
errors.push("element_id — обязательный параметр");
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// Валидация цвета
|
|
755
|
+
if (args.color && !/^#[0-9A-Fa-f]{6}$/.test(args.color)) {
|
|
756
|
+
errors.push(`color "${args.color}" — неверный формат. Используйте HEX: #RRGGBB (например #4CAF50)`);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
return errors;
|
|
760
|
+
}
|
|
761
|
+
|
|
290
762
|
/**
|
|
291
763
|
* Обработчики инструментов
|
|
292
764
|
*/
|
|
293
765
|
async function handleTool(name, args) {
|
|
766
|
+
// Валидация параметров
|
|
767
|
+
const validationErrors = validateArgs(name, args);
|
|
768
|
+
if (validationErrors.length > 0) {
|
|
769
|
+
const error = createError(
|
|
770
|
+
ErrorCodes.VALIDATION_ERROR,
|
|
771
|
+
`Ошибки в параметрах:\n\n• ${validationErrors.join("\n• ")}`
|
|
772
|
+
);
|
|
773
|
+
throw new Error(error.message);
|
|
774
|
+
}
|
|
775
|
+
|
|
294
776
|
switch (name) {
|
|
295
|
-
// ==========
|
|
777
|
+
// ========== СХЕМЫ ==========
|
|
296
778
|
case "list_schemas": {
|
|
297
779
|
const result = await apiRequest("/schemas");
|
|
298
780
|
|
|
@@ -309,6 +791,8 @@ async function handleTool(name, args) {
|
|
|
309
791
|
id: s.id,
|
|
310
792
|
name: s.name,
|
|
311
793
|
description: s.description || "",
|
|
794
|
+
projectId: s.projectId || null,
|
|
795
|
+
projectName: s.project?.name || "Общие",
|
|
312
796
|
updatedAt: s.updatedAt,
|
|
313
797
|
elementsCount: s.data?.elements?.length || 0,
|
|
314
798
|
connectionsCount: s.data?.connections?.length || 0,
|
|
@@ -322,7 +806,6 @@ async function handleTool(name, args) {
|
|
|
322
806
|
};
|
|
323
807
|
}
|
|
324
808
|
|
|
325
|
-
// ========== GET SCHEMA ==========
|
|
326
809
|
case "get_schema": {
|
|
327
810
|
const { schema_id } = args;
|
|
328
811
|
const result = await apiRequest(`/schemas/${schema_id}`);
|
|
@@ -336,6 +819,7 @@ async function handleTool(name, args) {
|
|
|
336
819
|
|
|
337
820
|
ID: ${schema.id}
|
|
338
821
|
Описание: ${schema.description || "(нет)"}
|
|
822
|
+
Проект: ${schema.project?.name || "Общие"}
|
|
339
823
|
Элементов: ${schema.data?.elements?.length || 0}
|
|
340
824
|
Связей: ${schema.data?.connections?.length || 0}
|
|
341
825
|
URL: ${API_BASE_URL}/canvas?id=${schema.id}
|
|
@@ -349,9 +833,8 @@ ${JSON.stringify(schema.data?.connections || [], null, 2)}`,
|
|
|
349
833
|
};
|
|
350
834
|
}
|
|
351
835
|
|
|
352
|
-
// ========== CREATE SCHEMA ==========
|
|
353
836
|
case "create_schema": {
|
|
354
|
-
const { name, description, elements, connections } = args;
|
|
837
|
+
const { name, description, project_id, elements, connections } = args;
|
|
355
838
|
|
|
356
839
|
const data = {
|
|
357
840
|
elements: prepareElements(elements),
|
|
@@ -361,15 +844,18 @@ ${JSON.stringify(schema.data?.connections || [], null, 2)}`,
|
|
|
361
844
|
|
|
362
845
|
const result = await apiRequest("/schemas", {
|
|
363
846
|
method: "POST",
|
|
364
|
-
body: JSON.stringify({ name, description, data }),
|
|
847
|
+
body: JSON.stringify({ name, description, data, projectId: project_id }),
|
|
365
848
|
});
|
|
366
849
|
|
|
850
|
+
const projectInfo = project_id ? `Проект: ${project_id}` : 'Проект: Общие';
|
|
851
|
+
|
|
367
852
|
return {
|
|
368
853
|
content: [{
|
|
369
854
|
type: "text",
|
|
370
855
|
text: `Схема "${result.schema.name}" создана!
|
|
371
856
|
|
|
372
857
|
ID: ${result.schema.id}
|
|
858
|
+
${projectInfo}
|
|
373
859
|
Элементов: ${data.elements.length}
|
|
374
860
|
Связей: ${data.connections.length}
|
|
375
861
|
|
|
@@ -380,7 +866,6 @@ URL: ${API_BASE_URL}/canvas?id=${result.schema.id}
|
|
|
380
866
|
};
|
|
381
867
|
}
|
|
382
868
|
|
|
383
|
-
// ========== REPLACE SCHEMA ==========
|
|
384
869
|
case "replace_schema": {
|
|
385
870
|
const { schema_id, name, description, elements, connections } = args;
|
|
386
871
|
|
|
@@ -423,7 +908,6 @@ URL: ${API_BASE_URL}/canvas?id=${schema_id}`,
|
|
|
423
908
|
};
|
|
424
909
|
}
|
|
425
910
|
|
|
426
|
-
// ========== DELETE SCHEMA ==========
|
|
427
911
|
case "delete_schema": {
|
|
428
912
|
const { schema_id } = args;
|
|
429
913
|
|
|
@@ -439,6 +923,253 @@ URL: ${API_BASE_URL}/canvas?id=${schema_id}`,
|
|
|
439
923
|
};
|
|
440
924
|
}
|
|
441
925
|
|
|
926
|
+
// ========== ПРОЕКТЫ ==========
|
|
927
|
+
case "list_projects": {
|
|
928
|
+
const result = await apiRequest("/projects");
|
|
929
|
+
|
|
930
|
+
if (!result.projects || result.projects.length === 0) {
|
|
931
|
+
return {
|
|
932
|
+
content: [{
|
|
933
|
+
type: "text",
|
|
934
|
+
text: `Проектов пока нет. Все схемы находятся в разделе "Общие" (${result.unassignedCount || 0} схем).\n\nСоздай проект с помощью create_project.`,
|
|
935
|
+
}],
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
const projectsList = result.projects.map(p => ({
|
|
940
|
+
id: p.id,
|
|
941
|
+
name: p.name,
|
|
942
|
+
description: p.description || "",
|
|
943
|
+
color: p.color,
|
|
944
|
+
icon: p.icon,
|
|
945
|
+
schemasCount: p.schemasCount || 0,
|
|
946
|
+
}));
|
|
947
|
+
|
|
948
|
+
return {
|
|
949
|
+
content: [{
|
|
950
|
+
type: "text",
|
|
951
|
+
text: `Найдено ${result.projects.length} проектов:\n\n${JSON.stringify(projectsList, null, 2)}\n\nСхем без проекта ("Общие"): ${result.unassignedCount || 0}`,
|
|
952
|
+
}],
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
case "create_project": {
|
|
957
|
+
const { name, description, color, icon } = args;
|
|
958
|
+
|
|
959
|
+
const result = await apiRequest("/projects", {
|
|
960
|
+
method: "POST",
|
|
961
|
+
body: JSON.stringify({ name, description, color, icon }),
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
return {
|
|
965
|
+
content: [{
|
|
966
|
+
type: "text",
|
|
967
|
+
text: `Проект "${result.project.name}" создан!\n\nID: ${result.project.id}`,
|
|
968
|
+
}],
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
case "delete_project": {
|
|
973
|
+
const { project_id } = args;
|
|
974
|
+
|
|
975
|
+
const result = await apiRequest(`/projects/${project_id}`, {
|
|
976
|
+
method: "DELETE",
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
return {
|
|
980
|
+
content: [{
|
|
981
|
+
type: "text",
|
|
982
|
+
text: result.message || "Проект удалён. Схемы перемещены в 'Общие'.",
|
|
983
|
+
}],
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
case "move_schema_to_project": {
|
|
988
|
+
const { schema_id, project_id } = args;
|
|
989
|
+
|
|
990
|
+
if (project_id) {
|
|
991
|
+
// Переместить в проект
|
|
992
|
+
const result = await apiRequest(`/projects/${project_id}/schemas/${schema_id}`, {
|
|
993
|
+
method: "PUT",
|
|
994
|
+
});
|
|
995
|
+
return {
|
|
996
|
+
content: [{
|
|
997
|
+
type: "text",
|
|
998
|
+
text: result.message || "Схема перемещена в проект.",
|
|
999
|
+
}],
|
|
1000
|
+
};
|
|
1001
|
+
} else {
|
|
1002
|
+
// Убрать из проекта (в "Общие")
|
|
1003
|
+
const result = await apiRequest(`/projects/null/schemas/${schema_id}`, {
|
|
1004
|
+
method: "DELETE",
|
|
1005
|
+
});
|
|
1006
|
+
return {
|
|
1007
|
+
content: [{
|
|
1008
|
+
type: "text",
|
|
1009
|
+
text: result.message || "Схема перемещена в 'Общие'.",
|
|
1010
|
+
}],
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
case "update_project": {
|
|
1016
|
+
const { project_id, name, description, color, icon } = args;
|
|
1017
|
+
|
|
1018
|
+
const updateBody = {};
|
|
1019
|
+
if (name !== undefined) updateBody.name = name;
|
|
1020
|
+
if (description !== undefined) updateBody.description = description;
|
|
1021
|
+
if (color !== undefined) updateBody.color = color;
|
|
1022
|
+
if (icon !== undefined) updateBody.icon = icon;
|
|
1023
|
+
|
|
1024
|
+
const result = await apiRequest(`/projects/${project_id}`, {
|
|
1025
|
+
method: "PUT",
|
|
1026
|
+
body: JSON.stringify(updateBody),
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
return {
|
|
1030
|
+
content: [{
|
|
1031
|
+
type: "text",
|
|
1032
|
+
text: `Проект "${result.project.name}" обновлён!\n\nID: ${result.project.id}`,
|
|
1033
|
+
}],
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// ========== ТЕГИ ==========
|
|
1038
|
+
case "add_tag": {
|
|
1039
|
+
const { schema_id, name, color } = args;
|
|
1040
|
+
|
|
1041
|
+
// Получаем текущую схему
|
|
1042
|
+
const currentResult = await apiRequest(`/schemas/${schema_id}`);
|
|
1043
|
+
const currentData = currentResult.schema.data || { elements: [], connections: [], tagsDictionary: [] };
|
|
1044
|
+
|
|
1045
|
+
// Создаём новый тег
|
|
1046
|
+
const newTag = {
|
|
1047
|
+
id: generateId(),
|
|
1048
|
+
name: name,
|
|
1049
|
+
color: color || "#9E9E9E",
|
|
1050
|
+
};
|
|
1051
|
+
|
|
1052
|
+
// Добавляем тег в tagsDictionary
|
|
1053
|
+
const tagsDictionary = currentData.tagsDictionary || [];
|
|
1054
|
+
tagsDictionary.push(newTag);
|
|
1055
|
+
|
|
1056
|
+
// Обновляем схему
|
|
1057
|
+
await apiRequest(`/schemas/${schema_id}`, {
|
|
1058
|
+
method: "PUT",
|
|
1059
|
+
body: JSON.stringify({
|
|
1060
|
+
data: { ...currentData, tagsDictionary },
|
|
1061
|
+
}),
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
return {
|
|
1065
|
+
content: [{
|
|
1066
|
+
type: "text",
|
|
1067
|
+
text: `Тег "${name}" добавлен!\n\nID: ${newTag.id}\nЦвет: ${newTag.color}`,
|
|
1068
|
+
}],
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
case "remove_tag": {
|
|
1073
|
+
const { schema_id, tag_id } = args;
|
|
1074
|
+
|
|
1075
|
+
// Получаем текущую схему
|
|
1076
|
+
const currentResult = await apiRequest(`/schemas/${schema_id}`);
|
|
1077
|
+
const currentData = currentResult.schema.data || { elements: [], connections: [], tagsDictionary: [] };
|
|
1078
|
+
|
|
1079
|
+
// Удаляем тег из tagsDictionary
|
|
1080
|
+
const tagsDictionary = (currentData.tagsDictionary || []).filter(t => t.id !== tag_id);
|
|
1081
|
+
|
|
1082
|
+
// Удаляем тег со всех элементов
|
|
1083
|
+
const elements = (currentData.elements || []).map(el => {
|
|
1084
|
+
if (el.tags && Array.isArray(el.tags)) {
|
|
1085
|
+
el.tags = el.tags.filter(t => t !== tag_id);
|
|
1086
|
+
}
|
|
1087
|
+
return el;
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
// Обновляем схему
|
|
1091
|
+
await apiRequest(`/schemas/${schema_id}`, {
|
|
1092
|
+
method: "PUT",
|
|
1093
|
+
body: JSON.stringify({
|
|
1094
|
+
data: { ...currentData, tagsDictionary, elements },
|
|
1095
|
+
}),
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
return {
|
|
1099
|
+
content: [{
|
|
1100
|
+
type: "text",
|
|
1101
|
+
text: `Тег удалён из схемы и со всех элементов.`,
|
|
1102
|
+
}],
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
case "tag_element": {
|
|
1107
|
+
const { schema_id, element_id, tag_id, action = "add" } = args;
|
|
1108
|
+
|
|
1109
|
+
// Получаем текущую схему
|
|
1110
|
+
const currentResult = await apiRequest(`/schemas/${schema_id}`);
|
|
1111
|
+
const currentData = currentResult.schema.data || { elements: [], connections: [], tagsDictionary: [] };
|
|
1112
|
+
|
|
1113
|
+
// Находим элемент и обновляем его теги
|
|
1114
|
+
const elements = (currentData.elements || []).map(el => {
|
|
1115
|
+
if (el.id === element_id) {
|
|
1116
|
+
const tags = el.tags || [];
|
|
1117
|
+
if (action === "add") {
|
|
1118
|
+
if (!tags.includes(tag_id)) {
|
|
1119
|
+
tags.push(tag_id);
|
|
1120
|
+
}
|
|
1121
|
+
} else if (action === "remove") {
|
|
1122
|
+
const index = tags.indexOf(tag_id);
|
|
1123
|
+
if (index > -1) {
|
|
1124
|
+
tags.splice(index, 1);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
el.tags = tags;
|
|
1128
|
+
}
|
|
1129
|
+
return el;
|
|
1130
|
+
});
|
|
1131
|
+
|
|
1132
|
+
// Обновляем схему
|
|
1133
|
+
await apiRequest(`/schemas/${schema_id}`, {
|
|
1134
|
+
method: "PUT",
|
|
1135
|
+
body: JSON.stringify({
|
|
1136
|
+
data: { ...currentData, elements },
|
|
1137
|
+
}),
|
|
1138
|
+
});
|
|
1139
|
+
|
|
1140
|
+
const actionText = action === "add" ? "добавлен к" : "убран с";
|
|
1141
|
+
return {
|
|
1142
|
+
content: [{
|
|
1143
|
+
type: "text",
|
|
1144
|
+
text: `Тег ${actionText} элемента ${element_id}.`,
|
|
1145
|
+
}],
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
case "list_tags": {
|
|
1150
|
+
const { schema_id } = args;
|
|
1151
|
+
|
|
1152
|
+
// Получаем схему
|
|
1153
|
+
const result = await apiRequest(`/schemas/${schema_id}`);
|
|
1154
|
+
const tagsDictionary = result.schema.data?.tagsDictionary || [];
|
|
1155
|
+
|
|
1156
|
+
if (tagsDictionary.length === 0) {
|
|
1157
|
+
return {
|
|
1158
|
+
content: [{
|
|
1159
|
+
type: "text",
|
|
1160
|
+
text: "В схеме нет тегов.\n\nДобавь тег с помощью add_tag.",
|
|
1161
|
+
}],
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
return {
|
|
1166
|
+
content: [{
|
|
1167
|
+
type: "text",
|
|
1168
|
+
text: `Теги схемы (${tagsDictionary.length}):\n\n${JSON.stringify(tagsDictionary, null, 2)}`,
|
|
1169
|
+
}],
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
|
|
442
1173
|
default:
|
|
443
1174
|
throw new Error(`Неизвестная команда: ${name}`);
|
|
444
1175
|
}
|
|
@@ -449,13 +1180,35 @@ URL: ${API_BASE_URL}/canvas?id=${schema_id}`,
|
|
|
449
1180
|
*/
|
|
450
1181
|
async function main() {
|
|
451
1182
|
if (!AUTH_TOKEN) {
|
|
452
|
-
console.error(
|
|
1183
|
+
console.error(`
|
|
1184
|
+
⚠️ SCHEMEOG_TOKEN не установлен!
|
|
1185
|
+
|
|
1186
|
+
Для работы MCP сервера необходим API токен.
|
|
1187
|
+
|
|
1188
|
+
1. Получите токен: ${PROFILE_URL}
|
|
1189
|
+
2. Добавьте в настройки MCP:
|
|
1190
|
+
|
|
1191
|
+
"env": {
|
|
1192
|
+
"SCHEMEOG_TOKEN": "schog_ваш-токен"
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
Документация: ${DOCS_URL}
|
|
1196
|
+
`);
|
|
1197
|
+
} else if (!AUTH_TOKEN.startsWith("schog_")) {
|
|
1198
|
+
console.error(`
|
|
1199
|
+
⚠️ Неверный формат токена!
|
|
1200
|
+
|
|
1201
|
+
Токен должен начинаться с "schog_".
|
|
1202
|
+
Получен: ${AUTH_TOKEN.substring(0, 10)}...
|
|
1203
|
+
|
|
1204
|
+
Создайте новый токен: ${PROFILE_URL}
|
|
1205
|
+
`);
|
|
453
1206
|
}
|
|
454
1207
|
|
|
455
1208
|
const server = new Server(
|
|
456
1209
|
{
|
|
457
1210
|
name: "schemeog-mcp",
|
|
458
|
-
version: "2.
|
|
1211
|
+
version: "2.2.1",
|
|
459
1212
|
},
|
|
460
1213
|
{
|
|
461
1214
|
capabilities: {
|
|
@@ -485,7 +1238,7 @@ async function main() {
|
|
|
485
1238
|
const transport = new StdioServerTransport();
|
|
486
1239
|
await server.connect(transport);
|
|
487
1240
|
|
|
488
|
-
console.error("SchemeOG MCP Server v2.
|
|
1241
|
+
console.error("SchemeOG MCP Server v2.2 запущен");
|
|
489
1242
|
}
|
|
490
1243
|
|
|
491
1244
|
main().catch(console.error);
|