mcp-proxy-adapter 2.1.1__py3-none-any.whl → 2.1.3__py3-none-any.whl
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.
- {mcp_proxy_adapter-2.1.1.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-2.1.3.dist-info/RECORD +18 -0
- mcp_proxy_adapter-2.1.3.dist-info/top_level.txt +1 -0
- docs/README.md +0 -172
- docs/README_ru.md +0 -172
- docs/architecture.md +0 -251
- docs/architecture_ru.md +0 -343
- docs/command_development.md +0 -250
- docs/command_development_ru.md +0 -593
- docs/deployment.md +0 -251
- docs/deployment_ru.md +0 -1298
- docs/examples.md +0 -254
- docs/examples_ru.md +0 -401
- docs/mcp_proxy_adapter.md +0 -251
- docs/mcp_proxy_adapter_ru.md +0 -405
- docs/quickstart.md +0 -251
- docs/quickstart_ru.md +0 -397
- docs/testing.md +0 -255
- docs/testing_ru.md +0 -469
- docs/validation_ru.md +0 -287
- examples/analyze_config.py +0 -141
- examples/basic_integration.py +0 -161
- examples/docstring_and_schema_example.py +0 -60
- examples/extension_example.py +0 -60
- examples/help_best_practices.py +0 -67
- examples/help_usage.py +0 -64
- examples/mcp_proxy_client.py +0 -131
- examples/mcp_proxy_config.json +0 -175
- examples/openapi_server.py +0 -369
- examples/project_structure_example.py +0 -47
- examples/testing_example.py +0 -53
- mcp_proxy_adapter-2.1.1.dist-info/RECORD +0 -61
- mcp_proxy_adapter-2.1.1.dist-info/top_level.txt +0 -5
- scripts/code_analyzer/code_analyzer.py +0 -328
- scripts/code_analyzer/register_commands.py +0 -446
- scripts/publish.py +0 -85
- tests/conftest.py +0 -12
- tests/test_adapter.py +0 -529
- tests/test_adapter_coverage.py +0 -274
- tests/test_basic_dispatcher.py +0 -169
- tests/test_command_registry.py +0 -328
- tests/test_examples.py +0 -32
- tests/test_mcp_proxy_adapter.py +0 -568
- tests/test_mcp_proxy_adapter_basic.py +0 -262
- tests/test_part1.py +0 -348
- tests/test_part2.py +0 -524
- tests/test_schema.py +0 -358
- tests/test_simple_adapter.py +0 -251
- {mcp_proxy_adapter-2.1.1.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-2.1.1.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/licenses/LICENSE +0 -0
docs/deployment_ru.md
DELETED
@@ -1,1298 +0,0 @@
|
|
1
|
-
# Руководство по развертыванию Command Registry
|
2
|
-
|
3
|
-
В этом руководстве описаны подходы и рекомендации по развертыванию приложений, использующих Command Registry, в различных окружениях.
|
4
|
-
|
5
|
-
## Содержание
|
6
|
-
|
7
|
-
- [Подготовка к развертыванию](#подготовка-к-развертыванию)
|
8
|
-
- [Развертывание в Docker](#развертывание-в-docker)
|
9
|
-
- [Развертывание на VPS](#развертывание-на-vps)
|
10
|
-
- [Развертывание в Kubernetes](#развертывание-в-kubernetes)
|
11
|
-
- [CI/CD для Command Registry](#cicd-для-command-registry)
|
12
|
-
- [Мониторинг и логирование](#мониторинг-и-логирование)
|
13
|
-
- [Масштабирование](#масштабирование)
|
14
|
-
- [Безопасность](#безопасность)
|
15
|
-
- [Гибридная схема и интеграция с MCPProxy](#гибридная-схема-и-интеграция-с-mcpproxy)
|
16
|
-
|
17
|
-
## Подготовка к развертыванию
|
18
|
-
|
19
|
-
### 1. Создание пакета приложения
|
20
|
-
|
21
|
-
Для удобного развертывания рекомендуется оформить приложение как Python-пакет:
|
22
|
-
|
23
|
-
```
|
24
|
-
my_app/
|
25
|
-
├── pyproject.toml
|
26
|
-
├── setup.py
|
27
|
-
├── setup.cfg
|
28
|
-
├── README.md
|
29
|
-
├── src/
|
30
|
-
│ └── my_app/
|
31
|
-
│ ├── __init__.py
|
32
|
-
│ ├── commands/
|
33
|
-
│ │ ├── __init__.py
|
34
|
-
│ │ └── ...
|
35
|
-
│ ├── app.py
|
36
|
-
│ └── main.py
|
37
|
-
└── tests/
|
38
|
-
└── ...
|
39
|
-
```
|
40
|
-
|
41
|
-
Пример `pyproject.toml`:
|
42
|
-
|
43
|
-
```toml
|
44
|
-
[build-system]
|
45
|
-
requires = ["setuptools>=42", "wheel"]
|
46
|
-
build-backend = "setuptools.build_meta"
|
47
|
-
|
48
|
-
[project]
|
49
|
-
name = "my-app"
|
50
|
-
version = "0.1.0"
|
51
|
-
description = "Command Registry Application"
|
52
|
-
authors = [{name = "Your Name", email = "your.email@example.com"}]
|
53
|
-
requires-python = ">=3.8"
|
54
|
-
dependencies = [
|
55
|
-
"command-registry>=0.1.0",
|
56
|
-
"fastapi>=0.68.0",
|
57
|
-
"uvicorn>=0.15.0",
|
58
|
-
]
|
59
|
-
```
|
60
|
-
|
61
|
-
### 2. Настройка конфигурации
|
62
|
-
|
63
|
-
Создайте систему конфигурации, поддерживающую различные окружения:
|
64
|
-
|
65
|
-
```python
|
66
|
-
# src/my_app/config.py
|
67
|
-
import os
|
68
|
-
from pydantic import BaseSettings
|
69
|
-
|
70
|
-
class Settings(BaseSettings):
|
71
|
-
"""Настройки приложения."""
|
72
|
-
APP_NAME: str = "Command Registry App"
|
73
|
-
DEBUG: bool = False
|
74
|
-
LOG_LEVEL: str = "INFO"
|
75
|
-
API_PORT: int = 8000
|
76
|
-
|
77
|
-
# Настройки Command Registry
|
78
|
-
STRICT_MODE: bool = True
|
79
|
-
AUTO_FIX: bool = False
|
80
|
-
|
81
|
-
# Настройки базы данных
|
82
|
-
DB_HOST: str = "localhost"
|
83
|
-
DB_PORT: int = 5432
|
84
|
-
DB_USER: str = "postgres"
|
85
|
-
DB_PASSWORD: str = ""
|
86
|
-
DB_NAME: str = "app_db"
|
87
|
-
|
88
|
-
class Config:
|
89
|
-
env_file = ".env"
|
90
|
-
env_prefix = "APP_"
|
91
|
-
|
92
|
-
# Загрузка настроек
|
93
|
-
settings = Settings()
|
94
|
-
```
|
95
|
-
|
96
|
-
### 3. Создание точки входа
|
97
|
-
|
98
|
-
```python
|
99
|
-
# src/my_app/main.py
|
100
|
-
import uvicorn
|
101
|
-
from my_app.app import app
|
102
|
-
from my_app.config import settings
|
103
|
-
|
104
|
-
def start():
|
105
|
-
"""Запускает приложение."""
|
106
|
-
uvicorn.run(
|
107
|
-
"my_app.app:app",
|
108
|
-
host="0.0.0.0",
|
109
|
-
port=settings.API_PORT,
|
110
|
-
log_level=settings.LOG_LEVEL.lower(),
|
111
|
-
reload=settings.DEBUG
|
112
|
-
)
|
113
|
-
|
114
|
-
if __name__ == "__main__":
|
115
|
-
start()
|
116
|
-
```
|
117
|
-
|
118
|
-
## Развертывание в Docker
|
119
|
-
|
120
|
-
### 1. Создание Dockerfile
|
121
|
-
|
122
|
-
```dockerfile
|
123
|
-
FROM python:3.10-slim
|
124
|
-
|
125
|
-
WORKDIR /app
|
126
|
-
|
127
|
-
# Копирование файлов зависимостей
|
128
|
-
COPY pyproject.toml setup.py setup.cfg ./
|
129
|
-
|
130
|
-
# Установка зависимостей
|
131
|
-
RUN pip install --no-cache-dir .
|
132
|
-
|
133
|
-
# Копирование кода приложения
|
134
|
-
COPY src/ ./src/
|
135
|
-
|
136
|
-
# Определение переменных окружения
|
137
|
-
ENV APP_DEBUG=false \
|
138
|
-
APP_LOG_LEVEL=INFO \
|
139
|
-
APP_API_PORT=8000 \
|
140
|
-
APP_STRICT_MODE=true \
|
141
|
-
APP_AUTO_FIX=false
|
142
|
-
|
143
|
-
# Открываем порт
|
144
|
-
EXPOSE 8000
|
145
|
-
|
146
|
-
# Запуск приложения
|
147
|
-
CMD ["python", "-m", "my_app.main"]
|
148
|
-
```
|
149
|
-
|
150
|
-
### 2. Docker Compose для локальной разработки
|
151
|
-
|
152
|
-
```yaml
|
153
|
-
# docker-compose.yml
|
154
|
-
version: '3.8'
|
155
|
-
|
156
|
-
services:
|
157
|
-
app:
|
158
|
-
build: .
|
159
|
-
ports:
|
160
|
-
- "8000:8000"
|
161
|
-
environment:
|
162
|
-
- APP_DEBUG=true
|
163
|
-
- APP_LOG_LEVEL=DEBUG
|
164
|
-
- APP_DB_HOST=db
|
165
|
-
depends_on:
|
166
|
-
- db
|
167
|
-
volumes:
|
168
|
-
- ./src:/app/src
|
169
|
-
|
170
|
-
db:
|
171
|
-
image: postgres:14
|
172
|
-
environment:
|
173
|
-
- POSTGRES_USER=postgres
|
174
|
-
- POSTGRES_PASSWORD=postgres
|
175
|
-
- POSTGRES_DB=app_db
|
176
|
-
volumes:
|
177
|
-
- postgres_data:/var/lib/postgresql/data
|
178
|
-
ports:
|
179
|
-
- "5432:5432"
|
180
|
-
|
181
|
-
volumes:
|
182
|
-
postgres_data:
|
183
|
-
```
|
184
|
-
|
185
|
-
### 3. Сборка и запуск
|
186
|
-
|
187
|
-
```bash
|
188
|
-
# Сборка образа
|
189
|
-
docker build -t my-app .
|
190
|
-
|
191
|
-
# Запуск контейнера
|
192
|
-
docker run -p 8000:8000 my-app
|
193
|
-
|
194
|
-
# Или с использованием Docker Compose
|
195
|
-
docker-compose up
|
196
|
-
```
|
197
|
-
|
198
|
-
## Развертывание на VPS
|
199
|
-
|
200
|
-
### 1. Установка зависимостей на сервере
|
201
|
-
|
202
|
-
```bash
|
203
|
-
# Обновление пакетов
|
204
|
-
sudo apt update
|
205
|
-
sudo apt upgrade -y
|
206
|
-
|
207
|
-
# Установка Python и зависимостей
|
208
|
-
sudo apt install -y python3 python3-pip python3-venv
|
209
|
-
|
210
|
-
# Установка Nginx
|
211
|
-
sudo apt install -y nginx
|
212
|
-
|
213
|
-
# Установка Supervisor
|
214
|
-
sudo apt install -y supervisor
|
215
|
-
```
|
216
|
-
|
217
|
-
### 2. Настройка Gunicorn
|
218
|
-
|
219
|
-
```bash
|
220
|
-
# Создание виртуального окружения
|
221
|
-
python3 -m venv venv
|
222
|
-
source venv/bin/activate
|
223
|
-
|
224
|
-
# Установка приложения и Gunicorn
|
225
|
-
pip install gunicorn
|
226
|
-
pip install . # установка вашего приложения
|
227
|
-
```
|
228
|
-
|
229
|
-
### 3. Настройка Supervisor
|
230
|
-
|
231
|
-
```ini
|
232
|
-
# /etc/supervisor/conf.d/my-app.conf
|
233
|
-
[program:my-app]
|
234
|
-
command=/home/user/my-app/venv/bin/gunicorn -w 4 -k uvicorn.workers.UvicornWorker my_app.app:app -b 127.0.0.1:8000
|
235
|
-
directory=/home/user/my-app
|
236
|
-
user=user
|
237
|
-
autostart=true
|
238
|
-
autorestart=true
|
239
|
-
environment=APP_DEBUG=false,APP_LOG_LEVEL=INFO,APP_STRICT_MODE=true
|
240
|
-
|
241
|
-
[supervisord]
|
242
|
-
logfile=/var/log/supervisor/supervisord.log
|
243
|
-
```
|
244
|
-
|
245
|
-
### 4. Настройка Nginx
|
246
|
-
|
247
|
-
```nginx
|
248
|
-
# /etc/nginx/sites-available/my-app
|
249
|
-
server {
|
250
|
-
listen 80;
|
251
|
-
server_name example.com;
|
252
|
-
|
253
|
-
location / {
|
254
|
-
proxy_pass http://127.0.0.1:8000;
|
255
|
-
proxy_set_header Host $host;
|
256
|
-
proxy_set_header X-Real-IP $remote_addr;
|
257
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
258
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
259
|
-
}
|
260
|
-
}
|
261
|
-
```
|
262
|
-
|
263
|
-
### 5. Активация конфигурации
|
264
|
-
|
265
|
-
```bash
|
266
|
-
# Активация конфигурации Nginx
|
267
|
-
sudo ln -s /etc/nginx/sites-available/my-app /etc/nginx/sites-enabled/
|
268
|
-
sudo nginx -t
|
269
|
-
sudo systemctl restart nginx
|
270
|
-
|
271
|
-
# Запуск приложения через Supervisor
|
272
|
-
sudo supervisorctl reread
|
273
|
-
sudo supervisorctl update
|
274
|
-
sudo supervisorctl start my-app
|
275
|
-
```
|
276
|
-
|
277
|
-
## Развертывание в Kubernetes
|
278
|
-
|
279
|
-
### 1. Создание Kubernetes Deployment
|
280
|
-
|
281
|
-
```yaml
|
282
|
-
# k8s/deployment.yaml
|
283
|
-
apiVersion: apps/v1
|
284
|
-
kind: Deployment
|
285
|
-
metadata:
|
286
|
-
name: my-app
|
287
|
-
labels:
|
288
|
-
app: my-app
|
289
|
-
spec:
|
290
|
-
replicas: 3
|
291
|
-
selector:
|
292
|
-
matchLabels:
|
293
|
-
app: my-app
|
294
|
-
template:
|
295
|
-
metadata:
|
296
|
-
labels:
|
297
|
-
app: my-app
|
298
|
-
spec:
|
299
|
-
containers:
|
300
|
-
- name: my-app
|
301
|
-
image: my-app:latest
|
302
|
-
imagePullPolicy: Always
|
303
|
-
ports:
|
304
|
-
- containerPort: 8000
|
305
|
-
env:
|
306
|
-
- name: APP_DEBUG
|
307
|
-
value: "false"
|
308
|
-
- name: APP_LOG_LEVEL
|
309
|
-
value: "INFO"
|
310
|
-
- name: APP_DB_HOST
|
311
|
-
value: "postgres-service"
|
312
|
-
resources:
|
313
|
-
limits:
|
314
|
-
cpu: "500m"
|
315
|
-
memory: "512Mi"
|
316
|
-
requests:
|
317
|
-
cpu: "100m"
|
318
|
-
memory: "256Mi"
|
319
|
-
readinessProbe:
|
320
|
-
httpGet:
|
321
|
-
path: /health
|
322
|
-
port: 8000
|
323
|
-
initialDelaySeconds: 5
|
324
|
-
periodSeconds: 10
|
325
|
-
livenessProbe:
|
326
|
-
httpGet:
|
327
|
-
path: /health
|
328
|
-
port: 8000
|
329
|
-
initialDelaySeconds: 15
|
330
|
-
periodSeconds: 20
|
331
|
-
```
|
332
|
-
|
333
|
-
### 2. Создание Service
|
334
|
-
|
335
|
-
```yaml
|
336
|
-
# k8s/service.yaml
|
337
|
-
apiVersion: v1
|
338
|
-
kind: Service
|
339
|
-
metadata:
|
340
|
-
name: my-app-service
|
341
|
-
spec:
|
342
|
-
selector:
|
343
|
-
app: my-app
|
344
|
-
ports:
|
345
|
-
- port: 80
|
346
|
-
targetPort: 8000
|
347
|
-
type: ClusterIP
|
348
|
-
```
|
349
|
-
|
350
|
-
### 3. Создание Ingress
|
351
|
-
|
352
|
-
```yaml
|
353
|
-
# k8s/ingress.yaml
|
354
|
-
apiVersion: networking.k8s.io/v1
|
355
|
-
kind: Ingress
|
356
|
-
metadata:
|
357
|
-
name: my-app-ingress
|
358
|
-
annotations:
|
359
|
-
nginx.ingress.kubernetes.io/rewrite-target: /
|
360
|
-
spec:
|
361
|
-
rules:
|
362
|
-
- host: api.example.com
|
363
|
-
http:
|
364
|
-
paths:
|
365
|
-
- path: /
|
366
|
-
pathType: Prefix
|
367
|
-
backend:
|
368
|
-
service:
|
369
|
-
name: my-app-service
|
370
|
-
port:
|
371
|
-
number: 80
|
372
|
-
tls:
|
373
|
-
- hosts:
|
374
|
-
- api.example.com
|
375
|
-
secretName: api-tls-secret
|
376
|
-
```
|
377
|
-
|
378
|
-
### 4. Развертывание в Kubernetes
|
379
|
-
|
380
|
-
```bash
|
381
|
-
# Применение манифестов
|
382
|
-
kubectl apply -f k8s/deployment.yaml
|
383
|
-
kubectl apply -f k8s/service.yaml
|
384
|
-
kubectl apply -f k8s/ingress.yaml
|
385
|
-
|
386
|
-
# Проверка состояния
|
387
|
-
kubectl get pods
|
388
|
-
kubectl get services
|
389
|
-
kubectl get ingress
|
390
|
-
```
|
391
|
-
|
392
|
-
## CI/CD для Command Registry
|
393
|
-
|
394
|
-
### 1. GitHub Actions
|
395
|
-
|
396
|
-
```yaml
|
397
|
-
# .github/workflows/ci.yml
|
398
|
-
name: CI/CD Pipeline
|
399
|
-
|
400
|
-
on:
|
401
|
-
push:
|
402
|
-
branches: [ main ]
|
403
|
-
pull_request:
|
404
|
-
branches: [ main ]
|
405
|
-
|
406
|
-
jobs:
|
407
|
-
test:
|
408
|
-
runs-on: ubuntu-latest
|
409
|
-
steps:
|
410
|
-
- uses: actions/checkout@v2
|
411
|
-
- name: Set up Python
|
412
|
-
uses: actions/setup-python@v2
|
413
|
-
with:
|
414
|
-
python-version: '3.10'
|
415
|
-
- name: Install dependencies
|
416
|
-
run: |
|
417
|
-
python -m pip install --upgrade pip
|
418
|
-
pip install pytest pytest-cov
|
419
|
-
pip install -e .
|
420
|
-
- name: Run tests
|
421
|
-
run: |
|
422
|
-
pytest --cov=my_app
|
423
|
-
|
424
|
-
validate-commands:
|
425
|
-
runs-on: ubuntu-latest
|
426
|
-
steps:
|
427
|
-
- uses: actions/checkout@v2
|
428
|
-
- name: Set up Python
|
429
|
-
uses: actions/setup-python@v2
|
430
|
-
with:
|
431
|
-
python-version: '3.10'
|
432
|
-
- name: Install dependencies
|
433
|
-
run: |
|
434
|
-
python -m pip install --upgrade pip
|
435
|
-
pip install -e .
|
436
|
-
- name: Validate commands
|
437
|
-
run: |
|
438
|
-
python -m my_app.tools.validate_commands --strict
|
439
|
-
|
440
|
-
build-and-push:
|
441
|
-
needs: [test, validate-commands]
|
442
|
-
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
443
|
-
runs-on: ubuntu-latest
|
444
|
-
steps:
|
445
|
-
- uses: actions/checkout@v2
|
446
|
-
- name: Build and push Docker image
|
447
|
-
uses: docker/build-push-action@v2
|
448
|
-
with:
|
449
|
-
context: .
|
450
|
-
push: true
|
451
|
-
tags: ghcr.io/${{ github.repository }}:latest
|
452
|
-
```
|
453
|
-
|
454
|
-
### 2. Скрипт для валидации команд
|
455
|
-
|
456
|
-
```python
|
457
|
-
# src/my_app/tools/validate_commands.py
|
458
|
-
import argparse
|
459
|
-
import sys
|
460
|
-
from my_app.app import registry
|
461
|
-
|
462
|
-
def validate_commands(strict: bool = True) -> bool:
|
463
|
-
"""
|
464
|
-
Проверяет все команды на соответствие требованиям документации.
|
465
|
-
|
466
|
-
Args:
|
467
|
-
strict: Если True, возвращает ошибку при несоответствии
|
468
|
-
|
469
|
-
Returns:
|
470
|
-
bool: True если все команды валидны, False иначе
|
471
|
-
"""
|
472
|
-
result = registry.validate_all_commands(strict=strict)
|
473
|
-
|
474
|
-
print(f"Проверено команд: {result['total']}")
|
475
|
-
print(f"Успешно: {result['successful']}")
|
476
|
-
print(f"С ошибками: {result['failed']}")
|
477
|
-
|
478
|
-
if result['failed'] > 0:
|
479
|
-
print("\nКоманды с ошибками:")
|
480
|
-
for command, errors in result['errors'].items():
|
481
|
-
print(f"\n{command}:")
|
482
|
-
for error in errors:
|
483
|
-
print(f" - {error}")
|
484
|
-
|
485
|
-
return result['failed'] == 0
|
486
|
-
|
487
|
-
if __name__ == "__main__":
|
488
|
-
parser = argparse.ArgumentParser(description="Валидация команд")
|
489
|
-
parser.add_argument("--strict", action="store_true", help="Строгий режим проверки")
|
490
|
-
args = parser.parse_args()
|
491
|
-
|
492
|
-
success = validate_commands(strict=args.strict)
|
493
|
-
sys.exit(0 if success else 1)
|
494
|
-
```
|
495
|
-
|
496
|
-
## Мониторинг и логирование
|
497
|
-
|
498
|
-
### 1. Настройка логирования
|
499
|
-
|
500
|
-
```python
|
501
|
-
# src/my_app/logging.py
|
502
|
-
import logging
|
503
|
-
import sys
|
504
|
-
from logging.handlers import RotatingFileHandler
|
505
|
-
from my_app.config import settings
|
506
|
-
|
507
|
-
def setup_logging():
|
508
|
-
"""Настраивает логирование для приложения."""
|
509
|
-
log_level = getattr(logging, settings.LOG_LEVEL.upper())
|
510
|
-
|
511
|
-
# Настройка корневого логгера
|
512
|
-
root_logger = logging.getLogger()
|
513
|
-
root_logger.setLevel(log_level)
|
514
|
-
|
515
|
-
# Форматтер для логов
|
516
|
-
formatter = logging.Formatter(
|
517
|
-
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
518
|
-
)
|
519
|
-
|
520
|
-
# Обработчик для вывода в консоль
|
521
|
-
console_handler = logging.StreamHandler(sys.stdout)
|
522
|
-
console_handler.setFormatter(formatter)
|
523
|
-
root_logger.addHandler(console_handler)
|
524
|
-
|
525
|
-
# Обработчик для записи в файл (в production)
|
526
|
-
if not settings.DEBUG:
|
527
|
-
file_handler = RotatingFileHandler(
|
528
|
-
'app.log',
|
529
|
-
maxBytes=10485760, # 10 MB
|
530
|
-
backupCount=5
|
531
|
-
)
|
532
|
-
file_handler.setFormatter(formatter)
|
533
|
-
root_logger.addHandler(file_handler)
|
534
|
-
|
535
|
-
# Отключаем логи библиотек
|
536
|
-
for logger_name in ['uvicorn.access']:
|
537
|
-
logging.getLogger(logger_name).setLevel(logging.WARNING)
|
538
|
-
```
|
539
|
-
|
540
|
-
### 2. Prometheus метрики
|
541
|
-
|
542
|
-
```python
|
543
|
-
# src/my_app/monitoring.py
|
544
|
-
from prometheus_client import Counter, Histogram, Summary
|
545
|
-
import time
|
546
|
-
|
547
|
-
# Счетчики для команд
|
548
|
-
command_counter = Counter(
|
549
|
-
'command_calls_total',
|
550
|
-
'Total number of command calls',
|
551
|
-
['command', 'status']
|
552
|
-
)
|
553
|
-
|
554
|
-
# Гистограмма времени выполнения
|
555
|
-
command_duration = Histogram(
|
556
|
-
'command_duration_seconds',
|
557
|
-
'Command execution duration in seconds',
|
558
|
-
['command']
|
559
|
-
)
|
560
|
-
|
561
|
-
# Middleware для измерения времени выполнения команд
|
562
|
-
class CommandMetricsMiddleware:
|
563
|
-
def __init__(self, dispatcher):
|
564
|
-
self.dispatcher = dispatcher
|
565
|
-
self.original_execute = dispatcher.execute
|
566
|
-
dispatcher.execute = self.execute_with_metrics
|
567
|
-
|
568
|
-
def execute_with_metrics(self, command_name, **params):
|
569
|
-
start_time = time.time()
|
570
|
-
try:
|
571
|
-
result = self.original_execute(command_name, **params)
|
572
|
-
command_counter.labels(command=command_name, status="success").inc()
|
573
|
-
return result
|
574
|
-
except Exception as e:
|
575
|
-
command_counter.labels(command=command_name, status="error").inc()
|
576
|
-
raise
|
577
|
-
finally:
|
578
|
-
duration = time.time() - start_time
|
579
|
-
command_duration.labels(command=command_name).observe(duration)
|
580
|
-
```
|
581
|
-
|
582
|
-
### 3. Интеграция с FastAPI
|
583
|
-
|
584
|
-
```python
|
585
|
-
# src/my_app/app.py
|
586
|
-
from fastapi import FastAPI, Request
|
587
|
-
from fastapi.middleware.cors import CORSMiddleware
|
588
|
-
from fastapi.responses import JSONResponse
|
589
|
-
import time
|
590
|
-
from starlette.middleware.base import BaseHTTPMiddleware
|
591
|
-
from prometheus_client import make_asgi_app
|
592
|
-
|
593
|
-
from my_app.config import settings
|
594
|
-
from my_app.logging import setup_logging
|
595
|
-
from my_app.registry import create_registry
|
596
|
-
from my_app.monitoring import CommandMetricsMiddleware
|
597
|
-
|
598
|
-
# Настройка логирования
|
599
|
-
setup_logging()
|
600
|
-
|
601
|
-
# Создание приложения
|
602
|
-
app = FastAPI(
|
603
|
-
title=settings.APP_NAME,
|
604
|
-
debug=settings.DEBUG
|
605
|
-
)
|
606
|
-
|
607
|
-
# Добавление middleware для CORS
|
608
|
-
app.add_middleware(
|
609
|
-
CORSMiddleware,
|
610
|
-
allow_origins=["*"],
|
611
|
-
allow_credentials=True,
|
612
|
-
allow_methods=["*"],
|
613
|
-
allow_headers=["*"],
|
614
|
-
)
|
615
|
-
|
616
|
-
# Middleware для измерения времени запросов
|
617
|
-
class RequestTimingMiddleware(BaseHTTPMiddleware):
|
618
|
-
async def dispatch(self, request: Request, call_next):
|
619
|
-
start_time = time.time()
|
620
|
-
response = await call_next(request)
|
621
|
-
process_time = time.time() - start_time
|
622
|
-
response.headers["X-Process-Time"] = str(process_time)
|
623
|
-
return response
|
624
|
-
|
625
|
-
app.add_middleware(RequestTimingMiddleware)
|
626
|
-
|
627
|
-
# Создание и настройка реестра команд
|
628
|
-
registry = create_registry(
|
629
|
-
strict=settings.STRICT_MODE,
|
630
|
-
auto_fix=settings.AUTO_FIX
|
631
|
-
)
|
632
|
-
|
633
|
-
# Применение метрик к диспетчеру команд
|
634
|
-
CommandMetricsMiddleware(registry.dispatcher)
|
635
|
-
|
636
|
-
# Добавление Prometheus метрик
|
637
|
-
metrics_app = make_asgi_app()
|
638
|
-
app.mount("/metrics", metrics_app)
|
639
|
-
|
640
|
-
# Эндпоинт для проверки состояния
|
641
|
-
@app.get("/health")
|
642
|
-
async def health_check():
|
643
|
-
return {"status": "ok"}
|
644
|
-
|
645
|
-
# Регистрация адаптера REST API
|
646
|
-
from command_registry.adapters import RESTAdapter
|
647
|
-
rest_adapter = RESTAdapter(registry)
|
648
|
-
rest_adapter.register_endpoints(app)
|
649
|
-
```
|
650
|
-
|
651
|
-
## Масштабирование
|
652
|
-
|
653
|
-
### 1. Горизонтальное масштабирование
|
654
|
-
|
655
|
-
Приложения с Command Registry могут легко масштабироваться горизонтально, так как не имеют состояния. Для масштабирования:
|
656
|
-
|
657
|
-
- Используйте балансировщик нагрузки (Nginx, HAProxy)
|
658
|
-
- В Kubernetes увеличьте количество реплик
|
659
|
-
- Используйте автомасштабирование на основе метрик
|
660
|
-
|
661
|
-
```yaml
|
662
|
-
# k8s/hpa.yaml
|
663
|
-
apiVersion: autoscaling/v2
|
664
|
-
kind: HorizontalPodAutoscaler
|
665
|
-
metadata:
|
666
|
-
name: my-app-hpa
|
667
|
-
spec:
|
668
|
-
scaleTargetRef:
|
669
|
-
apiVersion: apps/v1
|
670
|
-
kind: Deployment
|
671
|
-
name: my-app
|
672
|
-
minReplicas: 2
|
673
|
-
maxReplicas: 10
|
674
|
-
metrics:
|
675
|
-
- type: Resource
|
676
|
-
resource:
|
677
|
-
name: cpu
|
678
|
-
target:
|
679
|
-
type: Utilization
|
680
|
-
averageUtilization: 70
|
681
|
-
```
|
682
|
-
|
683
|
-
### 2. Асинхронное выполнение команд
|
684
|
-
|
685
|
-
Для долго выполняющихся команд используйте асинхронное выполнение:
|
686
|
-
|
687
|
-
```python
|
688
|
-
# src/my_app/commands/async_commands.py
|
689
|
-
import asyncio
|
690
|
-
from typing import Dict, Any, List
|
691
|
-
import logging
|
692
|
-
|
693
|
-
logger = logging.getLogger(__name__)
|
694
|
-
|
695
|
-
async def process_large_dataset(data_id: str, options: Dict[str, Any] = None) -> Dict[str, Any]:
|
696
|
-
"""
|
697
|
-
Асинхронно обрабатывает большой набор данных.
|
698
|
-
|
699
|
-
Args:
|
700
|
-
data_id: Идентификатор набора данных
|
701
|
-
options: Опции обработки
|
702
|
-
|
703
|
-
Returns:
|
704
|
-
Dict[str, Any]: Результат обработки
|
705
|
-
"""
|
706
|
-
logger.info(f"Starting processing of dataset {data_id}")
|
707
|
-
|
708
|
-
# Имитация долгой обработки
|
709
|
-
await asyncio.sleep(5)
|
710
|
-
|
711
|
-
logger.info(f"Completed processing of dataset {data_id}")
|
712
|
-
return {
|
713
|
-
"data_id": data_id,
|
714
|
-
"status": "completed",
|
715
|
-
"results": [
|
716
|
-
{"item_id": 1, "value": 100},
|
717
|
-
{"item_id": 2, "value": 200}
|
718
|
-
]
|
719
|
-
}
|
720
|
-
```
|
721
|
-
|
722
|
-
### 3. Очереди задач с Celery
|
723
|
-
|
724
|
-
```python
|
725
|
-
# src/my_app/tasks.py
|
726
|
-
from celery import Celery
|
727
|
-
from my_app.config import settings
|
728
|
-
|
729
|
-
# Создание Celery приложения
|
730
|
-
celery_app = Celery(
|
731
|
-
'my_app',
|
732
|
-
broker=f'redis://{settings.REDIS_HOST}:{settings.REDIS_PORT}/0',
|
733
|
-
backend=f'redis://{settings.REDIS_HOST}:{settings.REDIS_PORT}/0',
|
734
|
-
)
|
735
|
-
|
736
|
-
# Настройка Celery
|
737
|
-
celery_app.conf.update(
|
738
|
-
worker_concurrency=4,
|
739
|
-
task_serializer='json',
|
740
|
-
accept_content=['json'],
|
741
|
-
result_serializer='json',
|
742
|
-
timezone='UTC',
|
743
|
-
enable_utc=True,
|
744
|
-
)
|
745
|
-
|
746
|
-
@celery_app.task(name="process_data")
|
747
|
-
def process_data_task(data_id, options=None):
|
748
|
-
"""Фоновая задача для обработки данных."""
|
749
|
-
from my_app.commands.data_commands import process_data
|
750
|
-
return process_data(data_id, options)
|
751
|
-
```
|
752
|
-
|
753
|
-
### 4. Интеграция с Command Registry
|
754
|
-
|
755
|
-
```python
|
756
|
-
# src/my_app/commands/background_commands.py
|
757
|
-
from typing import Dict, Any
|
758
|
-
from my_app.tasks import process_data_task
|
759
|
-
|
760
|
-
def start_data_processing(data_id: str, options: Dict[str, Any] = None) -> Dict[str, Any]:
|
761
|
-
"""
|
762
|
-
Запускает обработку данных в фоновом режиме.
|
763
|
-
|
764
|
-
Args:
|
765
|
-
data_id: Идентификатор набора данных
|
766
|
-
options: Опции обработки
|
767
|
-
|
768
|
-
Returns:
|
769
|
-
Dict[str, Any]: Информация о запущенной задаче
|
770
|
-
"""
|
771
|
-
# Запуск задачи в Celery
|
772
|
-
task = process_data_task.delay(data_id, options)
|
773
|
-
|
774
|
-
return {
|
775
|
-
"task_id": task.id,
|
776
|
-
"status": "started",
|
777
|
-
"data_id": data_id
|
778
|
-
}
|
779
|
-
|
780
|
-
def get_task_status(task_id: str) -> Dict[str, Any]:
|
781
|
-
"""
|
782
|
-
Получает статус фоновой задачи.
|
783
|
-
|
784
|
-
Args:
|
785
|
-
task_id: Идентификатор задачи
|
786
|
-
|
787
|
-
Returns:
|
788
|
-
Dict[str, Any]: Статус и результат задачи, если она завершена
|
789
|
-
"""
|
790
|
-
from my_app.tasks import celery_app
|
791
|
-
task = celery_app.AsyncResult(task_id)
|
792
|
-
|
793
|
-
result = {
|
794
|
-
"task_id": task_id,
|
795
|
-
"status": task.status,
|
796
|
-
}
|
797
|
-
|
798
|
-
if task.status == 'SUCCESS':
|
799
|
-
result["result"] = task.result
|
800
|
-
elif task.status == 'FAILURE':
|
801
|
-
result["error"] = str(task.result)
|
802
|
-
|
803
|
-
return result
|
804
|
-
```
|
805
|
-
|
806
|
-
## Безопасность
|
807
|
-
|
808
|
-
### 1. Аутентификация и авторизация
|
809
|
-
|
810
|
-
```python
|
811
|
-
# src/my_app/auth.py
|
812
|
-
from fastapi import Depends, HTTPException, status
|
813
|
-
from fastapi.security import OAuth2PasswordBearer
|
814
|
-
import jwt
|
815
|
-
from datetime import datetime, timedelta
|
816
|
-
from typing import Dict, Any, Optional
|
817
|
-
from my_app.config import settings
|
818
|
-
|
819
|
-
# Схема OAuth2
|
820
|
-
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
821
|
-
|
822
|
-
def create_token(data: Dict[str, Any], expires_delta: timedelta = None) -> str:
|
823
|
-
"""Создает JWT токен."""
|
824
|
-
to_encode = data.copy()
|
825
|
-
|
826
|
-
if expires_delta:
|
827
|
-
expire = datetime.utcnow() + expires_delta
|
828
|
-
else:
|
829
|
-
expire = datetime.utcnow() + timedelta(minutes=15)
|
830
|
-
|
831
|
-
to_encode.update({"exp": expire})
|
832
|
-
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm="HS256")
|
833
|
-
return encoded_jwt
|
834
|
-
|
835
|
-
async def get_current_user(token: str = Depends(oauth2_scheme)) -> Dict[str, Any]:
|
836
|
-
"""Получает текущего пользователя по токену."""
|
837
|
-
credentials_exception = HTTPException(
|
838
|
-
status_code=status.HTTP_401_UNAUTHORIZED,
|
839
|
-
detail="Could not validate credentials",
|
840
|
-
headers={"WWW-Authenticate": "Bearer"},
|
841
|
-
)
|
842
|
-
|
843
|
-
try:
|
844
|
-
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
|
845
|
-
username: str = payload.get("sub")
|
846
|
-
if username is None:
|
847
|
-
raise credentials_exception
|
848
|
-
except jwt.PyJWTError:
|
849
|
-
raise credentials_exception
|
850
|
-
|
851
|
-
# Здесь должен быть код для получения пользователя из базы данных
|
852
|
-
user = {"username": username, "role": payload.get("role", "user")}
|
853
|
-
return user
|
854
|
-
|
855
|
-
def check_permission(user: Dict[str, Any], required_role: str) -> bool:
|
856
|
-
"""Проверяет, имеет ли пользователь требуемую роль."""
|
857
|
-
return user.get("role") == required_role
|
858
|
-
```
|
859
|
-
|
860
|
-
### 2. Защита эндпоинтов
|
861
|
-
|
862
|
-
```python
|
863
|
-
# src/my_app/app.py
|
864
|
-
from fastapi import Depends, HTTPException, status
|
865
|
-
from my_app.auth import get_current_user, check_permission
|
866
|
-
|
867
|
-
# Защита эндпоинта требованием аутентификации
|
868
|
-
@app.post("/protected/command/{command_name}")
|
869
|
-
async def execute_protected_command(
|
870
|
-
command_name: str,
|
871
|
-
params: Dict[str, Any],
|
872
|
-
current_user: Dict[str, Any] = Depends(get_current_user)
|
873
|
-
):
|
874
|
-
"""Защищенный эндпоинт для выполнения команд."""
|
875
|
-
# Проверка разрешений
|
876
|
-
if not check_permission(current_user, "admin") and command_name.startswith("admin_"):
|
877
|
-
raise HTTPException(
|
878
|
-
status_code=status.HTTP_403_FORBIDDEN,
|
879
|
-
detail="Not enough permissions"
|
880
|
-
)
|
881
|
-
|
882
|
-
# Выполнение команды
|
883
|
-
try:
|
884
|
-
result = registry.dispatcher.execute(command_name, **params)
|
885
|
-
return {"result": result}
|
886
|
-
except Exception as e:
|
887
|
-
raise HTTPException(
|
888
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
889
|
-
detail=str(e)
|
890
|
-
)
|
891
|
-
```
|
892
|
-
|
893
|
-
### 3. Защита от распространенных уязвимостей
|
894
|
-
|
895
|
-
```python
|
896
|
-
# src/my_app/app.py
|
897
|
-
from fastapi import FastAPI
|
898
|
-
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
899
|
-
from fastapi.middleware.gzip import GZipMiddleware
|
900
|
-
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
|
901
|
-
|
902
|
-
app = FastAPI()
|
903
|
-
|
904
|
-
# Редирект на HTTPS
|
905
|
-
if not settings.DEBUG:
|
906
|
-
app.add_middleware(HTTPSRedirectMiddleware)
|
907
|
-
|
908
|
-
# Ограничение хостов
|
909
|
-
app.add_middleware(
|
910
|
-
TrustedHostMiddleware,
|
911
|
-
allowed_hosts=["api.example.com", "localhost"]
|
912
|
-
)
|
913
|
-
|
914
|
-
# Сжатие ответов
|
915
|
-
app.add_middleware(GZipMiddleware, minimum_size=1000)
|
916
|
-
|
917
|
-
# Настройка заголовков безопасности
|
918
|
-
@app.middleware("http")
|
919
|
-
async def add_security_headers(request, call_next):
|
920
|
-
response = await call_next(request)
|
921
|
-
response.headers["X-Content-Type-Options"] = "nosniff"
|
922
|
-
response.headers["X-Frame-Options"] = "DENY"
|
923
|
-
response.headers["Content-Security-Policy"] = "default-src 'self'"
|
924
|
-
response.headers["X-XSS-Protection"] = "1; mode=block"
|
925
|
-
return response
|
926
|
-
```
|
927
|
-
|
928
|
-
## Заключение
|
929
|
-
|
930
|
-
При развертывании приложений с Command Registry важно учитывать:
|
931
|
-
|
932
|
-
1. **Конфигурацию** - используйте переменные окружения и файлы .env
|
933
|
-
2. **Логирование** - настройте логирование для отладки и мониторинга
|
934
|
-
3. **Масштабирование** - разработайте приложение для горизонтального масштабирования
|
935
|
-
4. **Безопасность** - защитите API с помощью аутентификации и авторизации
|
936
|
-
5. **CI/CD** - автоматизируйте тестирование и развертывание
|
937
|
-
6. **Мониторинг** - отслеживайте метрики производительности и использования
|
938
|
-
|
939
|
-
Эти рекомендации помогут вам успешно развернуть и поддерживать приложения на основе Command Registry в различных окружениях.
|
940
|
-
|
941
|
-
## Гибридная схема и интеграция с MCPProxy
|
942
|
-
|
943
|
-
### Проблема масштабирования OpenAPI схем
|
944
|
-
|
945
|
-
При большом количестве команд документация OpenAPI становится громоздкой и трудной для обработки. Это создает следующие проблемы:
|
946
|
-
|
947
|
-
1. Модели ИИ могут не справляться с обработкой больших схем
|
948
|
-
2. Клиентские библиотеки генерируются с ошибками
|
949
|
-
3. Документация становится менее удобной для разработчиков
|
950
|
-
4. Увеличивается время загрузки Swagger UI
|
951
|
-
|
952
|
-
### Решение: гибридная архитектура REST+JSONRPC
|
953
|
-
|
954
|
-
Command Registry предлагает гибридный подход, сочетающий преимущества REST и JSONRPC:
|
955
|
-
|
956
|
-
```
|
957
|
-
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
|
958
|
-
│ │ │ │ │ │
|
959
|
-
│ Command Registry │───►│ Гибридная схема │───►│ REST + JSONRPC API│
|
960
|
-
│ │ │ │ │ │
|
961
|
-
└───────────────────┘ └───────────────────┘ └───────────────────┘
|
962
|
-
│
|
963
|
-
▼
|
964
|
-
┌───────────────────┐
|
965
|
-
│ │
|
966
|
-
│ MCPProxy │
|
967
|
-
│ │
|
968
|
-
└───────────────────┘
|
969
|
-
│
|
970
|
-
▼
|
971
|
-
┌───────────────────┐
|
972
|
-
│ │
|
973
|
-
│ Инструменты модели│
|
974
|
-
│ │
|
975
|
-
└───────────────────┘
|
976
|
-
```
|
977
|
-
|
978
|
-
#### Компоненты решения:
|
979
|
-
|
980
|
-
1. **Традиционные REST эндпоинты** для стандартных операций
|
981
|
-
2. **Универсальный эндпоинт `cmd`** принимающий JSONRPC запросы
|
982
|
-
3. **Генератор гибридной схемы** создающий оптимизированную документацию API
|
983
|
-
|
984
|
-
### Генератор гибридной схемы
|
985
|
-
|
986
|
-
Для генерации гибридной схемы был создан отдельный генератор, который:
|
987
|
-
|
988
|
-
1. Анализирует команды из Command Registry
|
989
|
-
2. Создает оптимизированную OpenAPI схему
|
990
|
-
3. Формирует универсальный эндпоинт для JSONRPC
|
991
|
-
4. Поддерживает обратную совместимость с существующими клиентами
|
992
|
-
|
993
|
-
```python
|
994
|
-
# Пример использования генератора гибридной схемы
|
995
|
-
from command_registry.generators.hybrid_generator import HybridAPIGenerator
|
996
|
-
from my_app.registry import registry
|
997
|
-
|
998
|
-
# Создаем генератор
|
999
|
-
generator = HybridAPIGenerator(
|
1000
|
-
title="My Hybrid API",
|
1001
|
-
description="API с поддержкой REST и JSONRPC",
|
1002
|
-
version="1.0.0",
|
1003
|
-
cmd_endpoint="/api/cmd"
|
1004
|
-
)
|
1005
|
-
|
1006
|
-
# Регистрируем в Command Registry
|
1007
|
-
registry.add_generator(generator)
|
1008
|
-
|
1009
|
-
# Применяем к FastAPI приложению
|
1010
|
-
app = FastAPI()
|
1011
|
-
generator.apply_to_fastapi(app)
|
1012
|
-
```
|
1013
|
-
|
1014
|
-
### Интеграция с MCPProxy
|
1015
|
-
|
1016
|
-
MCPProxy позволяет преобразовать OpenAPI серверы в инструменты для моделей ИИ. Для успешной интеграции Command Registry с MCPProxy:
|
1017
|
-
|
1018
|
-
1. **Установите MCPProxy**:
|
1019
|
-
|
1020
|
-
```bash
|
1021
|
-
pip install mcp-proxy
|
1022
|
-
```
|
1023
|
-
|
1024
|
-
2. **Включите поддержку MCPProxy в вашем приложении**:
|
1025
|
-
|
1026
|
-
```python
|
1027
|
-
from command_registry.adapters import MCPProxyAdapter
|
1028
|
-
from my_app.registry import registry
|
1029
|
-
|
1030
|
-
# Создаем адаптер для MCPProxy
|
1031
|
-
mcp_adapter = MCPProxyAdapter(registry)
|
1032
|
-
|
1033
|
-
# Регистрируем в приложении
|
1034
|
-
app = FastAPI()
|
1035
|
-
mcp_adapter.register_endpoints(app)
|
1036
|
-
```
|
1037
|
-
|
1038
|
-
3. **Настройте маршрутизацию в MCPProxy**:
|
1039
|
-
|
1040
|
-
```yaml
|
1041
|
-
# mcp_proxy_config.yaml
|
1042
|
-
routes:
|
1043
|
-
- path: /api/cmd
|
1044
|
-
type: json_rpc
|
1045
|
-
schema_url: http://your-api.com/openapi.json
|
1046
|
-
command_field: method
|
1047
|
-
params_field: params
|
1048
|
-
```
|
1049
|
-
|
1050
|
-
### Рекомендации для больших проектов
|
1051
|
-
|
1052
|
-
При использовании Command Registry в крупных проектах с MCPProxy:
|
1053
|
-
|
1054
|
-
1. **Группируйте команды по функциональности**:
|
1055
|
-
```python
|
1056
|
-
# Пример структуры команд
|
1057
|
-
my_app/
|
1058
|
-
commands/
|
1059
|
-
user_commands.py
|
1060
|
-
data_commands.py
|
1061
|
-
admin_commands.py
|
1062
|
-
```
|
1063
|
-
|
1064
|
-
2. **Используйте подпроекты** для отдельных доменных областей:
|
1065
|
-
```
|
1066
|
-
my_solution/
|
1067
|
-
├── user_service/
|
1068
|
-
│ └── commands/
|
1069
|
-
├── data_service/
|
1070
|
-
│ └── commands/
|
1071
|
-
└── admin_service/
|
1072
|
-
└── commands/
|
1073
|
-
```
|
1074
|
-
|
1075
|
-
3. **Создайте отдельные гибридные схемы** для каждого подпроекта:
|
1076
|
-
```python
|
1077
|
-
# Для каждого подпроекта
|
1078
|
-
user_registry = CommandRegistry(...)
|
1079
|
-
user_generator = HybridAPIGenerator(...)
|
1080
|
-
user_registry.add_generator(user_generator)
|
1081
|
-
```
|
1082
|
-
|
1083
|
-
4. **Объедините схемы при необходимости** с помощью агрегатора:
|
1084
|
-
```python
|
1085
|
-
from command_registry.tools import SchemaAggregator
|
1086
|
-
|
1087
|
-
aggregator = SchemaAggregator()
|
1088
|
-
aggregator.add_schema("users", "http://user-service/openapi.json")
|
1089
|
-
aggregator.add_schema("data", "http://data-service/openapi.json")
|
1090
|
-
aggregator.add_schema("admin", "http://admin-service/openapi.json")
|
1091
|
-
|
1092
|
-
# Создание единой схемы
|
1093
|
-
combined_schema = aggregator.generate_combined_schema()
|
1094
|
-
```
|
1095
|
-
|
1096
|
-
### Обновление индекса кода
|
1097
|
-
|
1098
|
-
Для поддержания актуальности документации, обновляйте `code_index.yaml` при изменении структуры проекта:
|
1099
|
-
|
1100
|
-
```yaml
|
1101
|
-
# Пример обновления code_index.yaml
|
1102
|
-
sections:
|
1103
|
-
- name: "Генераторы"
|
1104
|
-
description: "Генераторы API схем"
|
1105
|
-
files:
|
1106
|
-
- path: "command_registry/generators/hybrid_generator.py"
|
1107
|
-
description: "Генератор гибридной схемы REST+JSONRPC для MCPProxy"
|
1108
|
-
|
1109
|
-
- name: "Адаптеры"
|
1110
|
-
description: "Адаптеры для различных протоколов"
|
1111
|
-
files:
|
1112
|
-
- path: "command_registry/adapters/mcp_proxy_adapter.py"
|
1113
|
-
description: "Адаптер для интеграции с MCPProxy"
|
1114
|
-
```
|
1115
|
-
|
1116
|
-
Этот подход к организации кода и документации позволит эффективно масштабировать проекты на базе Command Registry и успешно интегрировать их с MCPProxy для создания инструментов моделей ИИ.
|
1117
|
-
|
1118
|
-
# Руководство по публикации в PyPI
|
1119
|
-
|
1120
|
-
В этом руководстве описывается процесс подготовки и публикации пакета MCP Proxy Adapter в Python Package Index (PyPI).
|
1121
|
-
|
1122
|
-
## Подготовка пакета
|
1123
|
-
|
1124
|
-
### 1. Обновите метаданные пакета
|
1125
|
-
|
1126
|
-
Перед публикацией убедитесь, что файлы `pyproject.toml` и `setup.py` содержат актуальную информацию:
|
1127
|
-
|
1128
|
-
- Версия пакета
|
1129
|
-
- Описание
|
1130
|
-
- URL проекта
|
1131
|
-
- Адрес электронной почты автора
|
1132
|
-
- Классификаторы
|
1133
|
-
- Зависимости
|
1134
|
-
|
1135
|
-
### 2. Установите необходимые инструменты
|
1136
|
-
|
1137
|
-
```bash
|
1138
|
-
pip install build twine
|
1139
|
-
```
|
1140
|
-
|
1141
|
-
### 3. Соберите пакет
|
1142
|
-
|
1143
|
-
```bash
|
1144
|
-
python -m build
|
1145
|
-
```
|
1146
|
-
|
1147
|
-
Эта команда создаст как Source Distribution (sdist), так и Wheel Distribution (bdist_wheel) в директории `dist/`.
|
1148
|
-
|
1149
|
-
### 4. Проверьте пакет
|
1150
|
-
|
1151
|
-
```bash
|
1152
|
-
twine check dist/*
|
1153
|
-
```
|
1154
|
-
|
1155
|
-
Убедитесь, что все проверки пройдены без ошибок.
|
1156
|
-
|
1157
|
-
## Публикация пакета
|
1158
|
-
|
1159
|
-
### 1. Настройка аутентификации
|
1160
|
-
|
1161
|
-
Создайте файл `.pypirc` в вашем домашнем каталоге со следующим содержимым:
|
1162
|
-
|
1163
|
-
```
|
1164
|
-
[pypi]
|
1165
|
-
username = __token__
|
1166
|
-
password = <ваш_токен_pypi>
|
1167
|
-
```
|
1168
|
-
|
1169
|
-
Замените `<ваш_токен_pypi>` на ваш токен доступа к PyPI, который вы можете получить в своем аккаунте PyPI.
|
1170
|
-
|
1171
|
-
Альтернативно, вы можете передать учетные данные непосредственно в команду `twine upload`.
|
1172
|
-
|
1173
|
-
### 2. Публикация в тестовом PyPI (опционально)
|
1174
|
-
|
1175
|
-
Сначала рекомендуется опубликовать пакет в тестовом репозитории:
|
1176
|
-
|
1177
|
-
```bash
|
1178
|
-
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
|
1179
|
-
```
|
1180
|
-
|
1181
|
-
После этого вы можете установить пакет из тестового PyPI и проверить его работу:
|
1182
|
-
|
1183
|
-
```bash
|
1184
|
-
pip install --index-url https://test.pypi.org/simple/ mcp-proxy-adapter
|
1185
|
-
```
|
1186
|
-
|
1187
|
-
### 3. Публикация в основном PyPI
|
1188
|
-
|
1189
|
-
После успешного тестирования опубликуйте пакет в основном PyPI:
|
1190
|
-
|
1191
|
-
```bash
|
1192
|
-
twine upload dist/*
|
1193
|
-
```
|
1194
|
-
|
1195
|
-
### 4. Проверка установки
|
1196
|
-
|
1197
|
-
Проверьте, что пакет успешно загружен и может быть установлен:
|
1198
|
-
|
1199
|
-
```bash
|
1200
|
-
pip install mcp-proxy-adapter
|
1201
|
-
```
|
1202
|
-
|
1203
|
-
## Обновление пакета
|
1204
|
-
|
1205
|
-
Для публикации новой версии пакета:
|
1206
|
-
|
1207
|
-
1. Обновите версию в `pyproject.toml` и `setup.py`
|
1208
|
-
2. Обновите файл `CHANGELOG.md` (если есть)
|
1209
|
-
3. Соберите пакет заново
|
1210
|
-
4. Загрузите новую версию в PyPI
|
1211
|
-
|
1212
|
-
```bash
|
1213
|
-
# Обновите версию в файлах
|
1214
|
-
# ...
|
1215
|
-
|
1216
|
-
# Соберите пакет
|
1217
|
-
python -m build
|
1218
|
-
|
1219
|
-
# Загрузите пакет
|
1220
|
-
twine upload dist/*
|
1221
|
-
```
|
1222
|
-
|
1223
|
-
## Использование GitHub Actions для автоматической публикации
|
1224
|
-
|
1225
|
-
Вы можете автоматизировать процесс публикации пакета при создании нового релиза в GitHub.
|
1226
|
-
|
1227
|
-
Создайте файл `.github/workflows/publish.yml` со следующим содержимым:
|
1228
|
-
|
1229
|
-
```yaml
|
1230
|
-
name: Build and publish Python package
|
1231
|
-
|
1232
|
-
on:
|
1233
|
-
release:
|
1234
|
-
types: [created]
|
1235
|
-
|
1236
|
-
jobs:
|
1237
|
-
deploy:
|
1238
|
-
runs-on: ubuntu-latest
|
1239
|
-
steps:
|
1240
|
-
- uses: actions/checkout@v3
|
1241
|
-
- name: Set up Python
|
1242
|
-
uses: actions/setup-python@v4
|
1243
|
-
with:
|
1244
|
-
python-version: '3.x'
|
1245
|
-
- name: Install dependencies
|
1246
|
-
run: |
|
1247
|
-
python -m pip install --upgrade pip
|
1248
|
-
pip install build twine
|
1249
|
-
- name: Build and publish
|
1250
|
-
env:
|
1251
|
-
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
1252
|
-
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
1253
|
-
run: |
|
1254
|
-
python -m build
|
1255
|
-
twine upload dist/*
|
1256
|
-
```
|
1257
|
-
|
1258
|
-
Не забудьте добавить соответствующие секреты `PYPI_USERNAME` и `PYPI_PASSWORD` в настройках вашего GitHub репозитория.
|
1259
|
-
|
1260
|
-
## Проверка совместимости
|
1261
|
-
|
1262
|
-
Перед публикацией рекомендуется проверить совместимость пакета с различными версиями Python.
|
1263
|
-
Для этого можно использовать инструмент `tox`:
|
1264
|
-
|
1265
|
-
```bash
|
1266
|
-
pip install tox
|
1267
|
-
|
1268
|
-
# Создайте файл tox.ini в корне проекта
|
1269
|
-
# [tox]
|
1270
|
-
# envlist = py39, py310, py311, py312
|
1271
|
-
#
|
1272
|
-
# [testenv]
|
1273
|
-
# deps = pytest
|
1274
|
-
# commands = pytest
|
1275
|
-
|
1276
|
-
# Запустите тесты для разных версий Python
|
1277
|
-
tox
|
1278
|
-
```
|
1279
|
-
|
1280
|
-
## Документация по установке пакета для пользователей
|
1281
|
-
|
1282
|
-
После публикации пакета в PyPI, пользователи смогут установить его с помощью `pip`:
|
1283
|
-
|
1284
|
-
```bash
|
1285
|
-
pip install mcp-proxy-adapter
|
1286
|
-
```
|
1287
|
-
|
1288
|
-
Для установки конкретной версии:
|
1289
|
-
|
1290
|
-
```bash
|
1291
|
-
pip install mcp-proxy-adapter==1.0.0
|
1292
|
-
```
|
1293
|
-
|
1294
|
-
Для обновления до последней версии:
|
1295
|
-
|
1296
|
-
```bash
|
1297
|
-
pip install --upgrade mcp-proxy-adapter
|
1298
|
-
```
|