This is page 19 of 20. Use http://codebase.md/fujitsu-ai/mcp-server-for-mas-developments?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .gitattributes
├── .gitignore
├── agents
│ ├── __init__.py
│ ├── AgentInterface
│ │ ├── __init__.py
│ │ ├── Python
│ │ │ ├── __init__.py
│ │ │ ├── agent.py
│ │ │ ├── color.py
│ │ │ ├── config.py
│ │ │ ├── language.py
│ │ │ ├── local_file_handler.py
│ │ │ └── network.py
│ │ └── requirements.txt
│ ├── AgentMonitoring
│ │ ├── ChatBot-Agent Dashboard Example - Grafana.json
│ │ ├── images
│ │ │ ├── Grafana.png
│ │ │ └── Prometheus.png
│ │ ├── IoT-Agent Dashboard Example - Grafana.json
│ │ ├── OpenAI compatible API - Agent Dashboard Example - Grafana.json
│ │ ├── prometheus Example.yml
│ │ └── README.md
│ ├── ChatBotAgent
│ │ ├── __init__.py
│ │ ├── config.json.example
│ │ ├── html
│ │ │ ├── favicon.ico
│ │ │ ├── index_de.html
│ │ │ ├── index.html
│ │ │ ├── Logo_light.svg
│ │ │ ├── start_http_server.ps1
│ │ │ └── start_http_server.sh
│ │ ├── Python
│ │ │ ├── __init__.py
│ │ │ └── chatbot_agent.py
│ │ ├── README.md
│ │ └── requirements.txt
│ ├── IoTAgent
│ │ ├── config_example.json
│ │ ├── Python
│ │ │ ├── iot_mqtt_agent.py
│ │ │ └── language.py
│ │ ├── README.md
│ │ └── requirements.txt
│ ├── ISMAgent
│ │ ├── config_example.json
│ │ ├── PGPT Scenario Prompts
│ │ │ ├── ISM System Prompt - Detecting Error State.txt
│ │ │ ├── ISM User Post-Prompt - Detecting Error State.txt
│ │ │ ├── ISM User Pre-Prompt - Detecting Error State.txt
│ │ │ └── README.md
│ │ ├── Python
│ │ │ ├── ism_agent.py
│ │ │ └── language.py
│ │ ├── README.md
│ │ ├── requirements.txt
│ │ └── start_ism_agent.ps1
│ ├── MCP-Client
│ │ ├── __init__.py
│ │ ├── .env.example
│ │ ├── Python
│ │ │ ├── __init__.py
│ │ │ ├── chat_handler.py
│ │ │ ├── config.py
│ │ │ ├── environment.py
│ │ │ ├── llm_client.py
│ │ │ ├── mcp_client_sse.py
│ │ │ ├── mcp_client.py
│ │ │ ├── messages
│ │ │ │ ├── __init__.py
│ │ │ │ ├── message_types
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── incrementing_id_message.py
│ │ │ │ │ ├── initialize_message.py
│ │ │ │ │ ├── json_rpc_message.py
│ │ │ │ │ ├── ping_message.py
│ │ │ │ │ ├── prompts_messages.py
│ │ │ │ │ ├── prompts_models.py
│ │ │ │ │ ├── resources_messages.py
│ │ │ │ │ └── tools_messages.py
│ │ │ │ ├── send_call_tool.py
│ │ │ │ ├── send_initialize_message.py
│ │ │ │ ├── send_message.py
│ │ │ │ ├── send_ping.py
│ │ │ │ ├── send_prompts.py
│ │ │ │ ├── send_resources.py
│ │ │ │ └── send_tools_list.py
│ │ │ ├── system_prompt_generator.py
│ │ │ ├── tools_handler.py
│ │ │ └── transport
│ │ │ ├── __init__.py
│ │ │ └── stdio
│ │ │ ├── __init__.py
│ │ │ ├── stdio_client.py
│ │ │ ├── stdio_server_parameters.py
│ │ │ └── stdio_server_shutdown.py
│ │ ├── README.md
│ │ ├── requirements.txt
│ │ └── server_config.json
│ ├── OpenAI_Compatible_API_Agent
│ │ ├── __init__.py
│ │ ├── docker-compose.yml
│ │ ├── Dockerfile
│ │ ├── pgpt_openai_api_mcp.json.example
│ │ ├── pgpt_openai_api_proxy.json.example
│ │ ├── Python
│ │ │ ├── __init__.py
│ │ │ ├── client_tests
│ │ │ │ ├── __init__.py
│ │ │ │ ├── openai_test_client_structured.py
│ │ │ │ ├── openai_test_client_tools.py
│ │ │ │ ├── openai_test_client.py
│ │ │ │ ├── vllm_client_multimodal.py
│ │ │ │ ├── vllm_client.py
│ │ │ │ ├── vllm_structured.py
│ │ │ │ └── vllm_structured2.py
│ │ │ ├── generate_api_key.py
│ │ │ ├── open_ai_helper.py
│ │ │ ├── openai_compatible_api.py
│ │ │ ├── openai_mcp_api.py
│ │ │ ├── pgpt_api.py
│ │ │ ├── privategpt_api.py
│ │ │ └── vllmproxy.py
│ │ ├── README.md
│ │ └── requirements.txt
│ └── SourceManagerAgent
│ ├── __init__.py
│ ├── config.json.example
│ └── Python
│ ├── __init__.py
│ ├── file_tools
│ │ └── loader_factory.py
│ ├── file_upload_agent.py
│ └── local_db.py
├── clients
│ ├── __init__.py
│ ├── C# .Net
│ │ ├── 1.0 mcp_login
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_login.deps.json
│ │ │ │ ├── mcp_login.dll
│ │ │ │ ├── mcp_login.exe
│ │ │ │ ├── mcp_login.pdb
│ │ │ │ ├── mcp_login.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_login.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_login.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_login.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_login.assets.cache
│ │ │ │ │ ├── mcp_login.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_login.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_login.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_login.csproj.Up2Date
│ │ │ │ │ ├── mcp_login.dll
│ │ │ │ │ ├── mcp_login.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_login.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_login.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_login.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_login.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_login.dll
│ │ │ │ ├── mcp_login.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_login.csproj.nuget.g.props
│ │ │ │ ├── mcp_login.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 1.1 mcp_logout
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_logout.deps.json
│ │ │ │ ├── mcp_logout.dll
│ │ │ │ ├── mcp_logout.exe
│ │ │ │ ├── mcp_logout.pdb
│ │ │ │ ├── mcp_logout.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_logout.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_logout.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_logout.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_logout.assets.cache
│ │ │ │ │ ├── mcp_logout.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_logout.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_logout.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_logout.csproj.Up2Date
│ │ │ │ │ ├── mcp_logout.dll
│ │ │ │ │ ├── mcp_logout.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_logout.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_logout.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_logout.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_logout.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_logout.dll
│ │ │ │ ├── mcp_logout.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_logout.csproj.nuget.g.props
│ │ │ │ ├── mcp_logout.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 2.0 mcp_chat
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_chat.deps.json
│ │ │ │ ├── mcp_chat.dll
│ │ │ │ ├── mcp_chat.exe
│ │ │ │ ├── mcp_chat.pdb
│ │ │ │ ├── mcp_chat.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_chat.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_chat.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_chat.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_chat.assets.cache
│ │ │ │ │ ├── mcp_chat.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_chat.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_chat.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_chat.csproj.Up2Date
│ │ │ │ │ ├── mcp_chat.dll
│ │ │ │ │ ├── mcp_chat.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_chat.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_chat.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_chat.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_chat.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_chat.dll
│ │ │ │ ├── mcp_chat.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_chat.csproj.nuget.g.props
│ │ │ │ ├── mcp_chat.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 2.1 mcp_continue_chat
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_continue_chat.deps.json
│ │ │ │ ├── mcp_continue_chat.dll
│ │ │ │ ├── mcp_continue_chat.exe
│ │ │ │ ├── mcp_continue_chat.pdb
│ │ │ │ ├── mcp_continue_chat.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_continue_chat.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_cont.EF178231.Up2Date
│ │ │ │ │ ├── mcp_continue_chat.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_continue_chat.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_continue_chat.assets.cache
│ │ │ │ │ ├── mcp_continue_chat.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_continue_chat.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_continue_chat.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_continue_chat.dll
│ │ │ │ │ ├── mcp_continue_chat.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_continue_chat.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_continue_chat.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_continue_chat.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_continue_chat.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_continue_chat.dll
│ │ │ │ ├── mcp_continue_chat.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_continue_chat.csproj.nuget.g.props
│ │ │ │ ├── mcp_continue_chat.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_get_chat_info.deps.json
│ │ │ │ ├── mcp_get_chat_info.dll
│ │ │ │ ├── mcp_get_chat_info.exe
│ │ │ │ ├── mcp_get_chat_info.pdb
│ │ │ │ ├── mcp_get_chat_info.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── Dokumente - Verknüpfung.lnk
│ │ │ ├── mcp_get_chat_info.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_get_.DFF47B4E.Up2Date
│ │ │ │ │ ├── mcp_get_chat_info.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_get_chat_info.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_get_chat_info.assets.cache
│ │ │ │ │ ├── mcp_get_chat_info.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_get_chat_info.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_get_chat_info.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_get_chat_info.dll
│ │ │ │ │ ├── mcp_get_chat_info.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_get_chat_info.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_get_chat_info.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_get_chat_info.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_get_chat_info.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_get_chat_info.dll
│ │ │ │ ├── mcp_get_chat_info.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_get_chat_info.csproj.nuget.g.props
│ │ │ │ ├── mcp_get_chat_info.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 3.0 mcp_create_source
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_create_source.deps.json
│ │ │ │ ├── mcp_create_source.dll
│ │ │ │ ├── mcp_create_source.exe
│ │ │ │ ├── mcp_create_source.pdb
│ │ │ │ ├── mcp_create_source.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_create_source.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_crea.CB4ED912.Up2Date
│ │ │ │ │ ├── mcp_create_source.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_create_source.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_create_source.assets.cache
│ │ │ │ │ ├── mcp_create_source.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_create_source.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_create_source.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_create_source.dll
│ │ │ │ │ ├── mcp_create_source.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_create_source.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_create_source.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_create_source.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_create_source.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_create_source.dll
│ │ │ │ ├── mcp_create_source.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_create_source.csproj.nuget.g.props
│ │ │ │ ├── mcp_create_source.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 3.1 mcp_get_source
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_get_source.deps.json
│ │ │ │ ├── mcp_get_source.dll
│ │ │ │ ├── mcp_get_source.exe
│ │ │ │ ├── mcp_get_source.pdb
│ │ │ │ ├── mcp_get_source.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_get_source.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_get_.4E61956F.Up2Date
│ │ │ │ │ ├── mcp_get_source.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_get_source.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_get_source.assets.cache
│ │ │ │ │ ├── mcp_get_source.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_get_source.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_get_source.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_get_source.dll
│ │ │ │ │ ├── mcp_get_source.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_get_source.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_get_source.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_get_source.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_get_source.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_get_source.dll
│ │ │ │ ├── mcp_get_source.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_get_source.csproj.nuget.g.props
│ │ │ │ ├── mcp_get_source.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 3.2 mcp_list_sources
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_list_sources.deps.json
│ │ │ │ ├── mcp_list_sources.dll
│ │ │ │ ├── mcp_list_sources.exe
│ │ │ │ ├── mcp_list_sources.pdb
│ │ │ │ ├── mcp_list_sources.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_list_sources.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_list_sources.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_list_sources.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_list_sources.assets.cache
│ │ │ │ │ ├── mcp_list_sources.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_list_sources.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_list_sources.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_list_sources.dll
│ │ │ │ │ ├── mcp_list_sources.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_list_sources.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_list_sources.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_list_sources.pdb
│ │ │ │ │ ├── mcp_list.A720E197.Up2Date
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_list_sources.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_list_sources.dll
│ │ │ │ ├── mcp_list_sources.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_list_sources.csproj.nuget.g.props
│ │ │ │ ├── mcp_list_sources.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 3.3 mcp_edit_source
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_edit_source.deps.json
│ │ │ │ ├── mcp_edit_source.dll
│ │ │ │ ├── mcp_edit_source.exe
│ │ │ │ ├── mcp_edit_source.pdb
│ │ │ │ ├── mcp_edit_source.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_edit_source.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_edit_source.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_edit_source.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_edit_source.assets.cache
│ │ │ │ │ ├── mcp_edit_source.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_edit_source.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_edit_source.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_edit_source.dll
│ │ │ │ │ ├── mcp_edit_source.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_edit_source.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_edit_source.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_edit_source.pdb
│ │ │ │ │ ├── mcp_edit.7303BE3B.Up2Date
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_edit_source.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_edit_source.dll
│ │ │ │ ├── mcp_edit_source.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_edit_source.csproj.nuget.g.props
│ │ │ │ ├── mcp_edit_source.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 3.4 mcp_delete_source
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_delete_source.deps.json
│ │ │ │ ├── mcp_delete_source.dll
│ │ │ │ ├── mcp_delete_source.exe
│ │ │ │ ├── mcp_delete_source.pdb
│ │ │ │ ├── mcp_delete_source.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_delete_source.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_dele.67DD13F9.Up2Date
│ │ │ │ │ ├── mcp_delete_source.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_delete_source.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_delete_source.assets.cache
│ │ │ │ │ ├── mcp_delete_source.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_delete_source.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_delete_source.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_delete_source.dll
│ │ │ │ │ ├── mcp_delete_source.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_delete_source.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_delete_source.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_delete_source.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_delete_source.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_delete_source.dll
│ │ │ │ ├── mcp_delete_source.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_delete_source.csproj.nuget.g.props
│ │ │ │ ├── mcp_delete_source.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 4.0 mcp_list_groups
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_list_groups.deps.json
│ │ │ │ ├── mcp_list_groups.dll
│ │ │ │ ├── mcp_list_groups.exe
│ │ │ │ ├── mcp_list_groups.pdb
│ │ │ │ ├── mcp_list_groups.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_list_groups.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_list_groups.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_list_groups.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_list_groups.assets.cache
│ │ │ │ │ ├── mcp_list_groups.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_list_groups.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_list_groups.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_list_groups.dll
│ │ │ │ │ ├── mcp_list_groups.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_list_groups.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_list_groups.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_list_groups.pdb
│ │ │ │ │ ├── mcp_list.EBD5E0D2.Up2Date
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_list_groups.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_list_groups.dll
│ │ │ │ ├── mcp_list_groups.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_list_groups.csproj.nuget.g.props
│ │ │ │ ├── mcp_list_groups.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 4.1 mcp_store_group
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_store_group.deps.json
│ │ │ │ ├── mcp_store_group.dll
│ │ │ │ ├── mcp_store_group.exe
│ │ │ │ ├── mcp_store_group.pdb
│ │ │ │ ├── mcp_store_group.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_store_group.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_stor.AFB4AA35.Up2Date
│ │ │ │ │ ├── mcp_store_group.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_store_group.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_store_group.assets.cache
│ │ │ │ │ ├── mcp_store_group.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_store_group.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_store_group.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_store_group.dll
│ │ │ │ │ ├── mcp_store_group.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_store_group.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_store_group.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_store_group.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_store_group.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_store_group.dll
│ │ │ │ ├── mcp_store_group.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_store_group.csproj.nuget.g.props
│ │ │ │ ├── mcp_store_group.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 4.2 mcp_delete_group
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_delete_group.deps.json
│ │ │ │ ├── mcp_delete_group.dll
│ │ │ │ ├── mcp_delete_group.exe
│ │ │ │ ├── mcp_delete_group.pdb
│ │ │ │ ├── mcp_delete_group.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_delete_group.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_dele.FE1C6298.Up2Date
│ │ │ │ │ ├── mcp_delete_group.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_delete_group.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_delete_group.assets.cache
│ │ │ │ │ ├── mcp_delete_group.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_delete_group.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_delete_group.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_delete_group.dll
│ │ │ │ │ ├── mcp_delete_group.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_delete_group.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_delete_group.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_delete_group.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_delete_group.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_delete_group.dll
│ │ │ │ ├── mcp_delete_group.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_delete_group.csproj.nuget.g.props
│ │ │ │ ├── mcp_delete_group.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 5.0 mcp_store_user
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_store_user.deps.json
│ │ │ │ ├── mcp_store_user.dll
│ │ │ │ ├── mcp_store_user.exe
│ │ │ │ ├── mcp_store_user.pdb
│ │ │ │ ├── mcp_store_user.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_store_user.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_stor.6C0F0C8A.Up2Date
│ │ │ │ │ ├── mcp_store_user.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_store_user.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_store_user.assets.cache
│ │ │ │ │ ├── mcp_store_user.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_store_user.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_store_user.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_store_user.dll
│ │ │ │ │ ├── mcp_store_user.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_store_user.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_store_user.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_store_user.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_store_user.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_store_user.dll
│ │ │ │ ├── mcp_store_user.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_store_user.csproj.nuget.g.props
│ │ │ │ ├── mcp_store_user.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 5.1 mcp_edit_user
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_edit_user.deps.json
│ │ │ │ ├── mcp_edit_user.dll
│ │ │ │ ├── mcp_edit_user.exe
│ │ │ │ ├── mcp_edit_user.pdb
│ │ │ │ ├── mcp_edit_user.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_edit_user.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_edit_user.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_edit_user.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_edit_user.assets.cache
│ │ │ │ │ ├── mcp_edit_user.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_edit_user.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_edit_user.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_edit_user.dll
│ │ │ │ │ ├── mcp_edit_user.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_edit_user.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_edit_user.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_edit_user.pdb
│ │ │ │ │ ├── mcp_edit.94A30270.Up2Date
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_edit_user.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_edit_user.dll
│ │ │ │ ├── mcp_edit_user.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_edit_user.csproj.nuget.g.props
│ │ │ │ ├── mcp_edit_user.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 5.2 mcp_delete_user
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_delete_user.deps.json
│ │ │ │ ├── mcp_delete_user.dll
│ │ │ │ ├── mcp_delete_user.exe
│ │ │ │ ├── mcp_delete_user.pdb
│ │ │ │ ├── mcp_delete_user.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_delete_user.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_dele.CEB7E33D.Up2Date
│ │ │ │ │ ├── mcp_delete_user.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_delete_user.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_delete_user.assets.cache
│ │ │ │ │ ├── mcp_delete_user.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_delete_user.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_delete_user.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_delete_user.dll
│ │ │ │ │ ├── mcp_delete_user.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_delete_user.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_delete_user.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_delete_user.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_delete_user.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_delete_user.dll
│ │ │ │ ├── mcp_delete_user.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_delete_user.csproj.nuget.g.props
│ │ │ │ ├── mcp_delete_user.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── Code Archiv
│ │ │ ├── mcp_chat.cs
│ │ │ ├── mcp_continue_chat.cs
│ │ │ ├── mcp_create_source.cs
│ │ │ ├── mcp_delete_group.cs
│ │ │ ├── mcp_delete_source.cs
│ │ │ ├── mcp_delete_user.cs
│ │ │ ├── mcp_edit_source.cs
│ │ │ ├── mcp_edit_user.cs
│ │ │ ├── mcp_get_chat_info.cs
│ │ │ ├── mcp_get_source.cs
│ │ │ ├── mcp_list_groups.cs
│ │ │ ├── mcp_list_sources.cs
│ │ │ ├── mcp_login.cs
│ │ │ ├── mcp_logout.cs
│ │ │ ├── mcp_store_group.cs
│ │ │ └── mcp_store_user.cs
│ │ └── README.md
│ ├── C++
│ │ ├── .vscode
│ │ │ └── launch.json
│ │ ├── 1.0 mcp_login
│ │ │ ├── MCPLoginClient.cpp
│ │ │ └── Non-TLS version
│ │ │ ├── MCPLoginClient.cpp
│ │ │ └── MCPLoginClient.exe
│ │ ├── 1.1 mcp_logout
│ │ │ ├── MCPLogoutClient.cpp
│ │ │ └── MCPLogoutClient.exe
│ │ ├── 2.0 mcp_chat
│ │ │ ├── MCPChatClient.cpp
│ │ │ └── MCPChatClient.exe
│ │ ├── 2.1 mcp_continue_chat
│ │ │ ├── MCPChatContinuationClient.cpp
│ │ │ └── MCPChatContinuationClient.exe
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ ├── MCPGetChatInfoClient.cpp
│ │ │ └── MCPGetChatInfoClient.exe
│ │ ├── 3.0 mcp_create_source
│ │ │ ├── MCPCreateSourceClient.cpp
│ │ │ └── MCPCreateSourceClient.exe
│ │ ├── 3.1 mcp_get_source
│ │ │ ├── MCPGetSourceClient.cpp
│ │ │ └── MCPGetSourceClient.exe
│ │ ├── 3.2 mcp_list_sources
│ │ │ ├── MCPListSourcesClient.cpp
│ │ │ └── MCPListSourcesClient.exe
│ │ ├── 3.3 mcp_edit_source
│ │ │ ├── MCPEditSourceClient.cpp
│ │ │ └── MCPEditSourceClient.exe
│ │ ├── 3.4 mcp_delete_source
│ │ │ ├── MCPDeleteSourceClient.cpp
│ │ │ └── MCPDeleteSourceClient.exe
│ │ ├── 4.0 mcp_list_groups
│ │ │ ├── MCPListGroupsClient.cpp
│ │ │ └── MCPListGroupsClient.exe
│ │ ├── 4.1 mcp_store_group
│ │ │ ├── MCPStoreGroupClient.cpp
│ │ │ └── MCPStoreGroupClient.exe
│ │ ├── 4.2 mcp_delete_group
│ │ │ ├── MPCDeleteGroupClient.cpp
│ │ │ └── MPCDeleteGroupClient.exe
│ │ ├── 5.0 mcp_store_user
│ │ │ ├── MCPStoreUserClient.cpp
│ │ │ └── MCPStoreUserClient.exe
│ │ ├── 5.1 mcp_edit_user
│ │ │ ├── MCPEditUserClient.cpp
│ │ │ └── MCPEditUserClient.exe
│ │ ├── 5.2 mcp_delete_user
│ │ │ ├── MCPDeleteUserClient.cpp
│ │ │ └── MCPDeleteUserClient.exe
│ │ ├── 9.0 mcp_keygen
│ │ │ ├── MCPKeygenClient.cpp
│ │ │ └── MCPKeygenClient.exe
│ │ └── README.md
│ ├── Go
│ │ ├── 1.0 mcp_login
│ │ │ ├── go.mod
│ │ │ ├── MCPLoginClient.exe
│ │ │ └── MCPLoginClient.go
│ │ ├── 1.1 mcp_logout
│ │ │ ├── MCPLogoutClient.exe
│ │ │ └── MCPLogoutClient.go
│ │ ├── 2.0 mcp_chat
│ │ │ ├── MCPChatClient.exe
│ │ │ └── MCPChatClient.go
│ │ ├── 2.1 mcp_continue_chat
│ │ │ ├── MCPChatContinuationClient.exe
│ │ │ └── MCPChatContinuationClient.go
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ ├── MCPGetChatInfoClient.exe
│ │ │ └── MCPGetChatInfoClient.go
│ │ ├── 3.0 mcp_create_source
│ │ │ ├── MCPCreateSourceClient.exe
│ │ │ └── MCPCreateSourceClient.go
│ │ ├── 3.1 mcp_get_source
│ │ │ ├── MCPGetSourceClient.exe
│ │ │ └── MCPGetSourceClient.go
│ │ ├── 3.2 mcp_list_sources
│ │ │ ├── MCPListSourcesClient.exe
│ │ │ └── MCPListSourcesClient.go
│ │ ├── 3.3 mcp_edit_source
│ │ │ ├── MCPEditSourceClient.exe
│ │ │ └── MCPEditSourceClient.go
│ │ ├── 3.4 mcp_delete_source
│ │ │ ├── MCPDeleteSourceClient.exe
│ │ │ └── MCPDeleteSourceClient.go
│ │ ├── 4.0 mcp_list_groups
│ │ │ ├── MCPListGroupsClient.exe
│ │ │ └── MCPListGroupsClient.go
│ │ ├── 4.1 mcp_store_group
│ │ │ ├── MCPStoreGroupClient.exe
│ │ │ └── MCPStoreGroupClient.go
│ │ ├── 4.2 mcp_delete_group
│ │ │ ├── MCPDeleteGroupClient.exe
│ │ │ └── MCPDeleteGroupClient.go
│ │ ├── 5.0 mcp_store_user
│ │ │ ├── MCPStoreUserClient.exe
│ │ │ └── MCPStoreUserClient.go
│ │ ├── 5.1 mcp_edit_user
│ │ │ ├── MCPEditUserClient.exe
│ │ │ └── MCPEditUserClient.go
│ │ ├── 5.2 mcp_delete_user
│ │ │ ├── MCPDeleteUserClient.exe
│ │ │ └── MCPDeleteUserClient.go
│ │ ├── 9.0 mcp_keygen
│ │ │ ├── MCPKeygenClient.exe
│ │ │ └── MCPKeygenClient.go
│ │ └── README.md
│ ├── Gradio
│ │ ├── Api.py
│ │ ├── config.json.example
│ │ ├── config.py
│ │ ├── favicon.ico
│ │ ├── file_tools
│ │ │ └── loader_factory.py
│ │ ├── language.py
│ │ ├── logos
│ │ │ ├── fsas.png
│ │ │ └── Logo_dark.svg
│ │ ├── main.py
│ │ ├── mcp_client.py
│ │ ├── mcp_servers
│ │ │ ├── arxiv
│ │ │ │ ├── arxiv-stdio.js
│ │ │ │ ├── package.json
│ │ │ │ ├── README.md
│ │ │ │ ├── requirements.txt
│ │ │ │ └── server_config.example.json
│ │ │ ├── demo-mcp-server
│ │ │ │ ├── demo-tools-sse.js
│ │ │ │ ├── demo-tools-stdio.js
│ │ │ │ └── tools
│ │ │ │ ├── assets.js
│ │ │ │ ├── calculator.js
│ │ │ │ └── weather.js
│ │ │ ├── filesystem
│ │ │ │ ├── Dockerfile
│ │ │ │ ├── index.ts
│ │ │ │ ├── package.json
│ │ │ │ ├── README.md
│ │ │ │ ├── test
│ │ │ │ │ └── new.txt
│ │ │ │ └── tsconfig.json
│ │ │ ├── moondream
│ │ │ │ └── server.py
│ │ │ ├── pgpt
│ │ │ │ ├── __init__.py
│ │ │ │ ├── Api.py
│ │ │ │ ├── config.json.example
│ │ │ │ ├── config.py
│ │ │ │ ├── language.py
│ │ │ │ ├── pyproject.toml
│ │ │ │ ├── README.md
│ │ │ │ └── server.py
│ │ │ ├── replicate_flux
│ │ │ │ └── server.py
│ │ │ └── sqlite
│ │ │ ├── .python-version
│ │ │ ├── Dockerfile
│ │ │ ├── pyproject.toml
│ │ │ ├── README.md
│ │ │ └── src
│ │ │ └── mcp_server_sqlite
│ │ │ ├── __init__.py
│ │ │ └── server.py
│ │ ├── messages
│ │ │ ├── __init__.py
│ │ │ ├── message_types
│ │ │ │ ├── __init__.py
│ │ │ │ ├── incrementing_id_message.py
│ │ │ │ ├── initialize_message.py
│ │ │ │ ├── json_rpc_message.py
│ │ │ │ ├── ping_message.py
│ │ │ │ ├── prompts_messages.py
│ │ │ │ ├── prompts_models.py
│ │ │ │ ├── resources_messages.py
│ │ │ │ └── tools_messages.py
│ │ │ ├── send_call_tool.py
│ │ │ ├── send_initialize_message.py
│ │ │ ├── send_message.py
│ │ │ ├── send_ping.py
│ │ │ ├── send_prompts.py
│ │ │ ├── send_resources.py
│ │ │ └── send_tools_list.py
│ │ ├── README.md
│ │ ├── requirements.txt
│ │ ├── server_config.json
│ │ ├── SourceManagement.py
│ │ ├── transport
│ │ │ ├── __init__.py
│ │ │ └── stdio
│ │ │ ├── __init__.py
│ │ │ ├── stdio_client.py
│ │ │ ├── stdio_server_parameters.py
│ │ │ └── stdio_server_shutdown.py
│ │ ├── tsconfig.json
│ │ └── UserManagement.py
│ ├── Java
│ │ ├── 1.0 mcp_login
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPLoginClient.class
│ │ │ └── MCPLoginClient.java
│ │ ├── 1.1 mcp_logout
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPLogoutClient.class
│ │ │ └── MCPLogoutClient.java
│ │ ├── 2.0 mcp_chat
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPChatClient.class
│ │ │ └── MCPChatClient.java
│ │ ├── 2.1 mcp_continue_chat
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPContinueChatClient.class
│ │ │ └── MCPContinueChatClient.java
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPGetChatInfoClient.class
│ │ │ └── MCPGetChatInfoClient.java
│ │ ├── 3.0 mcp_create_source
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPCreateSourceClient.class
│ │ │ └── MCPCreateSourceClient.java
│ │ ├── 3.1 mcp_get_source
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPGetSourceClient.class
│ │ │ └── MCPGetSourceClient.java
│ │ ├── 3.2 mcp_list_sources
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPListSourcesClient.class
│ │ │ └── MCPListSourcesClient.java
│ │ ├── 3.3 mcp_edit_source
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPEditSourceClient.class
│ │ │ └── MCPEditSourceClient.java
│ │ ├── 3.4 mcp_delete_source
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPDeleteSourceClient.class
│ │ │ └── MCPDeleteSourceClient.java
│ │ ├── 4.0 mcp_list_groups
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPListGroupsClient.class
│ │ │ └── MCPListGroupsClient.java
│ │ ├── 4.1 mcp_store_group
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPStoreGroupClient.class
│ │ │ └── MCPStoreGroupClient.java
│ │ ├── 4.2 mcp_delete_group
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPDeleteGroupClient.class
│ │ │ └── MCPDeleteGroupClient.java
│ │ ├── 5.0 mcp_store_user
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPStoreUserClient.class
│ │ │ └── MCPStoreUserClient.java
│ │ ├── 5.1 mcp_edit_user
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPEditUserClient.class
│ │ │ └── MCPEditUserClient.java
│ │ ├── 5.2 mcp_delete_user
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPDeleteUserClient.class
│ │ │ └── MCPDeleteUserClient.java
│ │ └── README.md
│ ├── JavaScript
│ │ ├── 1.0 mcp_login
│ │ │ └── MCPLoginClient.js
│ │ ├── 1.1 mcp_logout
│ │ │ └── MCPLogoutClient.js
│ │ ├── 2.0 mcp_chat
│ │ │ └── MCPChatClient.js
│ │ ├── 2.1 mcp_continue_chat
│ │ │ └── MCPContinueChatClient.js
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ └── MCPGetChatInfoClient.js
│ │ ├── 3.0 mcp_create_source
│ │ │ └── MCPCreateSourceClient.js
│ │ ├── 3.1 mcp_get_source
│ │ │ └── MCPGetSourceClient.js
│ │ ├── 3.2 mcp_list_sources
│ │ │ └── MCPListSourcesClient.js
│ │ ├── 3.3 mcp_edit_source
│ │ │ └── MCPEditSourceClient.js
│ │ ├── 3.4 mcp_delete_source
│ │ │ └── MCPDeleteSourceClient.js
│ │ ├── 4.0 mcp_list_groups
│ │ │ └── MCPListGroupsClient.js
│ │ ├── 4.1 mcp_store_group
│ │ │ └── MCPStoreGroupClient.js
│ │ ├── 4.2 mcp_delete_group
│ │ │ └── MCPDeleteGroupClient.js
│ │ ├── 5.0 mcp_store_user
│ │ │ └── MCPStoreUserClient.js
│ │ ├── 5.1 mcp_edit_user
│ │ │ └── MCPEditUserClient.js
│ │ ├── 5.2 mcp_delete_user
│ │ │ └── MCPDeleteUserClient.js
│ │ ├── 9.0 mcp_keygen
│ │ │ └── MCPKeygenClient.js
│ │ └── README.md
│ ├── PHP
│ │ ├── 1.0 mcp_login
│ │ │ └── MCPLoginClient.php
│ │ ├── 1.1 mcp_logout
│ │ │ └── MCPLogoutClient.php
│ │ ├── 2.0 mcp_chat
│ │ │ └── MCPChatClient.php
│ │ ├── 2.1 mcp_continue_chat
│ │ │ └── MCPContinueChatClient.php
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ └── MCPGetChatInfoClient.php
│ │ ├── 3.0 mcp_create_source
│ │ │ └── MCPCreateSourceClient.php
│ │ ├── 3.1 mcp_get_source
│ │ │ └── MCPGetSourceClient.php
│ │ ├── 3.2 mcp_list_sources
│ │ │ └── MCPListSourcesClient.php
│ │ ├── 3.3 mcp_edit_source
│ │ │ └── MCPEditSourceClient.php
│ │ ├── 3.4 mcp_delete_source
│ │ │ └── MCPDeleteSourceClient.php
│ │ ├── 4.0 mcp_list_groups
│ │ │ └── MCPListGroupsClient.php
│ │ ├── 4.1 mcp_store_group
│ │ │ └── MCPStoreGroupClient.php
│ │ ├── 4.2 mcp_delete_group
│ │ │ └── MCPDeleteGroupClient.php
│ │ ├── 5.0 mcp_store_user
│ │ │ └── MCPStoreUserClient.php
│ │ ├── 5.1 mcp_edit_user
│ │ │ └── MCPEditUserClient.php
│ │ ├── 5.2 mcp_delete_user
│ │ │ └── MCPDeleteUserClient.php
│ │ ├── 9.0 mcp_keygen
│ │ │ └── MCPKeygenClient.php
│ │ └── README.md
│ └── Python
│ ├── __init__.py
│ ├── 1.0 mcp_login
│ │ └── MCPLoginClient.py
│ ├── 1.1 mcp_logout
│ │ └── MCPLogoutClient.py
│ ├── 2.0 mcp_chat
│ │ └── MCPChatClient.py
│ ├── 2.1 mcp_continue_chat
│ │ └── MCPContinueChatClient.py
│ ├── 2.2 mcp_get_chat_info
│ │ └── MCPGetChatInfoClient.py
│ ├── 2.3 mcp_delete_all_chats
│ │ └── MCPDeleteAllChatsClient.py
│ ├── 2.4 mcp_delete_chat
│ │ └── MCPDeleteChatClient.py
│ ├── 3.0 mcp_create_source
│ │ └── MCPCreateSourceClient.py
│ ├── 3.1 mcp_get_source
│ │ └── MCPGetSourceClient.py
│ ├── 3.2 mcp_list_sources
│ │ └── MCPListSourcesClient.py
│ ├── 3.3 mcp_edit_source
│ │ └── MCPEditSourceClient.py
│ ├── 3.4 mcp_delete_source
│ │ └── MCPDeleteSourceClient.py
│ ├── 4.0 mcp_list_groups
│ │ └── MCPListGroupsClient.py
│ ├── 4.1 mcp_store_group
│ │ └── MCPStoreGroupClient.py
│ ├── 4.2 mcp_delete_group
│ │ └── MCPDeleteGroupClient.py
│ ├── 5.0 mcp_store_user
│ │ └── MCPStoreUserClient.py
│ ├── 5.1 mcp_edit_user
│ │ └── MCPEditUserClient.py
│ ├── 5.2 mcp_delete_user
│ │ └── MCPDeleteUserClient.py
│ ├── 9.0 mcp_keygen
│ │ └── MCPKeygenClient.py
│ ├── Gradio
│ │ ├── __init__.py
│ │ └── server_config.json
│ └── README.md
├── examples
│ ├── create_users_from_csv
│ │ ├── config.json.example
│ │ ├── config.py
│ │ ├── create_users_from_csv.py
│ │ └── language.py
│ ├── dynamic_sources
│ │ └── rss_reader
│ │ ├── Api.py
│ │ ├── config.json.example
│ │ ├── config.py
│ │ ├── demo_dynamic_sources.py
│ │ └── rss_parser.py
│ ├── example_users_to_add_no_tz.csv
│ └── sftp_upload_with_id
│ ├── Api.py
│ ├── config_ftp.json.example
│ ├── config.py
│ ├── demo_upload.py
│ ├── language.py
│ └── requirements.txt
├── images
│ ├── alternative mcp client.png
│ ├── favicon
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ └── site.webmanifest
│ ├── mcp-general-architecture.png
│ ├── privateGPT-MCP.png
│ └── privateGPT.png
├── InstallMPCServer.sh
├── jest.config.js
├── LICENSE
├── package.json
├── pgpt.env.json.example
├── README.md
├── security
│ ├── generate_decrypted_password.js
│ └── generate_encrypted_password.js
├── src
│ ├── helper.js
│ ├── index.js
│ ├── logger.js
│ ├── pgpt-messages.js
│ ├── public
│ │ ├── index.html
│ │ └── pgpt-mcp-logo.png
│ ├── services
│ │ └── pgpt-service.ts
│ └── types
│ └── api.ts
├── start_chatbot_agent.ps1
├── start_chatbot_agent.sh
├── start_iot_agent.ps1
├── start_iot_agent.sh
├── start_openai_compatible_api_agent.ps1
├── start_openai_compatible_api_agent.sh
├── tsconfig.json
├── ver
│ ├── index_np.js
│ └── index_proxy_np.js
└── WORKLOG.md
```
# Files
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
```javascript
1 | #!/usr/bin/env node
2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4 | import {
5 | CallToolRequestSchema,
6 | ErrorCode,
7 | ListResourcesRequestSchema,
8 | ListResourceTemplatesRequestSchema,
9 | ListToolsRequestSchema,
10 | McpError,
11 | ReadResourceRequestSchema
12 | } from '@modelcontextprotocol/sdk/types.js';
13 | import axios from 'axios';
14 | import https from 'https';
15 | import dotenv from 'dotenv';
16 | import net from 'net';
17 | import { fileURLToPath } from 'url';
18 | import path from 'path';
19 | import fs from 'fs';
20 | import os from 'os';
21 | import crypto from 'crypto';
22 | import moment from 'moment'; // Optional: Entfernen, wenn nicht benötigt
23 | import { prefixMessages, messages } from './pgpt-messages.js';
24 | import { logEvent, setAllowWrittenLogfile, LOG_FILE_PATH } from './logger.js';
25 | import figlet from 'figlet';
26 | import chalk from 'chalk';
27 | import { promisify } from 'util';
28 | import express from 'express';
29 | import { createServer as createHttpServer } from 'http';
30 | import { Server as SocketIoServer } from 'socket.io';
31 | import chokidar from 'chokidar';
32 | import stripAnsi from 'strip-ansi';
33 | import tls from 'tls';
34 |
35 |
36 | // Promisifizieren von figlet.text für die Verwendung mit async/await
37 | const figletAsync = promisify(figlet.text);
38 |
39 | dotenv.config({ path: './pgpt.env' }); // Geben Sie explizit den Pfad zur Datei an
40 |
41 | // JSON-Datei laden
42 | // `__dirname`-Ersatz für ES-Module
43 | const __filename = fileURLToPath(import.meta.url);
44 | const __dirname = path.dirname(__filename);
45 |
46 | // JSON-Dateipfad relativ zum Skript
47 | const envFilePath = path.resolve(__dirname, '../pgpt.env.json');
48 | let envConfig;
49 |
50 | try {
51 | envConfig = JSON.parse(fs.readFileSync(envFilePath, 'utf-8'));
52 | } catch (error) {
53 | logEvent('system', 'conf', 'Env Load Err', error.message, 'error');
54 | process.exit(1);
55 | }
56 |
57 | // Helper-Funktionen
58 | function getEnvVar(key, nestedPath = null, fallback = null) {
59 | // Prüfen, ob ein verschachtelter Pfad angegeben ist
60 | if (nestedPath) {
61 | const value = nestedPath.reduce((acc, part) => acc && acc[part], envConfig);
62 | if (value === undefined || value === null) {
63 | if (fallback !== null) return fallback;
64 | logEvent(
65 | 'system',
66 | 'conf',
67 | 'Missing Config',
68 | `Missing .json configuration variable: ${key}`,
69 | 'error'
70 | );
71 | process.exit(1);
72 | }
73 | return value;
74 | }
75 | // Direkter Zugriff
76 | if (envConfig[key] === undefined || envConfig[key] === null) {
77 | if (fallback !== null) return fallback;
78 | logEvent(
79 | 'system',
80 | 'conf',
81 | 'Missing Config',
82 | `Missing .json configuration variable: ${key}`,
83 | 'error'
84 | );
85 | process.exit(1);
86 | }
87 | return envConfig[key];
88 | }
89 |
90 | // Nachrichten basierend auf Sprache
91 | let lang = getEnvVar('LANGUAGE', ['Server_Config', 'LANGUAGE'], 'en').toLowerCase();
92 | if (!(lang in messages)) {
93 | logEvent('system', 'conf', 'Lang Warning', `Language "${lang}" is not supported. Fallback in English.`, 'warn');
94 | lang = 'en';
95 | }
96 |
97 | const t = messages[lang];
98 | const l = prefixMessages[lang];
99 |
100 | /**
101 | * Funktion zum Anzeigen des Startheaders
102 | */
103 | function displayStartHeader() {
104 | // Generiere ASCII-Art
105 | figlet.text('Fujitsu PGPT MCP-Server', {
106 | font: 'Slant', // Schriftart, kann angepasst werden
107 | horizontalLayout: 'default',
108 | verticalLayout: 'default',
109 | width: 80,
110 | whitespaceBreak: true
111 | }, function(err, data) {
112 | if (err) {
113 | logEvent('system', 'CLI', l.prefix_Env_Load_Err, t.errorCreatingAsciiArt, 'error');
114 | console.dir(err);
115 | return;
116 | }
117 | // Farbige Ausgabe mit Chalk
118 | console.log(
119 | chalk.green.bold(data) + '\n' +
120 | chalk.blue(`${t.mcpVersion} 2.1.0\n`) +
121 | chalk.yellow(`${t.mcpPort} ${Port}\n`) +
122 | chalk.cyan(`${t.mcpStartTime} ${new Date().toLocaleString()}\n`) +
123 | chalk.magenta(`${t.mcpLicense} MIT`)
124 | );
125 | });
126 | }
127 |
128 | const privateApiUrl = getEnvVar('PRIVATE_GPT_API_URL', ['PGPT_Url', 'PRIVATE_GPT_API_URL']);
129 | const requestedLang = getEnvVar('LANGUAGE', ['Server_Config', 'LANGUAGE'], 'en').toLowerCase();
130 | const apiUrl = getEnvVar('API_URL', ['PGPT_Url', 'API_URL']);
131 | const Port = getEnvVar('PORT', ['Server_Config', 'PORT'], '5000');
132 | const restrictedGroups = getEnvVar('RESTRICTED_GROUPS', ['Restrictions', 'RESTRICTED_GROUPS'], 'false').toString();
133 | const OpenAICompAPI = getEnvVar('ENABLE_OPEN_AI_COMP_API', ['Restrictions', 'ENABLE_OPEN_AI_COMP_API'], 'false').toString();
134 | const sslValidate = getEnvVar('SSL_VALIDATE', ['Server_Config', 'SSL_VALIDATE'], 'false').toString();
135 | const enableTLS = getEnvVar('ENABLE_TLS', ['Server_Config', 'ENABLE_TLS'], 'false').toLowerCase() === 'true';
136 | const PwEncryption = getEnvVar('PW_ENCRYPTION', ['Server_Config', 'PW_ENCRYPTION'], 'false') === 'true';
137 | const AllowKeygen = getEnvVar('ALLOW_KEYGEN', ['Server_Config', 'ALLOW_KEYGEN'], 'false') === 'true';
138 | const allowWrittenLogfile = getEnvVar('WRITTEN_LOGFILE', ['Logging', 'WRITTEN_LOGFILE'], 'false').toString();
139 | const LogIps = getEnvVar('LOG_IPs', ['Logging', 'LOG_IPs'], 'false').toString();
140 | const anonymousMode = getEnvVar('ANONYMOUS_MODE', ['Logging', 'ANONYMOUS_MODE'], 'false').toString();
141 |
142 | // Funktion zur Pfad-Expansion
143 | function expandPath(filePath) {
144 | if (filePath.startsWith('~')) {
145 | return path.join(os.homedir(), filePath.slice(1));
146 | }
147 | return filePath;
148 | }
149 |
150 | // Load the public key
151 | const publicKeyPath = expandPath(getEnvVar('PUBLIC_KEY', ['Server_Config', 'PUBLIC_KEY']));
152 | const privateKeyPath = expandPath(getEnvVar('PRIVATE_KEY', ['Server_Config', 'PRIVATE_KEY']));
153 |
154 | const sslKeyPath = expandPath(getEnvVar('SSL_KEY_PATH', ['Server_Config', 'SSL_KEY_PATH']));
155 | const sslCertPath = expandPath(getEnvVar('SSL_CERT_PATH', ['Server_Config', 'SSL_CERT_PATH']));
156 |
157 | let publicKey;
158 | let privateKey;
159 |
160 | try {
161 | publicKey = fs.readFileSync(publicKeyPath, 'utf8');
162 | privateKey = fs.readFileSync(privateKeyPath, 'utf8');
163 | logEvent('system', 'conf', l.prefix_Public_API_URL, publicKey, 'info'); // Möglicherweise hier ein anderer Prefix benötigt
164 | logEvent('system', 'conf', l.prefix_Private_API_URL, privateKey, 'info'); // Möglicherweise hier ein anderer Prefix benötigt
165 | } catch (error) {
166 | logEvent('system', 'conf', l.prefix_File_Path, error.path, 'error');
167 | logEvent('system', 'conf', l.prefix_Env_Load_Err, error.message, 'error');
168 | process.exit(1); // Abbrechen, falls Schlüssel nicht geladen werden können
169 | }
170 |
171 | if (PwEncryption) {
172 | logEvent('system', 'conf', l.prefix_PW_Encryption, t.passwordEncEnabled, 'info');
173 | } else {
174 | logEvent('system', 'conf', l.prefix_PW_Encryption, t.passwordEncDisabled, 'info');
175 | }
176 |
177 | function validateUrl(url, t) {
178 | if (!url.startsWith('https://')) {
179 | logEvent('system', 'conf', l.prefix_URL_Warning, t.apiUrlWarning, 'warn');
180 | url = url.replace(/^http:\/\//, 'https://');
181 | }
182 | url = url.replace(/([^:]\/)\/+/g, '$1'); // Doppelte Schrägstriche nach "://" entfernen
183 | if (!url.endsWith('/api/v1')) {
184 | logEvent('system', 'conf', l.prefix_URL_Warning_V1, t.apiUrlWarningV1, 'warn');
185 | url = `${url.replace(/\/$/, '')}/api/v1`;
186 | }
187 | try {
188 | new URL(url);
189 | } catch {
190 | logEvent('system', 'conf', l.prefix_URL_Invalid, `${t.apiUrlInvalid} ${url}`, 'error');
191 | process.exit(1);
192 | }
193 | return url;
194 | }
195 |
196 | function validatePort(port, t) {
197 | const portNumber = parseInt(port, 10);
198 | if (isNaN(portNumber) || portNumber < 1 || portNumber > 65535) {
199 | logEvent('system', 'conf', l.prefix_Port_Invalid, t.portInvalid, 'error');
200 | process.exit(1);
201 | }
202 | return portNumber;
203 | }
204 |
205 | function validateBoolean(varName, value, t, useProxy = false) {
206 | if (useProxy && (varName === 'HEADER_ENCRYPTED')) {
207 | if (value !== 'true' && value !== 'false') {
208 | logEvent('system', 'conf', l.prefix_Validation_Err,
209 | t.validationError.replace('${var}', varName).replace('${value}', value), 'error');
210 | process.exit(1);
211 | }
212 | return value === 'true';
213 | }
214 | // Allgemeine Validierung
215 | if (value !== 'true' && value !== 'false') {
216 | logEvent('system', 'conf', l.prefix_Validation_Err,
217 | t.validationError.replace('${var}', varName).replace('${value}', value), 'error');
218 | process.exit(1);
219 | }
220 | return value === 'true';
221 | }
222 |
223 | /**
224 | * Decrypt a cryptographic string using the private key.
225 | * @param {string} encryptedData - The encrypted string in Base64 format.
226 | * @returns {string} - The decrypted password.
227 | */
228 | /**
229 | * Decrypt a cryptographic string using the private key.
230 | * @param {string} encryptedData - The encrypted string in Base64 format.
231 | * @returns {string} - The decrypted password.
232 | */
233 | function decryptPassword(encryptedData) {
234 | try {
235 | const decryptedPassword = crypto.privateDecrypt(
236 | {
237 | key: privateKey,
238 | padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, //padding: crypto.constants.RSA_PKCS1_PADDING, // Ensure consistent padding
239 | },
240 | Buffer.from(encryptedData, 'base64')
241 | ).toString('utf8');
242 |
243 | return decryptedPassword;
244 | } catch (error) {
245 | logEvent('system', 'conf', l.prefix_PW_Encryption, error.message, 'error'); // Möglicherweise hier ein anderer Prefix benötigt
246 | throw new Error(t.decryptPwdError);
247 | }
248 | }
249 |
250 | // Funktion für Verschlüsselung
251 | function encryptWithPublicKey(data) {
252 | try {
253 | return crypto.publicEncrypt(
254 | {
255 | key: publicKey,
256 | padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, // Explicitly set padding
257 | },
258 | Buffer.from(data)
259 | ).toString('base64');
260 | } catch (err) {
261 | logEvent('system', 'conf', l.prefix_PW_Encryption, err.message, 'error'); // Möglicherweise hier ein anderer Prefix benötigt
262 | throw new Error(t.encryptPwdError);
263 | }
264 | }
265 |
266 | /**
267 | * Encrypt a given password and return the encrypted key.
268 | * @param {string} password - The password to be encrypted.
269 | * @returns {string} - The encrypted password as a Base64 string.
270 | */
271 | function getEncryptedKey(password) {
272 | try {
273 | return encryptWithPublicKey(password);
274 | } catch (err) {
275 | // Die Fehlerbehandlung wurde bereits in encryptWithPublicKey durchgeführt
276 | throw err;
277 | }
278 | }
279 |
280 | const enableLogin = getEnvVar('ENABLE_LOGIN', ['Functions', 'ENABLE_LOGIN'], false);
281 | const enableLogout = getEnvVar('ENABLE_LOGOUT', ['Functions', 'ENABLE_LOGOUT'], false);
282 | const enableChat = getEnvVar('ENABLE_CHAT', ['Functions', 'ENABLE_CHAT'], false);
283 | const enableContinueChat = getEnvVar('ENABLE_CONTINUE_CHAT', ['Functions', 'ENABLE_CONTINUE_CHAT'], false);
284 | const enableGetChatInfo = getEnvVar('ENABLE_GET_CHAT_INFO', ['Functions', 'ENABLE_GET_CHAT_INFO'], false);
285 | const enableDeleteAllChats = getEnvVar('ENABLE_DELETE_ALL_CHATS', ['Functions', 'ENABLE_DELETE_ALL_CHATS'], false);
286 | const enableDeleteChat = getEnvVar('ENABLE_DELETE_CHAT', ['Functions', 'ENABLE_DELETE_CHAT'], false);
287 | const enableListGroups = getEnvVar('ENABLE_LIST_GROUPS', ['Functions', 'ENABLE_LIST_GROUPS'], false);
288 | const enableStoreGroup = getEnvVar('ENABLE_STORE_GROUP', ['Functions', 'ENABLE_STORE_GROUP'], false);
289 | const enableDeleteGroup = getEnvVar('ENABLE_DELETE_GROUP', ['Functions', 'ENABLE_DELETE_GROUP'], false);
290 | const enableCreateSource = getEnvVar('ENABLE_CREATE_SOURCE', ['Functions', 'ENABLE_CREATE_SOURCE'], false);
291 | const enableEditSource = getEnvVar('ENABLE_EDIT_SOURCE', ['Functions', 'ENABLE_EDIT_SOURCE'], false);
292 | const enableDeleteSource = getEnvVar('ENABLE_DELETE_SOURCE', ['Functions', 'ENABLE_DELETE_SOURCE'], false);
293 | const enableGetSource = getEnvVar('ENABLE_GET_SOURCE', ['Functions', 'ENABLE_GET_SOURCE'], false);
294 | const enableListSources = getEnvVar('ENABLE_LIST_SOURCES', ['Functions', 'ENABLE_LIST_SOURCES'], false);
295 | const enableStoreUser = getEnvVar('ENABLE_STORE_USER', ['Functions', 'ENABLE_STORE_USER'], false);
296 | const enableEditUser = getEnvVar('ENABLE_EDIT_USER', ['Functions', 'ENABLE_EDIT_USER'], false);
297 | const enableDeleteUser = getEnvVar('ENABLE_DELETE_USER', ['Functions', 'ENABLE_DELETE_USER'], false);
298 | const enableReactivateUser = getEnvVar('ENABLE_REACTIVATE_USER', ['Functions', 'ENABLE_REACTIVATE_USER'], false);
299 |
300 |
301 |
302 | // Loggen der Server-Konfiguration
303 | logEvent('system', 'conf', l.prefix_Server_Config, JSON.stringify(envConfig, null, 2), 'info');
304 | logEvent('system', 'conf', l.prefix_Private_API_URL, privateApiUrl, 'info');
305 | logEvent('system', 'conf', l.prefix_Public_API_URL, apiUrl, 'info');
306 | logEvent('system', 'conf', l.prefix_Port, Port, 'info');
307 | logEvent('system', 'conf', l.prefix_Language, requestedLang, 'info');
308 | logEvent('system', 'conf', l.prefix_SSL_Validation, sslValidate, 'info');
309 | logEvent('system', 'conf', l.prefix_EnableTLS, enableTLS, 'info');
310 | logEvent('system', 'conf', l.prefix_sslKeyPath, sslKeyPath, 'info');
311 | logEvent('system', 'conf', l.prefix_sslCertPath, sslCertPath, 'info');
312 | logEvent('system', 'conf', l.prefix_PW_Encryption, PwEncryption ? t.encryptionEnabled : t.encryptionDisabled, 'info');
313 | logEvent('system', 'conf', l.prefix_Allow_Keygen, AllowKeygen ? t.keygenEnabled : t.keygenDisabled, 'info');
314 | logEvent('system', 'conf', l.prefix_Private_API_URL, privateKeyPath, 'info'); // Möglicherweise hier ein anderer Prefix benötigt
315 | logEvent('system', 'conf', l.prefix_Public_API_URL, publicKeyPath, 'info'); // Möglicherweise hier ein anderer Prefix benötigt
316 | logEvent('system', 'conf', l.prefix_Restricted_Groups, restrictedGroups, 'info');
317 | logEvent('system', 'conf', l.prefix_openaicompAPI, OpenAICompAPI, 'info');
318 | logEvent('system', 'conf', l.prefix_WRITTEN_LOGFILE, allowWrittenLogfile, 'info');
319 | logEvent('system', 'conf', l.prefix_LOG_IPs, LogIps, 'info');
320 | logEvent('system', 'conf', l.prefix_ANONYMOUS_MODE, anonymousMode, 'info');
321 |
322 | // Loggen der deaktivierten Funktionen
323 | const allFunctions = [
324 | { name: 'Login', enabled: enableLogin },
325 | { name: 'Logout', enabled: enableLogout },
326 | { name: 'Chat', enabled: enableChat },
327 | { name: 'Continue Chat', enabled: enableContinueChat },
328 | { name: 'Get Chat Info', enabled: enableGetChatInfo },
329 | { name: 'Delete All Chats', enabled: enableDeleteAllChats },
330 | { name: 'Delete Chat', enabled: enableDeleteChat },
331 | { name: 'List Groups', enabled: enableListGroups },
332 | { name: 'Store Group', enabled: enableStoreGroup },
333 | { name: 'Delete Group', enabled: enableDeleteGroup },
334 | { name: 'Create Source', enabled: enableCreateSource },
335 | { name: 'Edit Source', enabled: enableEditSource },
336 | { name: 'Delete Source', enabled: enableDeleteSource },
337 | { name: 'Get Source', enabled: enableGetSource },
338 | { name: 'List Sources', enabled: enableListSources },
339 | { name: 'Store User', enabled: enableStoreUser },
340 | { name: 'Edit User', enabled: enableEditUser },
341 | { name: 'Delete User', enabled: enableDeleteUser },
342 | { name: 'Reactivate User', enabled: enableReactivateUser },
343 | // { name: 'Open AI compatible API Chat', enabled: enableChat },
344 | // { name: 'Continue Chat', enabled: enableContinueChat },
345 | ];
346 |
347 | // Filtern, um nur deaktivierte (false) zu bekommen
348 | const disabledFunctions = allFunctions.filter(f => !f.enabled);
349 |
350 | // Loggen der deaktivierten Funktionen
351 | if (disabledFunctions.length === 0) {
352 | logEvent(
353 | 'system',
354 | 'conf',
355 | l.prefix_All_Funcs,
356 | t.allFunctionsEnabled,
357 | 'info'
358 | );
359 | } else {
360 | logEvent('system', 'conf', l.prefix_Deact_Funcs, t.deactivatedFunctions, 'warn');
361 | disabledFunctions.forEach(func => {
362 | logEvent('system', 'conf', func.name, t.functionDisabled, 'warn');
363 | });
364 | }
365 |
366 | logEvent('system', 'conf', l.prefix_Validation_Err, t.apiUrlValidated.replace('${url}', apiUrl), 'info');
367 |
368 | // Debugging für RESTRICTED_GROUPS
369 | logEvent(
370 | 'system',
371 | 'conf',
372 | l.prefix_Restricted_Groups,
373 | t.accessRestrictedGroups.replace('${val}', envConfig.Restrictions?.RESTRICTED_GROUPS.toString()),
374 | 'info'
375 | );
376 |
377 | // Zugriff und Validierung von RESTRICTED_GROUPS
378 | const isRestrictedGroupsEnabled = validateBoolean(
379 | 'RESTRICTED_GROUPS',
380 | restrictedGroups,
381 | t
382 | );
383 |
384 | logEvent('system', 'conf', l.prefix_Restricted_Groups, t.restrictedGroupsSuccess.replace('${status}', isRestrictedGroupsEnabled.toString()), 'info');
385 |
386 | // Zugriff und Validierung von WRITTEN_LOGFILE
387 | const isWrittenLogfileEnabled = validateBoolean(
388 | 'WRITTEN_LOGFILE',
389 | allowWrittenLogfile,
390 | t
391 | );
392 | logEvent('system', 'conf', l.prefix_WRITTEN_LOGFILE, t.AllowLoggingSuccess.replace('${status}', isWrittenLogfileEnabled.toString()), 'info');
393 | setAllowWrittenLogfile(isWrittenLogfileEnabled);
394 |
395 | // Zugriff und Validierung von LOG_IPs
396 | const isLogIpsEnabled = validateBoolean(
397 | 'LOG_IPs',
398 | LogIps,
399 | t
400 | );
401 | logEvent('system', 'conf', l.prefix_LOG_IPs, t.LogIpsSuccess.replace('${status}', isLogIpsEnabled.toString()), 'info');
402 |
403 | // Zugriff und Validierung von ANONYMOUS_MODE
404 | const isanonymousModeEnabled = validateBoolean(
405 | 'ANONYMOUS_MODE',
406 | anonymousMode,
407 | t
408 | );
409 | logEvent('system', 'conf', l.prefix_ANONYMOUS_MODE, t.anonymousModeSuccess.replace('${status}', isanonymousModeEnabled.toString()), 'info');
410 |
411 | function baseLogOptions() {
412 | return {
413 | AllowLoggingEnabled: isWrittenLogfileEnabled,
414 | LogIps: isLogIpsEnabled,
415 | anonymousMode: isanonymousModeEnabled,
416 | };
417 | }
418 |
419 | // SSL-Validierung
420 | const isSSLValidationEnabled = validateBoolean(
421 | 'SSL_VALIDATE',
422 | getEnvVar('SSL_VALIDATE', ['Server_Config', 'SSL_VALIDATE'], 'false').toString(),
423 | t
424 | );
425 |
426 | const sslSymbol = isSSLValidationEnabled ? '✔️' : '⚠️';
427 | logEvent('system', 'conf', l.prefix_SSL_Validation,
428 | t.sslValidationSet
429 | .replace('${symbol}', sslSymbol)
430 | .replace('${value}', String(isSSLValidationEnabled)),
431 | 'info'
432 | );
433 |
434 | // Port validieren
435 | const validatedPort = validatePort(Port, t);
436 | logEvent('system', 'conf', l.prefix_Port_Validated, t.portValidated.replace('${port}', validatedPort), 'info');
437 |
438 | // Einlesen der Proxy_Config-Parameter
439 | const useProxy = validateBoolean(
440 | 'USE_PROXY',
441 | getEnvVar('USE_PROXY', ['Proxy_Config', 'USE_PROXY'], 'false').toString(),
442 | t
443 | );
444 |
445 | const authHeaderEncrypted = useProxy ? validateBoolean(
446 | 'HEADER_ENCRYPTED',
447 | getEnvVar('HEADER_ENCRYPTED', ['Proxy_Config', 'HEADER_ENCRYPTED'], 'false').toString(),
448 | t,
449 | useProxy
450 | ) : false;
451 |
452 | const AccessHeader = useProxy ? getEnvVar('ACCESS_HEADER', ['Proxy_Config', 'ACCESS_HEADER'], null) : null;
453 |
454 | // Verarbeiten des Proxy-Passworts
455 | let ProxyAccessHeader;
456 | if (authHeaderEncrypted) {
457 | try {
458 | ProxyAccessHeader = decryptPassword(AccessHeader);
459 | } catch (error) {
460 | logEvent('system', 'conf', l.prefix_API_Request_Error, error.message, 'error'); // Möglicherweise hier ein anderer Prefix benötigt
461 | process.exit(1);
462 | }
463 | } else {
464 | ProxyAccessHeader = AccessHeader;
465 | }
466 |
467 | // Falls in der HAProxy-Konfiguration ein X-Custom-Header verlangt wird:
468 | const customHeaderValue = ProxyAccessHeader;
469 |
470 | // Optional: Überprüfen, ob alle erforderlichen Proxy-Daten vorhanden sind
471 | if (useProxy && authHeaderEncrypted) {
472 | if (!ProxyAccessHeader) {
473 | logEvent('system', 'conf', l.prefix_API_Request_Error, t.proxyAuthMissing, 'error'); // Möglicherweise hier ein anderer Prefix benötigt
474 | process.exit(1);
475 | }
476 | }
477 |
478 | // Ausgabe der Proxy-Konfiguration (mit maskiertem Passwort)
479 | logEvent('system', 'conf', l.prefix_Proxy_Config, t.proxyUseProxy.replace('${val}', useProxy), 'info');
480 |
481 | // Beispiel: Tool-Überprüfung
482 | function isToolEnabled(toolName) {
483 | const envKey = `ENABLE_${toolName.toUpperCase()}`;
484 | if (!(envKey in envConfig.Functions)) {
485 | logEvent(
486 | 'system', 'N/A', l.prefix_Tool_Warn, t.toolNotDefinedInConfig.replace('${toolName}', toolName), 'warn'
487 | );
488 | return false;
489 | }
490 | return envConfig.Functions[envKey] === true;
491 | }
492 |
493 | /* ################ Helper Functions ############################*/
494 | // Helper-Funktion, um zu prüfen, ob ein Tool aktiviert ist, und eine Fehlermeldung zu generieren
495 | function checkToolEnabled(toolName) {
496 | if (toolName === "keygen" && AllowKeygen) {
497 | return null;
498 | }
499 |
500 | if (toolName === "oai_comp_api") {
501 | if (OpenAICompAPI) {
502 | return null;
503 | } else {
504 | logEvent('system', 'N/A', l.prefix_Tool_Disabled, t.toolDisabledLog.replace('${toolName}', toolName), 'error');
505 | }
506 | }
507 |
508 | if (!OpenAICompAPI || !isToolEnabled(toolName)) {
509 | logEvent(
510 | 'system',
511 | 'N/A',
512 | l.prefix_Tool_Disabled,
513 | t.toolDisabledLog.replace('${toolName}', toolName),
514 | 'error'
515 | );
516 | return {
517 | status: 'error',
518 | message: messages[lang].toolDisabledError.replace('${toolName}', toolName),
519 | };
520 | }
521 |
522 | return null; // Tool ist aktiviert
523 | }
524 |
525 | function validateToken(token) {
526 | if (!token) {
527 | if (!isanonymousModeEnabled) logEvent('system', 'N/A', l.prefix_API_Request_Error, t.missingTokenError, 'error'); // Möglicherweise hier ein anderer Prefix benötigt
528 | return {
529 | status: 'error',
530 | message: t.missingTokenError,
531 | statusCode: 401 // Optional für konsistenten HTTP-Status
532 | };
533 | }
534 | return null;
535 | }
536 |
537 | function getArguments(input) {
538 | if (input.arguments) {
539 | return input.arguments;
540 | } else if (input.params?.arguments) {
541 | return input.params.arguments;
542 | } else {
543 | if (!isanonymousModeEnabled) logEvent(
544 | 'system', 'N/A', l.prefix_API_Request_Error, t.invalidArgumentsError.replace('${args}', JSON.stringify(input)), 'error' // Möglicherweise hier ein anderer Prefix benötigt
545 | );
546 | return {}; // Leeres Objekt als Fallback
547 | }
548 | }
549 |
550 | // Parameter zuordnen
551 | const API_URL = apiUrl;
552 | const PORT = Port;
553 |
554 | // Server-Startkonfiguration ausgeben
555 | const serverConfig = JSON.stringify({ API_URL, PORT }, null, 2);
556 | logEvent('system', 'N/A', l.prefix_Server_Config, t.serverStartedLog, 'info');
557 | // mit Konfiguration: ${serverConfig}
558 |
559 | // Funktion zum Erstellen der Authorization-Header für Basic Auth
560 | function createBasicAuthHeader(username, password) {
561 | const authString = Buffer.from(`${username}:${password}`).toString('base64');
562 | return `Basic ${authString}`;
563 | }
564 |
565 |
566 | /* const t = { // Beispielhafte Sprachvariablen
567 | ConnectionEstablished: 'Verbindung hergestellt',
568 | dataReceivedMsg: 'Daten empfangen: ${data}',
569 | ResponseSuccessfullySent: 'Antwort erfolgreich gesendet',
570 | ConnectionClosed: 'Verbindung geschlossen',
571 | ServerStopped: 'Server gestoppt'
572 | };
573 | const l = { // Beispielhafte Log-Prefixes
574 | prefix_tcpServerError: 'TCP-Server Fehler',
575 | prefix_Shutdown: 'Herunterfahren'
576 | };*/
577 |
578 | export class TcpServerTransport {
579 | /**
580 | * Konstruktor
581 | * @param {number} port - Port, auf dem der Server lauschen soll.
582 | * @param {boolean} enableTLS - true, wenn SSL/TLS verwendet werden soll, ansonsten false.
583 | * @param {string} sslKeyPath - Pfad zur SSL-Schlüsseldatei (nur benötigt, wenn enableTLS true ist).
584 | * @param {string} sslCertPath - Pfad zur SSL-Zertifikatsdatei (nur benötigt, wenn enableTLS true ist).
585 | */
586 | constructor(port, enableTLS, sslKeyPath, sslCertPath) {
587 | this.port = port;
588 | this.server = null;
589 | this.clients = new Map(); // Map zur Speicherung der Clients
590 | this.enableTLS = enableTLS; // Flag, ob SSL/TLS verwendet werden soll
591 |
592 |
593 | if (this.enableTLS && (!fs.existsSync(sslKeyPath) || !fs.existsSync(sslCertPath))) {
594 | logEvent('system', 'TLS', l.prefix_sslError, t.NoTLSCertFound, 'error');
595 | process.exit(1);
596 | }
597 | //
598 | // Falls SSL aktiviert ist, laden wir die TLS-Optionen (Schlüssel und Zertifikat)
599 | if (this.enableTLS) {
600 | this.tlsOptions = {
601 | key: fs.readFileSync(sslKeyPath),
602 | cert: fs.readFileSync(sslCertPath)
603 | // Falls CA benötigt wird, z. B.:
604 | // ca: fs.readFileSync(caPath),
605 | // requestCert: false, // oder true, wenn Clients sich per Zertifikat ausweisen sollen
606 | };
607 | }
608 | }
609 |
610 | /**
611 | * Startet den Server.
612 | * @param {Function} onMessage - Callback-Funktion, die auf eingehende Nachrichten reagiert.
613 | * @returns {Promise} - Wird erfüllt, wenn der Server erfolgreich gestartet wurde.
614 | */
615 | async start(onMessage) {
616 | return new Promise((resolve, reject) => {
617 | // Entscheide anhand des enableTLS-Flags, ob ein TLS/SSL-Server oder ein normaler TCP-Server gestartet wird.
618 | if (this.enableTLS) {
619 | this.server = tls.createServer(this.tlsOptions, (socket) => {
620 | this.handleConnection(socket, onMessage);
621 | });
622 | } else {
623 | this.server = net.createServer((socket) => {
624 | this.handleConnection(socket, onMessage);
625 | });
626 | }
627 |
628 | // Hinzufügen des 'connection'-Listeners (einmalig außerhalb des createServer-Callbacks)
629 | this.server.on('connection', (socket) => {
630 | if (!isanonymousModeEnabled) {
631 | logEvent('server', socket.remotePort || 'unknown', 'Connection Established', t.ConnectionEstablished, 'info');
632 | }
633 | socket.setKeepAlive(true, 30000); // Keep-Alive für jede Verbindung
634 | });
635 |
636 | // Server starten
637 | this.server.listen(this.port, () => {
638 | const modus = this.enableTLS ? 'TLS/SSL' : 'Plain TCP';
639 | if (!isanonymousModeEnabled) {
640 | logEvent('server', this.port, 'Server Start', `Server lauscht auf Port ${this.port} [${modus}]`, 'info');
641 | }
642 | resolve();
643 | });
644 |
645 | // Fehlerbehandlung auf Server-Ebene
646 | this.server.on('error', (err) => {
647 | if (!isanonymousModeEnabled) {
648 | logEvent('server', this.port, l.prefix_tcpServerError, `Serverfehler: ${err.message || err}`, 'error');
649 | }
650 | reject(err);
651 | });
652 | });
653 | }
654 |
655 | /**
656 | * Behandelt eingehende Verbindungen.
657 | * @param {object} socket - Das Socket-Objekt der Verbindung.
658 | * @param {Function} onMessage - Callback, das auf empfangene Nachrichten reagiert.
659 | */
660 | handleConnection(socket, onMessage) {
661 | const clientIP = socket.remoteAddress || 'unknown';
662 | const clientPort = socket.remotePort || 'unknown';
663 | this.clients.set(socket, { ip: clientIP, port: clientPort });
664 |
665 | // Logging: Neue Verbindung
666 | if (isLogIpsEnabled) {
667 | if (!isanonymousModeEnabled) {
668 | logEvent(clientIP, clientPort, 'Connection New', t.ConnectionEstablished, 'info');
669 | }
670 | } else {
671 | if (!isanonymousModeEnabled) {
672 | logEvent('*****', '****', 'Connection New', t.ConnectionEstablished, 'info');
673 | }
674 | }
675 |
676 | socket.on('error', (err) => {
677 | const client = this.clients.get(socket);
678 | // ECONNRESET speziell behandeln
679 | if (err.code === 'ECONNRESET') {
680 | // Wenn gewünscht, nur auf „info“-Level loggen oder gar nicht
681 | if (!isanonymousModeEnabled) {
682 | if (isLogIpsEnabled) {
683 | logEvent(
684 | client?.ip || 'unknown',
685 | client?.port || 'unknown',
686 | 'Socket Warn',
687 | t.ErrorConnReset,
688 | 'info' );
689 | } else {
690 | logEvent(
691 | '*****',
692 | '*****',
693 | 'Socket Warn',
694 | t.ErrorConnReset,
695 | 'info' );
696 | }
697 | }
698 | return;
699 | }
700 |
701 | // Andere Fehler normal als 'error' loggen
702 | if (!isanonymousModeEnabled) {
703 | if (isLogIpsEnabled) {
704 | logEvent(
705 | client?.ip || 'unknown',
706 | client?.port || 'unknown',
707 | 'Socket Error',
708 | `Socket-Error: ${err.message || err}`,
709 | 'error' );
710 | } else {
711 | logEvent(
712 | '*****',
713 | '*****',
714 | 'Socket Error',
715 | `Socket-Error: ${err.message || err}`,
716 | 'error' );
717 | };
718 | }
719 | });
720 | // Ereignis: Daten empfangen
721 | socket.on('data', async (data) => {
722 | const client = this.clients.get(socket);
723 | if (isLogIpsEnabled) {
724 | if (!isanonymousModeEnabled) {
725 | logEvent(client.ip, client.port, 'Data Received', t.dataReceivedMsg.replace('${data}', data.toString()), 'info');
726 | }
727 | } else {
728 | if (!isanonymousModeEnabled) {
729 | logEvent('*****', '****', 'Data Received', t.dataReceivedMsg.replace('${data}', data.toString()), 'info');
730 | }
731 | }
732 |
733 | try {
734 | const message = JSON.parse(data.toString());
735 | const response = await onMessage(message);
736 | const responseString = JSON.stringify(response) + '\n'; // Delimiter hinzufügen
737 | socket.write(responseString, () => {
738 | socket.end(); // Verbindung schließen, wenn das Schreiben fertig ist
739 | });
740 |
741 | // Logging: Erfolgreiche Antwort
742 | if (isLogIpsEnabled) {
743 | if (!isanonymousModeEnabled) {
744 | logEvent(client.ip, client.port, 'Response Sent', t.ResponseSuccessfullySent, 'info');
745 | }
746 | } else {
747 | if (!isanonymousModeEnabled) {
748 | logEvent('*****', '****', 'Response Sent', t.ResponseSuccessfullySent, 'info');
749 | }
750 | }
751 | } catch (err) {
752 | if (isLogIpsEnabled) {
753 | if (!isanonymousModeEnabled) {
754 | logEvent(client.ip, client.port, 'Error Processing Message', `Fehler: ${err.message || err}`, 'error');
755 | }
756 | } else {
757 | if (!isanonymousModeEnabled) {
758 | logEvent('*****', '****', 'Error Processing Message', `Fehler: ${err.message || err}`, 'error');
759 | }
760 | }
761 | // Sende eine Fehlerantwort mit Delimiter
762 | const errorResponse = JSON.stringify({ error: 'Ungültiges Nachrichtenformat' }) + '\n';
763 | socket.write(errorResponse, () => {
764 | socket.end(); // Verbindung schließen
765 | });
766 | }
767 | });
768 |
769 | // Ereignis: Verbindung geschlossen
770 | socket.on('close', () => {
771 | const client = this.clients.get(socket);
772 | if (isLogIpsEnabled) {
773 | if (!isanonymousModeEnabled) {
774 | logEvent(client.ip, client.port, 'Connection Closed', t.ConnectionClosed, 'info');
775 | }
776 | } else {
777 | if (!isanonymousModeEnabled) {
778 | logEvent('*****', '****', 'Connection Closed', t.ConnectionClosed, 'info');
779 | }
780 | }
781 | this.clients.delete(socket); // Entferne den Client aus der Map
782 | });
783 |
784 | // Fehlerbehandlung für einzelne Sockets
785 | socket.on('error', (err) => {
786 | const client = this.clients.get(socket);
787 | if (!isanonymousModeEnabled) {
788 | logEvent(
789 | client?.ip || 'unknown',
790 | client?.port || 'unknown',
791 | 'Socket Error',
792 | `Socket-Fehler: ${err.message || err}`,
793 | 'error'
794 | );
795 | }
796 | });
797 | }
798 |
799 | /**
800 | * Stoppt den Server und leert die Clientliste.
801 | */
802 | async stop() {
803 | if (this.server) {
804 | this.server.close(() => {
805 | if (!isanonymousModeEnabled) {
806 | logEvent('server', this.port, l.prefix_Shutdown, t.ServerStopped, 'info');
807 | }
808 | this.clients.clear(); // Alle Clients entfernen
809 | });
810 | }
811 | }
812 | }
813 |
814 |
815 | class PrivateGPTServer {
816 | constructor() {
817 | this.server = new Server({
818 | name: 'pgpt-mcp-server',
819 | version: '2.8.0',
820 | }, {
821 | capabilities: {
822 | resources: {},
823 | tools: {},
824 | },
825 | });
826 |
827 | const axiosConfig = {
828 | baseURL: apiUrl,
829 | headers: {
830 | 'Accept': 'application/json',
831 | 'Content-Type': 'application/json',
832 | },
833 | httpsAgent: new https.Agent({
834 | rejectUnauthorized: isSSLValidationEnabled
835 | })
836 | };
837 |
838 | // Conditionally Header setzen, wenn USE_PROXY = true
839 | if (useProxy) {
840 | // Nur wenn der Proxy in der envConfig aktiviert ist,
841 | // wird der spezielle Header gesetzt
842 | axiosConfig.headers['X-Custom-Header'] = customHeaderValue;
843 | } else {
844 | // Falls du sicherstellen willst, dass der Header *nicht* gesetzt wird:
845 | delete axiosConfig.headers['X-Custom-Header'];
846 | }
847 |
848 | // Axios-Instanz anlegen
849 | this.axiosInstance = axios.create(axiosConfig);
850 |
851 | // Interceptors für Logging von Requests und Responses
852 | this.axiosInstance.interceptors.request.use((config) => {
853 | const headers = { ...config.headers };
854 | if (headers.Authorization) {
855 | // Prüfen, ob es sich um Bearer oder Basic handelt
856 | if (headers.Authorization.startsWith('Bearer ')) {
857 | // Bearer maskieren
858 | headers.Authorization = 'Bearer ********';
859 | } else if (headers.Authorization.startsWith('Basic ')) {
860 | // Basic maskieren
861 | headers.Authorization = 'Basic ********';
862 | }
863 | }
864 | if (!isanonymousModeEnabled) logEvent('axios', 'ReqHd', l.prefix_requestHeaders, `Headers: ${JSON.stringify(headers)}`, 'info');
865 |
866 | return config;
867 | }, (error) => {
868 | if (!isanonymousModeEnabled) logEvent('axios', 'ReqEr', l.prefix_apiRequestError, t.requestError.replace('${error}', error.message || error), 'error');
869 | return Promise.reject(error);
870 | });
871 |
872 | this.axiosInstance.interceptors.response.use((response) => {
873 | if (!isanonymousModeEnabled) {
874 | logEvent(
875 | 'axios',
876 | 'ResOK',
877 | l.prefix_responseReceived,
878 | t.responseReceived.replace('${status}', response?.status?.toString() || 'No Status'),
879 | 'info'
880 | );
881 | }
882 | return response;
883 | }, (error) => {
884 | const errorMsg = error.response ? JSON.stringify(error.response.data) : error.message;
885 | if (!isanonymousModeEnabled) logEvent('axios', 'ResEr', l.prefix_apiRequestError, t.responseError.replace('${error}', errorMsg), 'error');
886 | return Promise.reject(error);
887 | });
888 |
889 | this.setupResourceHandlers();
890 | this.setupToolHandlers();
891 |
892 | // Fehlerbehandlung
893 | this.server.onerror = (error) => {
894 | if (!isanonymousModeEnabled) logEvent(
895 | 'server',
896 | 'N/A',
897 | l.prefix_MCP_Error,
898 | t.mcpErrorPrefix.replace('${error}', error.message || JSON.stringify(error, null, 2)),
899 | 'error'
900 | );
901 | };
902 |
903 | process.on('SIGINT', async () => {
904 | await this.server.close();
905 | if (!isanonymousModeEnabled) logEvent('process', 'N/A', l.prefix_Shutdown, t.serverShutdownLog, 'info');
906 | process.exit(0);
907 | });
908 | }
909 | async ensureAuthenticated(token) {
910 | if (this.axiosInstance.defaults.headers.common['Authorization']) {
911 | delete this.axiosInstance.defaults.headers.common['Authorization'];
912 | }
913 | this.axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${token}`;
914 | }
915 |
916 | /**
917 | * Login-Funktion mit Logging
918 | * @param {string} email - Benutzer-E-Mail
919 | * @param {string} password - Benutzer-Passwort
920 | * @returns {string} - Authentifizierungs-Token
921 | */
922 | async login(email, password) {
923 | if (!isanonymousModeEnabled) logEvent(email, 'N/A', l.prefix_login, t.authStarted, 'info');
924 | try {
925 | const loginResponse = await this.axiosInstance.post('/login', {
926 | email,
927 | password
928 | });
929 | if (!isanonymousModeEnabled) logEvent(
930 | email,
931 | 'N/A',
932 | l.prefix_loginSuccess,
933 | t.loginTokenReceived.replace('${token}', loginResponse.data.data.token),
934 | 'info'
935 | );
936 | return loginResponse.data.data.token;
937 | } catch (error) {
938 | if (!isanonymousModeEnabled) logEvent(
939 | email,
940 | 'N/A',
941 | l.prefix_loginError,
942 | t.loginErrorPrefix.replace('${error}', error.message || error),
943 | 'error'
944 | );
945 | throw new Error(t.authFailed);
946 | }
947 | }
948 |
949 |
950 | /**
951 | * Authentifizierung sicherstellen mit Logging
952 | * @param {string} token - Authentifizierungs-Token
953 | */
954 | async ensureAuthenticated(token) {
955 | if (!token) {
956 | if (!isanonymousModeEnabled) logEvent('auth', 'check', l.prefix_apiRequestError, t.missingTokenError, 'error');
957 | throw new Error(t.missingTokenError);
958 | }
959 |
960 | if (!isanonymousModeEnabled) logEvent('auth', 'token', l.prefix_apiRequestError, t.settingToken, 'info');
961 |
962 | // Entferne den Basic Auth Header, falls vorhanden
963 | if (this.axiosInstance.defaults.headers.common['Authorization']) {
964 | delete this.axiosInstance.defaults.headers.common['Authorization'];
965 | }
966 |
967 | // Setze das Token als Authorization-Header
968 | this.axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${token}`;
969 | if (!isanonymousModeEnabled) logEvent('axios', 'Auth', l.prefix_loginSuccess, t.tokenSetSuccess, 'info');
970 | }
971 |
972 |
973 | /**
974 | * Gruppen validieren mit Logging
975 | * @param {Array} groups - Gruppenliste
976 | * @param {string} token - Authentifizierungs-Token
977 | * @returns {Object} - Validierungsergebnis
978 | */
979 | async validateGroups(groups, token, IP, Port) {
980 | try {
981 | if (!isanonymousModeEnabled) logEvent(
982 | IP,
983 | Port,
984 | l.prefix_Incoming_Message,
985 | t.checkingGroups.replace('${groups}', JSON.stringify(groups)),
986 | 'info'
987 | );
988 | if (!token) {
989 | if (!isanonymousModeEnabled) logEvent(IP, Port, l.prefix_apiRequestError, t.missingTokenError, 'error');
990 | throw new Error(t.missingTokenGroups);
991 | }
992 |
993 | const response = await this.axiosInstance.get('/groups', {
994 | headers: { Authorization: `Bearer ${token}` }
995 | });
996 |
997 | const availableGroups = response.data?.data?.assignableGroups || [];
998 | if (!isanonymousModeEnabled) logEvent(IP, Port, 'Available Groups', t.availableGroups.replace('${availableGroups}', JSON.stringify(availableGroups)), 'info');
999 | const invalidGroups = groups.filter(group => !availableGroups.includes(group));
1000 | if (invalidGroups.length > 0) {
1001 | if (!isanonymousModeEnabled) logEvent(
1002 | 'validateGroups',
1003 | 'N/A',
1004 | l.prefix_validationErr,
1005 | t.invalidGroupsLog.replace('${groups}', JSON.stringify(invalidGroups)),
1006 | 'error'
1007 | );
1008 | return { isValid: false, invalidGroups };
1009 | }
1010 | if (!isanonymousModeEnabled) logEvent(IP, Port, 'Validation OK', t.allGroupsValid, 'info');
1011 | return { isValid: true };
1012 | } catch (error) {
1013 | const errorMessage = error.response?.data || error.message;
1014 | if (!isanonymousModeEnabled) logEvent(
1015 | 'validateGroups',
1016 | 'N/A',
1017 | l.prefix_Validation_Err,
1018 | t.groupValidationErrorPrefix.replace('${error}', errorMessage),
1019 | 'error'
1020 | );
1021 | throw new Error(
1022 | error.response?.data?.message || t.fetchGroupsErrorBackup
1023 | );
1024 | }
1025 | }
1026 | setupResourceHandlers() {
1027 | // List available resources
1028 | this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
1029 | resources: []
1030 | }));
1031 | // List resource templates
1032 | this.server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
1033 | resourceTemplates: []
1034 | }));
1035 | // Read resource
1036 | this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
1037 | if (!request.params?.uri) {
1038 | throw new McpError(
1039 | ErrorCode.InvalidRequest,
1040 | t.missingUriParameter
1041 | );
1042 | }
1043 | throw new McpError(ErrorCode.InvalidRequest, `Invalid URI: ${request.params.uri}`);
1044 | });
1045 | }
1046 |
1047 | setupToolHandlers() {
1048 | this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
1049 | tools: [
1050 | { /* 1.0 Login #####################################################################################*/
1051 | name: 'login',
1052 | description: 'User login to retrieve an API token',
1053 | inputSchema: {
1054 | type: 'object',
1055 | properties: {
1056 | email: {
1057 | type: 'string',
1058 | description: 'User email address for login'
1059 | },
1060 | password: {
1061 | type: 'string',
1062 | description: 'User password for login'
1063 | }
1064 | },
1065 | required: ['email', 'password']
1066 | }
1067 | },
1068 | { /* 1.1 Logout ####################################################################################*/
1069 | name: 'logout',
1070 | description: 'Invalidate the API token',
1071 | inputSchema: { type: 'object', properties: {} },
1072 | },
1073 | { /* 2.0 Chat ######################################################################################*/
1074 | name: 'chat',
1075 | description: 'Start or continue a chat with PrivateGPT with optional RAG capabilities',
1076 | inputSchema: {
1077 | type: 'object',
1078 | properties: {
1079 | question: { type: 'string', description: 'The question or prompt to send' },
1080 | usePublic: { type: 'boolean', description: 'Use public knowledge base', default: false },
1081 | groups: {
1082 | type: 'array',
1083 | items: { type: 'string' },
1084 | description: 'Group names for RAG (exclusive with usePublic)',
1085 | },
1086 | language: { type: 'string', description: 'Language code (e.g., "en")', default: 'en' },
1087 | },
1088 | required: ['question'],
1089 | },
1090 | },
1091 | { /* 2.1 Continue Chat #############################################################################*/
1092 | name: 'continue_chat',
1093 | description: 'Continue an existing chat',
1094 | inputSchema: {
1095 | type: 'object',
1096 | properties: {
1097 | chatId: { type: 'string', description: 'ID of the existing chat to continue' },
1098 | question: { type: 'string', description: 'The next question or message in the chat' },
1099 | },
1100 | required: ['chatId', 'question'],
1101 | },
1102 | },
1103 | { /* 2.2 Get Chat Info #############################################################################*/
1104 | name: 'get_chat_info',
1105 | description: 'Retrieve details about an existing chat using its ID',
1106 | inputSchema: {
1107 | type: 'object',
1108 | properties: {
1109 | chatId: { type: 'string', description: 'ID of the chat to retrieve details for' },
1110 | token: { type: 'string', description: 'Authorization token for API access' },
1111 | },
1112 | required: ['chatId', 'token'],
1113 | },
1114 | },
1115 | { /* 3.0 Create Source #############################################################################*/
1116 | name: 'create_source',
1117 | description: 'Create a new source with automatic markdown formatting',
1118 | inputSchema: {
1119 | type: 'object',
1120 | properties: {
1121 | name: { type: 'string', description: 'Name of the source' },
1122 | content: { type: 'string', description: 'Markdown-formatted content' },
1123 | groups: {
1124 | type: 'array',
1125 | items: { type: 'string' },
1126 | description: 'Optional groups to assign the source to',
1127 | },
1128 | },
1129 | required: ['name', 'content'],
1130 | },
1131 | },
1132 | { /* 3.1 Get Source ################################################################################*/
1133 | name: 'get_source',
1134 | description: 'Retrieve information about a specific source',
1135 | inputSchema: {
1136 | type: 'object',
1137 | properties: {
1138 | sourceId: { type: 'string', description: 'ID of the source to retrieve' },
1139 | },
1140 | required: ['sourceId'],
1141 | },
1142 | },
1143 | { /* 3.2 List Sources ##############################################################################*/
1144 | name: 'list_sources',
1145 | description: 'List all sources in a specific group',
1146 | inputSchema: {
1147 | type: 'object',
1148 | properties: {
1149 | groupName: { type: 'string', description: 'Group name to list sources from' },
1150 | },
1151 | required: ['groupName'],
1152 | },
1153 | },
1154 | { /* 3.3 Edit Source ###############################################################################*/
1155 | name: 'edit_source',
1156 | description: 'Edit an existing source',
1157 | inputSchema: {
1158 | type: 'object',
1159 | properties: {
1160 | sourceId: {
1161 | type: 'string',
1162 | description: 'ID of the source to edit'
1163 | },
1164 | token: {
1165 | type: 'string',
1166 | description: 'Authorization token for API access'
1167 | },
1168 | title: {
1169 | type: 'string',
1170 | description: 'New title for the source (optional)'
1171 | },
1172 | content: {
1173 | type: 'string',
1174 | description: 'New markdown-formatted content for the source (optional)'
1175 | },
1176 | groups: {
1177 | type: 'array',
1178 | items: {
1179 | type: 'string'
1180 | },
1181 | description: 'Updated group(s) to assign to the source (optional)'
1182 | }
1183 | },
1184 | required: ['sourceId', 'token']
1185 | }
1186 | },
1187 | { /* 3.4 Delete Source #############################################################################*/
1188 | name: 'delete_source',
1189 | description: 'Delete a specific source',
1190 | inputSchema: {
1191 | type: 'object',
1192 | properties: {
1193 | sourceId: { type: 'string', description: 'ID of the source to delete' },
1194 | },
1195 | required: ['sourceId'],
1196 | },
1197 | },
1198 | { /* 4.0 List Groups ###############################################################################*/
1199 | name: 'list_groups',
1200 | description: 'Retrieve personal and assignable groups',
1201 | inputSchema: { type: 'object', properties: {} },
1202 | },
1203 | { /* 4.1 Store Group ###############################################################################*/
1204 | name: 'store_group',
1205 | description: 'Create a new group',
1206 | inputSchema: {
1207 | type: 'object',
1208 | properties: {
1209 | groupName: { type: 'string', description: 'Name of the new group' },
1210 | description: { type: 'string', description: 'Description of the new group' },
1211 | },
1212 | required: ['groupName'],
1213 | },
1214 | },
1215 | { /* 4.2 Delete Group ##############################################################################*/
1216 | name: 'delete_group',
1217 | description: 'Delete an existing group',
1218 | inputSchema: {
1219 | type: 'object',
1220 | properties: {
1221 | groupName: { type: 'string', description: 'Name of the group to delete' },
1222 | },
1223 | required: ['groupName'],
1224 | },
1225 | },
1226 | { /* 5.0 Store User ################################################################################*/
1227 | name: 'store_user',
1228 | description: 'Create a new user',
1229 | inputSchema: {
1230 | type: 'object',
1231 | properties: {
1232 | name: { type: 'string', description: 'Name of the user' },
1233 | email: { type: 'string', description: 'Email of the user' },
1234 | password: { type: 'string', description: 'Password for the user' },
1235 | language: { type: 'string', description: 'Preferred language (optional)', default: 'en' },
1236 | timezone: { type: 'string', description: 'Timezone (optional)', default: 'Europe/Berlin' },
1237 | roles: {
1238 | type: 'array',
1239 | items: { type: 'string' },
1240 | description: 'Roles to assign (optional)'
1241 | },
1242 | groups: {
1243 | type: 'array',
1244 | items: { type: 'string' },
1245 | description: 'Groups to assign (optional)'
1246 | },
1247 | usePublic: { type: 'boolean', description: 'Enable public knowledge (optional)', default: false }
1248 | },
1249 | required: ['name', 'email', 'password']
1250 | },
1251 | },
1252 | { /* 5.1 Edit User #################################################################################*/
1253 | name: 'edit_user',
1254 | description: 'Edit an existing user',
1255 | inputSchema: {
1256 | type: 'object',
1257 | properties: {
1258 | email: { type: 'string', description: 'Email of the user to edit' },
1259 | name: { type: 'string', description: 'New name for the user (optional)' },
1260 | password: { type: 'string', description: 'New password for the user (optional)' },
1261 | language: { type: 'string', description: 'Preferred language (optional)' },
1262 | timezone: { type: 'string', description: 'Timezone (optional)' },
1263 | roles: {
1264 | type: 'array',
1265 | items: { type: 'string' },
1266 | description: 'Updated roles (optional)'
1267 | },
1268 | groups: {
1269 | type: 'array',
1270 | items: { type: 'string' },
1271 | description: 'Updated groups (optional)'
1272 | },
1273 | usePublic: { type: 'boolean', description: 'Enable public knowledge (optional)' }
1274 | },
1275 | required: ['email']
1276 | }
1277 | },
1278 | { /* 5.2 Delete User ###############################################################################*/
1279 | name: 'delete_user',
1280 | description: 'Delete an existing user',
1281 | inputSchema: {
1282 | type: 'object',
1283 | properties: {
1284 | email: { type: 'string', description: 'Email of the user to delete' }
1285 | },
1286 | required: ['email']
1287 | }
1288 | },
1289 | { /* 6.0 pen AI compatible API Chat ######################################################################################*/
1290 | name: 'oai_comp_api_chat',
1291 | description: 'Start or continue a chat with PrivateGPT with optional RAG capabilities',
1292 | inputSchema: {
1293 | type: 'object',
1294 | properties: {
1295 | question: { type: 'string', description: 'The question or prompt to send' },
1296 | usePublic: { type: 'boolean', description: 'Use public knowledge base', default: false },
1297 | groups: {
1298 | type: 'array',
1299 | items: { type: 'string' },
1300 | description: 'Group names for RAG (exclusive with usePublic)',
1301 | },
1302 | language: { type: 'string', description: 'Language code (e.g., "en")', default: 'en' },
1303 | },
1304 | required: ['question'],
1305 | },
1306 | },
1307 | { /* 6.1 Open AI compatible API Continue Chat #############################################################################*/
1308 | name: 'oai_comp_api_continue_chat',
1309 | description: 'Continue an existing chat',
1310 | inputSchema: {
1311 | type: 'object',
1312 | properties: {
1313 | chatId: { type: 'string', description: 'ID of the existing chat to continue' },
1314 | question: { type: 'string', description: 'The next question or message in the chat' },
1315 | },
1316 | required: ['chatId', 'question'],
1317 | },
1318 | }
1319 | ],
1320 | }));
1321 |
1322 | this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
1323 | if (!request.params?.name) {
1324 | throw new McpError(
1325 | ErrorCode.InvalidRequest,
1326 | t.missingToolName
1327 | );
1328 | }
1329 | try {
1330 | //await this.ensureAuthenticated();
1331 | if (!isanonymousModeEnabled) logEvent(
1332 | 'system',
1333 | 'N/A',
1334 | l.prefix_Handling_Tool_Request,
1335 | t.handlingToolRequest.replace('${tool}', request.params.name),
1336 | 'info'
1337 | );
1338 | switch (request.params.name) {
1339 | /* 1.0 Login ######################################################################################*/
1340 | case 'login': {
1341 | const disabledResponse = checkToolEnabled('login');
1342 | if (disabledResponse) return disabledResponse;
1343 |
1344 | const { email, password } = request.params.arguments; // Extrahiere email und password aus der Nachricht
1345 |
1346 | if (!email || !password) {
1347 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_loginError, t.loginMissingCredentialsAlternative, 'error');
1348 | return {
1349 | status: 'E10-R-1000',
1350 | message: t.loginEmailPasswordRequired
1351 | };
1352 | }
1353 |
1354 | try {
1355 | // Aufruf des Login-Endpunkts der API
1356 | const loginResponse = await this.axiosInstance.post('/login', { email, password });
1357 |
1358 | // Loggen des erfolgreichen Logins
1359 | if (!isanonymousModeEnabled) logEvent(
1360 | 'server',
1361 | 'swreg',
1362 | l.prefix_loginSuccess,
1363 | t.loginTokenReceived.replace('${token}', JSON.stringify(loginResponse.data)),
1364 | 'info'
1365 | );
1366 | return { // Token zurückgeben
1367 | status: loginResponse.data?.status || 'I10-R-1001', // Dynamisch, falls der API-Status einheitlich ist
1368 | message: loginResponse.data?.message || '1.0 Login', // API-Nachricht verwenden oder Standardnachricht
1369 | token: loginResponse.data?.data?.token // Token aus API-Antwort
1370 | };
1371 | } catch (error) {
1372 | const errorMessage = error.response?.data?.message || error.message || t.unknownError;
1373 |
1374 | // Loggen des Fehlers beim Login
1375 | if (!isanonymousModeEnabled) logEvent(
1376 | 'server',
1377 | 'swreg',
1378 | l.prefix_loginError,
1379 | t.loginError.replace('${error}', errorMessage),
1380 | 'error'
1381 | );
1382 |
1383 | return {
1384 | status: error.response?.status || 'E10-R-1001', // API-Fehlerstatus oder Standardfehlerstatus
1385 | message: errorMessage,
1386 | };
1387 | }
1388 | }
1389 | /* 1.1 Logout #####################################################################################*/
1390 | case 'logout': {
1391 | const disabledResponse = checkToolEnabled('logout');
1392 | if (disabledResponse) return disabledResponse;
1393 |
1394 | const { token } = request.params; // Korrigiert von 'message' zu 'request.params'
1395 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_logout, t.extractedToken.replace('${token}', token), 'info');
1396 |
1397 | const tokenValidation = validateToken(token);
1398 | if (tokenValidation) return tokenValidation;
1399 |
1400 | try {
1401 | // Setze den Bearer Token als Standard-Authorization-Header
1402 | await this.ensureAuthenticated(token);
1403 |
1404 | // Console-Log für Header zu Debug-Zwecken
1405 | console.log('Logout Request Headers:', this.axiosInstance.defaults.headers.common);
1406 | const logoutResponse = await this.axiosInstance.delete('/logout', { headers: { Authorization: `Bearer ${token}` }})
1407 |
1408 | // Loggen des erfolgreichen Logouts
1409 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_logoutSuccess, t.logoutSuccess.replace('${data}', JSON.stringify(logoutResponse.data)), 'info');
1410 |
1411 | return {
1412 | data: {}, // Optional: Zusätzliche Daten könnten hier eingefügt werden
1413 | message: 'success',
1414 | status: 200, // OK
1415 | };
1416 | } catch (error) {
1417 | const logoutErrorMessage = error.response?.data || error.message;
1418 | // Loggen des Fehlers beim Logout
1419 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_logoutError, t.logoutError.replace('${error}', logoutErrorMessage), 'error');
1420 |
1421 | return {
1422 | data: {},
1423 | message: error.response?.data?.message || t.logoutFailedTryAgain,
1424 | status: error.response?.status || 'E11-R-1100', // Internal Server Error oder spezifischer Statuscode
1425 | };
1426 | }
1427 | }
1428 | /* 2.0 Chat #######################################################################################*/
1429 | case 'chat': {
1430 | const disabledResponse = checkToolEnabled('chat');
1431 | if (disabledResponse) return disabledResponse;
1432 |
1433 | const { token, arguments: args } = request.params;
1434 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_chat, t.extractedToken.replace('${token}', token), 'info');
1435 |
1436 | // Token prüfen und validieren
1437 | if (!token) {
1438 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_chatError, t.noTokenError, 'error');
1439 | return { status: 'E20-R-2000', message: t.missingTokenError };
1440 | }
1441 |
1442 | const tokenValidation = validateToken(token);
1443 | if (tokenValidation) return tokenValidation;
1444 |
1445 | // Argument-Validierung
1446 | if (!args || !args.question) {
1447 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_chatError, t.missingArgumentsError.replace('${args}', JSON.stringify(args)), 'error');
1448 | return {
1449 | status: 'error',
1450 | message: t.missingArgumentsError.replace('${args}', JSON.stringify(args)),
1451 | };
1452 | }
1453 |
1454 | const { question, usePublic, groups, language } = args;
1455 |
1456 | // Konflikt zwischen `usePublic` und `groups` lösen
1457 | if (usePublic && groups && groups.length > 0) {
1458 | if (!isanonymousModeEnabled) logEvent('system', 'swreg', l.prefix_chatWarning, t.publicGroupsConflictWarning, 'warn');
1459 | args.usePublic = false;
1460 | }
1461 |
1462 | try {
1463 | // Loggen der Chat-Anfrage
1464 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_chatRequest, t.sendingChatRequest
1465 | .replace('${question}', question)
1466 | .replace('${usePublic}', usePublic)
1467 | .replace('${groups}', JSON.stringify(groups))
1468 | .replace('${language}', language), 'info');
1469 |
1470 | const response = await this.axiosInstance.post(
1471 | '/chats',
1472 | {
1473 | question,
1474 | usePublic: usePublic || false,
1475 | groups: Array.isArray(groups) ? groups : [groups],
1476 | language: language || 'de',
1477 | },
1478 | { headers: { Authorization: `Bearer ${token}` } }
1479 | );
1480 |
1481 | const data = response.data?.data || {};
1482 | // Loggen der erfolgreichen Chat-Antwort
1483 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_chatSuccess, t.chatResponseSuccess.replace('${data}', JSON.stringify(data)), 'info');
1484 |
1485 | // Erfolgsantwort mit Status und Daten
1486 | return {
1487 | status: response.data?.status || 'ok',
1488 | message: response.data?.message || 'Chat erfolgreich.',
1489 | content: {
1490 | chatId: data.chatId,
1491 | answer: data.answer,
1492 | sources: data.sources || [],
1493 | },
1494 | };
1495 | } catch (error) {
1496 | const chatApiErrorMessage = error.message || error.response?.data;
1497 | // Loggen des Fehlers bei der Chat-API-Anfrage
1498 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_chatApiError, t.chatApiError.replace('${error}', chatApiErrorMessage), 'error');
1499 |
1500 | // Fehlerantwort mit Status und Nachricht
1501 | return {
1502 | status: error.response?.status || 'E20-R-2002',
1503 | message: error.response?.data?.message || t.chatApiErrorDefault,
1504 | };
1505 | }
1506 | }
1507 | /* 2.1 Continue Chat ##############################################################################*/
1508 | case 'continue_chat': {
1509 | const disabledResponse = checkToolEnabled('continue_chat');
1510 | if (disabledResponse) return disabledResponse;
1511 |
1512 | const args = request.params.arguments;
1513 |
1514 | if (!args || !args.chatId || !args.question) {
1515 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_continue_chatError, t.missingChatParams, 'error');
1516 | return {
1517 | status: 'E21-R-2100',
1518 | message: t.missingChatParams
1519 | };
1520 | }
1521 |
1522 | const { chatId, question } = args;
1523 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_continue_chat, t.conversationContinuation.replace('${chatId}', chatId), 'info');
1524 |
1525 | try {
1526 | const continueChatResponse = await this.axiosInstance.patch(`/chats/${chatId}`, {
1527 | question: question,
1528 | });
1529 | // Loggen der erfolgreichen Fortsetzung der Konversation
1530 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_continue_chatSuccess, t.conversationSuccess.replace('${data}', JSON.stringify(continueChatResponse.data, null, 2)), 'info');
1531 | return {
1532 | content: {
1533 | chatId: continueChatResponse.data.data.chatId,
1534 | answer: continueChatResponse.data.data.answer,
1535 | sources: continueChatResponse.data.sources || [],
1536 | message: continueChatResponse.data.message,
1537 | status: continueChatResponse.data.status,
1538 | },
1539 | };
1540 | } catch (error) {
1541 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_continue_chatError, t.apiRequestError.replace('${error}', error.message), 'error');
1542 | return {
1543 | status: error.response?.status || 'E21-R-2101',
1544 | message: error.response?.data?.message || t.continueConversationError,
1545 | };
1546 | }
1547 | }
1548 | /* 2.2 Get Chat Info ##############################################################################*/
1549 | case 'get_chat_info': {
1550 | const disabledResponse = checkToolEnabled('get_chat_info');
1551 | if (disabledResponse) return disabledResponse;
1552 |
1553 | const { token, arguments: args } = request.params;
1554 |
1555 | const tokenValidation = validateToken(token);
1556 | if (tokenValidation) return tokenValidation;
1557 |
1558 | const { chatId } = args;
1559 |
1560 | if (!chatId) {
1561 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_get_chat_infoError, t.missingChatId, 'error');
1562 | return { status: 'E22-R-2200', message: t.missingChatId };
1563 | }
1564 |
1565 | try {
1566 | const response = await this.axiosInstance.get(`/chats/${chatId}`, {
1567 | headers: { Authorization: `Bearer ${token}` }
1568 | });
1569 |
1570 | const chatData = response.data?.data;
1571 |
1572 | if (!chatData) {
1573 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_get_chat_infoError, t.noChatData, 'error');
1574 | return {
1575 | status: 'E22-R-2201',
1576 | message: t.noChatData,
1577 | };
1578 | }
1579 |
1580 | // Loggen der abgerufenen Chat-Informationen
1581 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_get_chat_infoSuccess, t.chatInfoRetrieved.replace('${chatData}', JSON.stringify(chatData)), 'info');
1582 |
1583 | return {
1584 | data: {
1585 | chatId: chatData.chatId,
1586 | title: chatData.title || 'Unbenannter Chat',
1587 | language: chatData.language || 'Unbekannt',
1588 | groups: chatData.groups || [],
1589 | messages: chatData.messages || []
1590 | },
1591 | message: response.data?.message || 'Erfolgreich abgerufen.'
1592 | };
1593 | } catch (error) {
1594 | const fetchChatErrorMessage = error.message || error.response?.data;
1595 | // Loggen des Fehlers beim Abrufen der Chat-Informationen
1596 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_get_chat_infoError, t.fetchChatInfoError.replace('${error}', fetchChatErrorMessage), 'error');
1597 | return {
1598 | status: 'E22-R-2202',
1599 | message: error.response?.data?.message || 'Fehler beim Abrufen der Chat-Informationen.'
1600 | };
1601 | }
1602 | }
1603 | /* 2.3 Delete All Chats ##############################################################################*/
1604 | case 'delete_all_chats': {
1605 | const disabledResponse = checkToolEnabled('delete_all_chats');
1606 | if (disabledResponse) return disabledResponse;
1607 |
1608 | const { token } = request.params;
1609 |
1610 | const tokenValidation = validateToken(token);
1611 | if (tokenValidation) return tokenValidation;
1612 |
1613 | try {
1614 | const response = await this.axiosInstance.delete('/chats/flush', {
1615 | headers: {
1616 | Authorization: `Bearer ${token}`,
1617 | Accept: 'application/json'
1618 | }
1619 | });
1620 |
1621 | // Erfolg loggen
1622 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_delete_all_chatsSuccess, t.chatsDeleted, 'info');
1623 |
1624 | return {
1625 | data: {},
1626 | message: response.data?.message || 'success',
1627 | status: response.status || 200
1628 | };
1629 | } catch (error) {
1630 | const deleteChatsErrorMessage = error.message || error.response?.data;
1631 |
1632 | // Fehler loggen
1633 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_delete_all_chatsError, t.deleteChatsError.replace('${error}', deleteChatsErrorMessage), 'error');
1634 |
1635 | return {
1636 | status: error.response?.status || 'E23-R-2300',
1637 | message: error.response?.data?.message || 'Error deleting all chat history.'
1638 | };
1639 | }
1640 | }
1641 | /* 2.4 Delete Specific Chat ##############################################################################*/
1642 | case 'delete_chat': {
1643 | const disabledResponse = checkToolEnabled('delete_chat');
1644 | if (disabledResponse) return disabledResponse;
1645 |
1646 | const { token, arguments: args } = request.params;
1647 |
1648 | const tokenValidation = validateToken(token);
1649 | if (tokenValidation) return tokenValidation;
1650 |
1651 | const { chatId } = args;
1652 |
1653 | if (!chatId) {
1654 | return { status: 'E24-R-2400', message: t.missingChatId };
1655 | }
1656 |
1657 | try {
1658 | const response = await this.axiosInstance.delete(`/chats/${chatId}`, {
1659 | headers: {
1660 | Authorization: `Bearer ${token}`,
1661 | Accept: 'application/json'
1662 | }
1663 | });
1664 |
1665 | // Erfolg loggen
1666 | if (!isanonymousModeEnabled) {
1667 | logEvent('server', 'swreg', l.prefix_delete_chatSuccess, t.chatDeleted.replace('${chatId}', chatId), 'info');
1668 | }
1669 |
1670 | return {
1671 | data: {},
1672 | message: response.data?.message || 'success',
1673 | status: response.status || 200
1674 | };
1675 | } catch (error) {
1676 | const deleteChatErrorMessage = error.message || error.response?.data;
1677 |
1678 | // Fehler loggen
1679 | if (!isanonymousModeEnabled) {
1680 | logEvent('server', 'swreg', l.prefix_delete_chatError,
1681 | t.deleteChatError.replace('${chatId}', chatId).replace('${error}', deleteChatErrorMessage), 'error');
1682 | }
1683 |
1684 | return {
1685 | status: error.response?.status || 'E24-R-2401',
1686 | message: error.response?.data?.message || `Error deleting chat with ID ${chatId}.`
1687 | };
1688 | }
1689 | }
1690 | /* 3.0 Create Source ##############################################################################*/
1691 | case 'create_source': {
1692 | const disabledResponse = checkToolEnabled('create_source');
1693 | if (disabledResponse) return disabledResponse;
1694 |
1695 | const args = request.params.arguments;
1696 | const token = request.params.token;
1697 |
1698 | // Validierung: Erforderliche Parameter prüfen
1699 | if (!token) {
1700 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_create_sourceError, t.tokenMissing, 'error');
1701 | return { status: 'E30-R-3000', message: t.missingTokenError };
1702 | }
1703 |
1704 | const tokenValidation = validateToken(token);
1705 | if (tokenValidation) return tokenValidation;
1706 |
1707 | if (!args || !args.name || !args.content) {
1708 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_create_sourceError, t.missingNameAndContent, 'error');
1709 | return {
1710 | status: 'E30-R-3001',
1711 | message: t.missingNameAndContent
1712 | };
1713 | }
1714 |
1715 | const { name, content, groups } = args;
1716 |
1717 | try {
1718 | // Token im Header setzen
1719 | this.axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${token}`;
1720 |
1721 | // Gruppenvalidierung vorab durchführen
1722 | if (groups && groups.length > 0) {
1723 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_create_sourceGroupCheck, t.checkingGroups.replace('${groups}', JSON.stringify(groups)), 'info');
1724 |
1725 | const response = await this.axiosInstance.get('/groups');
1726 | const availableGroups = response.data?.data?.assignableGroups || [];
1727 |
1728 | // Ungültige Gruppen ermitteln
1729 | const invalidGroups = groups.filter(group => !availableGroups.includes(group));
1730 | if (invalidGroups.length > 0) {
1731 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_create_sourceInvalidGroups, t.invalidGroups.replace('${groups}', invalidGroups.join(', ')), 'error');
1732 | return {
1733 | status: 'E30-R-3002',
1734 | message: t.invalidGroups.replace('${groups}', invalidGroups.join(', ')),
1735 | };
1736 | }
1737 | }
1738 |
1739 | // API-Aufruf zur Erstellung der Quelle
1740 | const createSourceResponse = await this.axiosInstance.post(
1741 | '/sources',
1742 | { name, content, groups },
1743 | { headers: { Authorization: `Bearer ${token}` } }
1744 | );
1745 |
1746 | // Loggen der erfolgreichen Erstellung der Quelle
1747 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_create_sourceSuccess, t.createSourceSuccess.replace('${data}', JSON.stringify(createSourceResponse.data)), 'info');
1748 |
1749 | // Erfolgsantwort
1750 | return {
1751 | status: createSourceResponse.data?.status || 'ok',
1752 | message: createSourceResponse.data?.message || 'Quelle erfolgreich erstellt.',
1753 | data: createSourceResponse.data?.data,
1754 | };
1755 | } catch (error) {
1756 | const createSourceError = error.response?.data || error.message;
1757 | // Loggen des Fehlers bei der Erstellung der Quelle
1758 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_create_sourceError, t.createSourceError.replace('${error}', createSourceError), 'error');
1759 |
1760 | // Fehlerhafte Antwort
1761 | if (error.response) {
1762 | if (!isanonymousModeEnabled) {
1763 | logEvent(
1764 | 'server',
1765 | 'swreg',
1766 | l.prefix_create_sourceResponseError,
1767 | t.returnStatus.replace('${Status}', error.response.status) +
1768 | `, Data: ${JSON.stringify(error.response.data)}`,
1769 | 'error'
1770 | );
1771 | }
1772 | return {
1773 | status: 'E30-R-3003',
1774 | message: 'Ein Fehler ist aufgetreten.',
1775 | details: {
1776 | status: error.response.status,
1777 | headers: error.response.headers,
1778 | data: error.response.data,
1779 | },
1780 | };
1781 | } else if (error.request) {
1782 | if (!isanonymousModeEnabled) logEvent(
1783 | 'server',
1784 | 'swreg',
1785 | l.prefix_create_sourceNoResponse,
1786 | t.noServerResponse + ` ${JSON.stringify(error.request)}`,
1787 | 'error'
1788 | );
1789 |
1790 | return {
1791 | status: 'E30-R-3004',
1792 | message: t.noServerResponse,
1793 | details: { request: error.request },
1794 | };
1795 | } else {
1796 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_create_sourceUnknownError, t.create_sourceUnknownError.replace('${error}', error.message), 'error');
1797 | return {
1798 | status: 'E30-R-3005',
1799 | message: error.message || t.unknownError,
1800 | };
1801 | }
1802 | }
1803 | }
1804 | /* 3.1 Get Source #################################################################################*/
1805 | case 'get_source': {
1806 | const disabledResponse = checkToolEnabled('get_source');
1807 | if (disabledResponse) return disabledResponse;
1808 |
1809 | const args = request.params.arguments;
1810 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_get_sourceRequest, t.makingGetSourceRequest.replace('${args}', JSON.stringify(args, null, 2)), 'info');
1811 |
1812 | try {
1813 | const getSourceResponse = await this.axiosInstance.get(`/sources/${args.sourceId}`);
1814 | // Loggen der erhaltenen Quellenantwort
1815 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_get_sourceSuccess, t.gotGetSourceResponse.replace('${data}', JSON.stringify(getSourceResponse.data, null, 2)), 'info');
1816 | return {
1817 | content: [
1818 | {
1819 | type: 'text',
1820 | text: JSON.stringify(getSourceResponse.data, null, 2)
1821 | }
1822 | ]
1823 | };
1824 | } catch (error) {
1825 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_get_sourceError, t.errorHandlingRequest.replace('${error}', error.message || JSON.stringify(error, null, 2)), 'error');
1826 | return {
1827 | status: 'E31-R-3101',
1828 | message: t.apiErrorDetails
1829 | .replace('${status}', error.response?.status || 'E31-R-3151')
1830 | .replace('${data}', JSON.stringify(error.response?.data || {}, null, 2)),
1831 | };
1832 | }
1833 | }
1834 | /* 3.2 List Sources ##############################################################################*/
1835 | case 'list_sources': {
1836 | const disabledResponse = checkToolEnabled('list_sources');
1837 | if (disabledResponse) return disabledResponse;
1838 |
1839 | const args = request.params.arguments;
1840 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_list_sourcesRequest, t.makingListSourcesRequest.replace('${args}', JSON.stringify(args, null, 2)), 'info');
1841 |
1842 | try {
1843 | const listSourcesResponse = await this.axiosInstance.post('/sources/groups', {
1844 | groupName: args.groupName
1845 | });
1846 | // Loggen der erhaltenen Quellenliste
1847 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_list_sourcesSuccess, t.gotListSourcesResponse.replace('${data}', JSON.stringify(listSourcesResponse.data, null, 2)), 'info');
1848 | return {
1849 | content: [
1850 | {
1851 | type: 'text',
1852 | text: JSON.stringify(listSourcesResponse.data, null, 2)
1853 | }
1854 | ]
1855 | };
1856 | } catch (error) {
1857 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_list_sourcesError, t.apiRequestError.replace('${error}', error.message || JSON.stringify(error, null, 2)), 'error');
1858 | return {
1859 | status: 'E32-R-3210',
1860 | message: error.response?.data?.message || t.fetchSourcesError,
1861 | };
1862 | }
1863 | }
1864 | /* 3.3 Edit Source ################################################################################*/
1865 | case 'edit_source': {
1866 | const disabledResponse = checkToolEnabled('edit_source');
1867 | if (disabledResponse) return disabledResponse;
1868 |
1869 | const { token, arguments: args } = request.params;
1870 | const { sourceId, title, content, groups } = args;
1871 |
1872 | const tokenValidation = validateToken(token);
1873 | if (tokenValidation) return tokenValidation;
1874 |
1875 | // Validierung: Erforderliche Parameter
1876 | if (!sourceId) {
1877 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_edit_sourceError, t.sourceIdRequiredEditSource, 'error');
1878 | return {
1879 | data: {},
1880 | message: t.missingParameterError.replace('${parameter}', 'sourceId'),
1881 | status: 'E33-R-3300', // Bad Request
1882 | };
1883 | }
1884 |
1885 | // Loggen des Beginns der Quellenbearbeitung
1886 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_edit_source, t.editSourceLog.replace('${sourceId}', sourceId).replace('${title}', title || 'unverändert'), 'info');
1887 |
1888 | try {
1889 | // Nur Felder senden, die tatsächlich aktualisiert werden sollen
1890 | const payload = {};
1891 | if (title) payload.title = title;
1892 | if (content) payload.content = content;
1893 | if (groups) payload.groups = groups;
1894 |
1895 | const editSourceResponse = await this.axiosInstance.patch(
1896 | `/sources/${sourceId}`,
1897 | payload,
1898 | {
1899 | headers: {
1900 | Authorization: `Bearer ${token}` // Nutze den bereitgestellten Token
1901 | },
1902 | }
1903 | );
1904 |
1905 | // Loggen der erfolgreichen Quellenbearbeitung
1906 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_edit_sourceSuccess, t.editSourceSuccess.replace('${data}', JSON.stringify(editSourceResponse.data, null, 2)), 'info');
1907 |
1908 | // Erfolgreiche Antwort
1909 | return {
1910 | data: editSourceResponse.data?.data || {}, // Optionale Daten aus der API
1911 | message: editSourceResponse.data?.message || 'Quelle erfolgreich bearbeitet.',
1912 | status: editSourceResponse.status || 200, // OK
1913 | };
1914 | } catch (error) {
1915 | const editSourceError = error.message || JSON.stringify(error.response?.data);
1916 | // Loggen des Fehlers bei der Quellenbearbeitung
1917 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_edit_sourceError, t.editSourceError.replace('${error}', editSourceError), 'error');
1918 |
1919 | // Fehlerhafte Antwort
1920 | return {
1921 | data: {},
1922 | message: error.response?.data?.message || 'Bearbeiten der Quelle fehlgeschlagen. Bitte versuchen Sie es später erneut.',
1923 | status: error.response?.status || 'E33-R-3301', // Internal Server Error
1924 | };
1925 | }
1926 | }
1927 | /* 3.4 Delete Source ##############################################################################*/
1928 | case 'delete_source': {
1929 | const disabledResponse = checkToolEnabled('delete_source');
1930 | if (disabledResponse) return disabledResponse;
1931 |
1932 | const { token, arguments: args } = request.params;
1933 |
1934 | // Validierung: Token erforderlich
1935 | const tokenValidation = validateToken(token);
1936 | if (tokenValidation) return tokenValidation;
1937 |
1938 | const { sourceId } = args;
1939 |
1940 | // Validierung: sourceId erforderlich
1941 | if (!sourceId) {
1942 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_delete_sourceError, t.sourceIdRequiredDeleteSource, 'error');
1943 | return {
1944 | data: {},
1945 | message: t.missingParameterError.replace('${parameter}', 'sourceId'),
1946 | status: 'E34-R-3400', // Bad Request
1947 | };
1948 | }
1949 |
1950 | try {
1951 | // API-Aufruf: Quelle löschen
1952 | const deleteResponse = await this.axiosInstance.delete(`/sources/${sourceId}`, {
1953 | headers: { Authorization: `Bearer ${token}` },
1954 | });
1955 |
1956 | // Loggen der erfolgreichen Quellenlöschung
1957 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_delete_sourceSuccess, t.deleteSourceSuccess.replace('${data}', JSON.stringify(deleteResponse.data, null, 2)), 'info');
1958 |
1959 | // Erfolgreiche Antwort
1960 | return {
1961 | data: deleteResponse.data?.data || {}, // Optionale Daten aus der API
1962 | message: deleteResponse.data?.message || 'Quelle erfolgreich gelöscht.',
1963 | status: deleteResponse.status || 200, // OK
1964 | };
1965 | } catch (error) {
1966 | // Loggen des Fehlers bei der Quellenlöschung
1967 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_delete_sourceError, t.deleteSourceError.replace('${error}', error.message || JSON.stringify(error.response?.data)), 'error');
1968 | if (axios.isAxiosError(error)) {
1969 | const message = error.response?.data?.message || 'Fehler beim Löschen der Quelle.';
1970 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_apiRequestError, t.apiErrorDetails.replace('${status}', error.response?.status || 'E41-R-4100').replace('${data}', JSON.stringify(error.response?.data || {}, null, 2)), 'error');
1971 | return {
1972 | content: [
1973 | {
1974 | type: 'text',
1975 | text: `API-Fehler: ${message}`,
1976 | },
1977 | ],
1978 | isError: true,
1979 | };
1980 | }
1981 | throw new McpError(
1982 | ErrorCode.InternalError,
1983 | t.deleteSourceInternalError
1984 | );
1985 | }
1986 | }
1987 | /* 4.0 List Groups ################################################################################*/
1988 | case 'list_groups': {
1989 | const disabledResponse = checkToolEnabled('list_groups');
1990 | if (disabledResponse) return disabledResponse;
1991 |
1992 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_list_groupsRequest, t.makingListGroupsRequest, 'info');
1993 |
1994 | try {
1995 | const listGroupsResponse = await this.axiosInstance.get('/groups');
1996 | // Loggen der erfolgreichen Gruppenliste
1997 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_list_groupsSuccess, t.gotListGroupsResponse.replace('${data}', JSON.stringify(listGroupsResponse.data)), 'info');
1998 | return {
1999 | content: [
2000 | {
2001 | type: 'text',
2002 | text: JSON.stringify(listGroupsResponse.data, null, 2)
2003 | }
2004 | ]
2005 | };
2006 | } catch (error) {
2007 | const fetchGroupsError = error.message || JSON.stringify(error.response?.data);
2008 | // Loggen des Fehlers beim Abrufen der Gruppen
2009 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_list_groupsError, t.fetchGroupsError.replace('${error}', fetchGroupsError), 'error');
2010 | return {
2011 | status: 'E40-R-4051',
2012 | message: `${t.fetchGroupsErrorPrefix} ${error.response?.data?.message || t.unknownError}`,
2013 | };
2014 | }
2015 | }
2016 | /* 4.1 Store Group ################################################################################*/
2017 | case 'store_group': {
2018 | const disabledResponse = checkToolEnabled('store_group');
2019 | if (disabledResponse) return disabledResponse;
2020 |
2021 | const args = request.params.arguments;
2022 |
2023 | if (!args || !args.groupName) {
2024 | throw new McpError(
2025 | ErrorCode.InvalidRequest,
2026 | t.missingGroupParameterStore
2027 | );
2028 | }
2029 |
2030 | // Loggen des Beginns der Gruppenspeicherung
2031 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_store_groupRequest, t.storeGroupLog
2032 | .replace('${groupName}', args.groupName)
2033 | .replace('${description}', args.description || t.noDescriptionProvided), 'info');
2034 |
2035 | try {
2036 | const storeGroupResponse = await this.axiosInstance.post('/groups', {
2037 | groupName: args.groupName,
2038 | description: args.description || ''
2039 | });
2040 | // Loggen der erfolgreichen Gruppenspeicherung
2041 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_store_groupSuccess, t.storeGroupSuccess.replace('${data}', JSON.stringify(storeGroupResponse.data, null, 2)), 'info');
2042 |
2043 | return {
2044 | content: [
2045 | {
2046 | type: 'text',
2047 | text: `Gruppe "${args.groupName}" erfolgreich erstellt mit ID: ${storeGroupResponse.data.id}`
2048 | }
2049 | ]
2050 | };
2051 | } catch (error) {
2052 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_store_groupError, t.errorHandlingRequest.replace('${error}', error.message || JSON.stringify(error, null, 2)), 'error');
2053 | if (axios.isAxiosError(error)) {
2054 | const message = error.response?.data?.message ?? error.message;
2055 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_apiRequestError, t.apiErrorDetails.replace('${status}', error.response?.status || 'E41-R-4100').replace('${data}', JSON.stringify(error.response?.data || {}, null, 2)), 'error');
2056 | return {
2057 | content: [
2058 | {
2059 | type: 'text',
2060 | text: `API-Fehler: ${message}`
2061 | }
2062 | ],
2063 | isError: true
2064 | };
2065 | }
2066 | throw error;
2067 | }
2068 | };
2069 | /* 4.2 Delete Group ###############################################################################*/
2070 | case 'delete_group': {
2071 | const disabledResponse = checkToolEnabled('delete_group');
2072 | if (disabledResponse) return disabledResponse;
2073 |
2074 | const { groupName } = request.params.arguments; // Extrahiere die Gruppe
2075 | if (!groupName) {
2076 | throw new McpError(
2077 | ErrorCode.InvalidRequest,
2078 | t.missingGroupParameterDelete
2079 | );
2080 | }
2081 |
2082 | // Loggen des Beginns der Gruppenlöschung
2083 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_delete_groupRequest, t.deleteGroupLog.replace('${groupName}', groupName), 'info');
2084 |
2085 | try {
2086 | // API-Aufruf mit dem notwendigen JSON-Body
2087 | const deleteGroupResponse = await this.axiosInstance.delete('/groups', {
2088 | data: { groupName }, // JSON-Body für den DELETE-Request
2089 | });
2090 |
2091 | // Loggen der erfolgreichen Gruppenlöschung
2092 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_delete_groupSuccess, t.deleteGroupSuccessLog.replace('${data}', JSON.stringify(deleteGroupResponse.data)), 'info');
2093 |
2094 | return {
2095 | content: [
2096 | {
2097 | type: 'text',
2098 | text: `Gruppe "${groupName}" wurde erfolgreich gelöscht.`,
2099 | },
2100 | ],
2101 | };
2102 | } catch (error) {
2103 | // Loggen des Fehlers bei der Gruppenlöschung
2104 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_delete_groupError, t.apiRequestError.replace('${error}', error.message || JSON.stringify(error.response?.data)), 'error');
2105 | if (axios.isAxiosError(error)) {
2106 | const message = error.response?.data?.message || 'Fehler beim Löschen der Gruppe.';
2107 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_apiRequestError, t.apiErrorDetails.replace('${status}', error.response?.status || 'E41-R-4100').replace('${data}', JSON.stringify(error.response?.data || {}, null, 2)), 'error');
2108 | return {
2109 | content: [
2110 | {
2111 | type: 'text',
2112 | text: `API-Fehler: ${message}`,
2113 | },
2114 | ],
2115 | isError: true,
2116 | };
2117 | }
2118 | throw new McpError(
2119 | ErrorCode.InternalError,
2120 | t.deleteGroupInternalError
2121 | );
2122 | }
2123 | }
2124 | /* 5.0 Store User ################################################################################*/
2125 | case 'store_user': {
2126 | const disabledResponse = checkToolEnabled('store_user');
2127 | if (disabledResponse) return disabledResponse;
2128 |
2129 | // Token und Argumente aus request.params entnehmen
2130 | const { token, arguments: args } = request.params;
2131 |
2132 | // Token validieren
2133 | const tokenValidation = validateToken(token);
2134 | if (tokenValidation) return tokenValidation;
2135 |
2136 | // Erforderliche Felder prüfen
2137 | if (!args || !args.name || !args.email || !args.password) {
2138 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_store_userError, t.missingNameEmailPwd, 'error');
2139 | return {
2140 | status: 'E50-R-5000',
2141 | message: t.missingNameEmailPwd
2142 | };
2143 | }
2144 |
2145 | try {
2146 | // Benutzer anlegen
2147 | const response = await this.axiosInstance.post(
2148 | '/users',
2149 | {
2150 | name: args.name,
2151 | email: args.email,
2152 | password: args.password,
2153 | language: args.language || 'en',
2154 | timezone: args.timezone || 'Europe/Berlin',
2155 | roles: args.roles || [],
2156 | groups: args.groups || [],
2157 | usePublic: args.usePublic || false
2158 | },
2159 | {
2160 | headers: {
2161 | Authorization: `Bearer ${token}`
2162 | }
2163 | }
2164 | );
2165 |
2166 | // Loggen der erfolgreichen Benutzererstellung
2167 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_store_userSuccess, t.createUserSuccess.replace('${data}', JSON.stringify(createUserResponse.data)), 'info');
2168 |
2169 | // Erfolgreiche Antwort
2170 | return {
2171 | status: response.data?.status || 'ok',
2172 | message: response.data?.message || 'Benutzer erfolgreich erstellt.',
2173 | data: response.data?.data
2174 | };
2175 | } catch (error) {
2176 | // Loggen des Fehlers bei der Benutzererstellung
2177 |
2178 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_store_userError, t.createUserError.replace('${error}', error.response?.data || error.message), 'error');
2179 | return {
2180 | status: error.response?.status || 'E50-R-5001',
2181 | message: error.response?.data?.message || t.createUserError.replace('${error}', error.response?.data || error.message),
2182 | };
2183 | }
2184 | }
2185 | /* 5.1 Edit User #################################################################################*/
2186 | case 'edit_user': {
2187 | const disabledResponse = checkToolEnabled('edit_user');
2188 | if (disabledResponse) return disabledResponse;
2189 |
2190 | const { token, arguments: args } = request.params;
2191 | const tokenValidation = validateToken(token);
2192 | if (tokenValidation) return tokenValidation;
2193 |
2194 | // Mindestens die E-Mail muss angegeben sein, um den User zu identifizieren
2195 | if (!args || !args.email) {
2196 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_edit_userError, t.emailRequiredForEdit, 'error');
2197 | return {
2198 | status: 'E51-R-5100',
2199 | message: t.emailRequiredForEdit
2200 | };
2201 | }
2202 |
2203 | try {
2204 | // Nur Felder senden, die tatsächlich aktualisiert werden sollen
2205 | const payload = {};
2206 | if (args.name) payload.name = args.name;
2207 | if (args.password) payload.password = args.password;
2208 | if (args.language) payload.language = args.language;
2209 | if (args.timezone) payload.timezone = args.timezone;
2210 | if (Array.isArray(args.roles)) payload.roles = args.roles;
2211 | if (Array.isArray(args.groups)) payload.groups = args.groups;
2212 | if (typeof args.usePublic === 'boolean') payload.usePublic = args.usePublic;
2213 |
2214 | // E-Mail ist Pflicht, um den Benutzer auf dem Server zu finden
2215 | payload.email = args.email;
2216 |
2217 | const response = await this.axiosInstance.patch(
2218 | '/users',
2219 | payload,
2220 | {
2221 | headers: { Authorization: `Bearer ${token}` }
2222 | }
2223 | );
2224 |
2225 | // Loggen der erfolgreichen Benutzerbearbeitung
2226 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_store_userSuccess, t.editUserSuccess.replace('${data}', JSON.stringify(response.data)), 'info');
2227 |
2228 | return {
2229 | status: response.data?.status || 'ok',
2230 | message: response.data?.message || t.editUserSuccess.replace('${data}', JSON.stringify(response.data)),
2231 | data: response.data?.data
2232 | };
2233 | } catch (error) {
2234 | const editUserError = error.response?.data || error.message;
2235 | // Loggen des Fehlers bei der Benutzerbearbeitung
2236 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_edit_userError, t.editUserError.replace('${error}', editUserError), 'error');
2237 | return {
2238 | status: error.response?.status || 'E51-R-5101',
2239 | message: error.response?.data?.message || 'Fehler beim Bearbeiten des Benutzers.'
2240 | };
2241 | }
2242 | }
2243 | /* 5.2 Delete User ################################################################################*/
2244 | case 'delete_user': {
2245 | const disabledResponse = checkToolEnabled('delete_user');
2246 | if (disabledResponse) return disabledResponse;
2247 |
2248 | const { token, arguments: args } = request.params;
2249 | const tokenValidation = validateToken(token);
2250 | if (tokenValidation) return tokenValidation;
2251 |
2252 | // E-Mail ist nötig, um den Benutzer zu löschen
2253 | if (!args || !args.email) {
2254 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_delete_userError, t.emailRequiredForDelete, 'error');
2255 | return {
2256 | status: 'E52-R-5200',
2257 | message: t.emailRequiredForDelete
2258 | };
2259 | }
2260 |
2261 | try {
2262 | // DELETE-Anfrage mit JSON-Body
2263 | const response = await this.axiosInstance.delete(
2264 | '/users',
2265 | {
2266 | data: { email: args.email },
2267 | headers: { Authorization: `Bearer ${token}` }
2268 | }
2269 | );
2270 |
2271 | // Loggen der erfolgreichen Benutzerlöschung
2272 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_delete_userSuccess, t.deleteUserSuccess.replace('${data}', JSON.stringify(response.data, null, 2)), 'info');
2273 |
2274 | return {
2275 | status: response.data?.status || 'ok',
2276 | message: response.data?.message || 'Benutzer erfolgreich gelöscht.',
2277 | data: response.data?.data
2278 | };
2279 | } catch (error) {
2280 | // Loggen des Fehlers bei der Benutzerlöschung
2281 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_delete_userError, t.deleteUserError.replace('${error}', error.response?.data || error.message), 'error');
2282 | return {
2283 | status: error.response?.status || 'E52-R-5201',
2284 | message: error.response?.data?.message || 'Fehler beim Löschen des Benutzers.'
2285 | };
2286 | }
2287 | }
2288 | /* 5.3 Reactivate User ################################################################################*/
2289 | case 'reactivate_user': {
2290 | const disabledResponse = checkToolEnabled('reactivate_user');
2291 | if (disabledResponse) return disabledResponse;
2292 |
2293 | const { token, arguments: args } = request.params;
2294 | const tokenValidation = validateToken(token);
2295 | if (tokenValidation) return tokenValidation;
2296 |
2297 | // E-Mail ist erforderlich, um einen Benutzer zu reaktivieren
2298 | if (!args || !args.email) {
2299 | if (!isanonymousModeEnabled) {
2300 | logEvent('server', 'swreg', l.prefix_reactivate_userError, t.emailRequiredForReactivate, 'error');
2301 | }
2302 | return {
2303 | status: 'E53-R-5300',
2304 | message: t.emailRequiredForReactivate
2305 | };
2306 | }
2307 |
2308 | try {
2309 | // POST-Anfrage mit JSON-Body für die Reaktivierung des Benutzers
2310 | const response = await this.axiosInstance.post(
2311 | '/api/v1/users/reactivate',
2312 | { email: args.email },
2313 | {
2314 | headers: {
2315 | Authorization: `Bearer ${token}`,
2316 | Accept: 'application/json'
2317 | }
2318 | }
2319 | );
2320 |
2321 | // Loggen der erfolgreichen Benutzerreaktivierung
2322 | if (!isanonymousModeEnabled) {
2323 | logEvent('server', 'swreg', l.prefix_reactivate_userSuccess, `Benutzer erfolgreich reaktiviert: ${JSON.stringify(response.data)}`, 'info');
2324 | }
2325 |
2326 | return {
2327 | status: response.data?.status || 'ok',
2328 | message: response.data?.message || 'Benutzer erfolgreich reaktiviert.',
2329 | data: response.data?.data
2330 | };
2331 | } catch (error) {
2332 | // Loggen des Fehlers bei der Benutzerreaktivierung
2333 | if (!isanonymousModeEnabled) {
2334 | logEvent('server', 'swreg', l.prefix_reactivate_userError, t.reactivateUserError.replace('${error}', error.response?.data || error.message), 'error');
2335 | }
2336 | return {
2337 | status: error.response?.status || 'E53-R-5301',
2338 | message: error.response?.data?.message || 'Fehler bei der Reaktivierung des Benutzers.'
2339 | };
2340 | }
2341 | }
2342 | /* 6.0 OpenAPI Compatible API Chat #######################################################################################*/
2343 | case 'oai_comp_api_chat': {
2344 | const disabledResponse = checkToolEnabled('oai_comp_api');
2345 | if (disabledResponse) return disabledResponse;
2346 |
2347 | const { token, arguments: args } = request.params;
2348 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_chat, t.extractedToken.replace('${token}', token), 'info');
2349 |
2350 | // Token prüfen und validieren
2351 | if (!token) {
2352 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_chatError, t.noTokenError, 'error');
2353 | return { status: 'E60-R-6000', message: t.missingTokenError };
2354 | }
2355 | const tokenValidation = validateToken(token);
2356 | if (tokenValidation) return tokenValidation;
2357 |
2358 |
2359 | // Argument-Validierung
2360 | if (!args || !args.question) {
2361 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_chatError, t.missingArgumentsError.replace('${args}', JSON.stringify(args)), 'error');
2362 | return {
2363 | status: 'error',
2364 | message: t.missingArgumentsError.replace('${args}', JSON.stringify(args)),
2365 | };
2366 | }
2367 |
2368 | const { question, usePublic, groups, language } = args;
2369 |
2370 | // Konflikt zwischen `usePublic` und `groups` lösen
2371 | if (usePublic && groups && groups.length > 0) {
2372 | if (!isanonymousModeEnabled) logEvent('system', 'swreg', l.prefix_chatWarning, t.publicGroupsConflictWarning, 'warn');
2373 | args.usePublic = false;
2374 | }
2375 |
2376 | try {
2377 | // Loggen der Chat-Anfrage
2378 | if (!isanonymousModeEnabled) logEvent('oaichat', 'swreg', l.prefix_chatRequest, t.sendingChatRequest
2379 | .replace('${question}', question)
2380 | .replace('${usePublic}', usePublic)
2381 | .replace('${groups}', JSON.stringify(groups))
2382 | .replace('${language}', language), 'info');
2383 |
2384 | const response = await this.axiosInstance.post(
2385 | '/chats',
2386 | {
2387 | question,
2388 | usePublic: usePublic || false,
2389 | groups: Array.isArray(groups) ? groups : [groups],
2390 | language: language || 'de',
2391 | },
2392 | { headers: { Authorization: `Bearer ${token}` } }
2393 | );
2394 |
2395 | const data = response.data?.data || {};
2396 | // Loggen der erfolgreichen Chat-Antwort
2397 | if (!isanonymousModeEnabled) logEvent('server', 'oareg', l.prefix_chatSuccess, t.chatResponseSuccess.replace('${data}', JSON.stringify(data)), 'info');
2398 |
2399 | // Erfolgsantwort mit Status und Daten
2400 | return {
2401 | status: response.data?.status || 'ok',
2402 | message: response.data?.message || 'Chat erfolgreich.',
2403 | content: {
2404 | chatId: data.chatId,
2405 | answer: data.answer,
2406 | sources: data.sources || [],
2407 | },
2408 | };
2409 | } catch (error) {
2410 | const chatApiErrorMessage = error.message || error.response?.data;
2411 | // Loggen des Fehlers bei der Chat-API-Anfrage
2412 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_chatApiError, t.chatApiError.replace('${error}', chatApiErrorMessage), 'error');
2413 |
2414 | // Fehlerantwort mit Status und Nachricht
2415 | return {
2416 | status: error.response?.status || 'E60-R-6002',
2417 | message: error.response?.data?.message || t.chatApiErrorDefault,
2418 | };
2419 | }
2420 | }
2421 | /* 6.1 Continue Chat ##############################################################################*/
2422 | case 'oai_comp_api_continue_chat': {
2423 | const disabledResponse = checkToolEnabled('oai_comp_api');
2424 | if (disabledResponse) return disabledResponse;
2425 |
2426 | const args = request.params.arguments;
2427 |
2428 | if (!args || !args.chatId || !args.question) {
2429 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_continue_chatError, t.missingChatParams, 'error');
2430 | return {
2431 | status: 'E21-R-6100',
2432 | message: t.missingChatParams
2433 | };
2434 | }
2435 |
2436 | const { chatId, question } = args;
2437 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_continue_chat, t.conversationContinuation.replace('${chatId}', chatId), 'info');
2438 |
2439 | try {
2440 | const continueChatResponse = await this.axiosInstance.patch(`/chats/${chatId}`, {
2441 | question: question,
2442 | });
2443 | // Loggen der erfolgreichen Fortsetzung der Konversation
2444 | if (!isanonymousModeEnabled) logEvent('server', 'oareg', l.prefix_continue_chatSuccess, t.conversationSuccess.replace('${data}', JSON.stringify(continueChatResponse.data, null, 2)), 'info');
2445 | return {
2446 | content: {
2447 | chatId: continueChatResponse.data.data.chatId,
2448 | answer: continueChatResponse.data.data.answer,
2449 | sources: continueChatResponse.data.sources || [],
2450 | message: continueChatResponse.data.message,
2451 | status: continueChatResponse.data.status,
2452 | },
2453 | };
2454 | } catch (error) {
2455 | if (!isanonymousModeEnabled) logEvent('server', 'swreg', l.prefix_continue_chatError, t.apiRequestError.replace('${error}', error.message), 'error');
2456 | return {
2457 | status: error.response?.status || 'E61-R-6101',
2458 | message: error.response?.data?.message || t.continueConversationError,
2459 | };
2460 | }
2461 | }
2462 | default:
2463 | // Loggen unbekannter Befehle
2464 | if (!isanonymousModeEnabled) logEvent(
2465 | 'system',
2466 | 'swreg',
2467 | l.prefix_unknownCommand,
2468 | t.unknownCommandError.replace('${cmd}', request.params.name),
2469 | 'warn'
2470 | );
2471 | throw new McpError(
2472 | ErrorCode.MethodNotFound,
2473 | t.unknownTool.replace('${toolName}', request.params.name)
2474 | );
2475 | }
2476 | }
2477 | catch (error) {
2478 | if (!isanonymousModeEnabled) logEvent('system', 'swreg', l.prefix_Unhandled_Error, t.errorHandlingRequest.replace('${error}', error.message || JSON.stringify(error, null, 2)), 'error');
2479 | if (axios.isAxiosError(error)) {
2480 | const message = error.response?.data?.message ?? error.message;
2481 | if (!isanonymousModeEnabled) logEvent('system', 'swreg', l.prefix_apiRequestError, t.apiErrorDetails.replace('${status}', error.response?.status || 'Unknown').replace('${data}', JSON.stringify(error.response?.data || {}, null, 2)), 'error');
2482 | return {
2483 | content: [
2484 | {
2485 | type: 'text',
2486 | text: `API error: ${message}`
2487 | }
2488 | ],
2489 | isError: true
2490 | };
2491 | }
2492 | throw error;
2493 | }
2494 | });
2495 | }
2496 |
2497 | /* ##################################################################################################
2498 | # MESSAGE HANDLER
2499 | ##################################################################################################*/
2500 | async run() {
2501 | const isPortInUse = (port) => new Promise((resolve, reject) => {
2502 | const tester = net.createServer()
2503 | .once('error', (err) => (err.code === 'EADDRINUSE' ? resolve(true) : reject(err)))
2504 | .once('listening', () => tester.once('close', () => resolve(false)).close())
2505 | .listen(port);
2506 | });
2507 |
2508 | const PORT = Port;
2509 | if (await isPortInUse(PORT)) {
2510 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_Port_Check, t.portInUse.replace('${PORT}', PORT), 'error');
2511 | throw new Error(t.portInUse.replace('${PORT}', PORT));
2512 | }
2513 |
2514 | const transport = new TcpServerTransport(PORT, enableTLS, sslKeyPath, sslCertPath);
2515 | await transport.start(async (message) => {
2516 | try {
2517 | // if (!isanonymousModeEnabled) logEvent('client', 'swmsg', 'Incoming Message', `Nachricht empfangen: ${JSON.stringify(message)}`, 'info');
2518 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_Incoming_Message, t.incomingMessage.replace('${MESSAGE}', JSON.stringify(message)), 'info');
2519 |
2520 | // Token-Validierung nur durchführen, wenn es nicht der "login"-Befehl ist
2521 | // if (message.command !== 'login') {
2522 | // const tokenValidation = validateToken(message.token);
2523 | // if (tokenValidation) return tokenValidation;
2524 | // }
2525 |
2526 | if (!message || typeof message !== 'object') {
2527 | throw new McpError(
2528 | ErrorCode.InvalidRequest,
2529 | t.invalidOrEmptyRequest
2530 | );
2531 | }
2532 |
2533 | // Verarbeite verschiedene Anfragen dynamisch
2534 | if (!message.command) {
2535 | throw new McpError(
2536 | ErrorCode.InvalidRequest,
2537 | t.missingCommandParameter
2538 | );
2539 | }
2540 |
2541 | switch (message.command) {
2542 | /* 1.0 Login ######################################################################################*/
2543 | // clientIP, clientPort, functionName, status, level = 'info')
2544 | case 'login': {
2545 | const disabledResponse = checkToolEnabled('login');
2546 | if (disabledResponse) return disabledResponse;
2547 |
2548 | // Extrahiere die Argumente aus der Nachricht
2549 | const args = getArguments(message);
2550 | const { email, password: Pwd } = args;
2551 |
2552 | // Überprüfe, ob die E-Mail und das Passwort vorhanden sind
2553 | if (!email || !Pwd) {
2554 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_loginError, t.loginEmailPasswordRequired, 'error');
2555 | return {
2556 | status: 'E10-M-1050',
2557 | message: t.loginEmailPasswordRequired,
2558 | };
2559 | }
2560 |
2561 | let password;
2562 |
2563 | // Passwort entschlüsseln, falls erforderlich
2564 | if (typeof PwEncryption !== 'undefined' && PwEncryption) {
2565 | password = decryptPassword(Pwd);
2566 | } else {
2567 | password = Pwd;
2568 | }
2569 |
2570 | try {
2571 | // Login-API aufrufen
2572 | const loginResponse = await this.axiosInstance.post('/login', { email, password });
2573 |
2574 | // Loggen des erfolgreichen Logins
2575 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_loginSuccess, t.loginSuccess.replace('${data}', JSON.stringify(loginResponse.data)), 'info');
2576 |
2577 | // Entfernen des Basic Auth Headers und Setzen des Bearer Tokens
2578 | delete this.axiosInstance.defaults.headers.common['Authorization'];
2579 | this.axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${loginResponse.data.data.token}`;
2580 |
2581 | // Token zurückgeben
2582 | return {
2583 | status: loginResponse.data?.status || 'ok', // Dynamisch, falls der API-Status einheitlich ist
2584 | message: loginResponse.data?.message || 'Login erfolgreich.', // API-Nachricht verwenden oder Standardnachricht
2585 | token: loginResponse.data?.data?.token, // Token aus API-Antwort
2586 | };
2587 | } catch (error) {
2588 | const errorMessage = error.response?.data || error.message;
2589 | // Loggen des Fehlers beim Login
2590 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_loginError, t.loginError.replace('${error}', errorMessage), 'error');
2591 |
2592 | return {
2593 | status: error.response?.status || 'E10-M-1051', // API-Fehlerstatus oder Standardfehlerstatus,
2594 | message: error.response?.data || error.message || 'no error message'
2595 | };
2596 | }
2597 | }
2598 | /* 1.1 Logout #####################################################################################*/
2599 | case 'logout': {
2600 | const disabledResponse = checkToolEnabled('logout');
2601 | if (disabledResponse) return disabledResponse;
2602 |
2603 | const { token } = message;
2604 |
2605 | try {
2606 | const logoutResponse = await this.axiosInstance.delete('/logout', {
2607 | headers: {
2608 | Authorization: `Bearer ${token}`
2609 | }
2610 | });
2611 |
2612 |
2613 | // Loggen des erfolgreichen Logouts
2614 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_logoutSuccess, t.logoutSuccess.replace('${data}', JSON.stringify(logoutResponse.data)), 'info');
2615 |
2616 | return {
2617 | data: {}, // Optional: Zusätzliche Daten könnten hier eingefügt werden
2618 | status: logoutResponse.data?.status || 'no status', // Dynamisch, falls der API-Status einheitlich ist
2619 | message: logoutResponse.data?.message || 'no message', // API-Nachricht verwenden oder Standardnachricht
2620 | };
2621 | } catch (error) {
2622 | const logoutErrorMessage = error.response?.data || error.message;
2623 | // Loggen des Fehlers beim Logout
2624 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_logoutError, t.logoutError.replace('${error}', logoutErrorMessage), 'error');
2625 |
2626 | return {
2627 | data: {},
2628 | message: error.response?.data || error.message || t.noErrorMessage,
2629 | status: error.response?.status || 'E11-R-1150', // Internal Server Error oder spezifischer Statuscode
2630 | };
2631 | }
2632 | }
2633 | /* 2.0 Chat #######################################################################################*/
2634 | case 'chat': {
2635 | const disabledResponse = checkToolEnabled('chat');
2636 | if (disabledResponse) return disabledResponse;
2637 |
2638 | const { token, arguments: args } = message;
2639 | if (!isanonymousModeEnabled) logEvent('server', 'swmsg', l.prefix_chat, t.extractedToken.replace('${token}', token), 'info');
2640 |
2641 | // Token prüfen und validieren
2642 | if (!token) {
2643 | if (!isanonymousModeEnabled) logEvent('server', 'swmsg', l.prefix_chatError, t.noTokenError, 'error');
2644 | return { status: 'E20-M-2000', message: t.missingTokenError };
2645 | }
2646 |
2647 | // Argument-Validierung
2648 | if (!args || !args.question) {
2649 | if (!isanonymousModeEnabled) logEvent('server', 'swmsg', l.prefix_chatError, t.missingArgumentsError.replace('${args}', JSON.stringify(args)), 'error');
2650 | return {
2651 | status: 'error',
2652 | message: t.missingArgumentsError.replace('${args}', JSON.stringify(args)),
2653 | };
2654 | }
2655 |
2656 | const { question, usePublic, groups, language } = args;
2657 |
2658 | // Konflikt zwischen `usePublic` und `groups` lösen
2659 | if (usePublic && groups && groups.length > 0) {
2660 | if (!isanonymousModeEnabled) logEvent('system', 'swmsg', l.prefix_chatWarning, t.publicGroupsConflictWarning, 'warn');
2661 | args.usePublic = false;
2662 | }
2663 |
2664 | try {
2665 | // Loggen der Chat-Anfrage
2666 | if (!isanonymousModeEnabled) logEvent('server', 'swmsg', l.prefix_chatRequest, t.sendingChatRequest
2667 | .replace('${question}', question)
2668 | .replace('${usePublic}', usePublic)
2669 | .replace('${groups}', JSON.stringify(groups))
2670 | .replace('${language}', language), 'info');
2671 |
2672 | const response = await this.axiosInstance.post(
2673 | '/chats',
2674 | {
2675 | question,
2676 | usePublic: usePublic || false,
2677 | groups: Array.isArray(groups) ? groups : [groups],
2678 | language: language || 'de',
2679 | },
2680 | { headers: { Authorization: `Bearer ${token}` } }
2681 | );
2682 |
2683 | const data = response.data?.data || {};
2684 | // Loggen der erfolgreichen Chat-Antwort
2685 | if (!isanonymousModeEnabled) logEvent('server', 'swmsg', l.prefix_chatSuccess, t.chatResponseSuccess.replace('${data}', JSON.stringify(data)), 'info');
2686 |
2687 | // Erfolgsantwort mit Status und Daten
2688 | return {
2689 | status: response.data?.status || 'ok',
2690 | message: response.data?.message || 'Chat erfolgreich.',
2691 | content: {
2692 | chatId: data.chatId,
2693 | answer: data.answer,
2694 | sources: data.sources || [],
2695 | },
2696 | };
2697 | } catch (error) {
2698 | const chatApiErrorMessage = error.message || error.response?.data;
2699 | // Loggen des Fehlers bei der Chat-API-Anfrage
2700 | if (!isanonymousModeEnabled) logEvent('server', 'swmsg', l.prefix_chatApiError, t.chatApiError.replace('${error}', chatApiErrorMessage), 'error');
2701 |
2702 | // Fehlerantwort mit Status und Nachricht
2703 | return {
2704 | status: error.response?.status || 'E20-R-2002',
2705 | message: error.response?.data?.message || t.chatApiErrorDefault,
2706 | };
2707 | }
2708 | }
2709 | /* 2.1 Continue Chat ##############################################################################*/
2710 | case 'continue_chat': {
2711 | const disabledResponse = checkToolEnabled('continue_chat');
2712 | if (disabledResponse) return disabledResponse;
2713 |
2714 | const token = message.token; // Token direkt extrahieren
2715 | const args = message.arguments || {}; // Sichere Extraktion der Argumente
2716 | const { chatId, question } = args;
2717 |
2718 | if (!args || !args.chatId || !args.question) {
2719 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_continue_chat, t.missingChatParams, 'error');
2720 | return { status: 'E21-M-2150', message: t.missingChatParams };
2721 | }
2722 |
2723 | try {
2724 | const continueChatResponse = await this.axiosInstance.patch(
2725 | `/chats/${chatId}`,
2726 | { question },
2727 | { headers: { Authorization: `Bearer ${token}` } }
2728 | );
2729 |
2730 | // Loggen der erfolgreichen Continue-Chat-Antwort
2731 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_continue_chatSuccess, t.conversationSuccess.replace('${data}', JSON.stringify(continueChatResponse.data, null, 2)), 'info');
2732 |
2733 | return {
2734 | content: {
2735 | chatId: continueChatResponse.data.data.chatId,
2736 | answer: continueChatResponse.data.data.answer,
2737 | sources: continueChatResponse.data.sources || [],
2738 | message: continueChatResponse.data.message,
2739 | status: continueChatResponse.data.status,
2740 | },
2741 | };
2742 | } catch (error) {
2743 | // Loggen des Fehlers bei der Continue-Chat-API-Anfrage
2744 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_apiRequestError, t.apiRequestError.replace('${error}', error.message), 'error');
2745 | return {
2746 | status: 'E21-M-2151',
2747 | message: error.response?.data?.message || error.message || t.noErrorMessage,
2748 | };
2749 | }
2750 | }
2751 | /* 2.2 Get Chat Info ##############################################################################*/
2752 | case 'get_chat_info': {
2753 | const disabledResponse = checkToolEnabled('get_chat_info');
2754 | if (disabledResponse) return disabledResponse;
2755 |
2756 | const { token } = message; // Token direkt aus `message` extrahieren
2757 | const args = message.arguments || {}; // Argumente aus `message` extrahieren
2758 | const { chatId } = args; // chatId aus den Argumenten extrahieren
2759 |
2760 | if (!chatId) {
2761 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_get_chat_info, t.missingChatId, 'error');
2762 | return { status: 'E22-M-2250', message: t.missingChatId };
2763 | }
2764 |
2765 | try {
2766 | const response = await this.axiosInstance.get(`/chats/${chatId}`, {
2767 | headers: { Authorization: `Bearer ${token}` }
2768 | });
2769 |
2770 | const chatData = response.data?.data;
2771 |
2772 | if (!chatData) {
2773 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_get_chat_infoError, t.noChatData, 'error');
2774 | return {
2775 | status: 'E22-M-2251',
2776 | message: t.noChatData,
2777 | };
2778 | }
2779 |
2780 | // Formatiertes Ergebnis zurückgeben
2781 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_get_chat_infoSuccess, t.ChatInfoRetrieved.replace('${chatData}', JSON.stringify(chatData)), 'info');
2782 |
2783 | return {
2784 | data: {
2785 | chatId: chatData.chatId,
2786 | title: chatData.title || 'Unbenannter Chat',
2787 | language: chatData.language || 'Unbekannt',
2788 | groups: chatData.groups || [],
2789 | messages: chatData.messages || []
2790 | },
2791 | message: response.data?.message || 'Erfolgreich abgerufen.'
2792 | };
2793 | } catch (error) {
2794 | const fetchChatErrorMessage = error.message || error.response?.data;
2795 | // Loggen des Fehlers beim Abrufen der Chat-Informationen
2796 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_get_chat_infoError, t.fetchChatInfoError.replace('${error}', fetchChatErrorMessage), 'error');
2797 | return {
2798 | status: 'E22-M-2252',
2799 | message: error.response?.data?.message || t.unknownError,
2800 | };
2801 | }
2802 | }
2803 | /* 2.3 Delete All Chats ##############################################################################*/
2804 | case 'delete_all_chats': {
2805 | const disabledResponse = checkToolEnabled('delete_all_chats');
2806 | if (disabledResponse) return disabledResponse;
2807 |
2808 | const token = message?.token;
2809 |
2810 | if (!token) {
2811 | return { status: 'E23-M-2301', message: t.missingAuthToken };
2812 | }
2813 |
2814 | const tokenValidation = validateToken(token);
2815 | if (tokenValidation) return tokenValidation;
2816 |
2817 | try {
2818 | const response = await this.axiosInstance.delete('/chats/flush', {
2819 | headers: {
2820 | Authorization: `Bearer ${token}`,
2821 | Accept: 'application/json'
2822 | }
2823 | });
2824 |
2825 | // Erfolg loggen
2826 | if (!isanonymousModeEnabled) {
2827 | logEvent('server', 'swmsg', l.prefix_delete_all_chatsSuccess, t.deleteChatsSuccess, 'info');
2828 | }
2829 |
2830 | return {
2831 | data: {},
2832 | message: response.data?.message || 'success',
2833 | status: response.status || 200
2834 | };
2835 | } catch (error) {
2836 | const deleteChatsErrorMessage = error.message || error.response?.data;
2837 |
2838 | // Fehler loggen
2839 | if (!isanonymousModeEnabled) {
2840 | logEvent('server', 'swmsg', l.prefix_delete_all_chatsError,
2841 | t.deleteChatsError.replace('${error}', deleteChatsErrorMessage), 'error');
2842 | }
2843 |
2844 | return {
2845 | status: error.response?.status || 'E23-M-2300',
2846 | message: error.response?.data?.message || 'Error deleting all chat history.'
2847 | };
2848 | }
2849 | }
2850 | /* 2.4 Delete Specific Chat ##############################################################################*/
2851 | case 'delete_chat': {
2852 | const disabledResponse = checkToolEnabled('delete_chat');
2853 | if (disabledResponse) return disabledResponse;
2854 |
2855 | const { token } = message; // Token direkt aus `message` extrahieren
2856 | const tokenValidation = validateToken(token);
2857 | if (tokenValidation) return tokenValidation;
2858 |
2859 | const args = message.arguments || {}; // Argumente aus `message` extrahieren
2860 | const { chatId } = args; // chatId aus den Argumenten extrahieren
2861 |
2862 | if (!chatId) {
2863 | return { status: 'E24-M-2400', message: t.missingChatId };
2864 | }
2865 |
2866 | try {
2867 | const response = await this.axiosInstance.delete(`/chats/${chatId}`, {
2868 | headers: {
2869 | Authorization: `Bearer ${token}`,
2870 | Accept: 'application/json'
2871 | }
2872 | });
2873 |
2874 | // Erfolg loggen
2875 | if (!isanonymousModeEnabled) {
2876 | logEvent('server', 'swmsg', l.prefix_delete_chatSuccess, t.chatDeleted.replace('${chatId}', chatId), 'info');
2877 | }
2878 |
2879 | return {
2880 | data: {},
2881 | message: response.data?.message || 'success',
2882 | status: response.status || 200
2883 | };
2884 | } catch (error) {
2885 | const deleteChatErrorMessage = error.message || error.response?.data;
2886 |
2887 | // Fehler loggen
2888 | if (!isanonymousModeEnabled) {
2889 | logEvent('server', 'swmsg', l.prefix_delete_chatError,
2890 | t.deleteChatError.replace('${chatId}', chatId).replace('${error}', deleteChatErrorMessage), 'error');
2891 | }
2892 |
2893 | return {
2894 | status: error.response?.status || 'E24-M-2401',
2895 | message: error.response?.data?.message || `Error deleting chat with ID ${chatId}.`
2896 | };
2897 | }
2898 | }
2899 | /* 3.0 Create Source ##############################################################################*/
2900 | case 'create_source': {
2901 | const disabledResponse = checkToolEnabled('create_source');
2902 | if (disabledResponse) return disabledResponse;
2903 |
2904 | const args = getArguments(message);
2905 | const token = message.token;
2906 |
2907 | // Validierung: Erforderliche Parameter prüfen
2908 | if (!token) {
2909 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_create_source, t.missingTokenError, 'error');
2910 | return { status: 'E30-M-3050', message: t.missingTokenError };
2911 | }
2912 | if (!args || !args.name || !args.content) {
2913 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_create_source, t.missingNameAndContent, 'error');
2914 | return { status: 'E30-M-3051', message: t.missingParametersError.replace('${parameters}', 'name und content') };
2915 | }
2916 |
2917 | const { name, content, groups } = args;
2918 |
2919 | try {
2920 | // Gruppenvalidierung vorab durchführen
2921 | if (groups && groups.length > 0) {
2922 | const groupValidation = await this.validateGroups(groups, token, 'client', 'swmsg');
2923 | if (!groupValidation.isValid) {
2924 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_create_sourceInvalidGroups, t.InvalidGroups.replace('${GROUPS}', groupValidation.invalidGroups.join(', ')), 'error');
2925 | return {
2926 | status: 'E30-M-3052',
2927 | message: t.invalidGroupsError.replace('${invalidGroups}', groupValidation.invalidGroups.join(', '))
2928 | };
2929 | }
2930 | }
2931 |
2932 | // API-Aufruf zur Erstellung der Quelle
2933 | const createSourceResponse = await this.axiosInstance.post(
2934 | '/sources',
2935 | { name, content, groups },
2936 | { headers: { Authorization: `Bearer ${token}` } }
2937 | );
2938 |
2939 | // Loggen der erfolgreichen Erstellung der Quelle
2940 | if (!isanonymousModeEnabled) {
2941 | logEvent(
2942 | 'client',
2943 | 'message',
2944 | l.prefix_create_sourceSuccess,
2945 | t.createSourceSuccess.replace('${data}', JSON.stringify(createSourceResponse.data)),
2946 | 'info'
2947 | );
2948 | }
2949 |
2950 | // Erfolgsantwort
2951 | return {
2952 | status: createSourceResponse.data?.status || 'ok',
2953 | message: createSourceResponse.data?.message || 'Quelle erfolgreich erstellt.',
2954 | data: createSourceResponse.data?.data,
2955 | };
2956 | } catch (error) {
2957 | const createSourceError = error.message || JSON.stringify(error.response?.data);
2958 | // Loggen des Fehlers bei der Erstellung der Quelle
2959 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_create_sourceError, t.createSourceError.replace('${error}', createSourceError), 'error');
2960 |
2961 | // Fehlerhafte Antwort
2962 | if (error.response) {
2963 | return {
2964 | status: 'E30-M-3053',
2965 | message: error.response?.data?.message || error.message || t.noErrorMessage,
2966 | details: {
2967 | status: error.response.status,
2968 | headers: error.response.headers,
2969 | data: error.response.data,
2970 | },
2971 | };
2972 | } else if (error.request) {
2973 | return {
2974 | status: 'E30-M-3054',
2975 | message: t.noServerResponse,
2976 | details: { request: error.request },
2977 | };
2978 | } else {
2979 | return {
2980 | status: 'E30-M-3055',
2981 | message: error.message || t.unknownError,
2982 | };
2983 | }
2984 | }
2985 | }
2986 | /* 3.1 Get Source #################################################################################*/
2987 | case 'get_source': {
2988 | const disabledResponse = checkToolEnabled('get_source');
2989 | if (disabledResponse) return disabledResponse;
2990 | const { token, arguments: args } = message; // Extrahiere den Token und die Argumente
2991 | const { sourceId } = args; // Extrahiere sourceId aus den Argumenten
2992 |
2993 | if (!sourceId) {
2994 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_get_source, t.sourceIdRequiredRetrieveSource, 'error');
2995 | return { status: 'E31-M-3150', message: t.sourceIdRequiredRetrieveSource };
2996 | }
2997 |
2998 | // Loggen des Beginns der Quellenanfrage
2999 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_get_source, t.makingGetSourceRequest.replace('${sourceId}', sourceId), 'info');
3000 |
3001 | try {
3002 | const sourceResponse = await this.axiosInstance.get(`/sources/${sourceId}`, {
3003 | headers: {
3004 | Authorization: `Bearer ${token}`, // Nutze den vom Client bereitgestellten Token
3005 | },
3006 | });
3007 |
3008 | // Loggen der erhaltenen Quellenantwort
3009 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_get_sourceSuccess, t.gotGetSourceResponse.replace('${data}', JSON.stringify(sourceResponse.data, null, 2)), 'info');
3010 |
3011 | return {
3012 | content: sourceResponse.data,
3013 | };
3014 | } catch (error) {
3015 | // Loggen des Fehlers bei der Quellenanfrage
3016 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_get_sourceError, t.errorHandlingRequest.replace('${error}', error.message || JSON.stringify(error.response?.data, null, 2)), 'error');
3017 | return {
3018 | status: 'E31-M-3151',
3019 | message: t.apiErrorDetails
3020 | .replace('${status}', error.response?.status || 'E31-M-3151')
3021 | .replace('${data}', JSON.stringify(error.response?.data || {}, null, 2)),
3022 | };
3023 | }
3024 | }
3025 | /* 3.2 List Sources ###############################################################################*/
3026 | case 'list_sources': {
3027 | const disabledResponse = checkToolEnabled('list_sources');
3028 | if (disabledResponse) return disabledResponse;
3029 | const { token, attributes } = message; // Extrahiere den Token und die Attribute
3030 |
3031 | if (!attributes || !attributes.groupName) {
3032 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_list_sources, t.groupNameRequired, 'error');
3033 | return { status: 'E32-M-3250', message: t.groupNameRequired };
3034 | }
3035 |
3036 | const groupName = attributes.groupName; // Extrahiere den groupName aus attributes
3037 |
3038 | // Loggen des Beginns der Quellenliste-Anfrage
3039 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_list_sources, t.fetchingSources.replace('${groupName}', groupName), 'info');
3040 |
3041 | try {
3042 | // Führe die API-Anfrage aus, um die Quellen für die Gruppe zu erhalten
3043 | const sourceResponse = await this.axiosInstance.post(
3044 | '/sources/groups',
3045 | { groupName },
3046 | {
3047 | headers: {
3048 | Authorization: `Bearer ${token}`, // Nutze den vom Client bereitgestellten Token
3049 | },
3050 | }
3051 | );
3052 |
3053 | // Loggen der erhaltenen Quellenliste
3054 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_list_sourcesSuccess, t.sourcesRetrieved.replace('${data}', JSON.stringify(sourceResponse.data, null, 2)), 'info');
3055 |
3056 | return {
3057 | content: sourceResponse.data, // Sende die Antwort zurück
3058 | };
3059 | } catch (error) {
3060 | // Loggen des Fehlers bei der Quellenliste-Anfrage
3061 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_list_sourcesError, t.groupValidationError.replace('${error}', error.message || JSON.stringify(error.response?.data)), 'error');
3062 | return {
3063 | status: 'E32-M-3251',
3064 | message: error.response?.data?.message || error.message || t.noErrorMessage,
3065 | };
3066 | }
3067 | }
3068 | /* 3.3 Edit Source ################################################################################*/
3069 | case 'edit_source': {
3070 | const disabledResponse = checkToolEnabled('edit_source');
3071 | if (disabledResponse) return disabledResponse;
3072 |
3073 | const { token, arguments: args } = message;
3074 | const { sourceId, title, content, groups } = args;
3075 |
3076 | // Validierung: Erforderliche Parameter
3077 | if (!sourceId) {
3078 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_edit_source, t.sourceIdRequiredEditSource, 'error');
3079 | return {
3080 | status: 'E33-M-3350',
3081 | message: t.missingParameterError.replace('${parameter}', 'sourceId'),
3082 | };
3083 | }
3084 |
3085 | // Loggen des Beginns der Quellenbearbeitung
3086 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_edit_source, t.editSourceLog.replace('${sourceId}', sourceId).replace('${title}', title || 'unverändert'), 'info');
3087 |
3088 | try {
3089 | // Nur Felder senden, die tatsächlich aktualisiert werden sollen
3090 | const payload = {};
3091 | if (title) payload.title = title;
3092 | if (content) payload.content = content;
3093 | if (groups) payload.groups = groups;
3094 |
3095 | const editSourceResponse = await this.axiosInstance.patch(
3096 | `/sources/${sourceId}`,
3097 | payload,
3098 | {
3099 | headers: {
3100 | Authorization: `Bearer ${token}` // Nutze den bereitgestellten Token
3101 | },
3102 | }
3103 | );
3104 |
3105 | // Loggen der erfolgreichen Quellenbearbeitung
3106 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_edit_sourceSuccess, t.editSourceSuccess.replace('${data}', JSON.stringify(editSourceResponse.data, null, 2)), 'info');
3107 |
3108 | // Erfolgreiche Antwort
3109 | return {
3110 | status: editSourceResponse.data?.status || 'ok',
3111 | message: editSourceResponse.data?.message || 'Quelle erfolgreich bearbeitet.',
3112 | data: editSourceResponse.data?.data
3113 | };
3114 | } catch (error) {
3115 | const editSourceError = error.message || JSON.stringify(error.response?.data);
3116 | // Loggen des Fehlers bei der Quellenbearbeitung
3117 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_edit_sourceError, t.editSourceError.replace('${error}', editSourceError), 'error');
3118 |
3119 | // Fehlerhafte Antwort
3120 | return {
3121 | data: {},
3122 | message: error.response?.data?.message || 'Bearbeiten der Quelle fehlgeschlagen. Bitte versuchen Sie es später erneut.',
3123 | status: error.response?.status || 'E33-M-3351', // Internal Server Error
3124 | };
3125 | }
3126 | }
3127 | /* 3.4 Delete Source ##############################################################################*/
3128 | case 'delete_source': {
3129 | const disabledResponse = checkToolEnabled('delete_source');
3130 | if (disabledResponse) return disabledResponse;
3131 | const { token, arguments: args } = message;
3132 | const { sourceId } = args;
3133 |
3134 | if (!sourceId) {
3135 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_source, t.sourceIdRequiredDeleteSource, 'error');
3136 | return { status: 'E34-M-3450', message: t.groupNameRequired.replace('${param}', 'sourceId') };
3137 | }
3138 |
3139 | // Loggen des Beginns der Quellenlöschung
3140 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_source, t.deletesourceLog.replace('${SourceName}', sourceId), 'info');
3141 |
3142 | try {
3143 | const deleteResponse = await this.axiosInstance.delete(`/sources/${sourceId}`, {
3144 | headers: { Authorization: `Bearer ${token}` },
3145 | });
3146 |
3147 | // Loggen der erfolgreichen Quellenlöschung
3148 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_sourceSuccess, t.deleteUserSuccess.replace('${data}', JSON.stringify(deleteResponse.data, null, 2)), 'info');
3149 |
3150 | return {
3151 | content: deleteResponse.data,
3152 | };
3153 | } catch (error) {
3154 | const deleteSourceError = error.message || JSON.stringify(error.response?.data);
3155 | // Loggen des Fehlers bei der Quellenbearbeitung
3156 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_sourceError, t.deleteSourceError.replace('${error}', deleteSourceError), 'error');
3157 |
3158 | return {
3159 | data: {},
3160 | message: error.response?.data?.message || 'Löschen der Quelle fehlgeschlagen. Bitte versuchen Sie es später erneut.',
3161 | status: error.response?.status || 'E34-M-3451', // Internal Server Error
3162 | };
3163 | }
3164 | }
3165 | /* 4.0 List Groups ################################################################################*/
3166 | case 'list_groups': {
3167 | const disabledResponse = checkToolEnabled('list_groups');
3168 | if (disabledResponse) return disabledResponse;
3169 |
3170 | const { token } = message; // Token direkt extrahieren
3171 |
3172 | try {
3173 | await this.ensureAuthenticated(token);
3174 |
3175 | const response = await this.axiosInstance.get('/groups');
3176 | let assignableGroups = response.data?.data?.assignableGroups || [];
3177 | const personalGroups = response.data?.data?.personalGroups || [];
3178 | const messageText = response.data?.message || 'no_message'; // Fallback für Nachricht
3179 | const status = response.data?.status || 'E40-M-4050'; // Fallback für Status
3180 |
3181 | if (isRestrictedGroupsEnabled) {
3182 | // Loggen der Einschränkung bei RESTRICTED_GROUPS
3183 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_list_groupsWarning, t.restrictedGroupsWarning, 'warn');
3184 | assignableGroups = ["NO ACCESS ALLOWED BY THE MCP-SERVER CONFIG"]; // Alle assignableGroups entfernen
3185 | }
3186 |
3187 | // Loggen der erfolgreichen Gruppenliste
3188 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_list_groupsSuccess, t.listGroupsSuccess.replace('${GROUPS}', JSON.stringify(response.data)), 'info');
3189 | // )`Gruppenliste abgerufen: ${JSON.stringify(response.data)}`, 'info');
3190 |
3191 | return {
3192 | data: {
3193 | personalGroups,
3194 | assignableGroups,
3195 | message: messageText,
3196 | status,
3197 | },
3198 | };
3199 | } catch (error) {
3200 | const fetchGroupsError = error.message || JSON.stringify(error.response?.data);
3201 | // Loggen des Fehlers beim Abrufen der Gruppen
3202 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_list_groupsError, t.fetchGroupsError.replace('${error}', fetchGroupsError), 'error');
3203 |
3204 | // Detaillierte Fehlerbehandlung
3205 | if (axios.isAxiosError(error)) {
3206 | const status = error.response?.status;
3207 | const serverMessage = error.response?.data?.message || error.message || 'no error message';
3208 | return {
3209 | status: 'E40-M-4051',
3210 | message: `${t.fetchGroupsErrorPrefix}: ${serverMessage} (Status: ${status})`,
3211 | // message: t.fetchGroupsErrorPrefix: ${serverMessage} (Status: ${status}),
3212 | };
3213 | }
3214 |
3215 | return {
3216 | status: 'E40-M-4052',
3217 | message: t.unknownErrorOccured,
3218 | };
3219 | }
3220 | }
3221 | /* 4.1 Store Group ################################################################################*/
3222 | case 'store_group': {
3223 | const disabledResponse = checkToolEnabled('store_group');
3224 | if (disabledResponse) return disabledResponse;
3225 |
3226 | const { groupName, description } = message.arguments; // Extrahiere die Argumente
3227 | const clientToken = message.token; // Token aus der Anfrage
3228 |
3229 | if (!groupName || !description) {
3230 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_store_group, t.missingGroupNameAndDesc, 'error');
3231 | return {
3232 | status: 'E41-M-4150',
3233 | message: t.missingGroupNameAndDesc
3234 | };
3235 | }
3236 |
3237 | if (!clientToken) {
3238 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_store_group, t.missingTokenError, 'error');
3239 | return { status: 'E41-M-4151', message: t.missingTokenError };
3240 | }
3241 |
3242 | try {
3243 | // API-Aufruf mit dem vom Client bereitgestellten Token
3244 | const createGroupResponse = await this.axiosInstance.post(
3245 | '/groups',
3246 | { groupName, description },
3247 | {
3248 | headers: {
3249 | Authorization: `Bearer ${clientToken}` // Nutze nur den Client-Token
3250 | }
3251 | }
3252 | );
3253 |
3254 | // Loggen der erfolgreichen Gruppenerstellung
3255 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_store_groupSuccess, t.createGroupSuccess.replace('${data}', JSON.stringify(createGroupResponse.data)), 'info');
3256 |
3257 | return {
3258 | content: createGroupResponse.data,
3259 | };
3260 | } catch (error) {
3261 | const apiError = error.response?.data?.message || error.message || t.noErrorMessage;
3262 |
3263 | if (!isanonymousModeEnabled) {
3264 | logEvent('client', 'swmsg', l.prefix_store_groupError, t.apiRequestError.replace('${error}', apiError), 'error');
3265 | }
3266 |
3267 | return {
3268 | status: 'E41-M-4152',
3269 | message: error.response?.data?.message || error.message || t.noErrorMessage,
3270 | };
3271 | }
3272 | }
3273 | /* 4.2 Delete Group ###################################################################################*/
3274 | case 'delete_group': {
3275 | const disabledResponse = checkToolEnabled('delete_group');
3276 | if (disabledResponse) return disabledResponse;
3277 |
3278 | const { token, arguments: args } = message; // Extrahiere Token und Argumente
3279 | const { groupName } = args;
3280 |
3281 | if (!groupName) {
3282 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_group, t.missingGroupNameParam, 'error');
3283 | return {
3284 | status: 'E42-M-4250',
3285 | message: t.missingGroupNameParam
3286 | };
3287 | }
3288 |
3289 | // Loggen des Beginns der Gruppenlöschung
3290 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_group, t.deleteGroupLog.replace('${groupName}', groupName), 'info');
3291 |
3292 | try {
3293 | // API-Aufruf mit dem Token des Clients
3294 | const deleteGroupResponse = await this.axiosInstance.delete('/groups', {
3295 | data: { groupName }, // JSON-Body für DELETE-Request
3296 | headers: {
3297 | Authorization: `Bearer ${token}` // Nutze den vom Client bereitgestellten Token
3298 | },
3299 | });
3300 |
3301 | // Loggen der erfolgreichen Gruppenlöschung
3302 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_groupSuccess, t.deleteGroupSuccessLog.replace('${data}', JSON.stringify(deleteGroupResponse.data)), 'info');
3303 |
3304 | return {
3305 | data: deleteGroupResponse.data?.data || {},
3306 | message: deleteGroupResponse.data?.message || 'success',
3307 | status: deleteGroupResponse.status || 200,
3308 | };
3309 | } catch (error) {
3310 | const deleteSourceError = error.response?.data || error.message;
3311 | // Loggen des Fehlers bei der Gruppenlöschung
3312 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_groupError, t.deleteSourceError.replace('${error}', deleteSourceError), 'error');
3313 |
3314 | return {
3315 | status: 'E42-M-4251',
3316 | message: error.response?.data?.message || error.message || t.noErrorMessage,
3317 | };
3318 | }
3319 | }
3320 | /* 5.0 Store User #################################################################################*/
3321 | case 'store_user': {
3322 | const disabledResponse = checkToolEnabled('store_user');
3323 | if (disabledResponse) return disabledResponse;
3324 | const { token, arguments: args } = message;
3325 |
3326 | // Validierung der erforderlichen Parameter
3327 | if (!args || !args.name || !args.email || !args.password) {
3328 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_store_user, t.missingNameEmailPwd, 'error');
3329 | return { status: 'E50-M-5050', message: t.missingNameEmailPwd };
3330 | }
3331 |
3332 | const Pwd = args.password;
3333 |
3334 | // Überprüfe, ob das Passwort vorhanden ist
3335 | if (!Pwd) {
3336 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_store_user, t.passwordIsRequired, 'error');
3337 | return {
3338 | status: 'E10-M-1050',
3339 | message: t.passwordIsRequired
3340 | };
3341 | }
3342 |
3343 | let password;
3344 |
3345 | // Passwort entschlüsseln, falls erforderlich
3346 | if (typeof PwEncryption !== 'undefined' && PwEncryption) {
3347 | password = decryptPassword(Pwd);
3348 | } else {
3349 | password = Pwd;
3350 | }
3351 |
3352 | try {
3353 | // Payload für die API-Anfrage
3354 | const payload = {
3355 | name: args.name,
3356 | email: args.email,
3357 | language: args.language || 'en',
3358 | timezone: args.timezone || 'Europe/Berlin',
3359 | password: password,
3360 | usePublic: args.usePublic || false,
3361 | groups: args.groups || [],
3362 | roles: args.roles || [],
3363 | activateFtp: args.activateFtp || false,
3364 | ftpPassword: args.ftpPassword || '',
3365 | };
3366 |
3367 | // Loggen des Payloads vor der API-Anfrage
3368 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_store_user, t.createUserLog.replace('${payload}', JSON.stringify(payload)), 'info');
3369 |
3370 | // API-Aufruf
3371 | const createUserResponse = await this.axiosInstance.post('/users', payload, {
3372 | headers: {
3373 | Authorization: `Bearer ${token}`
3374 | }
3375 | });
3376 |
3377 | // Loggen der erfolgreichen Benutzererstellung
3378 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_store_userSuccess, t.createUserSuccess.replace('${data}', JSON.stringify(createUserResponse.data)), 'info');
3379 |
3380 | return {
3381 | content: createUserResponse.data,
3382 | };
3383 | } catch (error) {
3384 | const createUserError = error.message || JSON.stringify(error.response?.data);
3385 | // Loggen des Fehlers bei der Quellenbearbeitung
3386 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_store_userError, t.createUserError.replace('${error}', createUserError), 'error');
3387 | // Fehlerhafte Antwort
3388 | return {
3389 | data: {},
3390 | message: error.response?.data?.message || 'Fehler beim Anlegen des Benutzers.',
3391 | status: error.response?.status || 'E50-M-5051', // Internal Server Error
3392 | };
3393 | }
3394 | }
3395 | /* 5.1 Edit User ##################################################################################*/
3396 | case 'edit_user': {
3397 | const disabledResponse = checkToolEnabled('edit_user');
3398 | if (disabledResponse) return disabledResponse;
3399 |
3400 | const { token, arguments: args } = message;
3401 | const tokenValidation = validateToken(token);
3402 | if (tokenValidation) return tokenValidation;
3403 |
3404 | // Mindestens die E-Mail muss angegeben sein, um den User zu identifizieren
3405 | if (!args || !args.email) {
3406 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_edit_user, t.emailRequiredForEdit, 'error');
3407 | return {
3408 | status: 'E51-M-5100',
3409 | message: t.emailRequiredForEdit
3410 | };
3411 | }
3412 | let password = null;
3413 |
3414 | if (args.password) {
3415 | const Pwd = args.password;
3416 | if (!Pwd) {
3417 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_edit_user, t.passwordIsRequired, 'error');
3418 | return {
3419 | status: 'E51-M-1050',
3420 | message: t.passwordIsRequired,
3421 | };
3422 | }
3423 | if (typeof PwEncryption !== 'undefined' && PwEncryption) {
3424 | password = decryptPassword(Pwd);
3425 | } else {
3426 | password = Pwd;
3427 | }
3428 | }
3429 |
3430 | try {
3431 | // Nur Felder senden, die tatsächlich aktualisiert werden sollen
3432 | const payload = {};
3433 | if (args.name) payload.name = args.name;
3434 | if (args.password) payload.password = password;
3435 | if (args.language) payload.language = args.language;
3436 | if (args.timezone) payload.timezone = args.timezone;
3437 | if (Array.isArray(args.roles)) payload.roles = args.roles;
3438 | if (Array.isArray(args.groups)) payload.groups = args.groups;
3439 | if (typeof args.usePublic === 'boolean') payload.usePublic = args.usePublic;
3440 |
3441 | // E-Mail ist Pflicht, um den Benutzer auf dem Server zu finden
3442 | payload.email = args.email;
3443 | const response = await this.axiosInstance.patch(
3444 | '/users',
3445 | payload,
3446 | {
3447 | headers: { Authorization: `Bearer ${token}` }
3448 | }
3449 | );
3450 |
3451 | // Loggen der erfolgreichen Benutzerbearbeitung
3452 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_edit_userSuccess, t.editUserSuccess.replace('${data}', JSON.stringify(response.data)), 'info');
3453 |
3454 | return {
3455 | status: response.data?.status || 'ok',
3456 | message: response.data?.message || 'Benutzer erfolgreich bearbeitet.',
3457 | data: response.data?.data
3458 | };
3459 | } catch (error) {
3460 | const editUserError = error.message || JSON.stringify(error.response?.data);
3461 | // Loggen des Fehlers bei der Quellenbearbeitung
3462 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_edit_userError, t.editUserError.replace('${error}', editUserError), 'error');
3463 | // Fehlerhafte Antwort
3464 | return {
3465 | data: {},
3466 | message: error.response?.data?.message || t.editUserError.replace('${error}', editUserError),
3467 | status: error.response?.status || 'E51-M-5151', // Internal Server Error
3468 | };
3469 | }
3470 | }
3471 | /* 5.2 Delete User ################################################################################*/
3472 | case 'delete_user': {
3473 | const disabledResponse = checkToolEnabled('delete_user');
3474 | if (disabledResponse) return disabledResponse;
3475 | const { token, arguments: args } = message;
3476 |
3477 | const { email } = args;
3478 |
3479 | if (!email) {
3480 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_user, t.emailRequiredForDelete, 'error');
3481 | return { status: 'E52-M-5250', message: t.emailRequiredForDelete };
3482 | }
3483 |
3484 | // Loggen des Beginns der Benutzerlöschung
3485 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_user, t.deleteUserLog.replace('${UserName}', email), 'info');
3486 |
3487 | try {
3488 | const response = await this.axiosInstance.delete(
3489 | '/users',
3490 | {
3491 | data: { email },
3492 | headers: { Authorization: `Bearer ${token}` },
3493 | }
3494 | );
3495 |
3496 | // Loggen der erfolgreichen Benutzerlöschung
3497 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_userSuccess, t.deleteUserSuccess.replace('${data}', JSON.stringify(response.data, null, 2)), 'info');
3498 |
3499 | return {
3500 | content: response.data,
3501 | };
3502 | } catch (error) {
3503 | const deleteUserError = error.message || JSON.stringify(error.response?.data);
3504 | // Loggen des Fehlers bei der Quellenbearbeitung
3505 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_delete_userError, t.deleteUserError.replace('${error}', deleteUserError), 'error');
3506 | // Fehlerhafte Antwort
3507 | return {
3508 | data: {},
3509 | message: error.response?.data?.message || 'Löschen des Users fehlgeschlagen. Bitte versuchen Sie es später erneut.',
3510 | status: error.response?.status || 'E52-M-5251', // Internal Server Error
3511 | };
3512 | }
3513 | }
3514 | /* 5.3 Reactivate User ################################################################################*/
3515 | case 'reactivate_user': {
3516 | const disabledResponse = checkToolEnabled('reactivate_user');
3517 | if (disabledResponse) return disabledResponse;
3518 | const { token, arguments: args } = message;
3519 |
3520 | const { email } = args;
3521 |
3522 | if (!email) {
3523 | if (!isanonymousModeEnabled) {
3524 | logEvent('client', 'swmsg', l.prefix_reactivate_user, t.emailRequiredForReactivate, 'error');
3525 | }
3526 | return { status: 'E53-M-5300', message: t.emailRequiredForReactivate };
3527 | }
3528 |
3529 | // Loggen des Beginns der Benutzerreaktivierung
3530 | if (!isanonymousModeEnabled) {
3531 | logEvent('client', 'swmsg', l.prefix_reactivate_user, t.reactivateUserLog.replace('${UserName}', email), 'info');
3532 | }
3533 |
3534 | try {
3535 | const response = await this.axiosInstance.post(
3536 | '/api/v1/users/reactivate',
3537 | { email },
3538 | {
3539 | headers: {
3540 | Authorization: `Bearer ${token}`,
3541 | Accept: 'application/json'
3542 | }
3543 | }
3544 | );
3545 |
3546 | // Loggen der erfolgreichen Benutzerreaktivierung
3547 | if (!isanonymousModeEnabled) {
3548 | logEvent('client', 'swmsg', l.prefix_reactivate_userSuccess,
3549 | t.reactivateUserSuccess.replace('${data}', JSON.stringify(response.data, null, 2)), 'info');
3550 | }
3551 |
3552 | return {
3553 | content: response.data,
3554 | };
3555 | } catch (error) {
3556 | const reactivateUserError = error.message || JSON.stringify(error.response?.data);
3557 | // Loggen des Fehlers bei der Benutzerreaktivierung
3558 | if (!isanonymousModeEnabled) {
3559 | logEvent('client', 'swmsg', l.prefix_reactivate_userError,
3560 | t.reactivateUserError.replace('${error}', reactivateUserError), 'error');
3561 | }
3562 | // Fehlerhafte Antwort
3563 | return {
3564 | data: {},
3565 | message: error.response?.data?.message || 'Reaktivierung des Benutzers fehlgeschlagen. Bitte versuchen Sie es später erneut.',
3566 | status: error.response?.status || 'E53-M-5301', // Internal Server Error
3567 | };
3568 | }
3569 | }
3570 | /* 6.0 Open AI compatible API Chat #######################################################################################*/
3571 | case 'oai_comp_api_chat': {
3572 | const disabledResponse = checkToolEnabled('oai_comp_api');
3573 | if (disabledResponse) return disabledResponse;
3574 |
3575 | const { token, arguments: args } = message;
3576 | if (!isanonymousModeEnabled) logEvent('server', 'swmsg', l.prefix_chat, t.extractedToken.replace('${token}', token), 'info');
3577 |
3578 | // Token prüfen und validieren
3579 | if (!token) {
3580 | if (!isanonymousModeEnabled) logEvent('server', 'swmsg', l.prefix_chatError, t.noTokenError, 'error');
3581 | return { status: 'E60-M-6000', message: t.missingTokenError };
3582 | }
3583 |
3584 | // Argument-Validierung
3585 | if (!args || !args.question) {
3586 | if (!isanonymousModeEnabled) logEvent('server', 'swmsg', l.prefix_chatError, t.missingArgumentsError.replace('${args}', JSON.stringify(args)), 'error');
3587 | return {
3588 | status: 'error',
3589 | message: t.missingArgumentsError.replace('${args}', JSON.stringify(args)),
3590 | };
3591 | }
3592 |
3593 | const { question, usePublic, groups, language } = args;
3594 |
3595 | // Konflikt zwischen `usePublic` und `groups` lösen
3596 | if (usePublic && groups && groups.length > 0) {
3597 | if (!isanonymousModeEnabled) logEvent('system', 'swmsg', l.prefix_chatWarning, t.publicGroupsConflictWarning, 'warn');
3598 | args.usePublic = false;
3599 | }
3600 |
3601 | try {
3602 | // Loggen der Chat-Anfrage
3603 | if (!isanonymousModeEnabled) logEvent('server', 'oamsg', l.prefix_chatRequest, t.sendingChatRequest
3604 | .replace('${question}', question)
3605 | .replace('${usePublic}', usePublic)
3606 | .replace('${groups}', JSON.stringify(groups))
3607 | .replace('${language}', language), 'info');
3608 |
3609 | const response = await this.axiosInstance.post(
3610 | '/chats',
3611 | {
3612 | question,
3613 | usePublic: usePublic || false,
3614 | groups: Array.isArray(groups) ? groups : [groups],
3615 | language: language || 'de',
3616 | },
3617 | { headers: { Authorization: `Bearer ${token}` } }
3618 | );
3619 |
3620 | const data = response.data?.data || {};
3621 | // Loggen der erfolgreichen Chat-Antwort
3622 | if (!isanonymousModeEnabled) logEvent('server', 'swmsg', l.prefix_chatSuccess, t.chatResponseSuccess.replace('${data}', JSON.stringify(data)), 'info');
3623 |
3624 | // Erfolgsantwort mit Status und Daten
3625 | return {
3626 | status: response.data?.status || 'ok',
3627 | message: response.data?.message || 'Chat erfolgreich.',
3628 | content: {
3629 | chatId: data.chatId,
3630 | answer: data.answer,
3631 | sources: data.sources || [],
3632 | },
3633 | };
3634 | } catch (error) {
3635 | const chatApiErrorMessage = error.message || error.response?.data;
3636 | // Loggen des Fehlers bei der Chat-API-Anfrage
3637 | if (!isanonymousModeEnabled) logEvent('server', 'swmsg', l.prefix_chatApiError, t.chatApiError.replace('${error}', chatApiErrorMessage), 'error');
3638 |
3639 | // Fehlerantwort mit Status und Nachricht
3640 | return {
3641 | status: error.response?.status || 'E60-M-6002',
3642 | message: error.response?.data?.message || t.chatApiErrorDefault,
3643 | };
3644 | }
3645 | }
3646 | /* 6.1 Open AI compatible API Continue Chat ##############################################################################*/
3647 | case 'oai_comp_api_continue_chat': {
3648 | const disabledResponse = checkToolEnabled('oai_comp_api');
3649 | if (disabledResponse) return disabledResponse;
3650 |
3651 | const token = message.token; // Token direkt extrahieren
3652 | const args = message.arguments || {}; // Sichere Extraktion der Argumente
3653 | const { chatId, question } = args;
3654 |
3655 | if (!args || !args.chatId || !args.question) {
3656 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_continue_chat, t.missingChatParams, 'error');
3657 | return { status: 'E61-M-6150', message: t.missingChatParams };
3658 | }
3659 |
3660 | try {
3661 | const continueChatResponse = await this.axiosInstance.patch(
3662 | `/chats/${chatId}`,
3663 | { question },
3664 | { headers: { Authorization: `Bearer ${token}` } }
3665 | );
3666 |
3667 | // Loggen der erfolgreichen Continue-Chat-Antwort
3668 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_continue_chatSuccess, t.conversationSuccess.replace('${data}', JSON.stringify(continueChatResponse.data, null, 2)), 'info');
3669 |
3670 | return {
3671 | content: {
3672 | chatId: continueChatResponse.data.data.chatId,
3673 | answer: continueChatResponse.data.data.answer,
3674 | sources: continueChatResponse.data.sources || [],
3675 | message: continueChatResponse.data.message,
3676 | status: continueChatResponse.data.status,
3677 | },
3678 | };
3679 | } catch (error) {
3680 | // Loggen des Fehlers bei der Continue-Chat-API-Anfrage
3681 | if (!isanonymousModeEnabled) logEvent('client', 'oamsg', l.prefix_apiRequestError, t.apiRequestError.replace('${error}', error.message), 'error');
3682 | return {
3683 | status: 'E61-M-6151',
3684 | message: error.response?.data?.message || error.message || t.noErrorMessage,
3685 | };
3686 | }
3687 | }
3688 | /* 9.0 Generate Key ###############################################################################*/
3689 | case 'keygen': {
3690 | const disabledResponse = checkToolEnabled('keygen');
3691 | if (disabledResponse) return disabledResponse;
3692 |
3693 | const { password } = message.arguments;
3694 |
3695 | try {
3696 | // Passwort verschlüsseln
3697 | const encryptedPassword = getEncryptedKey(password);
3698 |
3699 | // Loggen der erfolgreichen Key-Generierung
3700 | if (!isanonymousModeEnabled) logEvent('client', 'swmsg', l.prefix_keygen, t.keygenSuccess, 'info');
3701 |
3702 | // Schlüssel zurückgeben
3703 | return {
3704 | data: {
3705 | key: encryptedPassword
3706 | },
3707 | status: 'ok',
3708 | message: t.KeygenRequired,
3709 | };
3710 | } catch (error) {
3711 | // Loggen des Fehlers bei der Key-Generierung
3712 | if (!isanonymousModeEnabled) logEvent(
3713 | 'client', 'message', l.prefix_keygenError,
3714 | t.keygenErrorPrefix + ' ' + error.message,
3715 | 'error'
3716 | );
3717 | return {
3718 | data: {},
3719 | message: error.message || 'Keygen fehlgeschlagen.',
3720 | status: 'E90-M-1150',
3721 | };
3722 | }
3723 | }
3724 | default: {
3725 | // Loggen unbekannter Befehle
3726 | if (!isanonymousModeEnabled) logEvent(
3727 | 'system', 'message', l.prefix_unknownCommand,
3728 | t.unknownCommandError.replace('${cmd}', message.command),
3729 | 'warn'
3730 | )
3731 | return { status: 'E99-M-9950', message: t.unknownCommandError.replace('${cmd}', message.command) };
3732 | }
3733 | }
3734 | } catch (err) {
3735 | // Loggen des Fehlers im Haupt-Handler
3736 | console.log('Error object:', err);
3737 | console.log('Error message:', err?.message);
3738 | if (!isanonymousModeEnabled) logEvent('system', 'message', l.prefix_tcpServerError, `${t.tcpServerError} ${err.message || JSON.stringify(err, null, 2)}`, 'error');
3739 | return { status: 'E52-M-5252', message: err.message || t.internalServerError };
3740 | }
3741 | });
3742 | }
3743 | }
3744 | const server = new PrivateGPTServer();
3745 |
3746 | // Log-Viewer Webserver konfigurieren
3747 | const app = express();
3748 | const httpServer = createHttpServer(app);
3749 | const io = new SocketIoServer(httpServer);
3750 |
3751 |
3752 | // const LOG_FILE_PATH = path.join(__dirname, '../logs/server.log'); // Pfad zu Ihrer Logdatei
3753 |
3754 | // Statische Dateien bereitstellen (optional, falls eine HTML-Oberfläche benötigt wird)
3755 | app.use(express.static(path.join(__dirname, 'public')));
3756 | io.on('connection', (socket) => {
3757 | if (isWrittenLogfileEnabled) {
3758 | logEvent(
3759 | 'server',
3760 | 'websocket',
3761 | l.prefix_clientConnected,
3762 | messages[lang].clientConnected,
3763 | 'info'
3764 | );
3765 | sendLogContent(socket);
3766 | } else {
3767 | // Optional: Informieren Sie den Client, dass das Logfile nicht aktiviert ist
3768 | socket.emit('logUpdate', messages[lang].socketEmitLogNotActivated);
3769 | }
3770 |
3771 | socket.on('disconnect', () => {
3772 | if (isWrittenLogfileEnabled) {
3773 | logEvent(
3774 | 'server',
3775 | 'websocket',
3776 | l.prefix_clientDisconnected,
3777 | messages[lang].clientDisconnected,
3778 | 'info'
3779 | );
3780 | }
3781 | });
3782 | });
3783 |
3784 | // Funktion, um den Loginhalt an einen Client zu senden
3785 | const sendLogContent = async (socket) => {
3786 | try {
3787 | // Überprüfen, ob die Log-Datei existiert
3788 | await fs.promises.access(LOG_FILE_PATH, fs.constants.F_OK);
3789 | let data = await fs.promises.readFile(LOG_FILE_PATH, 'utf8');
3790 | data = stripAnsi(data); // nutzt jetzt den Import
3791 | socket.emit('logUpdate', data);
3792 | } catch (err) {
3793 | if (!isanonymousModeEnabled) logEvent(
3794 | 'server',
3795 | 'filesystem',
3796 | l.prefix_logReadError,
3797 | messages[lang].logReadError.replace('${error}', err.message),
3798 | 'error'
3799 | );
3800 | socket.emit('logUpdate', messages[lang].socketEmitLogReadError);
3801 | }
3802 | };
3803 |
3804 | // Überwachung der Logdatei auf Änderungen, nur wenn Schreiben aktiviert ist
3805 | if (isWrittenLogfileEnabled) {
3806 | chokidar.watch(LOG_FILE_PATH).on('change', async () => {
3807 | try {
3808 | const data = await fs.promises.readFile(LOG_FILE_PATH, 'utf8');
3809 | io.sockets.emit('logUpdate', data);
3810 | } catch (err) {
3811 | if (!isanonymousModeEnabled) logEvent(
3812 | 'server',
3813 | 'filesystem',
3814 | l.prefix_logChangeError,
3815 | messages[lang].logChangeError.replace('${error}', err.message),
3816 | 'error'
3817 | );
3818 | }
3819 | });
3820 | }
3821 |
3822 | // Überwachung der Logdatei auf Änderungen
3823 | /*chokidar.watch(LOG_FILE_PATH).on('change', async () => {
3824 | try {
3825 | const data = await fs.promises.readFile(LOG_FILE_PATH, 'utf8');
3826 | io.sockets.emit('logUpdate', data);
3827 | } catch (err) {
3828 | if (!isanonymousModeEnabled) logEvent(
3829 | 'server',
3830 | 'filesystem',
3831 | l.prefix_logChangeError,
3832 | messages[lang].logChangeError.replace('${error}', err.message),
3833 | 'error'
3834 | );
3835 | }
3836 | });*/
3837 |
3838 | // Log-Viewer HTTP-Server starten
3839 | const WEB_PORT = 3000;
3840 | httpServer.listen(WEB_PORT, () => {
3841 | if (!isanonymousModeEnabled) logEvent(
3842 | 'server',
3843 | 'web',
3844 | l.prefix_logViewerRunning,
3845 | messages[lang].logViewerRunning.replace('${port}', WEB_PORT),
3846 | 'info'
3847 | );
3848 | });
3849 |
3850 | // Server läuft
3851 | server.run().catch(error => {
3852 | if (!isanonymousModeEnabled) logEvent(
3853 | 'server',
3854 | 'N/A',
3855 | l.prefix_serverError,
3856 | messages[lang].serverError.replace('${error}', error.message),
3857 | 'error'
3858 | );
3859 | });
3860 |
3861 | // Anzeige des Start-Headers
3862 | displayStartHeader();
```