schemeog-mcp 2.2.0 → 2.3.0
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 +106 -151
- package/index.js +255 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,58 +1,58 @@
|
|
|
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
|
-
## 14
|
|
5
|
+
## 14 Commands
|
|
6
6
|
|
|
7
|
-
###
|
|
7
|
+
### Schemas (5 commands)
|
|
8
8
|
|
|
9
|
-
|
|
|
10
|
-
|
|
11
|
-
| `list_schemas` |
|
|
12
|
-
| `get_schema` |
|
|
13
|
-
| `create_schema` |
|
|
14
|
-
| `replace_schema` |
|
|
15
|
-
| `delete_schema` |
|
|
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
18
|
|
|
19
|
-
|
|
|
20
|
-
|
|
21
|
-
| `list_projects` |
|
|
22
|
-
| `create_project` |
|
|
23
|
-
| `update_project` |
|
|
24
|
-
| `delete_project` |
|
|
25
|
-
| `move_schema_to_project` |
|
|
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
26
|
|
|
27
|
-
###
|
|
27
|
+
### Tags (4 commands)
|
|
28
28
|
|
|
29
|
-
|
|
|
30
|
-
|
|
31
|
-
| `list_tags` |
|
|
32
|
-
| `add_tag` |
|
|
33
|
-
| `remove_tag` |
|
|
34
|
-
| `tag_element` |
|
|
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
35
|
|
|
36
|
-
##
|
|
36
|
+
## Installation
|
|
37
37
|
|
|
38
|
-
###
|
|
38
|
+
### Via npx (recommended)
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
41
|
npx schemeog-mcp
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Setup
|
|
45
45
|
|
|
46
|
-
### 1.
|
|
46
|
+
### 1. Get your token
|
|
47
47
|
|
|
48
|
-
1.
|
|
49
|
-
2.
|
|
50
|
-
3.
|
|
51
|
-
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
|
|
52
52
|
|
|
53
|
-
### 2.
|
|
53
|
+
### 2. Add to Claude Code / Cline
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
In `~/.claude.json` (or Cline settings):
|
|
56
56
|
|
|
57
57
|
```json
|
|
58
58
|
{
|
|
@@ -68,199 +68,154 @@ npx schemeog-mcp
|
|
|
68
68
|
}
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
##
|
|
71
|
+
## Schema Data Format
|
|
72
72
|
|
|
73
|
-
###
|
|
73
|
+
### Full schema example
|
|
74
74
|
|
|
75
75
|
```json
|
|
76
76
|
{
|
|
77
77
|
"name": "User Registration Flow",
|
|
78
|
-
"description": "
|
|
78
|
+
"description": "User registration process",
|
|
79
79
|
"elements": [
|
|
80
80
|
{
|
|
81
81
|
"id": "start",
|
|
82
82
|
"type": "card",
|
|
83
|
-
"title": "
|
|
83
|
+
"title": "Registration Form",
|
|
84
84
|
"color": "light_green",
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"description": "Пользователь заполняет форму с email и паролем"
|
|
85
|
+
"tags": ["user"],
|
|
86
|
+
"description": "User fills in email and password"
|
|
88
87
|
},
|
|
89
88
|
{
|
|
90
89
|
"id": "validate",
|
|
91
90
|
"type": "condition",
|
|
92
|
-
"title": "
|
|
91
|
+
"title": "Validate Data",
|
|
93
92
|
"color": "light_yellow",
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"description": "Проверка корректности email и сложности пароля"
|
|
93
|
+
"tags": ["system", "check"],
|
|
94
|
+
"description": "Check email format and password strength"
|
|
97
95
|
},
|
|
98
96
|
{
|
|
99
97
|
"id": "save",
|
|
100
98
|
"type": "card",
|
|
101
|
-
"title": "
|
|
99
|
+
"title": "Save to Database",
|
|
102
100
|
"color": "light_blue",
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"description": "Создание записи пользователя в базе данных"
|
|
101
|
+
"tags": ["system"],
|
|
102
|
+
"description": "Create user record in database"
|
|
106
103
|
},
|
|
107
104
|
{
|
|
108
105
|
"id": "error",
|
|
109
106
|
"type": "card",
|
|
110
|
-
"title": "
|
|
107
|
+
"title": "Validation Error",
|
|
111
108
|
"color": "light_red",
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"description": "Показать пользователю ошибки валидации"
|
|
109
|
+
"tags": ["system", "error"],
|
|
110
|
+
"description": "Show validation errors to user"
|
|
115
111
|
},
|
|
116
112
|
{
|
|
117
113
|
"id": "success",
|
|
118
114
|
"type": "card",
|
|
119
|
-
"title": "
|
|
115
|
+
"title": "Registration Complete",
|
|
120
116
|
"color": "light_green",
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"description": "Пользователь успешно зарегистрирован"
|
|
117
|
+
"tags": ["user"],
|
|
118
|
+
"description": "User successfully registered"
|
|
124
119
|
}
|
|
125
120
|
],
|
|
126
121
|
"connections": [
|
|
127
|
-
{"from": "start", "to": "validate", "label": "
|
|
128
|
-
{"from": "validate", "to": "save", "label": "
|
|
129
|
-
{"from": "validate", "to": "error", "label": "
|
|
122
|
+
{"from": "start", "to": "validate", "label": "submit"},
|
|
123
|
+
{"from": "validate", "to": "save", "label": "valid"},
|
|
124
|
+
{"from": "validate", "to": "error", "label": "invalid"},
|
|
130
125
|
{"from": "save", "to": "success"},
|
|
131
|
-
{"from": "error", "to": "start", "label": "
|
|
126
|
+
{"from": "error", "to": "start", "label": "retry"}
|
|
132
127
|
],
|
|
133
128
|
"tagsDictionary": [
|
|
134
|
-
{"id": "tag-user", "name": "
|
|
135
|
-
{"id": "tag-system", "name": "
|
|
136
|
-
{"id": "tag-check", "name": "
|
|
137
|
-
{"id": "tag-error", "name": "
|
|
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"}
|
|
138
133
|
]
|
|
139
134
|
}
|
|
140
135
|
```
|
|
141
136
|
|
|
142
|
-
###
|
|
137
|
+
### Element (card or condition)
|
|
143
138
|
|
|
144
139
|
```json
|
|
145
140
|
{
|
|
146
141
|
"id": "unique_id",
|
|
147
142
|
"type": "card",
|
|
148
|
-
"title": "
|
|
143
|
+
"title": "Card Title",
|
|
149
144
|
"color": "light_blue",
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
"description": "Подробное описание действия или процесса"
|
|
145
|
+
"tags": ["tag1", "tag2"],
|
|
146
|
+
"description": "Detailed description of the action or process"
|
|
153
147
|
}
|
|
154
148
|
```
|
|
155
149
|
|
|
156
|
-
|
|
157
|
-
- `card` —
|
|
158
|
-
- `condition` —
|
|
150
|
+
**Element types:**
|
|
151
|
+
- `card` — regular process/action card
|
|
152
|
+
- `condition` — decision point (diamond shape)
|
|
159
153
|
|
|
160
|
-
|
|
161
|
-
|
|
|
162
|
-
|
|
163
|
-
| `white` |
|
|
164
|
-
| `light_blue` |
|
|
165
|
-
| `light_green` |
|
|
166
|
-
| `light_yellow` |
|
|
167
|
-
| `light_orange` |
|
|
168
|
-
| `light_red` |
|
|
169
|
-
| `light_purple` |
|
|
170
|
-
| `light_gray` |
|
|
171
|
-
| `light_pink` |
|
|
172
|
-
| `light_teal` |
|
|
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 |
|
|
173
167
|
|
|
174
|
-
|
|
175
|
-
`default`, `blue`, `green`, `orange`, `purple`, `red`, `teal`, `yellow`, `gray`, `black`
|
|
168
|
+
**Border colors (`borderColor`):** `default`, `blue`, `green`, `orange`, `purple`, `red`, `teal`, `yellow`, `gray`, `black`
|
|
176
169
|
|
|
177
|
-
|
|
170
|
+
**Important:** Do NOT specify `width`, `height`, `x`, `y` — they are calculated automatically!
|
|
178
171
|
|
|
179
|
-
###
|
|
172
|
+
### Connection
|
|
180
173
|
|
|
181
174
|
```json
|
|
182
175
|
{
|
|
183
176
|
"from": "source_id",
|
|
184
177
|
"to": "target_id",
|
|
185
|
-
"label": "
|
|
178
|
+
"label": "optional label",
|
|
186
179
|
"style": "solid"
|
|
187
180
|
}
|
|
188
181
|
```
|
|
189
182
|
|
|
190
|
-
|
|
183
|
+
**Line styles (`style`):** `solid`, `dashed`, `dotted`
|
|
191
184
|
|
|
192
|
-
###
|
|
185
|
+
### Tags Dictionary (tagsDictionary)
|
|
193
186
|
|
|
194
187
|
```json
|
|
195
188
|
{
|
|
196
189
|
"tagsDictionary": [
|
|
197
|
-
{"id": "tag-1", "name": "
|
|
198
|
-
{"id": "tag-2", "name": "
|
|
199
|
-
{"id": "tag-3", "name": "
|
|
190
|
+
{"id": "tag-1", "name": "system", "color": "#2196F3"},
|
|
191
|
+
{"id": "tag-2", "name": "user", "color": "#4CAF50"},
|
|
192
|
+
{"id": "tag-3", "name": "check", "color": "#FF9800"}
|
|
200
193
|
]
|
|
201
194
|
}
|
|
202
195
|
```
|
|
203
196
|
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
-
|
|
207
|
-
- `муж`, `жена`, `ребёнок` (для личных схем)
|
|
197
|
+
**Tags = roles/actors.** Indicate WHO performs the action:
|
|
198
|
+
- `system`, `user`, `admin`
|
|
199
|
+
- `client`, `manager`, `bot`
|
|
208
200
|
|
|
209
|
-
##
|
|
201
|
+
## Schema Methodology
|
|
210
202
|
|
|
211
|
-
|
|
203
|
+
Schema = complete tree of **ACTIONS** and **CONSEQUENCES**:
|
|
212
204
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### Обновить схему
|
|
221
|
-
|
|
222
|
-
```
|
|
223
|
-
Добавь в схему блок "Двухфакторная аутентификация" между проверкой и успехом
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
### Работа с проектами
|
|
227
|
-
|
|
228
|
-
```
|
|
229
|
-
Создай проект "Backend API" с иконкой 🚀 и синим цветом
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
```
|
|
233
|
-
Перемести схему в проект Backend API
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### Работа с тегами
|
|
237
|
-
|
|
238
|
-
```
|
|
239
|
-
Добавь тег "Critical" красного цвета в схему
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
```
|
|
243
|
-
Пометь элемент "Валидация" тегом Critical
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
## Методология создания схем
|
|
247
|
-
|
|
248
|
-
Схема = полное дерево **ДЕЙСТВИЙ** и **ПОСЛЕДСТВИЙ**:
|
|
249
|
-
|
|
250
|
-
1. Каждое решение → показать ВСЕ возможные варианты
|
|
251
|
-
2. Каждый вариант → показать ВСЕ последствия
|
|
252
|
-
3. Использовать `condition` для точек принятия решений
|
|
253
|
-
4. НЕ абстрактные размышления — КОНКРЕТНЫЕ пути развития
|
|
254
|
-
5. Теги указывают КТО выполняет действие
|
|
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
|
|
255
210
|
|
|
256
|
-
|
|
211
|
+
**Example:**
|
|
257
212
|
```
|
|
258
|
-
"
|
|
259
|
-
├── "
|
|
260
|
-
└── "
|
|
213
|
+
"Submit Form" → condition "Validate" →
|
|
214
|
+
├── "Data Valid" → "Save" → "Success"
|
|
215
|
+
└── "Error" → "Show Errors" → "Fix Form"
|
|
261
216
|
```
|
|
262
217
|
|
|
263
|
-
##
|
|
218
|
+
## Links
|
|
264
219
|
|
|
265
220
|
- [SchemeOG Cloud](https://scheme.smartlaunchhub.com)
|
|
266
221
|
- [GitLab](https://gitlab.com/serter2069/schemeog-cloud)
|
package/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* SchemeOG MCP Server v2.
|
|
4
|
+
* SchemeOG MCP Server v2.2
|
|
5
5
|
*
|
|
6
6
|
* MCP сервер для работы со схемами, проектами и тегами в SchemeOG Cloud.
|
|
7
7
|
*
|
|
@@ -114,11 +114,11 @@ async function apiRequest(endpoint, options = {}) {
|
|
|
114
114
|
throw new Error(error.message);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
// Базовая валидация формата токена
|
|
118
|
-
if (!AUTH_TOKEN.startsWith("
|
|
117
|
+
// Базовая валидация формата токена (schog_ - новый формат)
|
|
118
|
+
if (!AUTH_TOKEN.startsWith("schog_") || AUTH_TOKEN.length < 20) {
|
|
119
119
|
const error = createError(
|
|
120
120
|
ErrorCodes.AUTH_INVALID,
|
|
121
|
-
`Неверный формат токена. Токен должен начинаться с "
|
|
121
|
+
`Неверный формат токена. Токен должен начинаться с "schog_" и содержать минимум 20 символов.\n\nПолучен: ${AUTH_TOKEN.substring(0, 10)}...`
|
|
122
122
|
);
|
|
123
123
|
throw new Error(error.message);
|
|
124
124
|
}
|
|
@@ -209,18 +209,208 @@ function generateId() {
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
/**
|
|
212
|
-
*
|
|
212
|
+
* Допустимые именованные цвета для элементов
|
|
213
|
+
*/
|
|
214
|
+
const VALID_COLORS = ["white", "light_blue", "light_green", "light_yellow", "light_orange", "light_red", "light_purple", "light_gray", "light_pink", "light_teal"];
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Маппинг HEX цветов к именованным (ближайшее соответствие)
|
|
218
|
+
*/
|
|
219
|
+
const HEX_TO_NAMED_COLOR = {
|
|
220
|
+
// Белые/серые
|
|
221
|
+
"#FFFFFF": "white", "#FFF": "white", "#FAFAFA": "white", "#F5F5F5": "light_gray",
|
|
222
|
+
"#E0E0E0": "light_gray", "#BDBDBD": "light_gray", "#9E9E9E": "light_gray",
|
|
223
|
+
"#CFD8DC": "light_gray", "#ECEFF1": "light_gray",
|
|
224
|
+
|
|
225
|
+
// Синие
|
|
226
|
+
"#E3F2FD": "light_blue", "#BBDEFB": "light_blue", "#90CAF9": "light_blue",
|
|
227
|
+
"#64B5F6": "light_blue", "#42A5F5": "light_blue", "#2196F3": "light_blue",
|
|
228
|
+
"#1E88E5": "light_blue", "#1976D2": "light_blue",
|
|
229
|
+
|
|
230
|
+
// Зелёные
|
|
231
|
+
"#E8F5E9": "light_green", "#C8E6C9": "light_green", "#A5D6A7": "light_green",
|
|
232
|
+
"#81C784": "light_green", "#66BB6A": "light_green", "#4CAF50": "light_green",
|
|
233
|
+
"#43A047": "light_green", "#388E3C": "light_green", "#DCEDC8": "light_green",
|
|
234
|
+
|
|
235
|
+
// Жёлтые
|
|
236
|
+
"#FFFDE7": "light_yellow", "#FFF9C4": "light_yellow", "#FFF59D": "light_yellow",
|
|
237
|
+
"#FFF176": "light_yellow", "#FFEE58": "light_yellow", "#FFEB3B": "light_yellow",
|
|
238
|
+
"#FDD835": "light_yellow", "#FBC02D": "light_yellow",
|
|
239
|
+
|
|
240
|
+
// Оранжевые
|
|
241
|
+
"#FFF3E0": "light_orange", "#FFE0B2": "light_orange", "#FFCC80": "light_orange",
|
|
242
|
+
"#FFB74D": "light_orange", "#FFA726": "light_orange", "#FF9800": "light_orange",
|
|
243
|
+
"#FB8C00": "light_orange", "#F57C00": "light_orange",
|
|
244
|
+
"#FFE5B4": "light_orange", "#FFCCBC": "light_orange", // персиковые
|
|
245
|
+
|
|
246
|
+
// Красные
|
|
247
|
+
"#FFEBEE": "light_red", "#FFCDD2": "light_red", "#EF9A9A": "light_red",
|
|
248
|
+
"#E57373": "light_red", "#EF5350": "light_red", "#F44336": "light_red",
|
|
249
|
+
"#E53935": "light_red", "#D32F2F": "light_red",
|
|
250
|
+
"#FCE4EC": "light_pink", "#F8BBD0": "light_pink", // розовые → light_pink
|
|
251
|
+
|
|
252
|
+
// Фиолетовые
|
|
253
|
+
"#F3E5F5": "light_purple", "#E1BEE7": "light_purple", "#CE93D8": "light_purple",
|
|
254
|
+
"#BA68C8": "light_purple", "#AB47BC": "light_purple", "#9C27B0": "light_purple",
|
|
255
|
+
"#8E24AA": "light_purple", "#7B1FA2": "light_purple",
|
|
256
|
+
"#D1C4E9": "light_purple", "#EDE7F6": "light_purple",
|
|
257
|
+
|
|
258
|
+
// Розовые
|
|
259
|
+
"#FCE4EC": "light_pink", "#F8BBD0": "light_pink", "#F48FB1": "light_pink",
|
|
260
|
+
"#F06292": "light_pink", "#EC407A": "light_pink", "#E91E63": "light_pink",
|
|
261
|
+
|
|
262
|
+
// Бирюзовые/Teal
|
|
263
|
+
"#E0F7FA": "light_teal", "#B2DFDB": "light_teal", "#80CBC4": "light_teal",
|
|
264
|
+
"#4DB6AC": "light_teal", "#26A69A": "light_teal", "#009688": "light_teal",
|
|
265
|
+
"#E0F2F1": "light_teal",
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Конвертировать HEX цвет в ближайший именованный
|
|
270
|
+
*/
|
|
271
|
+
function hexToNamedColor(hex) {
|
|
272
|
+
if (!hex) return "white";
|
|
273
|
+
|
|
274
|
+
// Если уже именованный — проверяем и возвращаем
|
|
275
|
+
if (VALID_COLORS.includes(hex)) return hex;
|
|
276
|
+
|
|
277
|
+
// Нормализуем HEX
|
|
278
|
+
const normalizedHex = hex.toUpperCase().trim();
|
|
279
|
+
|
|
280
|
+
// Ищем точное соответствие
|
|
281
|
+
if (HEX_TO_NAMED_COLOR[normalizedHex]) {
|
|
282
|
+
return HEX_TO_NAMED_COLOR[normalizedHex];
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Если не нашли — пытаемся определить по оттенку
|
|
286
|
+
// Простой алгоритм: анализируем RGB компоненты
|
|
287
|
+
const match = normalizedHex.match(/^#?([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})$/i);
|
|
288
|
+
if (match) {
|
|
289
|
+
const r = parseInt(match[1], 16);
|
|
290
|
+
const g = parseInt(match[2], 16);
|
|
291
|
+
const b = parseInt(match[3], 16);
|
|
292
|
+
|
|
293
|
+
// Определяем доминирующий цвет
|
|
294
|
+
const max = Math.max(r, g, b);
|
|
295
|
+
const min = Math.min(r, g, b);
|
|
296
|
+
const brightness = (r + g + b) / 3;
|
|
297
|
+
|
|
298
|
+
// Белый/серый
|
|
299
|
+
if (max - min < 30) {
|
|
300
|
+
return brightness > 200 ? "white" : "light_gray";
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Красный доминирует
|
|
304
|
+
if (r === max && r > g + 20 && r > b + 20) {
|
|
305
|
+
return g > 150 ? "light_orange" : (b > 100 ? "light_pink" : "light_red");
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Зелёный доминирует
|
|
309
|
+
if (g === max && g > r + 20 && g > b + 20) {
|
|
310
|
+
return b > 150 ? "light_teal" : "light_green";
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Синий доминирует
|
|
314
|
+
if (b === max && b > r + 20 && b > g + 20) {
|
|
315
|
+
return r > 150 ? "light_purple" : "light_blue";
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Жёлтый (R и G высокие, B низкий)
|
|
319
|
+
if (r > 200 && g > 200 && b < 150) {
|
|
320
|
+
return "light_yellow";
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Оранжевый (R высокий, G средний, B низкий)
|
|
324
|
+
if (r > 200 && g > 100 && g < 200 && b < 150) {
|
|
325
|
+
return "light_orange";
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Fallback
|
|
330
|
+
return "light_blue";
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Нормализовать элементы — исправить типы, цвета, удалить лишние поля
|
|
335
|
+
* Возвращает { elements, warnings }
|
|
336
|
+
*/
|
|
337
|
+
function normalizeElements(elements) {
|
|
338
|
+
if (!elements || !Array.isArray(elements)) return { elements: [], warnings: [] };
|
|
339
|
+
|
|
340
|
+
const warnings = [];
|
|
341
|
+
|
|
342
|
+
const normalized = elements.map((el, index) => {
|
|
343
|
+
const fixed = {
|
|
344
|
+
id: el.id || generateId(),
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
// Тип: block/note → card
|
|
348
|
+
if (el.type === "block" || el.type === "note" || el.type === "group") {
|
|
349
|
+
fixed.type = "card";
|
|
350
|
+
warnings.push(`Элемент ${index + 1}: type "${el.type}" → "card"`);
|
|
351
|
+
} else if (el.type === "condition" || el.type === "diamond") {
|
|
352
|
+
fixed.type = "condition";
|
|
353
|
+
} else {
|
|
354
|
+
fixed.type = el.type || "card";
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Title: text → title
|
|
358
|
+
if (el.text && !el.title) {
|
|
359
|
+
fixed.title = el.text;
|
|
360
|
+
warnings.push(`Элемент ${index + 1}: "text" → "title"`);
|
|
361
|
+
} else {
|
|
362
|
+
fixed.title = el.title || "";
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Цвет: HEX → именованный
|
|
366
|
+
if (el.color) {
|
|
367
|
+
if (el.color.startsWith("#")) {
|
|
368
|
+
const namedColor = hexToNamedColor(el.color);
|
|
369
|
+
fixed.color = namedColor;
|
|
370
|
+
warnings.push(`Элемент ${index + 1}: color "${el.color}" → "${namedColor}"`);
|
|
371
|
+
} else if (VALID_COLORS.includes(el.color)) {
|
|
372
|
+
fixed.color = el.color;
|
|
373
|
+
} else {
|
|
374
|
+
fixed.color = "white";
|
|
375
|
+
warnings.push(`Элемент ${index + 1}: неизвестный color "${el.color}" → "white"`);
|
|
376
|
+
}
|
|
377
|
+
} else {
|
|
378
|
+
fixed.color = "white";
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// borderColor — оставляем если валидный
|
|
382
|
+
const validBorderColors = ["default", "blue", "green", "orange", "purple", "red", "teal", "yellow", "gray", "black"];
|
|
383
|
+
if (el.borderColor && validBorderColors.includes(el.borderColor)) {
|
|
384
|
+
fixed.borderColor = el.borderColor;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Description
|
|
388
|
+
if (el.description) {
|
|
389
|
+
fixed.description = el.description;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Tags
|
|
393
|
+
if (el.tags && Array.isArray(el.tags)) {
|
|
394
|
+
fixed.tags = el.tags;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// НЕ копируем: x, y, width, height — они автоматические
|
|
398
|
+
if (el.x !== undefined || el.y !== undefined || el.width !== undefined || el.height !== undefined) {
|
|
399
|
+
warnings.push(`Элемент ${index + 1}: x/y/width/height удалены (рассчитываются автоматически)`);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return fixed;
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
return { elements: normalized, warnings };
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Подготовить элементы — нормализовать и добавить ID
|
|
410
|
+
* Возвращает { elements, warnings }
|
|
213
411
|
*/
|
|
214
412
|
function prepareElements(elements) {
|
|
215
|
-
|
|
216
|
-
return elements.map(el => ({
|
|
217
|
-
id: el.id || generateId(),
|
|
218
|
-
type: el.type || "block",
|
|
219
|
-
x: el.x || 0,
|
|
220
|
-
y: el.y || 0,
|
|
221
|
-
text: el.text || "",
|
|
222
|
-
...el
|
|
223
|
-
}));
|
|
413
|
+
return normalizeElements(elements);
|
|
224
414
|
}
|
|
225
415
|
|
|
226
416
|
/**
|
|
@@ -259,11 +449,22 @@ const TOOLS = [
|
|
|
259
449
|
Возвращает:
|
|
260
450
|
- name: название схемы
|
|
261
451
|
- description: описание
|
|
262
|
-
- elements: массив элементов (
|
|
452
|
+
- elements: массив элементов (card или condition)
|
|
263
453
|
- connections: массив связей между элементами
|
|
454
|
+
- tagsDictionary: справочник тегов
|
|
455
|
+
|
|
456
|
+
Формат элемента:
|
|
457
|
+
{
|
|
458
|
+
"id": "unique_id",
|
|
459
|
+
"type": "card", // card или condition
|
|
460
|
+
"title": "Название", // заголовок
|
|
461
|
+
"color": "light_blue", // ТОЛЬКО: white, light_blue, light_green, light_yellow, light_orange, light_red, light_purple, light_gray, light_pink, light_teal
|
|
462
|
+
"description": "Текст", // описание
|
|
463
|
+
"tags": ["тег1"] // массив тегов
|
|
464
|
+
}
|
|
264
465
|
|
|
265
|
-
|
|
266
|
-
|
|
466
|
+
ВАЖНО: НЕ используй x, y, width, height — они рассчитываются автоматически!
|
|
467
|
+
ВАЖНО: Цвета ТОЛЬКО именованные (light_blue), НЕ HEX (#FFFFFF)!`,
|
|
267
468
|
inputSchema: {
|
|
268
469
|
type: "object",
|
|
269
470
|
properties: {
|
|
@@ -837,12 +1038,15 @@ ${JSON.stringify(schema.data?.connections || [], null, 2)}`,
|
|
|
837
1038
|
}
|
|
838
1039
|
|
|
839
1040
|
case "create_schema": {
|
|
840
|
-
const { name, description, project_id, elements, connections } = args;
|
|
1041
|
+
const { name, description, project_id, elements, connections, tagsDictionary } = args;
|
|
1042
|
+
|
|
1043
|
+
// Нормализуем элементы и получаем предупреждения
|
|
1044
|
+
const { elements: normalizedElements, warnings } = prepareElements(elements);
|
|
841
1045
|
|
|
842
1046
|
const data = {
|
|
843
|
-
elements:
|
|
1047
|
+
elements: normalizedElements,
|
|
844
1048
|
connections: prepareConnections(connections),
|
|
845
|
-
tagsDictionary: [],
|
|
1049
|
+
tagsDictionary: tagsDictionary || [],
|
|
846
1050
|
};
|
|
847
1051
|
|
|
848
1052
|
const result = await apiRequest("/schemas", {
|
|
@@ -852,6 +1056,16 @@ ${JSON.stringify(schema.data?.connections || [], null, 2)}`,
|
|
|
852
1056
|
|
|
853
1057
|
const projectInfo = project_id ? `Проект: ${project_id}` : 'Проект: Общие';
|
|
854
1058
|
|
|
1059
|
+
// Формируем сообщение о предупреждениях
|
|
1060
|
+
let warningsText = "";
|
|
1061
|
+
if (warnings.length > 0) {
|
|
1062
|
+
warningsText = `\n\n⚠️ Автоисправления (${warnings.length}):\n• ${warnings.slice(0, 10).join("\n• ")}`;
|
|
1063
|
+
if (warnings.length > 10) {
|
|
1064
|
+
warningsText += `\n• ...и ещё ${warnings.length - 10}`;
|
|
1065
|
+
}
|
|
1066
|
+
warningsText += `\n\n💡 Подсказка: используй type "card"/"condition", цвета light_blue/light_green/etc, НЕ указывай x/y/width/height`;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
855
1069
|
return {
|
|
856
1070
|
content: [{
|
|
857
1071
|
type: "text",
|
|
@@ -864,7 +1078,7 @@ ${projectInfo}
|
|
|
864
1078
|
|
|
865
1079
|
URL: ${API_BASE_URL}/canvas?id=${result.schema.id}
|
|
866
1080
|
|
|
867
|
-
Открой ссылку в браузере чтобы увидеть
|
|
1081
|
+
Открой ссылку в браузере чтобы увидеть схему.${warningsText}`,
|
|
868
1082
|
}],
|
|
869
1083
|
};
|
|
870
1084
|
}
|
|
@@ -879,6 +1093,7 @@ URL: ${API_BASE_URL}/canvas?id=${result.schema.id}
|
|
|
879
1093
|
|
|
880
1094
|
// Формируем обновление
|
|
881
1095
|
const updateBody = {};
|
|
1096
|
+
let warnings = [];
|
|
882
1097
|
|
|
883
1098
|
if (name) updateBody.name = name;
|
|
884
1099
|
if (description !== undefined) updateBody.description = description;
|
|
@@ -886,7 +1101,9 @@ URL: ${API_BASE_URL}/canvas?id=${result.schema.id}
|
|
|
886
1101
|
// Обновляем данные только если переданы
|
|
887
1102
|
const newData = { ...currentData };
|
|
888
1103
|
if (elements !== undefined) {
|
|
889
|
-
|
|
1104
|
+
const normalized = prepareElements(elements);
|
|
1105
|
+
newData.elements = normalized.elements;
|
|
1106
|
+
warnings = normalized.warnings;
|
|
890
1107
|
}
|
|
891
1108
|
if (connections !== undefined) {
|
|
892
1109
|
newData.connections = prepareConnections(connections);
|
|
@@ -898,6 +1115,16 @@ URL: ${API_BASE_URL}/canvas?id=${result.schema.id}
|
|
|
898
1115
|
body: JSON.stringify(updateBody),
|
|
899
1116
|
});
|
|
900
1117
|
|
|
1118
|
+
// Формируем сообщение о предупреждениях
|
|
1119
|
+
let warningsText = "";
|
|
1120
|
+
if (warnings.length > 0) {
|
|
1121
|
+
warningsText = `\n\n⚠️ Автоисправления (${warnings.length}):\n• ${warnings.slice(0, 10).join("\n• ")}`;
|
|
1122
|
+
if (warnings.length > 10) {
|
|
1123
|
+
warningsText += `\n• ...и ещё ${warnings.length - 10}`;
|
|
1124
|
+
}
|
|
1125
|
+
warningsText += `\n\n💡 Подсказка: используй type "card"/"condition", цвета light_blue/light_green/etc, НЕ указывай x/y/width/height`;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
901
1128
|
return {
|
|
902
1129
|
content: [{
|
|
903
1130
|
type: "text",
|
|
@@ -906,7 +1133,7 @@ URL: ${API_BASE_URL}/canvas?id=${result.schema.id}
|
|
|
906
1133
|
Элементов: ${result.schema.data?.elements?.length || 0}
|
|
907
1134
|
Связей: ${result.schema.data?.connections?.length || 0}
|
|
908
1135
|
|
|
909
|
-
URL: ${API_BASE_URL}/canvas?id=${schema_id}`,
|
|
1136
|
+
URL: ${API_BASE_URL}/canvas?id=${schema_id}${warningsText}`,
|
|
910
1137
|
}],
|
|
911
1138
|
};
|
|
912
1139
|
}
|
|
@@ -1192,16 +1419,16 @@ async function main() {
|
|
|
1192
1419
|
2. Добавьте в настройки MCP:
|
|
1193
1420
|
|
|
1194
1421
|
"env": {
|
|
1195
|
-
"SCHEMEOG_TOKEN": "
|
|
1422
|
+
"SCHEMEOG_TOKEN": "schog_ваш-токен"
|
|
1196
1423
|
}
|
|
1197
1424
|
|
|
1198
1425
|
Документация: ${DOCS_URL}
|
|
1199
1426
|
`);
|
|
1200
|
-
} else if (!AUTH_TOKEN.startsWith("
|
|
1427
|
+
} else if (!AUTH_TOKEN.startsWith("schog_")) {
|
|
1201
1428
|
console.error(`
|
|
1202
1429
|
⚠️ Неверный формат токена!
|
|
1203
1430
|
|
|
1204
|
-
Токен должен начинаться с "
|
|
1431
|
+
Токен должен начинаться с "schog_".
|
|
1205
1432
|
Получен: ${AUTH_TOKEN.substring(0, 10)}...
|
|
1206
1433
|
|
|
1207
1434
|
Создайте новый токен: ${PROFILE_URL}
|
|
@@ -1211,7 +1438,7 @@ async function main() {
|
|
|
1211
1438
|
const server = new Server(
|
|
1212
1439
|
{
|
|
1213
1440
|
name: "schemeog-mcp",
|
|
1214
|
-
version: "2.
|
|
1441
|
+
version: "2.3.0",
|
|
1215
1442
|
},
|
|
1216
1443
|
{
|
|
1217
1444
|
capabilities: {
|
|
@@ -1241,7 +1468,7 @@ async function main() {
|
|
|
1241
1468
|
const transport = new StdioServerTransport();
|
|
1242
1469
|
await server.connect(transport);
|
|
1243
1470
|
|
|
1244
|
-
console.error("SchemeOG MCP Server v2.
|
|
1471
|
+
console.error("SchemeOG MCP Server v2.3 запущен");
|
|
1245
1472
|
}
|
|
1246
1473
|
|
|
1247
1474
|
main().catch(console.error);
|