You've already forked 1cai-public
mirror of
https://github.com/DmitrL-dev/1cai-public.git
synced 2026-04-29 02:41:52 +02:00
317 lines
9.9 KiB
Python
317 lines
9.9 KiB
Python
# [NEXUS IDENTITY] ID: 5968713849743023239 | DATE: 2025-11-19
|
|
|
|
"""
|
|
MCP Code Generator
|
|
|
|
Генерирует TypeScript API из MCP tool definitions
|
|
для использования в Code Execution Environment
|
|
"""
|
|
|
|
import logging
|
|
from pathlib import Path
|
|
from typing import Any, Dict, List
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class MCPCodeGenerator:
|
|
"""Генератор TypeScript API из MCP tools"""
|
|
|
|
def __init__(self, output_dir: str = "./execution-env/servers"):
|
|
self.output_dir = Path(output_dir)
|
|
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
def generate_from_mcp_server(
|
|
self,
|
|
server_name: str,
|
|
tools: List[Dict[str, Any]]
|
|
):
|
|
"""
|
|
Генерировать TypeScript API для MCP server
|
|
|
|
Args:
|
|
server_name: Имя сервера ("1c", "neo4j", "qdrant", etc.)
|
|
tools: Список tool definitions
|
|
"""
|
|
|
|
logger.info(f"Generating TypeScript API for server '{server_name}'...")
|
|
|
|
server_dir = self.output_dir / server_name
|
|
server_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Generate index.ts (экспортирует все tools)
|
|
self._generate_index(server_dir, tools, server_name)
|
|
|
|
# Generate individual tool files
|
|
for tool in tools:
|
|
self._generate_tool_file(server_dir, tool, server_name)
|
|
|
|
logger.info(
|
|
f"✅ Generated {len(tools)} tools for server '{server_name}' "
|
|
f"in {server_dir}"
|
|
)
|
|
|
|
def _generate_index(
|
|
self,
|
|
server_dir: Path,
|
|
tools: List[Dict[str, Any]],
|
|
server_name: str
|
|
):
|
|
"""Генерировать index.ts для server"""
|
|
|
|
exports = []
|
|
for tool in tools:
|
|
tool_name = self._sanitize_tool_name(tool['name'])
|
|
exports.append(
|
|
f"export {{ {tool_name} }} from './{tool_name}.ts';"
|
|
)
|
|
|
|
index_content = f"""/**
|
|
* {server_name.upper()} MCP Server API
|
|
*
|
|
* Auto-generated from MCP tool definitions
|
|
* Generated: {self._get_timestamp()}
|
|
*/
|
|
|
|
{chr(10).join(exports)}
|
|
"""
|
|
|
|
index_path = server_dir / 'index.ts'
|
|
index_path.write_text(index_content, encoding='utf-8')
|
|
|
|
def _generate_tool_file(
|
|
self,
|
|
server_dir: Path,
|
|
tool: Dict[str, Any],
|
|
server_name: str
|
|
):
|
|
"""Генерировать файл для одного tool"""
|
|
|
|
tool_name = self._sanitize_tool_name(tool['name'])
|
|
file_path = server_dir / f"{tool_name}.ts"
|
|
|
|
# Генерировать interfaces
|
|
interfaces = self._generate_interfaces(tool, tool_name)
|
|
|
|
# Генерировать function
|
|
function = self._generate_function(tool, tool_name, server_name)
|
|
|
|
# Собрать всё вместе
|
|
code = f"""/**
|
|
* {tool.get('description', tool_name)}
|
|
*
|
|
* Auto-generated from MCP tool definition
|
|
*/
|
|
|
|
import {{ callMCPTool }} from '../../client.ts';
|
|
|
|
{interfaces}
|
|
|
|
{function}
|
|
"""
|
|
|
|
file_path.write_text(code, encoding='utf-8')
|
|
|
|
def _generate_interfaces(
|
|
self,
|
|
tool: Dict[str, Any],
|
|
tool_name: str
|
|
) -> str:
|
|
"""Генерировать TypeScript interfaces из JSON Schema"""
|
|
|
|
input_schema = tool.get('inputSchema', {})
|
|
properties = input_schema.get('properties', {})
|
|
required = input_schema.get('required', [])
|
|
|
|
# Input interface
|
|
input_type_name = self._get_input_type_name(tool_name)
|
|
input_interface = f"export interface {input_type_name} {{\n"
|
|
|
|
if properties:
|
|
for prop_name, prop_schema in properties.items():
|
|
prop_type = self._json_schema_to_ts_type(prop_schema)
|
|
is_required = prop_name in required
|
|
optional_marker = '' if is_required else '?'
|
|
description = prop_schema.get('description', '')
|
|
|
|
if description:
|
|
input_interface += f" /** {description} */\n"
|
|
|
|
input_interface += f" {prop_name}{optional_marker}: {prop_type};\n"
|
|
else:
|
|
# Empty interface
|
|
input_interface += " // No parameters\n"
|
|
|
|
input_interface += "}\n\n"
|
|
|
|
# Return type interface (generic для начала)
|
|
return_type_name = self._get_return_type_name(tool_name)
|
|
return_interface = f"export interface {return_type_name} {{\n"
|
|
return_interface += " [key: string]: any;\n"
|
|
return_interface += "}\n"
|
|
|
|
return input_interface + return_interface
|
|
|
|
def _generate_function(
|
|
self,
|
|
tool: Dict[str, Any],
|
|
tool_name: str,
|
|
server_name: str
|
|
) -> str:
|
|
"""Генерировать TypeScript function для tool"""
|
|
|
|
input_type = self._get_input_type_name(tool_name)
|
|
return_type = self._get_return_type_name(tool_name)
|
|
description = tool.get('description', '')
|
|
|
|
# Full tool name: server__tool_name
|
|
full_tool_name = f"{server_name}__{tool['name']}"
|
|
|
|
function = f"""/**
|
|
* {description}
|
|
*/
|
|
export async function {tool_name}(
|
|
input: {input_type}
|
|
): Promise<{return_type}> {{
|
|
return await callMCPTool<{return_type}>(
|
|
'{full_tool_name}',
|
|
input
|
|
);
|
|
}}
|
|
"""
|
|
|
|
return function
|
|
|
|
def _json_schema_to_ts_type(self, schema: Dict[str, Any]) -> str:
|
|
"""Конвертировать JSON Schema type в TypeScript type"""
|
|
|
|
schema_type = schema.get('type', 'any')
|
|
|
|
type_map = {
|
|
'string': 'string',
|
|
'number': 'number',
|
|
'integer': 'number',
|
|
'boolean': 'boolean',
|
|
'null': 'null',
|
|
}
|
|
|
|
if schema_type == 'array':
|
|
items = schema.get('items', {})
|
|
item_type = self._json_schema_to_ts_type(items)
|
|
return f"{item_type}[]"
|
|
|
|
elif schema_type == 'object':
|
|
# Для object возвращаем generic object или Record
|
|
return 'Record<string, any>'
|
|
|
|
else:
|
|
return type_map.get(schema_type, 'any')
|
|
|
|
def _sanitize_tool_name(self, name: str) -> str:
|
|
"""Sanitize tool name для использования как function/file name"""
|
|
# Убрать server prefix если есть
|
|
if '__' in name:
|
|
name = name.split('__', 1)[1]
|
|
|
|
# Convert to camelCase
|
|
parts = name.replace('-', '_').split('_')
|
|
return parts[0].lower() + ''.join(word.capitalize() for word in parts[1:])
|
|
|
|
def _get_input_type_name(self, tool_name: str) -> str:
|
|
"""Получить имя для Input type"""
|
|
return f"{tool_name[0].upper()}{tool_name[1:]}Input"
|
|
|
|
def _get_return_type_name(self, tool_name: str) -> str:
|
|
"""Получить имя для Return type"""
|
|
return f"{tool_name[0].upper()}{tool_name[1:]}Result"
|
|
|
|
def _get_timestamp(self) -> str:
|
|
"""Получить текущий timestamp для documentation"""
|
|
from datetime import datetime
|
|
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
|
def generate_all_servers(
|
|
servers_config: Dict[str, List[Dict[str, Any]]],
|
|
output_dir: str = "./execution-env/servers"
|
|
):
|
|
"""
|
|
Генерировать TypeScript API для всех MCP servers
|
|
|
|
Args:
|
|
servers_config: Dict вида:
|
|
{
|
|
'1c': [tool1, tool2, ...],
|
|
'neo4j': [tool1, tool2, ...],
|
|
...
|
|
}
|
|
output_dir: Output directory
|
|
"""
|
|
|
|
generator = MCPCodeGenerator(output_dir)
|
|
|
|
total_tools = 0
|
|
|
|
for server_name, tools in servers_config.items():
|
|
generator.generate_from_mcp_server(server_name, tools)
|
|
total_tools += len(tools)
|
|
|
|
logger.info(
|
|
f"✅ Generation complete! "
|
|
f"Generated {total_tools} tools for {len(servers_config)} servers"
|
|
)
|
|
|
|
return total_tools
|
|
|
|
|
|
# Example usage
|
|
if __name__ == "__main__":
|
|
# Example MCP tool definition
|
|
example_tools = [
|
|
{
|
|
'name': 'get_configuration',
|
|
'description': 'Get 1C configuration metadata',
|
|
'inputSchema': {
|
|
'type': 'object',
|
|
'properties': {
|
|
'name': {
|
|
'type': 'string',
|
|
'description': 'Configuration name'
|
|
},
|
|
'include_metadata': {
|
|
'type': 'boolean',
|
|
'description': 'Include full metadata'
|
|
}
|
|
},
|
|
'required': ['name']
|
|
}
|
|
},
|
|
{
|
|
'name': 'execute_query',
|
|
'description': 'Execute SQL query in 1C database',
|
|
'inputSchema': {
|
|
'type': 'object',
|
|
'properties': {
|
|
'query': {
|
|
'type': 'string',
|
|
'description': 'SQL query'
|
|
},
|
|
'limit': {
|
|
'type': 'integer',
|
|
'description': 'Result limit'
|
|
}
|
|
},
|
|
'required': ['query']
|
|
}
|
|
}
|
|
]
|
|
|
|
# Generate
|
|
generator = MCPCodeGenerator()
|
|
generator.generate_from_mcp_server('1c', example_tools)
|
|
|
|
print("✅ Example generation complete!")
|
|
print("📁 Check ./execution-env/servers/1c/")
|
|
|
|
|