enotkrutoy commited on
Commit
7136ebe
·
verified ·
1 Parent(s): 165912b

Delete FastMCPToolGenerator

Browse files
Files changed (34) hide show
  1. FastMCPToolGenerator/.gitattributes +0 -35
  2. FastMCPToolGenerator/.gitignore +0 -63
  3. FastMCPToolGenerator/App.tsx +0 -283
  4. FastMCPToolGenerator/Dockerfile +0 -77
  5. FastMCPToolGenerator/GEMINI.md +0 -50
  6. FastMCPToolGenerator/README0.md +0 -20
  7. FastMCPToolGenerator/backend/__pycache__/main.cpython-313.pyc +0 -0
  8. FastMCPToolGenerator/backend/main.py +0 -164
  9. FastMCPToolGenerator/components/AiPrompt.tsx +0 -52
  10. FastMCPToolGenerator/components/CodeOutput.tsx +0 -340
  11. FastMCPToolGenerator/components/FunctionEditor.tsx +0 -146
  12. FastMCPToolGenerator/components/ToolForm.tsx +0 -115
  13. FastMCPToolGenerator/components/ui/Button.tsx +0 -28
  14. FastMCPToolGenerator/components/ui/Card.tsx +0 -21
  15. FastMCPToolGenerator/components/ui/Input.tsx +0 -19
  16. FastMCPToolGenerator/components/ui/Label.tsx +0 -16
  17. FastMCPToolGenerator/components/ui/Select.tsx +0 -28
  18. FastMCPToolGenerator/components/ui/Textarea.tsx +0 -20
  19. FastMCPToolGenerator/constants.ts +0 -18
  20. FastMCPToolGenerator/dist/assets/index-CjZgBbLF.js +0 -0
  21. FastMCPToolGenerator/dist/index.html +0 -46
  22. FastMCPToolGenerator/examples.ts +0 -60
  23. FastMCPToolGenerator/index.html +0 -45
  24. FastMCPToolGenerator/index.tsx +0 -20
  25. FastMCPToolGenerator/metadata.json +0 -7
  26. FastMCPToolGenerator/package-lock.json +0 -0
  27. FastMCPToolGenerator/package.json +0 -42
  28. FastMCPToolGenerator/requirements.txt +0 -11
  29. FastMCPToolGenerator/services/aiService.ts +0 -71
  30. FastMCPToolGenerator/services/codeGenerator.ts +0 -428
  31. FastMCPToolGenerator/style.css +0 -28
  32. FastMCPToolGenerator/tsconfig.json +0 -32
  33. FastMCPToolGenerator/types.ts +0 -72
  34. FastMCPToolGenerator/vite.config.ts +0 -72
FastMCPToolGenerator/.gitattributes DELETED
@@ -1,35 +0,0 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/.gitignore DELETED
@@ -1,63 +0,0 @@
1
- 
2
- # Logs
3
-
4
- logs
5
-
6
- *.log
7
-
8
- npm-debug.log*
9
-
10
- yarn-debug.log*
11
-
12
- yarn-error.log*
13
-
14
- pnpm-debug.log*
15
-
16
- lerna-debug.log*
17
-
18
-
19
-
20
- node_modules
21
-
22
- dist
23
-
24
- dist-ssr
25
-
26
- *.local
27
-
28
- .env
29
-
30
-
31
-
32
- # Editor directories and files
33
-
34
- .vscode/*
35
-
36
- !.vscode/extensions.json
37
-
38
- .idea
39
-
40
- .DS_Store
41
-
42
- *.suo
43
-
44
- *.ntvs*
45
-
46
- *.njsproj
47
-
48
- *.sln
49
-
50
- *.sw?
51
-
52
-
53
-
54
- # Python
55
-
56
- __pycache__/
57
-
58
- *.pyc
59
-
60
- .venv
61
-
62
- venv/
63
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/App.tsx DELETED
@@ -1,283 +0,0 @@
1
-
2
- import React, { useState, useMemo } from 'react';
3
-
4
- import { ToolDefinition, GeneratedCode, ToolType, FunctionDefinition, ParameterType } from './types';
5
-
6
- import ToolForm from './components/ToolForm';
7
-
8
- import CodeOutput from './components/CodeOutput';
9
-
10
- import { generateAllCode } from './services/codeGenerator';
11
-
12
- import { nmapScannerExample } from './examples';
13
-
14
- import Button from './components/ui/Button';
15
-
16
- import AiPrompt from './components/AiPrompt';
17
-
18
- import { generateToolDefinitionFromPrompt } from './services/aiService';
19
-
20
-
21
-
22
- const initialFunction: FunctionDefinition = {
23
-
24
- id: crypto.randomUUID(),
25
-
26
- name: 'example_function',
27
-
28
- description: 'Краткое описание того, что делает эта функция.',
29
-
30
- parameters: [
31
-
32
- {
33
-
34
- id: crypto.randomUUID(),
35
-
36
- name: 'example_param',
37
-
38
- type: ParameterType.STRING, // Исправлено с 'str' as any
39
-
40
- description: 'Описание параметра.',
41
-
42
- required: true,
43
-
44
- },
45
-
46
- ],
47
-
48
- returnType: ParameterType.STRING, // Исправлено с 'str' as any
49
-
50
- returnDescription: 'Описание возвращаемого значения.',
51
-
52
- };
53
-
54
-
55
-
56
- const initialToolDefinition: ToolDefinition = {
57
-
58
- name: 'my_tool',
59
-
60
- type: ToolType.UTILITY,
61
-
62
- dependencies: '',
63
-
64
- functions: [initialFunction],
65
-
66
- };
67
-
68
-
69
-
70
- const App: React.FC = () => {
71
-
72
- const [toolDefinition, setToolDefinition] = useState<ToolDefinition>(initialToolDefinition);
73
-
74
- const [aiPrompt, setAiPrompt] = useState<string>('');
75
-
76
- const [isGenerating, setIsGenerating] = useState<boolean>(false);
77
-
78
- const [aiError, setAiError] = useState<string | null>(null);
79
-
80
-
81
-
82
- const generatedCode = useMemo<GeneratedCode | null>(() => {
83
-
84
- try {
85
-
86
- if (toolDefinition.name && toolDefinition.functions.length > 0 && toolDefinition.functions.every(f => f.name)) {
87
-
88
- return generateAllCode(toolDefinition);
89
-
90
- }
91
-
92
- return null;
93
-
94
- } catch (error) {
95
-
96
- console.error("Error generating code:", error);
97
-
98
- return null;
99
-
100
- }
101
-
102
- }, [toolDefinition]);
103
-
104
-
105
-
106
- const loadNmapExample = () => {
107
-
108
- setToolDefinition(nmapScannerExample);
109
-
110
- };
111
-
112
-
113
-
114
- const handleAiGenerate = async () => {
115
-
116
- if (!aiPrompt.trim()) {
117
-
118
- setAiError("Пожалуйста, введите описание инструмента.");
119
-
120
- return;
121
-
122
- }
123
-
124
- setIsGenerating(true);
125
-
126
- setAiError(null);
127
-
128
- try {
129
-
130
- const jsonString = await generateToolDefinitionFromPrompt(aiPrompt);
131
-
132
-
133
-
134
- // Бэкенд уже должен был очистить markdown, но на всякий случай
135
-
136
- const cleanedJsonString = jsonString.replace(/^```json\s*|\s*```$/g, '').trim();
137
-
138
- const newToolDefinition = JSON.parse(cleanedJsonString);
139
-
140
-
141
-
142
- // Добавим уникальные ID, так как AI их не генерирует
143
-
144
- if (newToolDefinition.functions) {
145
-
146
- newToolDefinition.functions.forEach((func: FunctionDefinition) => {
147
-
148
- func.id = crypto.randomUUID();
149
-
150
- if (func.parameters) {
151
-
152
- func.parameters.forEach((param: any) => {
153
-
154
- param.id = crypto.randomUUID();
155
-
156
- });
157
-
158
- } else {
159
-
160
- func.parameters = []; // Убедимся, что параметры существуют
161
-
162
- }
163
-
164
- });
165
-
166
- } else {
167
-
168
- newToolDefinition.functions = []; // Убедимся, что функции существуют
169
-
170
- }
171
-
172
-
173
-
174
- setToolDefinition(newToolDefinition);
175
-
176
-
177
-
178
- } catch (error) {
179
-
180
- console.error("AI generation failed:", error);
181
-
182
- setAiError(`Не удалось сгенерировать инструмент: ${error.message}. Проверьте консоль.`);
183
-
184
- } finally {
185
-
186
- setIsGenerating(false);
187
-
188
- }
189
-
190
- };
191
-
192
-
193
-
194
- return (
195
-
196
- <div className="min-h-screen bg-gray-900 text-gray-100 p-4 sm:p-6 lg:p-8">
197
-
198
- <div className="max-w-screen-2xl mx-auto">
199
-
200
- <header className="mb-8">
201
-
202
- <div className="text-center">
203
-
204
- <h1 className="text-4xl sm:text-5xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-sky-400 to-blue-600">
205
-
206
- Gemini CLI Tool Generator
207
-
208
- </h1>
209
-
210
- <p className="mt-2 text-lg text-gray-400">
211
-
212
- Создайте кастомные расширения, которые Gemini сможет вызывать для решения ваших задач.
213
-
214
- </p>
215
-
216
- </div>
217
-
218
- <div className="text-center mt-4">
219
-
220
- <Button onClick={loadNmapExample} variant="secondary">
221
-
222
- Загрузить пример: Nmap Scanner
223
-
224
- </Button>
225
-
226
- </div>
227
-
228
- </header>
229
-
230
-
231
-
232
- <AiPrompt
233
-
234
- prompt={aiPrompt}
235
-
236
- setPrompt={setAiPrompt}
237
-
238
- onGenerate={handleAiGenerate}
239
-
240
- isLoading={isGenerating}
241
-
242
- error={aiError}
243
-
244
- />
245
-
246
-
247
-
248
- <main className="grid grid-cols-1 xl:grid-cols-2 gap-8 mt-8">
249
-
250
- <ToolForm toolDefinition={toolDefinition} setToolDefinition={setToolDefinition} />
251
-
252
- <CodeOutput generatedCode={generatedCode} toolName={toolDefinition.name} />
253
-
254
- </main>
255
-
256
-
257
-
258
- <footer className="text-center mt-12 py-4 border-t border-gray-700">
259
-
260
- <p className="text-gray-500">
261
-
262
- Разработано с использованием React, Tailwind CSS и Gemini.
263
-
264
- </p>
265
-
266
- </footer>
267
-
268
- </div>
269
-
270
- </div>
271
-
272
- );
273
-
274
- };
275
-
276
-
277
-
278
- export default App;
279
-
280
-
281
-
282
-
283
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/Dockerfile DELETED
@@ -1,77 +0,0 @@
1
- 
2
- # Этап 1: Сборка React-фронтенда
3
-
4
- FROM node:18-slim AS build
5
-
6
- WORKDIR /app
7
-
8
-
9
-
10
- # Копируем package.json и устанавливаем npm зависимости
11
-
12
- COPY package.json package-lock.json ./
13
-
14
- RUN npm install
15
-
16
-
17
-
18
- # Копируем остальной код фронтенда
19
-
20
- COPY . .
21
-
22
-
23
-
24
- # Собираем production build (создает папку 'dist')
25
-
26
- RUN npm run build
27
-
28
-
29
-
30
- # Этап 2: Настройка Python-сервера (FastAPI)
31
-
32
- FROM python:3.10-slim
33
-
34
- WORKDIR /app
35
-
36
-
37
-
38
- # Установка переменных окружения
39
-
40
- ENV PYTHONUNBUFFERED 1
41
-
42
- ENV PYTHONDONTWRITEBYTECODE 1
43
-
44
-
45
-
46
- # Копируем Python-зависимости и устанавливаем их
47
-
48
- COPY requirements.txt .
49
-
50
- RUN pip install --no-cache-dir -r requirements.txt
51
-
52
-
53
-
54
- # Копируем код бэкенда (FastAPI)
55
-
56
- COPY ./backend ./backend
57
-
58
-
59
-
60
- # Копируем собранный фронтенд из Этапа 1
61
-
62
- COPY --from=build /app/dist ./dist
63
-
64
-
65
-
66
- # Порт 7860 - стандартный для HF Spaces
67
-
68
- EXPOSE 7860
69
-
70
- ENV PORT=7860
71
-
72
-
73
-
74
- # Команда для запуска Uvicorn (FastAPI)
75
-
76
- CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "7860"]
77
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/GEMINI.md DELETED
@@ -1,50 +0,0 @@
1
- # Инструкция для Агента: Инструмент "nmap_scanner"
2
-
3
- ## Описание
4
-
5
- Этот инструмент предоставляет прямой доступ к сетевому сканеру Nmap для проведения разведки и обнаружения хостов в сети. Он относится к типу **UTILITY**. Используй его для анализа сетевой безопасности, инвентаризации устройств и проверки открытых портов.
6
-
7
- ## Функции
8
-
9
- ### `nmap_scanner:run_scan`
10
-
11
- Запускает детальное сканирование Nmap на указанные цели. Позволяет гибко настраивать тип сканирования, определять службы и версии ПО.
12
-
13
- **Параметры:**
14
- - `targets` (*str*): Цели для сканирования (IP-адрес, домен, CIDR-диапазон). Например: '192.168.1.1', 'scanme.nmap.org', '10.0.0.0/24'. (обязательный)
15
- - `ports` (*str*): Порты для сканирования. Например: '21-25,80,443', '1-1024'. (обязательный)
16
- - `arguments` (*str*): Дополнительные аргументы командной строки Nmap. Например: '-sV -sC' для определения версий и запуска скриптов, или '-A' для агрессивного сканирования. (обязательный)
17
-
18
- **Возвращает:**
19
- *dict* - Результат сканирования в формате JSON, содержащий информацию о хостах, их состоянии, открытых портах, службах и версиях.
20
-
21
- ---
22
-
23
- ### `nmap_scanner:host_discovery`
24
-
25
- Быстро обнаруживает активные (включенные) хосты в указанной сети с помощью 'ping scan' (`-sn`), не проводя полного сканирования портов.
26
-
27
- **Параметры:**
28
- - `network_cidr` (*str*): Сетевой диапазон в формате CIDR для обнаружения хостов. Например: '192.168.1.0/24'. (обязательный)
29
-
30
- **Возвращает:**
31
- *list* - Список IP-адресов активных хостов, обнаруженных в сети.
32
-
33
- ## Примеры использования
34
-
35
- **ВАЖНО:** Всегда используй формат `nmap_scanner:имя_функции()`.
36
-
37
- **Пример 1: Обнаружение всех активных устройств в локальной сети**
38
- ```
39
- nmap_scanner:host_discovery(network_cidr="192.168.0.0/24")
40
- ```
41
-
42
- **Пример 2: Быстрое сканирование популярных портов на конкретном хосте**
43
- ```
44
- nmap_scanner:run_scan(targets="192.168.1.1", ports="1-1024", arguments="-T4")
45
- ```
46
-
47
- **Пример 3: Агрессивное сканирование веб-сервера для определения ОС, служб и уязвимостей**
48
- ```
49
- nmap_scanner:run_scan(targets="scanme.nmap.org", ports="80,443", arguments="-A -v")
50
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/README0.md DELETED
@@ -1,20 +0,0 @@
1
- <div align="center">
2
- <img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
3
- </div>
4
-
5
- # Run and deploy your AI Studio app
6
-
7
- This contains everything you need to run your app locally.
8
-
9
- View your app in AI Studio: https://ai.studio/apps/drive/1DWLDNsbZ8bO_lQPzuDVQB3cpW92HgYCC
10
-
11
- ## Run Locally
12
-
13
- **Prerequisites:** Node.js
14
-
15
-
16
- 1. Install dependencies:
17
- `npm install`
18
- 2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
19
- 3. Run the app:
20
- `npm run dev`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/backend/__pycache__/main.cpython-313.pyc DELETED
Binary file (6.89 kB)
 
FastMCPToolGenerator/backend/main.py DELETED
@@ -1,164 +0,0 @@
1
- import os
2
- import re
3
- from fastapi import FastAPI, HTTPException
4
- from fastapi.responses import FileResponse
5
- from fastapi.staticfiles import StaticFiles
6
- from pydantic import BaseModel
7
- import google.generativeai as genai
8
- from google.generativeai.types import HarmCategory, HarmBlockThreshold
9
-
10
- # Получаем ключ из переменных окружения (HF Secrets)
11
- API_KEY = os.environ.get("GEMINI_API_KEY")
12
-
13
- if not API_KEY:
14
- print("ВНИМАНИЕ: GEMINI_API_KEY не установлен в переменных окружения.")
15
- else:
16
- genai.configure(api_key=API_KEY)
17
-
18
- app = FastAPI()
19
-
20
- # Модель для входящего запроса от фронтенда
21
- class PromptRequest(BaseModel):
22
- prompt: str
23
-
24
- def get_ai_prompt(user_prompt: str):
25
- return f"""
26
- Вы — эксперт по генерации JSON-определений инструментов (ToolDefinition) для FastMCP (Gemini CLI).
27
- Ваша задача — принять текстовое описание инструмента от пользователя и вернуть ТОЛЬКО JSON-структуру, соответствующую интерфейсу ToolDefinition.
28
-
29
- Интерфейс ToolDefinition (TypeScript):
30
- export enum ToolType {{
31
- REST_API = 'REST_API',
32
- CLI = 'CLI',
33
- DATABASE = 'DATABASE',
34
- CUSTOM = 'CUSTOM',
35
- UTILITY = 'UTILITY',
36
- CALCULATOR = 'CALCULATOR',
37
- CONVERTER = 'CONVERTER'
38
- }}
39
- export enum ParameterType {{
40
- STRING = 'str',
41
- INTEGER = 'int',
42
- FLOAT = 'float',
43
- BOOLEAN = 'bool',
44
- LIST = 'list',
45
- DICTIONARY = 'dict'
46
- }}
47
- export interface ParameterDefinition {{
48
- name: string;
49
- type: ParameterType;
50
- description: string;
51
- required: boolean;
52
- }}
53
- export interface FunctionDefinition {{
54
- name: string;
55
- description: string;
56
- parameters: ParameterDefinition[];
57
- returnType: ParameterType;
58
- returnDescription: string;
59
- }}
60
- export interface ToolDefinition {{
61
- name: string;
62
- type: ToolType;
63
- dependencies: string;
64
- functions: FunctionDefinition[];
65
- }}
66
-
67
- Правила:
68
- 1. НЕ добавляйте ID. Фронтенд сделает это.
69
- 2. Возвращайте ТОЛЬКО JSON-код. Без markdown, без "вот ваш JSON".
70
- 3. Имена функций и параметров должны быть в snake_case.
71
- 4. Тип (ToolType) должен быть наиболее подходящим (часто это UTILITY или CLI).
72
- 5. Dependencies (зависимости) должны быть пустыми (""), если не указано иное (например, для 'nmap' нужна 'python-nmap').
73
-
74
- Пример запроса пользователя:
75
- "Инструмент для получения текущей погоды в городе."
76
-
77
- Пример вашего ИДЕАЛЬНОГО ответа (ТОЛЬКО JSON):
78
- {{
79
- "name": "weather_tool",
80
- "type": "REST_API",
81
- "dependencies": "requests",
82
- "functions": [
83
- {{
84
- "name": "get_current_weather",
85
- "description": "Получает текущую погоду для указанного города.",
86
- "parameters": [
87
- {{
88
- "name": "city_name",
89
- "type": "str",
90
- "description": "Название города, для которого нужно получить погоду.",
91
- "required": true
92
- }}
93
- ],
94
- "returnType": "dict",
95
- "returnDescription": "Словарь с данными о погоде (температура, влажность и т.д.)."
96
- }}
97
- ]
98
- }}
99
- ---
100
- ЗАПРОС ПОЛЬЗОВАТЕЛЯ:
101
- "{user_prompt}"
102
-
103
- ВАШ ОТВЕТ (ТОЛЬКО JSON):
104
- """
105
-
106
- generation_config = {
107
- "temperature": 0.7,
108
- "top_p": 1.0,
109
- "top_k": 32,
110
- "max_output_tokens": 4096,
111
- }
112
-
113
- safety_settings = [
114
- {"category": HarmCategory.HARM_CATEGORY_HARASSMENT, "threshold": HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE},
115
- {"category": HarmCategory.HARM_CATEGORY_HATE_SPEECH, "threshold": HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE},
116
- {"category": HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, "threshold": HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE},
117
- {"category": HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, "threshold": HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE},
118
- ]
119
-
120
- @app.post("/api/generate")
121
- async def handle_generate(request: PromptRequest):
122
- if not API_KEY:
123
- raise HTTPException(status_code=500, detail="GEMINI_API_KEY не настроен на сервере.")
124
-
125
- try:
126
- model = genai.GenerativeModel(
127
- model_name="gemini-1.5-pro-latest",
128
- generation_config=generation_config,
129
- safety_settings=safety_settings
130
- )
131
-
132
- prompt_parts = [get_ai_prompt(request.prompt)]
133
- response = model.generate_content(prompt_parts)
134
-
135
- json_string = response.text
136
-
137
- cleaned_json_string = re.sub(r'^```json\s*|\s*```$', '', json_string, flags=re.MULTILINE).strip()
138
-
139
- return {"jsonString": cleaned_json_string}
140
-
141
- except Exception as e:
142
- print(f"Ошибка вызова Gemini API: {e}")
143
- raise HTTPException(status_code=500, detail=f"Ошибка генерации AI: {str(e)}")
144
-
145
- # --- Настройки для развертывания на Hugging Face Spaces/Docker ---
146
- # PORT=7860 устанавливается Hugging Face при запуске контейнера
147
- IS_HUGGINGFACE_SPACE = os.environ.get("PORT") == "7860"
148
-
149
- if IS_HUGGINGFACE_SPACE:
150
-
151
- # Монтируем статические файлы (React build)
152
- app.mount("/assets", StaticFiles(directory="/app/dist/assets"), name="assets")
153
-
154
- @app.get("/{full_path:path}")
155
- async def serve_react_app(full_path: str):
156
- # Обслуживаем index.html для всех non-API маршрутов
157
- return FileResponse("/app/dist/index.html")
158
-
159
- else:
160
- # При локальной разработке (Vite) FastAPI отвечает ТОЛЬКО за API.
161
- # Статику раздает Vite (порт 3000).
162
- print("ℹ️ Режим локальной разработки. Статические файлы обслуживаются Vite.")
163
-
164
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/components/AiPrompt.tsx DELETED
@@ -1,52 +0,0 @@
1
-
2
- import React from 'react';
3
- import Card from './ui/Card';
4
- import Textarea from './ui/Textarea';
5
- import Button from './ui/Button';
6
- import Label from './ui/Label';
7
-
8
- interface AiPromptProps {
9
- prompt: string;
10
- setPrompt: (value: string) => void;
11
- onGenerate: () => void;
12
- isLoading: boolean;
13
- error: string | null;
14
- }
15
-
16
- const AiPrompt: React.FC<AiPromptProps> = ({ prompt, setPrompt, onGenerate, isLoading, error }) => {
17
- return (
18
- <Card className="mb-8 border-sky-500 border-2 shadow-lg shadow-sky-500/10">
19
- <h2 className="text-2xl font-bold mb-4 text-sky-400">
20
- ✨ Создание с помощью AI
21
- </h2>
22
- <p className="text-gray-400 mb-4 text-sm">
23
- Опишите инструмент, который вы хотите создать, на естественном языке. AI проанализирует ваш запрос и автоматически заполнит форму ниже.
24
- </p>
25
-
26
- <div>
27
- <Label htmlFor="ai-prompt">Ваш запрос:</Label>
28
- <Textarea
29
- id="ai-prompt"
30
- value={prompt}
31
- onChange={(e) => setPrompt(e.target.value)}
32
- placeholder="Например: 'Инструмент для получения текущей погоды в городе' или 'Утилита для работы с файлами: чтение, запись и удаление'"
33
- rows={3}
34
- disabled={isLoading}
35
- />
36
- </div>
37
-
38
- <div className="mt-4 flex items-center justify-between">
39
- <Button onClick={onGenerate} disabled={isLoading}>
40
- {isLoading ? 'Генерация...' : 'Сгенерировать'}
41
- </Button>
42
- {error && <p className="text-red-400 text-sm ml-4">{error}</p>}
43
- </div>
44
- </Card>
45
- );
46
- };
47
-
48
- export default AiPrompt;
49
-
50
-
51
-
52
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/components/CodeOutput.tsx DELETED
@@ -1,340 +0,0 @@
1
- import React, { useState } from 'react';
2
-
3
- import { GeneratedCode } from '../types';
4
-
5
- import JSZip from 'jszip'; // Импортируем JSZip из npm
6
-
7
-
8
-
9
- interface CodeOutputProps {
10
-
11
- generatedCode: GeneratedCode | null;
12
-
13
- toolName: string;
14
-
15
- }
16
-
17
-
18
-
19
- type Tab = 'setup.py' | 'server.py' | '.gemini/settings.json' | 'GEMINI.md' | 'Инструкция' | 'Примеры';
20
-
21
-
22
-
23
- const CodeOutput: React.FC<CodeOutputProps> = ({ generatedCode, toolName }) => {
24
-
25
- const [activeTab, setActiveTab] = useState<Tab>('Примеры');
26
-
27
- const [copiedTab, setCopiedTab] = useState<Tab | null>(null);
28
-
29
-
30
-
31
- const handleCopy = (content: string, tab: Tab) => {
32
-
33
- navigator.clipboard.writeText(content);
34
-
35
- setCopiedTab(tab);
36
-
37
- setTimeout(() => setCopiedTab(null), 2000);
38
-
39
- };
40
-
41
-
42
-
43
- const handleDownloadZip = () => {
44
-
45
- if (!generatedCode || !toolName) return;
46
-
47
-
48
-
49
- const zip = new JSZip(); // Теперь JSZip импортирован
50
-
51
- const rootFolder = zip.folder(toolName);
52
-
53
- if (!rootFolder) return;
54
-
55
-
56
-
57
- rootFolder.file('setup.py', generatedCode.setupPy);
58
-
59
- rootFolder.file('server.py', generatedCode.serverPy);
60
-
61
- rootFolder.file('GEMINI.md', generatedCode.geminiMd);
62
-
63
-
64
-
65
- const geminiFolder = rootFolder.folder('.gemini');
66
-
67
- if (geminiFolder) {
68
-
69
- geminiFolder.file('settings.json', generatedCode.settingsJson);
70
-
71
- }
72
-
73
-
74
-
75
- zip.generateAsync({ type: 'blob' }).then(content => {
76
-
77
- const link = document.createElement('a');
78
-
79
- link.href = URL.createObjectURL(content);
80
-
81
- link.download = `${toolName}.zip`;
82
-
83
- document.body.appendChild(link);
84
-
85
- link.click();
86
-
87
- document.body.removeChild(link);
88
-
89
- });
90
-
91
- };
92
-
93
-
94
-
95
- const tabs: Tab[] = ['Примеры', 'GEMINI.md', 'server.py', 'setup.py', '.gemini/settings.json', 'Инструкция'];
96
-
97
-
98
-
99
- const getContentForTab = (tab: Tab): string => {
100
-
101
- if (!generatedCode) return "Сгенерируйте код, заполнив форму слева.";
102
-
103
- switch (tab) {
104
-
105
- case 'setup.py': return generatedCode.setupPy;
106
-
107
- case 'server.py': return generatedCode.serverPy;
108
-
109
- case '.gemini/settings.json': return generatedCode.settingsJson;
110
-
111
- case 'GEMINI.md': return generatedCode.geminiMd;
112
-
113
- case 'Примеры': return generatedCode.examplesMd;
114
-
115
- case 'Инструкция': return getInstructions(toolName, generatedCode);
116
-
117
- default: return '';
118
-
119
- }
120
-
121
- };
122
-
123
-
124
-
125
- const getLanguageForTab = (tab: Tab): string => {
126
-
127
- switch(tab) {
128
-
129
- case 'setup.py':
130
-
131
- case 'server.py':
132
-
133
- return 'python';
134
-
135
- case '.gemini/settings.json':
136
-
137
- return 'json';
138
-
139
- case 'GEMINI.md':
140
-
141
- case 'Инструкция':
142
-
143
- case 'Примеры':
144
-
145
- return 'markdown';
146
-
147
- default:
148
-
149
- return 'plaintext';
150
-
151
- }
152
-
153
- }
154
-
155
-
156
-
157
- const getInstructions = (toolName: string, code: GeneratedCode): string => {
158
-
159
- const primaryFunctionMatch = code.serverPy?.match(/def\s+([a-zA-Z0-9_]+)\(/);
160
-
161
- const primaryFunction = primaryFunctionMatch && primaryFunctionMatch[1] ? primaryFunctionMatch[1] : 'your_function';
162
-
163
-
164
-
165
- return `
166
-
167
- # Набор Инструкций для Создания Нового Инструмента
168
-
169
-
170
-
171
- ## 1. 📂 Структура проекта
172
-
173
- Создайте следующую структуру папок и файлов (или просто нажмите "Скачать .zip"):
174
-
175
-
176
-
177
- ${toolName}/
178
-
179
- ├── .gemini/
180
-
181
- │ └── settings.json
182
-
183
- ├── GEMINI.md
184
-
185
- ├── setup.py
186
-
187
- └── server.py
188
-
189
-
190
-
191
- ## 2. 🐍 Содержимое файлов
192
-
193
- Скопируйте содержимое из соответствующих вкладок в созданные файлы.
194
-
195
-
196
-
197
- ## 3. 📦 Установка и запуск
198
-
199
- Откройте терминал в папке \`${toolName}\` и выполните:
200
-
201
-
202
-
203
- \`\`\`bash
204
-
205
- # Установка зависимостей и инструмента в режиме разработки
206
-
207
- pip install -e .
208
-
209
-
210
-
211
- # Запуск инструмента (Gemini CLI сделает это автоматически)
212
-
213
- # Для ручной проверки можно запустить:
214
-
215
- python server.py
216
-
217
- \`\`\`
218
-
219
-
220
-
221
- ## 4. 🚀 Использование в Gemini CLI
222
-
223
- После установки Gemini CLI автоматически обнаружит ваш инструмент.
224
-
225
- См. вкладку "Примеры", чтобы увидеть, как ваши запросы на естественном языке будут превращаться в вызовы функций.
226
-
227
-
228
-
229
- ### ⚠️ Правило вызова
230
-
231
- \`\`\`
232
-
233
- ${toolName}:${primaryFunction}
234
-
235
- \`\`\`
236
-
237
- `;
238
-
239
- };
240
-
241
-
242
-
243
- return (
244
-
245
- <div className="bg-gray-800/50 border border-gray-700 rounded-lg overflow-hidden h-full flex flex-col">
246
-
247
- <div className="flex-shrink-0 bg-gray-900/70 border-b border-gray-700 flex justify-between items-center pr-2">
248
-
249
- <nav className="flex space-x-1 p-1" aria-label="Tabs">
250
-
251
- {tabs.map(tab => (
252
-
253
- <button
254
-
255
- key={tab}
256
-
257
- onClick={() => setActiveTab(tab)}
258
-
259
- className={`whitespace-nowrap px-3 py-2 text-sm font-medium rounded-md transition ${
260
-
261
- activeTab === tab
262
-
263
- ? 'bg-sky-600 text-white'
264
-
265
- : 'text-gray-400 hover:bg-gray-700 hover:text-gray-200'
266
-
267
- }`}
268
-
269
- >
270
-
271
- {tab}
272
-
273
- </button>
274
-
275
- ))}
276
-
277
- </nav>
278
-
279
- {generatedCode && (
280
-
281
- <button
282
-
283
- onClick={handleDownloadZip}
284
-
285
- className="bg-sky-600 hover:bg-sky-500 text-white px-3 py-1.5 rounded-md text-xs font-semibold transition disabled:opacity-50"
286
-
287
- disabled={!generatedCode}
288
-
289
- >
290
-
291
- Скачать .zip
292
-
293
- </button>
294
-
295
- )}
296
-
297
- </div>
298
-
299
- <div className="relative flex-grow min-h-0">
300
-
301
- <pre className="h-full overflow-auto p-4 text-sm font-mono bg-gray-800">
302
-
303
- <code className={`language-${getLanguageForTab(activeTab)}`}>
304
-
305
- {getContentForTab(activeTab)}
306
-
307
- </code>
308
-
309
- </pre>
310
-
311
- {activeTab !== 'Инструкция' && generatedCode && (
312
-
313
- <button
314
-
315
- onClick={() => handleCopy(getContentForTab(activeTab), activeTab)}
316
-
317
- className="absolute top-4 right-4 bg-gray-700 hover:bg-gray-600 text-gray-200 px-3 py-1 rounded-md text-xs transition"
318
-
319
- >
320
-
321
- {copiedTab === activeTab ? 'Скопировано!' : 'Копировать'}
322
-
323
- </button>
324
-
325
- )}
326
-
327
- </div>
328
-
329
- </div>
330
-
331
- );
332
-
333
- };
334
-
335
-
336
-
337
- export default CodeOutput;
338
-
339
-
340
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/components/FunctionEditor.tsx DELETED
@@ -1,146 +0,0 @@
1
-
2
- import React from 'react';
3
- import { FunctionDefinition, ParameterDefinition, ParameterType } from '../types';
4
- import { PARAMETER_TYPES, PARAMETER_TYPE_DESCRIPTIONS } from '../constants';
5
- import Input from './ui/Input';
6
- import Textarea from './ui/Textarea';
7
- import Select from './ui/Select';
8
- import Label from './ui/Label';
9
- import Button from './ui/Button';
10
- import Card from './ui/Card';
11
-
12
- interface FunctionEditorProps {
13
- func: FunctionDefinition;
14
- updateFunction: (func: FunctionDefinition) => void;
15
- removeFunction: () => void;
16
- isOnlyFunction: boolean;
17
- }
18
-
19
- const ParameterRow: React.FC<{
20
- param: ParameterDefinition;
21
- updateParameter: (param: ParameterDefinition) => void;
22
- removeParameter: () => void;
23
- }> = ({ param, updateParameter, removeParameter }) => {
24
-
25
- const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
26
- const { name, value, type } = e.target;
27
- const isCheckbox = type === 'checkbox';
28
- const checked = isCheckbox ? (e.target as HTMLInputElement).checked : undefined;
29
-
30
- updateParameter({
31
- ...param,
32
- [name]: isCheckbox ? checked : value
33
- });
34
- };
35
-
36
- return (
37
- <div className="grid grid-cols-1 md:grid-cols-[1fr,1fr,2fr,auto,auto] gap-2 items-center p-2 bg-gray-900/50 rounded">
38
- <Input name="name" value={param.name} onChange={handleChange} placeholder="Имя параметра" />
39
- <div>
40
- <Select name="type" value={param.type} onChange={handleChange}>
41
- {PARAMETER_TYPES.map(t => <option key={t} value={t} title={PARAMETER_TYPE_DESCRIPTIONS[t]}>{t}</option>)}
42
- </Select>
43
- <p className="text-xs text-gray-400 mt-1 pl-1">{PARAMETER_TYPE_DESCRIPTIONS[param.type]}</p>
44
- </div>
45
- <Input name="description" value={param.description} onChange={handleChange} placeholder="Описание" />
46
- <label className="flex items-center space-x-2 text-sm text-gray-300 justify-center">
47
- <input type="checkbox" name="required" checked={param.required} onChange={handleChange} className="rounded bg-gray-700 border-gray-600 text-sky-500 focus:ring-sky-500"/>
48
- <span>Req.</span>
49
- </label>
50
- <Button onClick={removeParameter} variant="danger" className="px-2 py-1 text-xs">X</Button>
51
- </div>
52
- );
53
- };
54
-
55
-
56
- const FunctionEditor: React.FC<FunctionEditorProps> = ({ func, updateFunction, removeFunction, isOnlyFunction }) => {
57
- const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
58
- updateFunction({ ...func, [e.target.name]: e.target.value });
59
- };
60
-
61
- const addParameter = () => {
62
- const newParam: ParameterDefinition = {
63
- id: crypto.randomUUID(),
64
- name: `param_${func.parameters.length + 1}`,
65
- type: ParameterType.STRING,
66
- description: '',
67
- required: true
68
- };
69
- updateFunction({ ...func, parameters: [...func.parameters, newParam] });
70
- };
71
-
72
- const updateParameter = (updatedParam: ParameterDefinition) => {
73
- updateFunction({
74
- ...func,
75
- parameters: func.parameters.map(p => p.id === updatedParam.id ? updatedParam : p)
76
- });
77
- };
78
-
79
- const removeParameter = (id: string) => {
80
- updateFunction({
81
- ...func,
82
- parameters: func.parameters.filter(p => p.id !== id)
83
- });
84
- };
85
-
86
- return (
87
- <Card>
88
- <div className="flex justify-between items-start mb-4">
89
- <div className="flex-grow">
90
- <Label htmlFor={`func-name-${func.id}`}>Имя функции</Label>
91
- <Input id={`func-name-${func.id}`} name="name" value={func.name} onChange={handleInputChange} />
92
- </div>
93
- <Button onClick={removeFunction} variant="danger" disabled={isOnlyFunction} className="ml-4 mt-6">
94
- Удалить функцию
95
- </Button>
96
- </div>
97
-
98
- <div>
99
- <Label htmlFor={`func-desc-${func.id}`}>Описание функции</Label>
100
- <Textarea id={`func-desc-${func.id}`} name="description" value={func.description} onChange={handleInputChange} />
101
- </div>
102
-
103
- <div className="mt-4">
104
- <h4 className="font-semibold text-gray-300 mb-2">Параметры</h4>
105
- <div className="flex flex-col gap-2">
106
- {func.parameters.length > 0 && (
107
- <div className="hidden md:grid md:grid-cols-[1fr,1fr,2fr,auto,auto] gap-2 text-xs text-gray-400 px-2">
108
- <span>Имя</span>
109
- <span>РўРёРї</span>
110
- <span>Описание</span>
111
- <span className="text-center">РћР±СЏР·.</span>
112
- </div>
113
- )}
114
- {func.parameters.map((param) => (
115
- <ParameterRow
116
- key={param.id}
117
- param={param}
118
- updateParameter={updateParameter}
119
- removeParameter={() => removeParameter(param.id)}
120
- />
121
- ))}
122
- </div>
123
- <Button onClick={addParameter} variant="secondary" className="mt-3 text-xs">+ Добавить параметр</Button>
124
- </div>
125
-
126
- <div className="mt-4 grid grid-cols-1 md:grid-cols-2 gap-4">
127
- <div>
128
- <Label htmlFor={`func-return-type-${func.id}`}>Тип возвращаемого значения</Label>
129
- <Select id={`func-return-type-${func.id}`} name="returnType" value={func.returnType} onChange={handleInputChange}>
130
- {PARAMETER_TYPES.map(t => <option key={t} value={t}>{t}</option>)}
131
- </Select>
132
- </div>
133
- <div>
134
- <Label htmlFor={`func-return-desc-${func.id}`}>Описание возвращаемого значения</Label>
135
- <Input id={`func-return-desc-${func.id}`} name="returnDescription" value={func.returnDescription} onChange={handleInputChange} />
136
- </div>
137
- </div>
138
- </Card>
139
- );
140
- };
141
-
142
- export default FunctionEditor;
143
-
144
-
145
-
146
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/components/ToolForm.tsx DELETED
@@ -1,115 +0,0 @@
1
-
2
- import React from 'react';
3
- import { ToolDefinition, FunctionDefinition, ToolType, ParameterType } from '../types';
4
- import { TOOL_TYPES } from '../constants';
5
- import FunctionEditor from './FunctionEditor';
6
- import Input from './ui/Input';
7
- import Select from './ui/Select';
8
- import Label from './ui/Label';
9
- import Button from './ui/Button';
10
- import Card from './ui/Card';
11
-
12
- interface ToolFormProps {
13
- toolDefinition: ToolDefinition;
14
- setToolDefinition: React.Dispatch<React.SetStateAction<ToolDefinition>>;
15
- }
16
-
17
- const ToolForm: React.FC<ToolFormProps> = ({ toolDefinition, setToolDefinition }) => {
18
- const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
19
- const { name, value } = e.target;
20
- setToolDefinition(prev => ({ ...prev, [name]: value }));
21
- };
22
-
23
- const addFunction = () => {
24
- const newFunction: FunctionDefinition = {
25
- id: crypto.randomUUID(),
26
- name: `new_function_${toolDefinition.functions.length + 1}`,
27
- description: 'Описание новой функции.',
28
- parameters: [],
29
- returnType: ParameterType.STRING,
30
- returnDescription: 'Описание возвращаемого значения.'
31
- };
32
- setToolDefinition(prev => ({
33
- ...prev,
34
- functions: [...prev.functions, newFunction]
35
- }));
36
- };
37
-
38
- const updateFunction = (updatedFunction: FunctionDefinition) => {
39
- setToolDefinition(prev => ({
40
- ...prev,
41
- functions: prev.functions.map(fn => fn.id === updatedFunction.id ? updatedFunction : fn)
42
- }));
43
- };
44
-
45
- const removeFunction = (id: string) => {
46
- setToolDefinition(prev => ({
47
- ...prev,
48
- functions: prev.functions.filter(fn => fn.id !== id)
49
- }));
50
- };
51
-
52
- return (
53
- <div className="flex flex-col gap-6">
54
- <Card>
55
- <h2 className="text-2xl font-bold mb-4 text-sky-400">1. Конфигурация инструмента</h2>
56
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
57
- <div>
58
- <Label htmlFor="name">Название инструмента (Tool Name)</Label>
59
- <Input
60
- id="name"
61
- name="name"
62
- value={toolDefinition.name}
63
- onChange={handleInputChange}
64
- placeholder="e.g., web_scraper"
65
- />
66
- </div>
67
- <div>
68
- <Label htmlFor="type">Тип инструмента (Tool Type)</Label>
69
- <Select id="type" name="type" value={toolDefinition.type} onChange={handleInputChange}>
70
- {TOOL_TYPES.map(type => (
71
- <option key={type} value={type}>{type}</option>
72
- ))}
73
- </Select>
74
- </div>
75
- <div className="md:col-span-2">
76
- <Label htmlFor="dependencies">Зависимости (Dependencies)</Label>
77
- <Input
78
- id="dependencies"
79
- name="dependencies"
80
- value={toolDefinition.dependencies}
81
- onChange={handleInputChange}
82
- placeholder="e.g., requests, beautifulsoup4"
83
- />
84
- <p className="text-xs text-gray-500 mt-1">Перечислите через запятую или пробел.</p>
85
- </div>
86
- </div>
87
- </Card>
88
-
89
- <div className="flex flex-col gap-6">
90
- <h2 className="text-2xl font-bold text-sky-400">2. Функции</h2>
91
- {toolDefinition.functions.map((func, index) => (
92
- <FunctionEditor
93
- key={func.id}
94
- func={func}
95
- updateFunction={updateFunction}
96
- removeFunction={() => removeFunction(func.id)}
97
- isOnlyFunction={toolDefinition.functions.length === 1}
98
- />
99
- ))}
100
- </div>
101
-
102
- <div className="mt-2">
103
- <Button onClick={addFunction} variant="secondary">
104
- + Добавить функцию
105
- </Button>
106
- </div>
107
- </div>
108
- );
109
- };
110
-
111
- export default ToolForm;
112
-
113
-
114
-
115
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/components/ui/Button.tsx DELETED
@@ -1,28 +0,0 @@
1
-
2
- import React from 'react';
3
-
4
- interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
5
- variant?: 'primary' | 'secondary' | 'danger';
6
- }
7
-
8
- const Button: React.FC<ButtonProps> = ({ variant = 'primary', className, children, ...props }) => {
9
- const baseClasses = "px-4 py-2 rounded-md font-semibold text-sm transition-all focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 disabled:opacity-50 disabled:cursor-not-allowed";
10
-
11
- const variantClasses = {
12
- primary: 'bg-sky-600 text-white hover:bg-sky-500 focus:ring-sky-500',
13
- secondary: 'bg-gray-700 text-gray-200 hover:bg-gray-600 focus:ring-gray-500',
14
- danger: 'bg-red-600 text-white hover:bg-red-500 focus:ring-red-500',
15
- };
16
-
17
- return (
18
- <button className={`${baseClasses} ${variantClasses[variant]} ${className}`} {...props}>
19
- {children}
20
- </button>
21
- );
22
- };
23
-
24
- export default Button;
25
-
26
-
27
-
28
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/components/ui/Card.tsx DELETED
@@ -1,21 +0,0 @@
1
-
2
- import React from 'react';
3
-
4
- interface CardProps {
5
- children: React.ReactNode;
6
- className?: string;
7
- }
8
-
9
- const Card: React.FC<CardProps> = ({ children, className }) => {
10
- return (
11
- <div className={`bg-gray-800/50 border border-gray-700 rounded-lg p-6 ${className}`}>
12
- {children}
13
- </div>
14
- );
15
- };
16
-
17
- export default Card;
18
-
19
-
20
-
21
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/components/ui/Input.tsx DELETED
@@ -1,19 +0,0 @@
1
-
2
- import React from 'react';
3
-
4
- type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
5
-
6
- const Input: React.FC<InputProps> = (props) => {
7
- return (
8
- <input
9
- {...props}
10
- className="w-full bg-gray-800 border border-gray-600 rounded-md px-3 py-2 text-gray-200 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-sky-500 transition"
11
- />
12
- );
13
- };
14
-
15
- export default Input;
16
-
17
-
18
-
19
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/components/ui/Label.tsx DELETED
@@ -1,16 +0,0 @@
1
-
2
- import React from 'react';
3
-
4
- type LabelProps = React.LabelHTMLAttributes<HTMLLabelElement>;
5
-
6
- const Label: React.FC<LabelProps> = (props) => {
7
- return (
8
- <label {...props} className="block text-sm font-medium text-gray-300 mb-1" />
9
- );
10
- };
11
-
12
- export default Label;
13
-
14
-
15
-
16
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/components/ui/Select.tsx DELETED
@@ -1,28 +0,0 @@
1
-
2
- import React from 'react';
3
-
4
- type SelectProps = React.SelectHTMLAttributes<HTMLSelectElement>;
5
-
6
- const Select: React.FC<SelectProps> = (props) => {
7
- return (
8
- <select
9
- {...props}
10
- className="w-full bg-gray-800 border border-gray-600 rounded-md px-3 py-2 text-gray-200 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-sky-500 transition appearance-none"
11
- style={{
12
- backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`,
13
- backgroundPosition: 'right 0.5rem center',
14
- backgroundRepeat: 'no-repeat',
15
- backgroundSize: '1.5em 1.5em',
16
- paddingRight: '2.5rem',
17
- }}
18
- >
19
- {props.children}
20
- </select>
21
- );
22
- };
23
-
24
- export default Select;
25
-
26
-
27
-
28
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/components/ui/Textarea.tsx DELETED
@@ -1,20 +0,0 @@
1
-
2
- import React from 'react';
3
-
4
- type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
5
-
6
- const Textarea: React.FC<TextareaProps> = (props) => {
7
- return (
8
- <textarea
9
- {...props}
10
- className="w-full bg-gray-800 border border-gray-600 rounded-md px-3 py-2 text-gray-200 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-sky-500 transition"
11
- rows={2}
12
- />
13
- );
14
- };
15
-
16
- export default Textarea;
17
-
18
-
19
-
20
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/constants.ts DELETED
@@ -1,18 +0,0 @@
1
-
2
- import { ToolType, ParameterType } from './types';
3
-
4
- export const TOOL_TYPES: ToolType[] = Object.values(ToolType);
5
- export const PARAMETER_TYPES: ParameterType[] = Object.values(ParameterType);
6
-
7
- export const PARAMETER_TYPE_DESCRIPTIONS: Record<ParameterType, string> = {
8
- [ParameterType.STRING]: 'Текстовая строка (e.g., "hello world").',
9
- [ParameterType.INTEGER]: 'Целое число (e.g., 10, -5).',
10
- [ParameterType.FLOAT]: 'Число с плавающей точкой (e.g., 3.14).',
11
- [ParameterType.BOOLEAN]: 'Логическое значение (True или False).',
12
- [ParameterType.LIST]: 'Упорядоченный список элементов (e.g., ["a", "b"]).',
13
- [ParameterType.DICTIONARY]: 'Словарь пар ключ-значение (e.g., {"key": "value"}).'
14
- };
15
-
16
-
17
-
18
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/dist/assets/index-CjZgBbLF.js DELETED
The diff for this file is too large to render. See raw diff
 
FastMCPToolGenerator/dist/index.html DELETED
@@ -1,46 +0,0 @@
1
-
2
- <!DOCTYPE html>
3
- <html lang="en">
4
- <head>
5
- <meta charset="UTF-8" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>FastMCP Tool Generator</title>
8
- <script src="https://cdn.tailwindcss.com"></script>
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
10
- <style>
11
- /* Custom scrollbar for webkit browsers */
12
- ::-webkit-scrollbar {
13
- width: 8px;
14
- height: 8px;
15
- }
16
- ::-webkit-scrollbar-track {
17
- background: #1f2937; /* bg-gray-800 */
18
- }
19
- ::-webkit-scrollbar-thumb {
20
- background: #4b5563; /* bg-gray-600 */
21
- border-radius: 4px;
22
- }
23
- ::-webkit-scrollbar-thumb:hover {
24
- background: #6b7280; /* bg-gray-500 */
25
- }
26
- </style>
27
-
28
- <link rel="stylesheet" href="/index.css">
29
- <script type="importmap">
30
- {
31
- "imports": {
32
- "react": "https://aistudiocdn.com/react@^19.2.0",
33
- "react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
34
- "react/": "https://aistudiocdn.com/react@^19.2.0/",
35
- "@google/genai": "https://aistudiocdn.com/@google/genai@^1.29.0"
36
- }
37
- }
38
- </script>
39
- <script type="module" crossorigin src="/assets/index-CjZgBbLF.js"></script>
40
- </head>
41
- <body class="bg-gray-900 text-gray-100">
42
- <div id="root"></div>
43
- </body>
44
- </html>
45
-
46
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/examples.ts DELETED
@@ -1,60 +0,0 @@
1
-
2
- import { ToolDefinition, ToolType, ParameterType } from './types';
3
-
4
- export const nmapScannerExample: ToolDefinition = {
5
- name: 'nmap_scanner',
6
- type: ToolType.UTILITY,
7
- dependencies: 'python-nmap',
8
- functions: [
9
- {
10
- id: 'nmap-func-1',
11
- name: 'run_scan',
12
- description: 'Запускает сканирование Nmap на указанные цели с заданными аргументами. Позволяет выполнять гибкую разведку сети.',
13
- parameters: [
14
- {
15
- id: 'nmap-param-1',
16
- name: 'targets',
17
- type: ParameterType.STRING,
18
- description: "Цели для сканирования (IP, домен, CIDR). Например: '192.168.1.1', 'scanme.nmap.org', '10.0.0.0/24'.",
19
- required: true,
20
- },
21
- {
22
- id: 'nmap-param-2',
23
- name: 'ports',
24
- type: ParameterType.STRING,
25
- description: "Порты для сканирования. Например: '21-25,80,443,8080'.",
26
- required: true,
27
- },
28
- {
29
- id: 'nmap-param-3',
30
- name: 'arguments',
31
- type: ParameterType.STRING,
32
- description: "Дополнительные аргументы Nmap для тонкой настройки сканирования. Например: '-sV -sC -O'.",
33
- required: true,
34
- },
35
- ],
36
- returnType: ParameterType.DICTIONARY,
37
- returnDescription: 'Результат сканирования в формате JSON, содержащий информацию о хостах, портах, службах и их версиях.',
38
- },
39
- {
40
- id: 'nmap-func-2',
41
- name: 'host_discovery',
42
- description: 'Обнаруживает активные хосты в указанной сети (ping scan), не проводя сканирование портов.',
43
- parameters: [
44
- {
45
- id: 'nmap-param-4',
46
- name: 'network_cidr',
47
- type: ParameterType.STRING,
48
- description: "Сетевой диапазон в формате CIDR для обнаружения хостов. Например: '192.168.1.0/24'.",
49
- required: true,
50
- },
51
- ],
52
- returnType: ParameterType.LIST,
53
- returnDescription: 'Список IP-адресов активных хостов, обнаруженных в сети.',
54
- },
55
- ],
56
- };
57
-
58
-
59
-
60
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/index.html DELETED
@@ -1,45 +0,0 @@
1
- 
2
- <!DOCTYPE html>
3
- <html lang="en">
4
- <head>
5
- <meta charset="UTF-8" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>FastMCP Tool Generator</title>
8
- <script src="https://cdn.tailwindcss.com"></script>
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
10
- <style>
11
- /* Custom scrollbar for webkit browsers */
12
- ::-webkit-scrollbar {
13
- width: 8px;
14
- height: 8px;
15
- }
16
- ::-webkit-scrollbar-track {
17
- background: #1f2937; /* bg-gray-800 */
18
- }
19
- ::-webkit-scrollbar-thumb {
20
- background: #4b5563; /* bg-gray-600 */
21
- border-radius: 4px;
22
- }
23
- ::-webkit-scrollbar-thumb:hover {
24
- background: #6b7280; /* bg-gray-500 */
25
- }
26
- </style>
27
- <script type="importmap">
28
- {
29
- "imports": {
30
- "react": "https://aistudiocdn.com/react@^19.2.0",
31
- "react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
32
- "react/": "https://aistudiocdn.com/react@^19.2.0/",
33
- "@google/genai": "https://aistudiocdn.com/@google/genai@^1.29.0"
34
- }
35
- }
36
- </script>
37
- <link rel="stylesheet" href="/index.css">
38
- </head>
39
- <body class="bg-gray-900 text-gray-100">
40
- <div id="root"></div>
41
- <script type="module" src="/index.tsx"></script>
42
- </body>
43
- </html>
44
-
45
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/index.tsx DELETED
@@ -1,20 +0,0 @@
1
-
2
- import React from 'react';
3
- import ReactDOM from 'react-dom/client';
4
- import App from './App';
5
-
6
- const rootElement = document.getElementById('root');
7
- if (!rootElement) {
8
- throw new Error("Could not find root element to mount to");
9
- }
10
-
11
- const root = ReactDOM.createRoot(rootElement);
12
- root.render(
13
- <React.StrictMode>
14
- <App />
15
- </React.StrictMode>
16
- );
17
-
18
-
19
-
20
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/metadata.json DELETED
@@ -1,7 +0,0 @@
1
- {
2
- "name": "Copy of Copy of Copy of FastMCP Tool Generator",
3
- "description": "A web application to generate complete, self-contained, and deployable FastMCP tool boilerplates for Gemini CLI based on user's technical requirements. It creates all necessary files including server logic, setup configuration, and agent instructions.",
4
- "requestFramePermissions": []
5
- }
6
-
7
-
 
 
 
 
 
 
 
 
FastMCPToolGenerator/package-lock.json DELETED
The diff for this file is too large to render. See raw diff
 
FastMCPToolGenerator/package.json DELETED
@@ -1,42 +0,0 @@
1
-
2
- {
3
- "name": "fastmcp-tool-generator-hf",
4
- "version": "0.0.0",
5
- "private": true,
6
- "scripts": {
7
- "dev": "vite",
8
- "build": "tsc && vite build",
9
- "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10
- "preview": "vite preview"
11
- },
12
- "dependencies": {
13
- "autoprefixer": "^10.4.19",
14
- "axios": "^1.7.2",
15
- "highlight.js": "^11.9.0",
16
- "jszip": "^3.10.1",
17
- "postcss": "^8.4.38",
18
- "react": "^18.2.0",
19
- "react-dom": "^18.2.0",
20
- "react-hot-toast": "^2.4.1",
21
- "tailwindcss": "^3.4.4"
22
- },
23
- "devDependencies": {
24
- "@types/highlight.js": "^10.1.0",
25
- "@types/jszip": "^3.10.1",
26
- "@types/react": "^18.2.66",
27
- "@types/react-dom": "^18.2.22",
28
- "@typescript-eslint/eslint-plugin": "^7.2.0",
29
- "@typescript-eslint/parser": "^7.2.0",
30
- "@vitejs/plugin-react": "^4.2.1",
31
- "eslint": "^8.57.0",
32
- "eslint-plugin-react-hooks": "^4.6.0",
33
- "eslint-plugin-react-refresh": "^0.4.6",
34
- "typescript": "^5.2.2",
35
- "vite": "^5.2.0"
36
- }
37
- }
38
-
39
-
40
-
41
-
42
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/requirements.txt DELETED
@@ -1,11 +0,0 @@
1
- 
2
- fastapi
3
-
4
- uvicorn[standard]
5
-
6
- google-generativeai
7
-
8
- pydantic
9
-
10
- python-dotenv
11
-
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/services/aiService.ts DELETED
@@ -1,71 +0,0 @@
1
-
2
- import { ToolDefinition, FunctionDefinition } from '../types';
3
-
4
-
5
-
6
- export async function generateToolDefinitionFromPrompt(prompt: string): Promise<string> {
7
-
8
- console.log("Отправка запроса на бэкенд /api/generate...");
9
-
10
-
11
-
12
- try {
13
-
14
- const response = await fetch('/api/generate', {
15
-
16
- method: 'POST',
17
-
18
- headers: {
19
-
20
- 'Content-Type': 'application/json',
21
-
22
- },
23
-
24
- body: JSON.stringify({ prompt: prompt }),
25
-
26
- });
27
-
28
-
29
-
30
- if (!response.ok) {
31
-
32
- const errorData = await response.json();
33
-
34
- throw new Error(errorData.detail || `HTTP error! status: ${response.status}`);
35
-
36
- }
37
-
38
-
39
-
40
- const data = await response.json();
41
-
42
-
43
-
44
- // Бэкенд теперь возвращает объект { jsonString: "..." }
45
-
46
- if (typeof data.jsonString !== 'string') {
47
-
48
- throw new Error("Бэкенд вернул неверный формат ответа.");
49
-
50
- }
51
-
52
-
53
-
54
- return data.jsonString;
55
-
56
-
57
-
58
- } catch (error) {
59
-
60
- console.error("Ошибка при вызове бэкенда /api/generate:", error);
61
-
62
- throw new Error(`Не удалось связаться с сервером: ${error.message}`);
63
-
64
- }
65
-
66
- }
67
-
68
-
69
-
70
-
71
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/services/codeGenerator.ts DELETED
@@ -1,428 +0,0 @@
1
-
2
- import { ToolDefinition, FunctionDefinition, ParameterDefinition, ParameterType, GeneratedCode } from '../types';
3
-
4
- const toPythonType = (type: ParameterType): string => {
5
- const mapping: Record<ParameterType, string> = {
6
- [ParameterType.STRING]: 'str',
7
- [ParameterType.INTEGER]: 'int',
8
- [ParameterType.FLOAT]: 'float',
9
- [ParameterType.BOOLEAN]: 'bool',
10
- [ParameterType.LIST]: 'list',
11
- [ParameterType.DICTIONARY]: 'dict',
12
- };
13
- return mapping[type] || 'Any';
14
- };
15
-
16
- const generateSetupPy = (def: ToolDefinition): string => {
17
- const dependencies = def.dependencies.split(/[\s,]+/).filter(Boolean);
18
- const installRequires = dependencies.length > 0
19
- ? `install_requires=${JSON.stringify(dependencies)},`
20
- : '';
21
-
22
- return `
23
- from setuptools import setup, find_packages
24
-
25
- setup(
26
- name='${def.name}',
27
- version='0.1.0',
28
- packages=find_packages(),
29
- ${installRequires}
30
- entry_points={
31
- 'gemini_tools': [
32
- '${def.name} = server:main',
33
- ],
34
- },
35
- )
36
- `.trim();
37
- };
38
-
39
- const generateServerPy = (def: ToolDefinition): string => {
40
- const functionStrings = def.functions.map(func => generateFunction(def, func)).join('\n\n');
41
- const imports = def.name === 'nmap_scanner' ? 'import nmap' : '# TODO: Добавьте необходимые импорты';
42
-
43
- return `
44
- # -*- coding: utf-8 -*-
45
- import sys
46
- import json
47
- from typing import Any, Dict, List
48
-
49
- # =====================================================================================
50
- # ⚠️ Важно: Этот код сгенерирован автоматически.
51
- # Внесите свои изменения в секцию "Реализация функций"
52
- # =====================================================================================
53
-
54
- # =====================================================================================
55
- # Секция: Импорты
56
- # =====================================================================================
57
- ${imports}
58
-
59
-
60
- # =====================================================================================
61
- # Секция: Реализация функций
62
- # =====================================================================================
63
- # TODO: Добавьте здесь вашу бизнес-логику для каждой функции.
64
-
65
- ${functionStrings}
66
-
67
-
68
- # =====================================================================================
69
- # Секция: FastMCP/STDIO Транспорт (Не изменять)
70
- # =====================================================================================
71
-
72
- def _get_function_schema(func) -> Dict[str, Any]:
73
- """Генерирует OpenAPI-совместимую схему из докстринга функции."""
74
- if not func.__doc__:
75
- return {}
76
-
77
- lines = func.__doc__.strip().split('\\n')
78
- description = lines[0].strip()
79
-
80
- properties = {}
81
- required = []
82
-
83
- args_section = False
84
- for line in lines:
85
- line = line.strip()
86
- if line.startswith('Args:'):
87
- args_section = True
88
- continue
89
- if line.startswith('Returns:'):
90
- args_section = False
91
- continue
92
-
93
- if args_section and ':' in line:
94
- # Обработка необязательных параметров, обозначенных (*), например "аргумент (*str*):"
95
- is_required = not line.strip().startswith('(')
96
-
97
- arg_name_part, arg_desc = line.split(':', 1)
98
- arg_name = arg_name_part.split('(')[0].strip()
99
-
100
- # Предполагаем тип из аннотации
101
- param_type_hint = func.__annotations__.get(arg_name, 'string')
102
- if hasattr(param_type_hint, '__name__'):
103
- param_type_hint = param_type_hint.__name__
104
-
105
- openapi_type = {
106
- 'str': 'string',
107
- 'int': 'integer',
108
- 'float': 'number',
109
- 'bool': 'boolean',
110
- 'list': 'array',
111
- 'dict': 'object'
112
- }.get(param_type_hint, 'string')
113
-
114
- properties[arg_name] = {
115
- 'type': openapi_type,
116
- 'description': arg_desc.strip()
117
- }
118
- if is_required:
119
- required.append(arg_name)
120
-
121
- return {
122
- "name": func.__name__,
123
- "description": description,
124
- "parameters": {
125
- "type": "object",
126
- "properties": properties,
127
- "required": required
128
- }
129
- }
130
-
131
-
132
- def main():
133
- """Главная функция для обработки stdio."""
134
- functions = {
135
- ${def.functions.map(f => `"${f.name}": ${f.name}`).join(',\n ')}
136
- }
137
-
138
- if len(sys.argv) > 1 and sys.argv[1] == 'discover':
139
- tool_schema = {
140
- "name": "${def.name}",
141
- "tool_spec": {
142
- "function_declarations": [
143
- _get_function_schema(func) for func in functions.values()
144
- ]
145
- }
146
- }
147
- print(json.dumps(tool_schema, ensure_ascii=False))
148
- return
149
-
150
- for line in sys.stdin:
151
- try:
152
- call = json.loads(line)
153
- function_name = call['function_call']['name']
154
- args = call['function_call']['args']
155
-
156
- if function_name in functions:
157
- result = functions[function_name](**args)
158
- response = {
159
- "tool_response": {
160
- "name": function_name,
161
- "content": json.dumps(result, ensure_ascii=False)
162
- }
163
- }
164
- print(json.dumps(response, ensure_ascii=False))
165
- else:
166
- # Обработка ошибки: функция не найдена
167
- error_response = {"tool_response": {"name": function_name, "content": json.dumps({"error": f"Function {function_name} not found."})}}
168
- print(json.dumps(error_response, ensure_ascii=False))
169
- except (json.JSONDecodeError, KeyError) as e:
170
- # Обработка ошибок парсинга или структуры JSON
171
- error_response = {"tool_response": {"name": "unknown", "content": json.dumps({"error": f"Invalid input JSON: {e}"})}}
172
- print(json.dumps(error_response, ensure_ascii=False))
173
-
174
-
175
- if __name__ == "__main__":
176
- main()
177
- `.trim();
178
- };
179
-
180
- const generateFunctionBody = (def: ToolDefinition, func: FunctionDefinition): string => {
181
- // Generate real, working code for the nmap_scanner example
182
- if (def.name === 'nmap_scanner') {
183
- if (func.name === 'run_scan') {
184
- return `
185
- try:
186
- nm = nmap.PortScanner()
187
- # nmap.scan() возвращает результат сканирования
188
- scan_result = nm.scan(hosts=targets, ports=ports, arguments=arguments)
189
- return scan_result
190
- except nmap.PortScannerError as e:
191
- return {"error": f"Ошибка сканирования Nmap: {e}. Убедитесь, что nmap установлен и доступен в системном PATH."}
192
- except Exception as e:
193
- return {"error": f"Произошла непредвиденная ошибка: {e}"}
194
- `.trim();
195
- }
196
- if (func.name === 'host_discovery') {
197
- return `
198
- try:
199
- nm = nmap.PortScanner()
200
- # Аргумент -sn выполняет "ping scan" для обнаружения хостов без сканирования портов
201
- nm.scan(hosts=network_cidr, arguments='-sn')
202
- # nm.all_hosts() возвращает список хостов, которые находятся в состоянии 'up'
203
- return {"active_hosts": nm.all_hosts()}
204
- except nmap.PortScannerError as e:
205
- return {"error": f"Ошибка сканирования Nmap: {e}. Убедитесь, что nmap установлен и доступен в системном PATH."}
206
- except Exception as e:
207
- return {"error": f"Произошла непредвиденная ошибка: {e}"}
208
- `.trim();
209
- }
210
- }
211
-
212
- // Default placeholder for other tools
213
- const mockReturnValue = () => {
214
- switch(func.returnType) {
215
- case ParameterType.STRING: return '"Результат выполнен��ёСЏ функции"';
216
- case ParameterType.INTEGER: return '123';
217
- case ParameterType.FLOAT: return '123.45';
218
- case ParameterType.BOOLEAN: return 'True';
219
- case ParameterType.LIST: return '["элемент1", "элемент2"]';
220
- case ParameterType.DICTIONARY: return '{"ключ": "значение"}';
221
- default: return 'None';
222
- }
223
- };
224
-
225
- return `
226
- # TODO: Реализуйте логику функции здесь
227
- # Это пример. Замените его своей реализацией.
228
- print(f"Функция '${func.name}' вызвана со следующими аргументами:")
229
- ${func.parameters.map(p => ` print(f"- ${p.name}: {${p.name}}")`).join('\n')}
230
-
231
- return ${mockReturnValue()}
232
- `.trim();
233
- };
234
-
235
-
236
- const generateFunction = (def: ToolDefinition, func: FunctionDefinition): string => {
237
- const paramsString = func.parameters.map(p => {
238
- const typeHint = toPythonType(p.type);
239
- const defaultValue = p.required ? '' : ' = None';
240
- return `${p.name}: ${typeHint}${defaultValue}`;
241
- }).join(', ');
242
- const returnTypeString = toPythonType(func.returnType);
243
-
244
- const docstringParams = func.parameters.map(p =>
245
- ` ${p.name} (${toPythonType(p.type)}): ${p.description}`
246
- ).join('\n');
247
-
248
- const docstring = `
249
- """${func.description}
250
-
251
- Args:
252
- ${docstringParams || ' Нет.'}
253
-
254
- Returns:
255
- ${returnTypeString}: ${func.returnDescription}
256
- """
257
- `.trim();
258
-
259
- const body = generateFunctionBody(def, func);
260
-
261
- return `
262
- def ${func.name}(${paramsString}) -> ${returnTypeString}:
263
- ${docstring}
264
- ${body}
265
- `.trim();
266
- };
267
-
268
-
269
- const generateSettingsJson = (def: ToolDefinition): string => {
270
- return JSON.stringify({
271
- servers: [
272
- {
273
- name: def.name,
274
- command: ['python', 'server.py'],
275
- transport: 'stdio',
276
- type: def.type
277
- }
278
- ]
279
- }, null, 2);
280
- };
281
-
282
- const generateGeminiMd = (def: ToolDefinition): string => {
283
- const functionDocs = def.functions.map(func => {
284
- const paramsList = func.parameters.map(p => `- \`${p.name}\` (*${toPythonType(p.type)}*): ${p.description}${p.required ? ' (обязательный)' : ''}`).join('\n');
285
- return `
286
- ### \`${def.name}:${func.name}\`
287
-
288
- ${func.description}
289
-
290
- **Параметры:**
291
- ${paramsList || 'Нет параметров.'}
292
-
293
- **Возвращает:**
294
- *${toPythonType(func.returnType)}* - ${func.returnDescription}
295
- `.trim();
296
- }).join('\n\n---\n\n');
297
-
298
- const nmapExamples = `
299
- ## Правила и Примеры Использования
300
-
301
- **ВАЖНО:** Всегда используй формат \`nmap_scanner:имя_функции()\`.
302
-
303
- Если пользователь просит **обнаружить активные устройства в сети**, используй \`host_discovery\`.
304
- *Запрос пользователя:* "Найди все работающие компьютеры в сети 192.168.0.0/24"
305
- *Твой вызов:* \`nmap_scanner:host_discovery(network_cidr="192.168.0.0/24")\`
306
-
307
- Если пользователь просит **просканировать порты или найти уязвимости**, используй \`run_scan\`.
308
- *Запрос пользователя:* "Просканируй хост 192.168.1.1 на наличие открытых портов и определи запущенные службы"
309
- *Твой вызов:* \`nmap_scanner:run_scan(targets="192.168.1.1", ports="1-1024", arguments="-sV")\`
310
-
311
- *Запрос пользователя:* "Проведи агрессивное сканирование scanme.nmap.org, чтобы найти возможные векторы ата��и"
312
- *Твой вызов:* \`nmap_scanner:run_scan(targets="scanme.nmap.org", ports="1-65535", arguments="-A -v")\`
313
- `.trim();
314
-
315
- const genericExample = `
316
- ## Пример использования
317
-
318
- **Простой вызов:**
319
- \`\`\`
320
- ${def.name}:${def.functions[0]?.name}(${def.functions[0]?.parameters.filter(p => p.required).map(p => `${p.name}="значение"`).join(', ')})
321
- \`\`\`
322
- `.trim();
323
-
324
- return `
325
- # Инструкция для Агента: Инструмент "${def.name}"
326
-
327
- ## Описание
328
-
329
- Этот инструмент предоставляет набор утилит для [опишите общую цель инструмента, например: сетевой разведки с помощью Nmap]. Он относится к типу **${def.type}**.
330
-
331
- ## Функции
332
-
333
- ${functionDocs}
334
-
335
- ${def.name === 'nmap_scanner' ? nmapExamples : genericExample}
336
- `.trim();
337
- };
338
-
339
- const getExampleValue = (param: ParameterDefinition): string => {
340
- const { name, type } = param;
341
- const lowerParamName = name.toLowerCase();
342
-
343
- if (type === ParameterType.STRING) {
344
- if (lowerParamName.includes('target') || lowerParamName.includes('host') || lowerParamName.includes('domain')) return "'scanme.nmap.org'";
345
- if (lowerParamName.includes('port')) return "'80,443,8080'";
346
- if (lowerParamName.includes('cidr') || lowerParamName.includes('network')) return "'192.168.1.0/24'";
347
- if (lowerParamName.includes('argument')) return "'-A -v'";
348
- if (lowerParamName.includes('file') || lowerParamName.includes('path')) return "'/path/to/file.txt'";
349
- if (lowerParamName.includes('url')) return "'https://example.com'";
350
- if (lowerParamName.includes('name')) return "'John Doe'";
351
- return "'example_value'";
352
- }
353
-
354
- switch (type) {
355
- case ParameterType.INTEGER: return '1024';
356
- case ParameterType.FLOAT: return '3.14';
357
- case ParameterType.BOOLEAN: return 'True';
358
- case ParameterType.LIST: return '["item1", "item2"]';
359
- case ParameterType.DICTIONARY: return '{"key": "value"}';
360
- default: return 'None';
361
- }
362
- };
363
-
364
- const getNaturalLanguageExample = (defName: string, func: FunctionDefinition): string => {
365
- if (defName === 'nmap_scanner') {
366
- if (func.name === 'run_scan') {
367
- return '> "Просканируй scanme.nmap.org, чтобы найти возможные векторы атаки."';
368
- }
369
- if (func.name === 'host_discovery') {
370
- return '> "Найди все активные устройства в моей локальной сети 192.168.1.0/24."';
371
- }
372
- }
373
- return `> "Выполни функцию ${func.name} с тестовыми параметрами."`;
374
- }
375
-
376
-
377
- const generateExamplesMd = (def: ToolDefinition): string => {
378
- if (!def.functions || def.functions.length === 0) {
379
- return '# Примеры использования\n\nИнструмент не содержит функций для генерации примеров.';
380
- }
381
-
382
- const exampleSnippets = def.functions.map(func => {
383
- const paramsString = func.parameters
384
- .map(p => `${p.name}=${getExampleValue(p)}`)
385
- .join(', ');
386
-
387
- const exampleCall = `${def.name}:${func.name}(${paramsString})`;
388
- const naturalLanguageQuery = getNaturalLanguageExample(def.name, func);
389
-
390
- return `
391
- ### Функция: \`${func.name}\`
392
-
393
- ${func.description}
394
-
395
- **Пример запроса на естественном языке:**
396
- ${naturalLanguageQuery}
397
-
398
- **В ответ Gemini CLI сгенерирует следующий вызов:**
399
- \`\`\`bash
400
- ${exampleCall}
401
- \`\`\`
402
- `.trim();
403
- }).join('\n\n---\n\n');
404
-
405
- return `
406
- # Примеры использования для инструмента "${def.name}"
407
-
408
- Gemini CLI понимает естественный язык. Он анализирует ваш запрос и вызывает соответствующую функцию инструмента. Ниже показано, как ваши запросы преобразуются в конкретные вызовы.
409
-
410
- ---
411
-
412
- ${exampleSnippets}
413
- `.trim();
414
- };
415
-
416
-
417
- export const generateAllCode = (def: ToolDefinition): GeneratedCode => {
418
- return {
419
- setupPy: generateSetupPy(def),
420
- serverPy: generateServerPy(def),
421
- settingsJson: generateSettingsJson(def),
422
- geminiMd: generateGeminiMd(def),
423
- examplesMd: generateExamplesMd(def),
424
- };
425
- };
426
-
427
-
428
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/style.css DELETED
@@ -1,28 +0,0 @@
1
- body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
4
- }
5
-
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
9
- }
10
-
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
- }
17
-
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
- }
25
-
26
- .card p:last-child {
27
- margin-bottom: 0;
28
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/tsconfig.json DELETED
@@ -1,32 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "experimentalDecorators": true,
5
- "useDefineForClassFields": false,
6
- "module": "ESNext",
7
- "lib": [
8
- "ES2022",
9
- "DOM",
10
- "DOM.Iterable"
11
- ],
12
- "skipLibCheck": true,
13
- "types": [
14
- "node"
15
- ],
16
- "moduleResolution": "bundler",
17
- "isolatedModules": true,
18
- "moduleDetection": "force",
19
- "allowJs": true,
20
- "jsx": "react-jsx",
21
- "paths": {
22
- "@/*": [
23
- "./*"
24
- ]
25
- },
26
- "allowImportingTsExtensions": true,
27
- "noEmit": true
28
- }
29
- }
30
-
31
-
32
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/types.ts DELETED
@@ -1,72 +0,0 @@
1
-
2
- export enum ToolType {
3
- REST_API = 'REST_API',
4
- CLI = 'CLI',
5
- DATABASE = 'DATABASE',
6
- CUSTOM = 'CUSTOM',
7
- UTILITY = 'UTILITY',
8
- CALCULATOR = 'CALCULATOR',
9
- CONVERTER = 'CONVERTER'
10
- }
11
-
12
- export enum ParameterType {
13
- STRING = 'str',
14
- INTEGER = 'int',
15
- FLOAT = 'float',
16
- BOOLEAN = 'bool',
17
- LIST = 'list',
18
- DICTIONARY = 'dict'
19
- }
20
-
21
- export interface ParameterDefinition {
22
- id: string;
23
- name: string;
24
- type: ParameterType;
25
- description: string;
26
- required: boolean;
27
- }
28
-
29
- export interface FunctionDefinition {
30
- id: string;
31
- name: string;
32
- description: string;
33
- parameters: ParameterDefinition[];
34
- returnType: ParameterType;
35
- returnDescription: string;
36
- }
37
-
38
- export interface ToolDefinition {
39
- name: string;
40
- type: ToolType;
41
- dependencies: string;
42
- functions: FunctionDefinition[];
43
- }
44
-
45
- export interface GeneratedCode {
46
- setupPy: string;
47
- serverPy: string;
48
- settingsJson: string;
49
- geminiMd: string;
50
- examplesMd: string;
51
- }
52
-
53
- // Экспортируем для использования в AI промпте
54
- export const initialFunctionForPrompt: Omit<FunctionDefinition, 'id'> = {
55
- name: 'example_function',
56
- description: 'Краткое описание того, что делает эта функция.',
57
- parameters: [
58
- {
59
- id: 'param-id-1', // id здесь для примера, в реальности он генерируется
60
- name: 'example_param',
61
- type: ParameterType.STRING,
62
- description: 'Описание параметра.',
63
- required: true,
64
- },
65
- ],
66
- returnType: ParameterType.STRING,
67
- returnDescription: 'Описание возвращаемого значения.',
68
- };
69
-
70
-
71
-
72
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FastMCPToolGenerator/vite.config.ts DELETED
@@ -1,72 +0,0 @@
1
- import path from 'path';
2
-
3
- import { defineConfig, loadEnv } from 'vite';
4
-
5
- import react from '@vitejs/plugin-react';
6
-
7
-
8
-
9
- export default defineConfig(({ mode }) => {
10
-
11
- const env = loadEnv(mode, '.', '');
12
-
13
-
14
-
15
- // Порт для FastAPI (бэкенда) при локальной разработке
16
-
17
- const PYTHON_BACKEND_PORT = 8000;
18
-
19
-
20
-
21
- return {
22
-
23
- server: {
24
-
25
- // Используем порт 3000 для Vite (фронтенда)
26
-
27
- port: 3000,
28
-
29
- host: '0.0.0.0',
30
-
31
- proxy: {
32
-
33
- // Перенаправляем все /api запросы на наш Python бэкенд
34
-
35
- '/api': {
36
-
37
- target: `http://127.0.0.1:${PYTHON_BACKEND_PORT}`, // ИСПРАВЛЕНО
38
-
39
- changeOrigin: true,
40
-
41
- secure: false,
42
-
43
- }
44
-
45
- }
46
-
47
- },
48
-
49
- plugins: [react()],
50
-
51
- define: {
52
-
53
- // Ключ API БОЛЬШЕ НЕ НУЖЕН в define!
54
-
55
- },
56
-
57
- resolve: {
58
-
59
- alias: {
60
-
61
- '@': path.resolve(__dirname, '.'),
62
-
63
- }
64
-
65
- }
66
-
67
- };
68
-
69
- });
70
-
71
-
72
-