This is page 18 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
--------------------------------------------------------------------------------
/ver/index_np.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 { CallToolRequestSchema, ErrorCode, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, McpError, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
5 | import axios from 'axios';
6 | import https from 'https';
7 | import dotenv from 'dotenv';
8 | import net from 'net';
9 | import { fileURLToPath } from 'url';
10 | import path from 'path';
11 | import fs from 'fs';
12 | import crypto from 'crypto';
13 |
14 |
15 | dotenv.config({ path: './pgpt.env' }); // Geben Sie explizit den Pfad zur Datei an
16 |
17 | const templates = {
18 | success: '✔️ ${action}: ${details}',
19 | error: '❌ ${action} Fehler: ${details}',
20 | warning: '⚠️ ${action}: ${details}',
21 | configStart: '🚀 ${action}: ${details}',
22 | info: '📤 ${action}...',
23 | };
24 |
25 | const messages = {
26 | de: {
27 | apiErrorDetails: templates.error.replace('${action}', 'API-Fehler').replace('${details}', 'Status: ${status}, Daten: ${data}'),
28 | apiUrlInvalid: templates.error.replace('${action}', 'Ungültige API_URL').replace('${details}', ''),
29 | apiUrlValidated: templates.success.replace('${action}', 'API_URL erfolgreich validiert').replace('${details}', '${url}'),
30 | apiUrlWarning: templates.warning.replace('${action}', 'Warnung').replace('${details}', 'API_URL beginnt nicht mit "https://". Die URL wird angepasst.'),
31 | apiUrlWarningV1: templates.warning.replace('${action}', 'Warnung').replace('${details}', 'API_URL endet nicht mit "/api/v1". Die URL wird angepasst.'),
32 | availableGroups: templates.success.replace('${action}', 'Verfügbare Gruppen').replace('${details}', '${data}'),
33 | errorHandlingRequest: templates.error.replace('${action}', 'Fehler bei der Verarbeitung der Anfrage').replace('${details}', '${error}'),
34 | fetchingSources: templates.info.replace('${action}', 'Abrufen von Quellen für Gruppe: ${groupName}'),
35 | groupFetchError: templates.error.replace('${action}', 'Fehler beim Abrufen der Gruppen').replace('${details}', 'Bitte versuchen Sie es später erneut.'),
36 | groupNameRequired: 'Gruppenname erforderlich für diese Anfrage.',
37 | gotGetSourceResponse: templates.success.replace('${action}', 'Antwort auf get_source erhalten').replace('${details}', '${data}'),
38 | gotListGroupsResponse: templates.success.replace('${action}', 'Antwort auf list_groups erhalten').replace('${details}', '${response}'),
39 | gotListSourcesResponse: templates.success.replace('${action}', 'Antwort auf list_sources erhalten').replace('${details}', '${data}'),
40 | handlingToolRequest: templates.info.replace('${action}', 'Verarbeite Tool-Anfrage: ${name}'),
41 | headers: 'Header: ${headers}',
42 | incomingMessage: '📥 Eingehende Nachricht:',
43 | internalServerError: 'Interner Serverfehler',
44 | invalidGroups: templates.error.replace('${action}', 'Ungültige Gruppen').replace('${details}', '${groups}'),
45 | loginResponse: templates.success.replace('${action}', 'Login-Antwort').replace('${details}', ''),
46 | makingGetSourceRequest: templates.info.replace('${action}', 'Erstellen einer get_source-Anfrage').replace('${details}', '${args}'),
47 | makingListGroupsRequest: templates.info.replace('${action}', 'Erstellen einer list_groups-Anfrage'),
48 | makingListSourcesRequest: templates.info.replace('${action}', 'Erstellen einer list_sources-Anfrage').replace('${details}', '${args}'),
49 | mcpError: templates.error.replace('${action}', '[MCP Fehler]').replace('${details}', '${error}'),
50 | method: 'Methode: ${method}',
51 | payload: 'Daten: ${payload}',
52 | portInUse: templates.error.replace('${action}', 'Port Fehler').replace('${details}', 'Port ${PORT} ist bereits in Verwendung.'),
53 | portInvalid: templates.error.replace('${action}', 'Port Fehler').replace('${details}', 'PORT muss eine Zahl zwischen 1 und 65535 sein.'),
54 | portValidated: templates.success.replace('${action}', 'PORT erfolgreich validiert').replace('${details}', '${port}'),
55 | requestError: templates.error.replace('${action}', 'Anfragefehler').replace('${details}', '${error}'),
56 | requestSent: templates.info.replace('${action}', 'Anfrage gesendet'),
57 | responseError: templates.error.replace('${action}', 'Fehler bei der Antwort').replace('${details}', '${error}'),
58 | responseReceived: templates.success.replace('${action}', 'Antwort erhalten').replace('${details}', '${response}'),
59 | serverError: templates.error.replace('${action}', 'Server-Fehler').replace('${details}', '${error}'),
60 | sendingChatRequest: templates.info.replace('${action}', 'Senden einer Chat-Anfrage an die API'),
61 | sourcesRetrieved: templates.success.replace('${action}', 'Quellen erhalten').replace('${details}', '${data}'),
62 | tcpServerError: templates.error.replace('${action}', 'TCP Server Fehler').replace('${details}', '${error}'),
63 | restrictedGroupsError: templates.error.replace('${action}', 'Ungültige RESTRICTED_GROUPS-Konfiguration').replace('${details}', "muss 'true' oder 'false' sein. Aktueller Wert: ${value}"),
64 | restrictedGroupsSuccess: templates.success.replace('${action}', 'RESTRICTED_GROUPS').replace('${details}', 'ist aktiviert: ${status}'),
65 | toolDisabledError: templates.error.replace('${action}', 'Tool deaktiviert').replace('${details}', 'Die Funktion "${toolName}" ist auf dem Server deaktiviert.'),
66 | sslValidationSet: '${symbol} SSL-Validierung ist eingestellt auf: ${value}',
67 | startingServerWithConfig: templates.configStart.replace('${action}', 'Starten des Servers').replace('${details}', 'mit folgender Konfiguration:\n${config}'),
68 | serverRunning: templates.info.replace('${action}', 'Server läuft').replace('${details}', 'auf Port ${port}'),
69 | connection: {
70 | new: '📥 Neue Verbindung akzeptiert von ${ip}:${port}',
71 | established: '🚀 Verbindung hergestellt',
72 | closed: '🔌 Verbindung geschlossen: ${ip}:${port}',
73 | dataReceived: '📥 Empfangene Daten von ${ip}:${port}: ${data}',
74 | },
75 | errors: {
76 | processMessage: '❌ Fehler bei der Verarbeitung der Nachricht: ${error}',
77 | invalidMessage: 'Ungültiges Nachrichtenformat',
78 | socketError: '❌ Socket-Fehler bei ${ip}:${port}: ${error}',
79 | serverError: '❌ Server-Fehler: ${error}',
80 | },
81 | server: {
82 | running: '📡 Server läuft auf Port ${port}',
83 | stopped: '🛑 Server wurde gestopped',
84 | },
85 | loginSuccess: '✔️ Login erfolgreich: ${data}',
86 | invalidArgumentsError: '❌ Fehler: Keine gültigen Argumente in der Eingabe gefunden: ${input}',
87 | missingArgumentsError: '❌ Fehlende Argumente: ${args}',
88 | noTokenError: '❌ Kein Token bereitgestellt.',
89 | publicGroupsConflictWarning: '⚠️ Konflikt: usePublic wurde auf false gesetzt, da Gruppen angegeben sind.',
90 | sendingChatRequest: '📤 Sende Chat-Anfrage: Frage: "${question}", Öffentlich: ${usePublic}, Gruppen: ${groups}, Sprache: ${language}',
91 | checkingGroups: '📤 Überprüfen der Gruppen: ${groups}',
92 | invalidGroupsError: '❌ Ungültige Gruppen gefunden: ${invalidGroups}',
93 | availableGroups: '✔️ Verfügbare Gruppen: ${availableGroups}',
94 | groupValidationError: '❌ Fehler bei der Gruppenvalidierung: ${error}',
95 | loginError: '❌ Fehler beim Login: ${error}',
96 | logoutSuccess: '✔️ Logout erfolgreich: ${data}',
97 | logoutError: '❌ Fehler beim Logout: ${error}',
98 | chatResponseSuccess: '✔️ Chat-Antwort erfolgreich erhalten: ${data}',
99 | chatApiError: '❌ Fehler bei der Chat-API-Anfrage: ${error}',
100 | conversationContinuation: '✔️ Fortsetzung der Konversation mit ID: ${chatId}',
101 | conversationSuccess: '✔️ Konversation erfolgreich fortgesetzt: ${data}',
102 | apiRequestError: '❌ Fehler bei der API-Anfrage: ${error}',
103 | noChatData: 'Keine Daten für den angegebenen Chat gefunden.',
104 | fetchChatInfoError: '❌ Fehler beim Abrufen der Chat-Informationen: ${error}',
105 | missingTokenError: 'Token fehlt. Bitte einloggen und erneut versuchen.',
106 | missingParametersError: 'Fehlende erforderliche Parameter: ${parameters}.',
107 | invalidGroupsError: 'Ungültige Gruppen: ${invalidGroups}',
108 | createSourceSuccess: '✔️ Quelle erfolgreich erstellt: ${data}',
109 | createSourceError: '❌ Fehler beim Erstellen der Quelle: ${error}',
110 | noServerResponse: 'Keine Antwort vom Server erhalten.',
111 | missingParameterError: 'Fehlender erforderlicher Parameter: ${parameter}.',
112 | editSourceSuccess: '✔️ Quelle erfolgreich bearbeitet: ${data}',
113 | editSourceError: '❌ Fehler beim Bearbeiten der Quelle: ${error}',
114 | deleteSourceError: '❌ Fehler beim Löschen der Quelle: ${error}',
115 | storeGroupLog: 'Speichere neue Gruppe mit Name: ${groupName} und Beschreibung: ${description}',
116 | storeGroupSuccess: 'Gruppe erfolgreich gespeichert: ${data}',
117 | storeGroupText: 'Gruppe "${groupName}" erfolgreich gespeichert mit ID: ${id}',
118 | deleteGroupLog: 'Lösche Gruppe mit Name: ${groupName}',
119 | deleteGroupSuccessLog: 'Gruppe erfolgreich gelöscht: ${data}',
120 | deleteGroupText: 'Gruppe "${groupName}" wurde erfolgreich gelöscht.',
121 | apiRequestError: 'Fehler bei der API-Anfrage: ${error}',
122 | createUserError: '❌ Fehler beim Erstellen des Benutzers: ${error}',
123 | editUserError: '❌ Fehler beim Bearbeiten des Benutzers: ${error}',
124 | deleteUserError: '❌ Fehler beim Löschen des Benutzers: ${error}',
125 | deleteUserSuccess: '✔️ Benutzer erfolgreich gelöscht: ${data}',
126 | editUserSuccess: '✔️ Benutzer erfolgreich bearbeitet: ${data}',
127 | createUserSuccess: '✔️ Benutzer erfolgreich erstellt: ${data}',
128 | createUserLog: '📤 Erstellen eines neuen Benutzers: ${payload}',
129 | createGroupSuccess: '✔️ Gruppe erfolgreich erstellt: ${data}',
130 | fetchGroupsError: '❌ Fehler beim Abrufen der Gruppen: ${error}',
131 | apiRequestError: '❌ Fehler bei der API-Anfrage: ${error}',
132 | restrictedGroupsWarning: '⚠️ RESTRICTED_GROUPS aktiviert. Verfügbare Gruppen werden eingeschränkt.',
133 | editSourceLog: 'Bearbeite Quelle mit ID: ${sourceId}, Titel: ${title}',
134 | },
135 | en: {
136 | editSourceLog: 'Editing source with ID: ${sourceId}, Title: ${title}',
137 | fetchGroupsError: '❌ Error fetching groups: ${error}',
138 | apiRequestError: '❌ Error during API request: ${error}',
139 | restrictedGroupsWarning: '⚠️ RESTRICTED_GROUPS enabled. Available groups are restricted.',
140 | deleteUserSuccess: '✔️ User successfully deleted: ${data}',
141 | editUserSuccess: '✔️ User successfully edited: ${data}',
142 | createUserSuccess: '✔️ User successfully created: ${data}',
143 | createUserLog: '📤 Creating a new user: ${payload}',
144 | createGroupSuccess: '✔️ Group successfully created: ${data}',
145 | deleteSourceError: '❌ Error deleting source: ${error}',
146 | storeGroupLog: 'Storing new group with name: ${groupName} and description: ${description}',
147 | storeGroupSuccess: 'Group stored successfully: ${data}',
148 | storeGroupText: 'Group "${groupName}" successfully stored with ID: ${id}',
149 | deleteGroupLog: 'Deleting group with name: ${groupName}',
150 | deleteGroupSuccessLog: 'Group successfully deleted: ${data}',
151 | deleteGroupText: 'Group "${groupName}" was successfully deleted.',
152 | apiRequestError: 'Error during API request: ${error}',
153 | createUserError: '❌ Error creating user: ${error}',
154 | editUserError: '❌ Error editing user: ${error}',
155 | deleteUserError: '❌ Error deleting user: ${error}',
156 | missingTokenError: 'Token is missing. Please log in and try again.',
157 | missingParametersError: 'Missing required parameters: ${parameters}.',
158 | invalidGroupsError: 'Invalid groups: ${invalidGroups}',
159 | createSourceSuccess: '✔️ Source successfully created: ${data}',
160 | createSourceError: '❌ Error creating the source: ${error}',
161 | noServerResponse: 'No response received from the server.',
162 | missingParameterError: 'Missing required parameter: ${parameter}.',
163 | editSourceSuccess: '✔️ Source successfully edited: ${data}',
164 | editSourceError: '❌ Error editing the source: ${error}',
165 | loginError: '❌ Error during login: ${error}',
166 | logoutSuccess: '✔️ Logout successful: ${data}',
167 | logoutError: '❌ Error during logout: ${error}',
168 | chatResponseSuccess: '✔️ Chat response successfully received: ${data}',
169 | chatApiError: '❌ Error during chat API request: ${error}',
170 | conversationContinuation: '✔️ Continuing conversation with ID: ${chatId}',
171 | conversationSuccess: '✔️ Conversation successfully continued: ${data}',
172 | apiRequestError: '❌ Error during API request: ${error}',
173 | noChatData: 'No data found for the specified chat.',
174 | fetchChatInfoError: '❌ Error fetching chat information: ${error}',
175 | checkingGroups: '📤 Checking groups: ${groups}',
176 | invalidGroupsError: '❌ Invalid groups found: ${invalidGroups}',
177 | availableGroups: '✔️ Available groups: ${availableGroups}',
178 | groupValidationError: '❌ Error during group validation: ${error}',
179 | missingArgumentsError: '❌ Missing arguments: ${args}',
180 | invalidArgumentsError: '❌ Error: No valid arguments found in the input: ${input}',
181 | loginSuccess: '✔️ Login successful: ${data}',
182 | sslValidationSet: '${symbol} SSL validation is set to: ${value}',
183 | serverRunning: templates.info.replace('${action}', 'Server is running').replace('${details}', 'on port ${port}'),
184 | toolDisabledError: templates.error.replace('${action}', 'Tool disabled').replace('${details}', 'The feature "${toolName}" is disabled on the server.'),
185 | restrictedGroupsError: templates.error.replace('${action}', 'Invalid RESTRICTED_GROUPS configuration').replace('${details}', "must be 'true' or 'false'. Current value: ${value}"),
186 | restrictedGroupsSuccess: templates.success.replace('${action}', 'RESTRICTED_GROUPS').replace('${details}', 'is enabled: ${status}'),
187 | apiErrorDetails: templates.error.replace('${action}', 'API Error').replace('${details}', 'Status: ${status}, Data: ${data}'),
188 | apiUrlInvalid: templates.error.replace('${action}', 'Invalid API_URL').replace('${details}', ''),
189 | apiUrlValidated: templates.success.replace('${action}', 'API_URL successfully validated').replace('${details}', '${url}'),
190 | apiUrlWarning: templates.warning.replace('${action}', 'Warning').replace('${details}', 'API_URL does not start with "https://". The URL will be adjusted.'),
191 | apiUrlWarningV1: templates.warning.replace('${action}', 'Warning').replace('${details}', 'API_URL does not end with "/api/v1". The URL will be adjusted.'),
192 | availableGroups: templates.success.replace('${action}', 'Available groups').replace('${details}', '${data}'),
193 | errorHandlingRequest: templates.error.replace('${action}', 'Error handling request').replace('${details}', '${error}'),
194 | fetchingSources: templates.info.replace('${action}', 'Fetching sources for group: ${groupName}'),
195 | groupFetchError: templates.error.replace('${action}', 'Error fetching groups').replace('${details}', 'Please try again later.'),
196 | groupNameRequired: 'Group name is required for this request.',
197 | gotGetSourceResponse: templates.success.replace('${action}', 'Got get_source response').replace('${details}', '${data}'),
198 | gotListGroupsResponse: templates.success.replace('${action}', 'Got list_groups response').replace('${details}', '${response}'),
199 | gotListSourcesResponse: templates.success.replace('${action}', 'Got list_sources response').replace('${details}', '${data}'),
200 | handlingToolRequest: templates.info.replace('${action}', 'Handling tool request: ${name}'),
201 | headers: 'Headers: ${headers}',
202 | incomingMessage: '📥 Incoming message:',
203 | internalServerError: 'Internal server error',
204 | invalidGroups: templates.error.replace('${action}', 'Invalid groups').replace('${details}', '${groups}'),
205 | loginResponse: templates.success.replace('${action}', 'Login response').replace('${details}', ''),
206 | makingGetSourceRequest: templates.info.replace('${action}', 'Making get_source request').replace('${details}', '${args}'),
207 | makingListGroupsRequest: templates.info.replace('${action}', 'Making list_groups request'),
208 | makingListSourcesRequest: templates.info.replace('${action}', 'Making list_sources request').replace('${details}', '${args}'),
209 | mcpError: templates.error.replace('${action}', '[MCP Error]').replace('${details}', '${error}'),
210 | method: 'Method: ${method}',
211 | payload: 'Payload: ${payload}',
212 | portInUse: templates.error.replace('${action}', 'Port Error').replace('${details}', 'Port ${PORT} is already in use.'),
213 | portInvalid: templates.error.replace('${action}', 'Port Error').replace('${details}', 'PORT must be a number between 1 and 65535.'),
214 | portValidated: templates.success.replace('${action}', 'PORT successfully validated').replace('${details}', '${port}'),
215 | requestError: templates.error.replace('${action}', 'Request Error').replace('${details}', '${error}'),
216 | requestSent: templates.info.replace('${action}', 'Request sent'),
217 | responseError: templates.error.replace('${action}', 'Response error').replace('${details}', '${error}'),
218 | responseReceived: templates.success.replace('${action}', 'Response received').replace('${details}', '${response}'),
219 | serverError: templates.error.replace('${action}', 'Server Error').replace('${details}', '${error}'),
220 | sendingChatRequest: templates.info.replace('${action}', 'Sending a chat request to the API'),
221 | sourcesRetrieved: templates.success.replace('${action}', 'Sources retrieved').replace('${details}', '${data}'),
222 | startingServerWithConfig: templates.warning.replace('${action}', 'Starting the server').replace('${details}', 'with the following configuration:'),
223 | tcpServerError: templates.error.replace('${action}', 'TCP Server Error').replace('${details}', '${error}'),
224 | connection: {
225 | new: '📥 New connection accepted from ${ip}:${port}',
226 | established: '🚀 Connection established',
227 | closed: '🔌 Connection closed: ${ip}:${port}',
228 | dataReceived: '📥 Received data from ${ip}:${port}: ${data}',
229 | },
230 | errors: {
231 | processMessage: '❌ Error while processing the message: ${error}',
232 | invalidMessage: 'Invalid message format',
233 | socketError: '❌ Socket error for ${ip}:${port}: ${error}',
234 | serverError: '❌ Server error: ${error}',
235 | },
236 | server: {
237 | running: '📡 Server runs on port ${port}',
238 | stopped: '🛑 Server stopped',
239 | },
240 | }
241 | };
242 |
243 | // JSON-Datei laden
244 | // `__dirname`-Ersatz für ES-Module
245 | const __filename = fileURLToPath(import.meta.url);
246 | const __dirname = path.dirname(__filename);
247 |
248 | // JSON-Dateipfad relativ zum Skript
249 | const envFilePath = path.resolve(__dirname, '../pgpt.env.json');
250 | let envConfig;
251 |
252 | try {
253 | envConfig = JSON.parse(fs.readFileSync(envFilePath, 'utf-8'));
254 | } catch (error) {
255 | console.error(`❌ Error loading pgpt.env.json: ${error.message}`);
256 | process.exit(1);
257 | }
258 |
259 | // Helper-Funktionen
260 | function getEnvVar(key, nestedPath = null, fallback = null) {
261 | // Prüfen, ob ein verschachtelter Pfad angegeben ist
262 | if (nestedPath) {
263 | const value = nestedPath.reduce((acc, part) => acc && acc[part], envConfig);
264 | if (!value) {
265 | if (fallback !== null) return fallback;
266 | console.error(`❌ Missing .json configuration variable: ${key}`);
267 | process.exit(1);
268 | }
269 | return value;
270 | }
271 | // Direkter Zugriff
272 | if (!envConfig[key]) {
273 | if (fallback !== null) return fallback;
274 | console.error(`❌ Missing .json configuration variable: ${key}`);
275 | process.exit(1);
276 | }
277 | return envConfig[key];
278 | }
279 |
280 | const privateApiUrl = getEnvVar('PRIVATE_GPT_API_URL', ['PGPT_Url', 'PRIVATE_GPT_API_URL']);
281 | const requestedLang = getEnvVar('LANGUAGE', ['Server_Config', 'LANGUAGE'], 'en').toLowerCase();
282 | const apiUrl = getEnvVar('API_URL', ['PGPT_Url', 'API_URL']);
283 | const Port = getEnvVar('PORT', ['Server_Config', 'PORT'], '5000');
284 | const restrictedGroups = getEnvVar('RESTRICTED_GROUPS', ['Restrictions', 'RESTRICTED_GROUPS'], 'false').toString();
285 | const sslValidate = getEnvVar('SSL_VALIDATE', ['Server_Config', 'SSL_VALIDATE'], 'false').toString();
286 | const PwEncryption = getEnvVar('PW_ENCRYPTION', ['Server_Config', 'PW_ENCRYPTION'], 'false') === 'true';
287 | const AllowKeygen = getEnvVar('ALLOW_KEYGEN', ['Server_Config', 'ALLOW_KEYGEN'], 'false') === 'true';
288 | const publicKeyPath = getEnvVar('PUBLIC_KEY', ['Server_Config', 'PUBLIC_KEY']);
289 | const privateKeyPath = getEnvVar('PRIVATE_KEY', ['Server_Config', 'PRIVATE_KEY']);
290 |
291 |
292 | // Load the public key
293 | const publicKey = fs.readFileSync(getEnvVar('PUBLIC_KEY', ['Server_Config', 'PUBLIC_KEY']), 'utf8');
294 |
295 | // Load the private key
296 | const privateKey = fs.readFileSync(getEnvVar('PRIVATE_KEY', ['Server_Config', 'PRIVATE_KEY']), 'utf8');
297 |
298 |
299 | if (PwEncryption) {
300 | console.log('Password encryption is enabled.');
301 | } else {
302 | console.log('Password encryption is disabled.');
303 | }
304 |
305 | function validateUrl(url, t) {
306 | if (!url.startsWith('https://')) {
307 | console.warn(t.apiUrlWarning);
308 | url = url.replace(/^http:\/\//, 'https://');
309 | }
310 | url = url.replace(/([^:]\/)\/+/g, '$1'); // Doppelte Schrägstriche nach "://" entfernen
311 | if (!url.endsWith('/api/v1')) {
312 | console.warn(t.apiUrlWarningV1);
313 | url = `${url.replace(/\/$/, '')}/api/v1`;
314 | }
315 | try {
316 | new URL(url);
317 | } catch {
318 | console.error(t.apiUrlInvalid, url);
319 | process.exit(1);
320 | }
321 | return url;
322 | }
323 |
324 | function validatePort(port, t) {
325 | const portNumber = parseInt(port, 10);
326 | if (isNaN(portNumber) || portNumber < 1 || portNumber > 65535) {
327 | console.error(t.portInvalid);
328 | process.exit(1);
329 | }
330 | return portNumber;
331 | }
332 |
333 | function validateBoolean(varName, value, t) {
334 | if (value !== 'true' && value !== 'false') {
335 | console.error(
336 | t.restrictedGroupsError.replace('${value}', value)
337 | );
338 | process.exit(1);
339 | }
340 | return value === 'true';
341 | }
342 |
343 | /**
344 | * Decrypt a cryptographic string using the private key.
345 | * @param {string} encryptedData - The encrypted string in Base64 format.
346 | * @returns {string} - The decrypted password.
347 | */
348 | function decryptPassword(encryptedData) {
349 | try {
350 | const decryptedPassword = crypto.privateDecrypt(
351 | {
352 | key: privateKey,
353 | padding: crypto.constants.RSA_PKCS1_PADDING, // Ensure consistent padding
354 | },
355 | Buffer.from(encryptedData, 'base64')
356 | ).toString('utf8');
357 |
358 | return decryptedPassword;
359 | } catch (error) {
360 | console.error('Decryption error:', error.message);
361 | throw new Error('Failed to decrypt the password.');
362 | }
363 | }
364 |
365 |
366 | // Function for encryption
367 | function encryptWithPublicKey(data) {
368 | return crypto.publicEncrypt(
369 | {
370 | key: publicKey,
371 | padding: crypto.constants.RSA_PKCS1_PADDING, // Explicitly set padding
372 | },
373 | Buffer.from(data)
374 | ).toString('base64');
375 | }
376 |
377 | /**
378 | * Encrypt a given password and return the encrypted key.
379 | * @param {string} password - The password to be encrypted.
380 | * @returns {string} - The encrypted password as a Base64 string.
381 | */
382 | function getEncryptedKey(password) {
383 | try {
384 | return encryptWithPublicKey(password);
385 | } catch (err) {
386 | console.error('Encryption error:', err.message);
387 | throw new Error('Failed to encrypt the password.');
388 | }
389 | }
390 |
391 | const enableLogin = getEnvVar('ENABLE_LOGIN', ['Functions', 'ENABLE_LOGIN'], false);
392 | const enableLogout = getEnvVar('ENABLE_LOGOUT', ['Functions', 'ENABLE_LOGOUT'], false);
393 | const enableChat = getEnvVar('ENABLE_CHAT', ['Functions', 'ENABLE_CHAT'], false);
394 | const enableContinueChat = getEnvVar('ENABLE_CONTINUE_CHAT', ['Functions', 'ENABLE_CONTINUE_CHAT'], false);
395 | const enableGetChatInfo = getEnvVar('ENABLE_GET_CHAT_INFO', ['Functions', 'ENABLE_GET_CHAT_INFO'], false);
396 | const enableListGroups = getEnvVar('ENABLE_LIST_GROUPS', ['Functions', 'ENABLE_LIST_GROUPS'], false);
397 | const enableStoreGroup = getEnvVar('ENABLE_STORE_GROUP', ['Functions', 'ENABLE_STORE_GROUP'], false);
398 | const enableDeleteGroup = getEnvVar('ENABLE_DELETE_GROUP', ['Functions', 'ENABLE_DELETE_GROUP'], false);
399 | const enableCreateSource = getEnvVar('ENABLE_CREATE_SOURCE', ['Functions', 'ENABLE_CREATE_SOURCE'], false);
400 | const enableEditSource = getEnvVar('ENABLE_EDIT_SOURCE', ['Functions', 'ENABLE_EDIT_SOURCE'], false);
401 | const enableDeleteSource = getEnvVar('ENABLE_DELETE_SOURCE', ['Functions', 'ENABLE_DELETE_SOURCE'], false);
402 | const enableGetSource = getEnvVar('ENABLE_GET_SOURCE', ['Functions', 'ENABLE_GET_SOURCE'], false);
403 | const enableListSources = getEnvVar('ENABLE_LIST_SOURCES', ['Functions', 'ENABLE_LIST_SOURCES'], false);
404 | const enableStoreUser = getEnvVar('ENABLE_STORE_USER', ['Functions', 'ENABLE_STORE_USER'], false);
405 | const enableEditUser = getEnvVar('ENABLE_EDIT_USER', ['Functions', 'ENABLE_EDIT_USER'], false);
406 | const enableDeleteUser = getEnvVar('ENABLE_DELETE_USER', ['Functions', 'ENABLE_DELETE_USER'], false);
407 |
408 | console.log('🌐 Server Config:', JSON.stringify(envConfig, null, 2));
409 |
410 | console.log('✅ Private API URL:', privateApiUrl);
411 | console.log('✅ Public API URL:', apiUrl);
412 | console.log('✅ Port:', Port);
413 | console.log('✅ Language:', requestedLang);
414 | console.log('✅ SSL-validation:', sslValidate);
415 | console.log('✅ PW_Encryption:', PwEncryption);
416 | console.log('✅ Allow_Keygen:', AllowKeygen);
417 | console.log('✅ Private_Key:', privateKeyPath);
418 | console.log('✅ Public_Key:', publicKeyPath);
419 | console.log('✅ Restricted Groups:', restrictedGroups);
420 |
421 |
422 | // Alle Funktionen mit ihren Enable-Flags in einem Array organisieren
423 | const allFunctions = [
424 | { name: 'Login', enabled: enableLogin },
425 | { name: 'Logout', enabled: enableLogout },
426 | { name: 'Chat', enabled: enableChat },
427 | { name: 'Continue Chat', enabled: enableContinueChat },
428 | { name: 'Get Chat Info', enabled: enableGetChatInfo },
429 | { name: 'List Groups', enabled: enableListGroups },
430 | { name: 'Store Group', enabled: enableStoreGroup },
431 | { name: 'Delete Group', enabled: enableDeleteGroup },
432 | { name: 'Create Source', enabled: enableCreateSource },
433 | { name: 'Edit Source', enabled: enableEditSource },
434 | { name: 'Delete Source', enabled: enableDeleteSource },
435 | { name: 'Get Source', enabled: enableGetSource },
436 | { name: 'List Sources', enabled: enableListSources },
437 | { name: 'Store User', enabled: enableStoreUser },
438 | { name: 'Edit User', enabled: enableEditUser },
439 | { name: 'Delete User', enabled: enableDeleteUser }
440 | ];
441 |
442 | // Filtern, um nur deaktivierte (false) zu bekommen
443 | const disabledFunctions = allFunctions.filter(f => !f.enabled);
444 |
445 | // Wenn gar keine Funktionen deaktiviert sind, kurze Info ausgeben
446 | if (disabledFunctions.length === 0) {
447 | console.log('✅ All functions are enabled.');
448 | } else {
449 | console.log('⚠️ Deactivated functions:');
450 | disabledFunctions.forEach(func => {
451 | console.log(` ➡️ ${func.name}: false`);
452 | });
453 | }
454 |
455 | // Nachrichten basierend auf Sprache
456 | let lang = getEnvVar('LANGUAGE', ['Server_Config', 'LANGUAGE'], 'en').toLowerCase();
457 | if (!(lang in messages)) {
458 | console.warn(`⚠️ Language "${lang}" is not supported. Fallback in English.`);
459 | lang = 'en';
460 | }
461 |
462 | const t = messages[lang];
463 | console.log(t.apiUrlValidated.replace('${url}', apiUrl));
464 |
465 | // Port validieren
466 | console.log(t.portValidated.replace('${port}', Port));
467 |
468 | // Debugging für RESTRICTED_GROUPS
469 | console.log('🛠️ Access to RESTRICTED_GROUPS:', envConfig.Restrictions?.RESTRICTED_GROUPS);
470 |
471 | // Zugriff und Validierung von RESTRICTED_GROUPS
472 | const isRestrictedGroupsEnabled = validateBoolean(
473 | 'RESTRICTED_GROUPS',
474 | restrictedGroups,
475 | t
476 | );
477 |
478 | console.log(
479 | t.restrictedGroupsSuccess.replace('${status}', isRestrictedGroupsEnabled)
480 | );
481 |
482 |
483 | // SSL-Validierung
484 | const isSSLValidationEnabled = validateBoolean(
485 | 'SSL_VALIDATE',
486 | getEnvVar('SSL_VALIDATE', ['Server_Config', 'SSL_VALIDATE'], 'false').toString(),
487 | t
488 | );
489 |
490 | const sslSymbol = isSSLValidationEnabled ? '✔️' : '⚠️';
491 | console.log(
492 | t.sslValidationSet
493 | .replace('${symbol}', sslSymbol)
494 | .replace('${value}', String(isSSLValidationEnabled))
495 | );
496 | // console.log('sslValidationSet String ist:', t.sslValidationSet);
497 |
498 | const validatedPort = validatePort(Port, t);
499 | console.log(t.portValidated.replace('${port}', validatedPort));
500 |
501 |
502 | // Beispiel: Tool-Überprüfung
503 | function isToolEnabled(toolName) {
504 | const envKey = `ENABLE_${toolName.toUpperCase()}`;
505 | if (!(envKey in envConfig.Functions)) {
506 | console.warn(`⚠️ Tool "${toolName}" is not defined in the configuration. Default: deactivated.`);
507 | return false;
508 | }
509 | return envConfig.Functions[envKey] === true;
510 | }
511 |
512 |
513 |
514 | /* ################ Helper Functions ############################*/
515 | // Helper-Funktion, um zu prüfen, ob ein Tool aktiviert ist, und eine Fehlermeldung zu generieren
516 | function checkToolEnabled(toolName) {
517 | if (toolName === "keygen" && AllowKeygen) {
518 | return null;
519 | }
520 |
521 | if (!isToolEnabled(toolName)) {
522 | return {
523 | status: 'error',
524 | message: messages[lang].toolDisabledError.replace('${toolName}', toolName),
525 | };
526 | }
527 | return null; // Tool ist aktiviert
528 | }
529 |
530 | function validateToken(token) {
531 | if (!token) {
532 | return {
533 | status: 'error',
534 | message: 'Token fehlt. Bitte einloggen und erneut versuchen.',
535 | statusCode: 401 // Optional für konsistenten HTTP-Status
536 | };
537 | }
538 | return null;
539 | }
540 |
541 | function getArguments(input) {
542 | if (input.arguments) {
543 | return input.arguments;
544 | } else if (input.params?.arguments) {
545 | return input.params.arguments;
546 | } else {
547 | console.error(t.invalidArgumentsError.replace('${input}', JSON.stringify(input)));
548 | return {}; // Leeres Objekt als Fallback
549 | }
550 | }
551 |
552 | // Parameter zuordnen
553 | const API_URL = apiUrl;
554 | const PORT = Port;
555 |
556 | // Server-Startkonfiguration ausgeben
557 | const serverConfig = JSON.stringify({ API_URL, PORT }, null, 2);
558 | console.log(
559 | messages[lang].startingServerWithConfig
560 | .replace('${config}', serverConfig)
561 | );
562 |
563 | //const net = require('net');
564 |
565 | class TcpServerTransport {
566 | constructor(port) {
567 | this.port = port;
568 | this.server = null;
569 | this.clients = new Map(); // Map zur Speicherung der Clients
570 | }
571 |
572 | async start(onMessage) {
573 | return new Promise((resolve, reject) => {
574 | // Server erstellen
575 | this.server = net.createServer((socket) => {
576 | const clientIP = socket.remoteAddress || 'unbekannt';
577 | const clientPort = socket.remotePort || 'unbekannt';
578 |
579 | // Client-Informationen in der Map speichern
580 | this.clients.set(socket, { ip: clientIP, port: clientPort });
581 |
582 | console.log(t.connection.new.replace('${ip}', clientIP).replace('${port}', clientPort));
583 |
584 | // Ereignis: Daten empfangen
585 | socket.on('data', async (data) => {
586 | const client = this.clients.get(socket);
587 | console.log(t.connection.dataReceived
588 | .replace('${ip}', client.ip)
589 | .replace('${port}', client.port)
590 | .replace('${data}', data.toString()));
591 | try {
592 | const message = JSON.parse(data.toString());
593 | const response = await onMessage(message);
594 | socket.write(JSON.stringify(response));
595 | } catch (err) {
596 | console.error(t.errors.processMessage.replace('${error}', err.message || err));
597 | socket.write(JSON.stringify({ error: t.errors.invalidMessage }));
598 | }
599 | });
600 |
601 | // Ereignis: Verbindung geschlossen
602 | socket.on('close', () => {
603 | const client = this.clients.get(socket);
604 | console.log(t.connection.closed.replace('${ip}', client.ip).replace('${port}', client.port));
605 | this.clients.delete(socket); // Client aus der Map entfernen
606 | });
607 |
608 | // Fehlerbehandlung für einzelne Sockets
609 | socket.on('error', (err) => {
610 | const client = this.clients.get(socket);
611 | console.error(t.errors.socketError
612 | .replace('${ip}', client?.ip || 'unknown')
613 | .replace('${port}', client?.port || 'unknown')
614 | .replace('${error}', err.message || err));
615 | });
616 |
617 | // Server-Ereignis: Verbindung hergestellt
618 | this.server.on('connection', (socket) => {
619 | console.log(t.connection.established);
620 | socket.setKeepAlive(true, 30000); // Keep-Alive für jede Verbindung setzen
621 | });
622 | });
623 |
624 | // Server starten
625 | this.server.listen(this.port, () => {
626 | console.log(t.server.running.replace('${port}', this.port));
627 | resolve();
628 | });
629 |
630 | // Server-Ereignis: Fehler
631 | this.server.on('error', (err) => {
632 | console.error(t.errors.serverError.replace('${error}', err.message || err));
633 | reject(err);
634 | });
635 | });
636 | }
637 |
638 | async stop() {
639 | if (this.server) {
640 | this.server.close(() => {
641 | console.error(t.server.stopped);
642 | this.clients.clear(); // Alle Clients aus der Map entfernen
643 | });
644 | }
645 | }
646 | }
647 |
648 | class PrivateGPTServer {
649 | server;
650 | axiosInstance;
651 | authToken = null; // Initialisierung des Authentifizierungs-Tokens
652 | authTokenTimestamp = 0; // Initialisierung des Zeitstempels für Token-Gültigkeit
653 |
654 | constructor() {
655 | this.server = new Server({
656 | name: 'pgpt-mcp-server',
657 | version: '2.1.0',
658 | }, {
659 | capabilities: {
660 | resources: {},
661 | tools: {},
662 | },
663 | });
664 |
665 | // Create axios instance with SSL disabled for development
666 | this.axiosInstance = axios.create({
667 | baseURL: API_URL,
668 | headers: {
669 | 'Accept': 'application/json',
670 | 'Content-Type': 'application/json'
671 | },
672 | httpsAgent: new https.Agent({
673 | rejectUnauthorized: isSSLValidationEnabled // Dynamisch durch SSL_VALIDATE gesteuert
674 | })
675 | });
676 |
677 | // console.log(t.sslValidationSet.replace('${value}', sslValidate));
678 | // Interceptors for logging requests and responses
679 | this.axiosInstance.interceptors.request.use((config) => {
680 | console.log(t.requestSent);
681 | console.log('URL:', config.baseURL + config.url);
682 | console.log('Method:', config.method.toUpperCase());
683 | console.log('Headers:', config.headers);
684 | if (config.data) {
685 | console.log('Payload:', config.data);
686 | }
687 | return config;
688 | }, (error) => {
689 | console.error(t.requestError.replace('${error}', error.message || error));
690 | return Promise.reject(error);
691 | });
692 |
693 | this.axiosInstance.interceptors.response.use((response) => {
694 | console.log(t.responseReceived);
695 | console.log('Status:', response.status);
696 | console.log('Data:', response.data);
697 | return response;
698 | }, (error) => {
699 | console.error(t.responseError, error.response ? error.response.data : error.message);
700 | return Promise.reject(error);
701 | });
702 |
703 | this.setupResourceHandlers();
704 | this.setupToolHandlers();
705 |
706 | // Error handling
707 | this.server.onerror = (error) => {
708 | console.error(t.mcpError.replace('${error}', error.message || JSON.stringify(error, null, 2)));
709 | };
710 |
711 | process.on('SIGINT', async () => {
712 | await this.server.close();
713 | process.exit(0);
714 | });
715 | }
716 | // Neue Login-Funktion
717 | async login(email, password) {
718 | console.error(`Authenticating user: ${email}`);
719 | try {
720 | const loginResponse = await this.axiosInstance.post('/login', {
721 | email,
722 | password
723 | });
724 |
725 | console.error('Login response:', loginResponse.data);
726 |
727 | // Rückgabe des Tokens
728 | return loginResponse.data.data.token;
729 | } catch (error) {
730 | console.error('Login error:', error.message || error);
731 | throw new Error('Authentication failed');
732 | }
733 | }
734 |
735 | // ensureAuthenticated nutzt die neue login-Funktion
736 | async ensureAuthenticated(token) {
737 | if (!token) {
738 | console.error('Fehlendes Token. Bitte zuerst einloggen.');
739 | throw new Error('Fehlendes Token.');
740 | }
741 |
742 | console.log('Setting token for authentication...');
743 | // Setze das Token als Authorization-Header
744 | this.axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${token}`;
745 | console.log('Token erfolgreich gesetzt.');
746 | }
747 |
748 | isTokenExpired() {
749 | // Beispielprüfung: Token sollte innerhalb einer Stunde erneuert werden
750 | const EXPIRATION_THRESHOLD = 3600 * 1000; // 1 Stunde
751 | const now = Date.now();
752 | const tokenAge = now - this.authTokenTimestamp;
753 | return tokenAge >= EXPIRATION_THRESHOLD;
754 | }
755 | async validateGroups(groups, token) {
756 | try {
757 | console.log(t.checkingGroups.replace('${groups}', JSON.stringify(groups)));
758 |
759 | // Sicherstellen, dass der Token gesetzt ist
760 | if (!token) {
761 | throw new Error('Token fehlt. Kann Gruppen nicht validieren.');
762 | }
763 |
764 | // Temporär den Header setzen, falls global nicht vorhanden
765 | const response = await this.axiosInstance.get('/groups', {
766 | headers: { Authorization: `Bearer ${token}` }
767 | });
768 |
769 | const availableGroups = response.data?.data?.assignableGroups || [];
770 | console.log(t.availableGroups.replace('${availableGroups}', JSON.stringify(availableGroups)));
771 |
772 | // Überprüfen, ob die übergebenen Gruppen gültig sind
773 | const invalidGroups = groups.filter(group => !availableGroups.includes(group));
774 | if (invalidGroups.length > 0) {
775 | console.error(t.invalidGroupsError.replace('${invalidGroups}', JSON.stringify(invalidGroups)));
776 | return { isValid: false, invalidGroups };
777 | }
778 |
779 | return { isValid: true };
780 | } catch (error) {
781 | const errorMessage = error.response?.data || error.message;
782 | console.error(t.groupValidationError.replace('${error}', errorMessage));
783 | throw new Error(error.response?.data?.message || 'Fehler beim Abrufen der Gruppen.');
784 | }
785 | }
786 |
787 | setupResourceHandlers() {
788 | // List available resources
789 | this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
790 | resources: []
791 | }));
792 | // List resource templates
793 | this.server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
794 | resourceTemplates: []
795 | }));
796 | // Read resource
797 | this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
798 | if (!request.params?.uri) {
799 | throw new McpError(ErrorCode.InvalidRequest, 'Missing URI parameter');
800 | }
801 | throw new McpError(ErrorCode.InvalidRequest, `Invalid URI: ${request.params.uri}`);
802 | });
803 | }
804 | setupToolHandlers() {
805 | this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
806 | tools: [
807 | { /* 1.0 Login #####################################################################################*/
808 | name: 'login',
809 | description: 'User login to retrieve an API token',
810 | inputSchema: {
811 | type: 'object',
812 | properties: {
813 | email: {
814 | type: 'string',
815 | description: 'User email address for login'
816 | },
817 | password: {
818 | type: 'string',
819 | description: 'User password for login'
820 | }
821 | },
822 | required: ['email', 'password']
823 | }
824 | },
825 | { /* 1.1 Logout ####################################################################################*/
826 | name: 'logout',
827 | description: 'Invalidate the API token',
828 | inputSchema: { type: 'object', properties: {} },
829 | },
830 | { /* 2.0 Chat ######################################################################################*/
831 | name: 'chat',
832 | description: 'Start or continue a chat with PrivateGPT with optional RAG capabilities',
833 | inputSchema: {
834 | type: 'object',
835 | properties: {
836 | question: { type: 'string', description: 'The question or prompt to send' },
837 | usePublic: { type: 'boolean', description: 'Use public knowledge base', default: false },
838 | groups: {
839 | type: 'array',
840 | items: { type: 'string' },
841 | description: 'Group names for RAG (exclusive with usePublic)',
842 | },
843 | language: { type: 'string', description: 'Language code (e.g., "en")', default: 'en' },
844 | },
845 | required: ['question'],
846 | },
847 | },
848 | { /* 2.1 Continue Chat #############################################################################*/
849 | name: 'continue_chat',
850 | description: 'Continue an existing chat',
851 | inputSchema: {
852 | type: 'object',
853 | properties: {
854 | chatId: { type: 'string', description: 'ID of the existing chat to continue' },
855 | question: { type: 'string', description: 'The next question or message in the chat' },
856 | },
857 | required: ['chatId', 'question'],
858 | },
859 | },
860 | { /* 2.2 Get Chat Info #############################################################################*/
861 | name: 'get_chat_info',
862 | description: 'Retrieve details about an existing chat using its ID',
863 | inputSchema: {
864 | type: 'object',
865 | properties: {
866 | chatId: { type: 'string', description: 'ID of the chat to retrieve details for' },
867 | token: { type: 'string', description: 'Authorization token for API access' },
868 | },
869 | required: ['chatId', 'token'],
870 | },
871 | },
872 | { /* 3.0 Create Source #############################################################################*/
873 | name: 'create_source',
874 | description: 'Create a new source with automatic markdown formatting',
875 | inputSchema: {
876 | type: 'object',
877 | properties: {
878 | name: { type: 'string', description: 'Name of the source' },
879 | content: { type: 'string', description: 'Markdown-formatted content' },
880 | groups: {
881 | type: 'array',
882 | items: { type: 'string' },
883 | description: 'Optional groups to assign the source to',
884 | },
885 | },
886 | required: ['name', 'content'],
887 | },
888 | },
889 | { /* 3.1 Get Source ################################################################################*/
890 | name: 'get_source',
891 | description: 'Retrieve information about a specific source',
892 | inputSchema: {
893 | type: 'object',
894 | properties: {
895 | sourceId: { type: 'string', description: 'ID of the source to retrieve' },
896 | },
897 | required: ['sourceId'],
898 | },
899 | },
900 | { /* 3.2 List Sources ##############################################################################*/
901 | name: 'list_sources',
902 | description: 'List all sources in a specific group',
903 | inputSchema: {
904 | type: 'object',
905 | properties: {
906 | groupName: { type: 'string', description: 'Group name to list sources from' },
907 | },
908 | required: ['groupName'],
909 | },
910 | },
911 | { /* 3.3 Edit Source ###############################################################################*/
912 | name: 'edit_source',
913 | description: 'Edit an existing source',
914 | inputSchema: {
915 | type: 'object',
916 | properties: {
917 | sourceId: {
918 | type: 'string',
919 | description: 'ID of the source to edit'
920 | },
921 | token: {
922 | type: 'string',
923 | description: 'Authorization token for API access'
924 | },
925 | title: {
926 | type: 'string',
927 | description: 'New title for the source (optional)'
928 | },
929 | content: {
930 | type: 'string',
931 | description: 'New markdown-formatted content for the source (optional)'
932 | },
933 | groups: {
934 | type: 'array',
935 | items: {
936 | type: 'string'
937 | },
938 | description: 'Updated group(s) to assign to the source (optional)'
939 | }
940 | },
941 | required: ['sourceId', 'token']
942 | }
943 | },
944 | { /* 3.4 Delete Source #############################################################################*/
945 | name: 'delete_source',
946 | description: 'Delete a specific source',
947 | inputSchema: {
948 | type: 'object',
949 | properties: {
950 | sourceId: { type: 'string', description: 'ID of the source to delete' },
951 | },
952 | required: ['sourceId'],
953 | },
954 | },
955 | { /* 4.0 List Groups ###############################################################################*/
956 | name: 'list_groups',
957 | description: 'Retrieve personal and assignable groups',
958 | inputSchema: { type: 'object', properties: {} },
959 | },
960 | { /* 4.1 Store Group ###############################################################################*/
961 | name: 'store_group',
962 | description: 'Create a new group',
963 | inputSchema: {
964 | type: 'object',
965 | properties: {
966 | groupName: { type: 'string', description: 'Name of the new group' },
967 | description: { type: 'string', description: 'Description of the new group' },
968 | },
969 | required: ['groupName'],
970 | },
971 | },
972 | { /* 4.2 Delete Group ##############################################################################*/
973 | name: 'delete_group',
974 | description: 'Delete an existing group',
975 | inputSchema: {
976 | type: 'object',
977 | properties: {
978 | groupName: { type: 'string', description: 'Name of the group to delete' },
979 | },
980 | required: ['groupName'],
981 | },
982 | },
983 | { /* 5.0 Store User ################################################################################*/
984 | name: 'store_user',
985 | description: 'Create a new user',
986 | inputSchema: {
987 | type: 'object',
988 | properties: {
989 | name: { type: 'string', description: 'Name of the user' },
990 | email: { type: 'string', description: 'Email of the user' },
991 | password: { type: 'string', description: 'Password for the user' },
992 | language: { type: 'string', description: 'Preferred language (optional)', default: 'en' },
993 | timezone: { type: 'string', description: 'Timezone (optional)', default: 'Europe/Berlin' },
994 | roles: {
995 | type: 'array',
996 | items: { type: 'string' },
997 | description: 'Roles to assign (optional)'
998 | },
999 | groups: {
1000 | type: 'array',
1001 | items: { type: 'string' },
1002 | description: 'Groups to assign (optional)'
1003 | },
1004 | usePublic: { type: 'boolean', description: 'Enable public knowledge (optional)', default: false }
1005 | },
1006 | required: ['name', 'email', 'password']
1007 | },
1008 | },
1009 | { /* 5.1 Edit User #################################################################################*/
1010 | name: 'edit_user',
1011 | description: 'Edit an existing user',
1012 | inputSchema: {
1013 | type: 'object',
1014 | properties: {
1015 | email: { type: 'string', description: 'Email of the user to edit' },
1016 | name: { type: 'string', description: 'New name for the user (optional)' },
1017 | password: { type: 'string', description: 'New password for the user (optional)' },
1018 | language: { type: 'string', description: 'Preferred language (optional)' },
1019 | timezone: { type: 'string', description: 'Timezone (optional)' },
1020 | roles: {
1021 | type: 'array',
1022 | items: { type: 'string' },
1023 | description: 'Updated roles (optional)'
1024 | },
1025 | groups: {
1026 | type: 'array',
1027 | items: { type: 'string' },
1028 | description: 'Updated groups (optional)'
1029 | },
1030 | usePublic: { type: 'boolean', description: 'Enable public knowledge (optional)' }
1031 | },
1032 | required: ['email']
1033 | }
1034 | },
1035 | { /* 5.2 Delete User ###############################################################################*/
1036 | name: 'delete_user',
1037 | description: 'Delete an existing user',
1038 | inputSchema: {
1039 | type: 'object',
1040 | properties: {
1041 | email: { type: 'string', description: 'Email of the user to delete' }
1042 | },
1043 | required: ['email']
1044 | }
1045 | }
1046 | ],
1047 | }));
1048 | this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
1049 | if (!request.params?.name) {
1050 | throw new McpError(ErrorCode.InvalidRequest, 'Missing tool name');
1051 | }
1052 | try {
1053 | //await this.ensureAuthenticated();
1054 | console.error(t.handlingToolRequest.replace('${name}', request.params.name), request.params);
1055 | switch (request.params.name) {
1056 | /* 1.0 Login ######################################################################################*/
1057 | case 'login': {
1058 | const disabledResponse = checkToolEnabled('login');
1059 | if (disabledResponse) return disabledResponse;
1060 |
1061 | const { email, password } = request.params.arguments; // Extrahiere email und password aus der Nachricht
1062 |
1063 | if (!email || !password) {
1064 | return {
1065 | status: 'E10-R-1000',
1066 | message: 'Login fehlgeschlagen: E-Mail und Passwort sind erforderlich.',
1067 | };
1068 | }
1069 |
1070 | try {
1071 | // Aufruf des Login-Endpunkts der API
1072 | const loginResponse = await this.axiosInstance.post('/login', { email, password });
1073 |
1074 | console.log(t.loginSuccess.replace('${data}', JSON.stringify(loginResponse.data)));
1075 | ;
1076 |
1077 | // Token zurückgeben
1078 | return {
1079 | status: loginResponse.data?.status || 'ok', // Dynamisch, falls der API-Status einheitlich ist
1080 | message: loginResponse.data?.message || 'Login erfolgreich.', // API-Nachricht verwenden oder Standardnachricht
1081 | token: loginResponse.data?.data?.token, // Token aus API-Antwort
1082 | };
1083 | } catch (error) {
1084 | const errorMessage = error.response?.data || error.message;
1085 | console.error(t.loginError.replace('${error}', errorMessage));
1086 |
1087 | return {
1088 | status: error.response?.status || 'E10-R-1001', // API-Fehlerstatus oder Standardfehlerstatus,
1089 | message: error.response?.data?.message || 'Login fehlgeschlagen.',
1090 | };
1091 | }
1092 | }
1093 | /* 1.1 Logout #####################################################################################*/
1094 | case 'logout': {
1095 | const disabledResponse = checkToolEnabled('logout');
1096 | if (disabledResponse) return disabledResponse;
1097 |
1098 | const { token } = message;
1099 | //const { token, arguments: args } = request.params;
1100 |
1101 | const tokenValidation = validateToken(token);
1102 | if (tokenValidation) return tokenValidation;
1103 |
1104 |
1105 | try {
1106 | const logoutResponse = await this.axiosInstance.delete('/logout', {
1107 | headers: {
1108 | Authorization: `Bearer ${token}`
1109 | }
1110 | });
1111 |
1112 | console.log(t.logoutSuccess.replace('${data}', JSON.stringify(logoutResponse.data)));
1113 |
1114 |
1115 | return {
1116 | data: {}, // Optional: Zusätzliche Daten könnten hier eingefügt werden
1117 | message: 'success',
1118 | status: 200, // OK
1119 | };
1120 | } catch (error) {
1121 | const logoutErrorMessage = error.response?.data || error.message;
1122 | console.error(t.logoutError.replace('${error}', logoutErrorMessage));
1123 | return {
1124 | data: {},
1125 | message: error.response?.data?.message || 'Logout fehlgeschlagen. Bitte versuchen Sie es später erneut.',
1126 | status: error.response?.status || 'E11-R-1100', // Internal Server Error oder spezifischer Statuscode
1127 | };
1128 | }
1129 | }
1130 | /* 2.0 Chat #######################################################################################*/
1131 | case 'chat': {
1132 | const disabledResponse = checkToolEnabled('chat');
1133 | if (disabledResponse) return disabledResponse;
1134 |
1135 | const { token, arguments: args } = request.params;
1136 | console.log('Extrahierter Token:', token);
1137 |
1138 |
1139 | // Token prüfen und validieren
1140 | if (!token) {
1141 | console.error(t.noTokenError);
1142 | return { status: 'E20-R-2000', message: t.missingTokenError };
1143 | }
1144 |
1145 | /*const tokenValidation = validateToken(token);
1146 | if (tokenValidation) {
1147 | console.error('❌ Token-Validierung fehlgeschlagen. Token:', token, 'Fehler:', tokenValidation);
1148 | return {
1149 | status: 'error',
1150 | message: 'Token ist ungültig oder abgelaufen. Bitte erneut einloggen.',
1151 | };
1152 | }*/
1153 |
1154 | // Argument-Validierung
1155 | if (!args || !args.question) {
1156 | console.error(t.missingArgumentsError.replace('${args}', JSON.stringify(args)));
1157 | return {
1158 | status: 'error',
1159 | message: t.missingArgumentsError.replace('${args}', JSON.stringify(args)),
1160 | };
1161 | }
1162 |
1163 | const { question, usePublic, groups, language } = args;
1164 |
1165 | // Konflikt zwischen `usePublic` und `groups` lösen
1166 | if (usePublic && groups && groups.length > 0) {
1167 | console.warn(t.publicGroupsConflictWarning);
1168 | args.usePublic = false;
1169 | }
1170 |
1171 | try {
1172 | console.log(t.sendingChatRequest
1173 | .replace('${question}', question)
1174 | .replace('${usePublic}', usePublic)
1175 | .replace('${groups}', JSON.stringify(groups))
1176 | .replace('${language}', language)
1177 | );
1178 |
1179 | const response = await this.axiosInstance.post(
1180 | '/chats',
1181 | {
1182 | question,
1183 | usePublic: usePublic || false,
1184 | groups: Array.isArray(groups) ? groups : [groups],
1185 | language: language || 'de',
1186 | },
1187 | { headers: { Authorization: `Bearer ${token}` } }
1188 | );
1189 |
1190 | const data = response.data?.data || {};
1191 | console.log(t.chatResponseSuccess.replace('${data}', JSON.stringify(data)));
1192 |
1193 | // Erfolgsantwort mit Status und Daten
1194 | return {
1195 | status: response.data?.status || 'ok',
1196 | message: response.data?.message || 'Chat erfolgreich.',
1197 | content: {
1198 | chatId: data.chatId,
1199 | answer: data.answer,
1200 | sources: data.sources || [],
1201 | },
1202 | };
1203 | } catch (error) {
1204 | const chatApiErrorMessage = error.message || error.response?.data;
1205 | console.error(t.chatApiError.replace('${error}', chatApiErrorMessage));
1206 |
1207 | // Fehlerantwort mit Status und Nachricht
1208 | return {
1209 | status: error.response?.status || 'E20-R-2002',
1210 | message: error.response?.data?.message || 'Fehler bei der Chat-Anfrage.',
1211 | };
1212 | }
1213 | }
1214 | /* 2.1 Continue Chat ##############################################################################*/
1215 | case 'continue_chat': {
1216 | const disabledResponse = checkToolEnabled('continue_chat');
1217 | if (disabledResponse) return disabledResponse;
1218 |
1219 | const args = request.params.arguments;
1220 |
1221 | if (!args || !args.chatId || !args.question) {
1222 | return { status: 'E21-R-2100', message: 'Fehlende erforderliche Parameter: chatId und/oder question.' };
1223 | }
1224 |
1225 | const { chatId, question } = args;
1226 | console.log(t.conversationContinuation.replace('${chatId}', chatId));
1227 |
1228 | try {
1229 | const continueChatResponse = await this.axiosInstance.patch(`/chats/${chatId}`, {
1230 | question: question,
1231 | });
1232 | console.log(t.conversationSuccess.replace('${data}', JSON.stringify(continueChatResponse.data, null, 2)));
1233 | return {
1234 | content: {
1235 | chatId: continueChatResponse.data.data.chatId,
1236 | answer: continueChatResponse.data.data.answer,
1237 | sources: continueChatResponse.data.sources || [],
1238 | message: continueChatResponse.data.message,
1239 | status: continueChatResponse.data.status,
1240 | },
1241 | };
1242 | } catch (error) {
1243 | console.error(t.apiRequestError.replace('${error}', error.message));
1244 | return {
1245 | status: error.response?.status || 'E21-R-2101',
1246 | message: error.response?.data?.message || 'Fehler beim Fortsetzen der Konversation.',
1247 | };
1248 | }
1249 | }
1250 | /* 2.2 Get Chat Info ##############################################################################*/
1251 | case 'get_chat_info': {
1252 | const disabledResponse = checkToolEnabled('get_chat_info');
1253 | if (disabledResponse) return disabledResponse;
1254 |
1255 | const { token, arguments: args } = request.params;
1256 |
1257 | const tokenValidation = validateToken(token);
1258 | if (tokenValidation) return tokenValidation;
1259 |
1260 | const { chatId } = args;
1261 |
1262 | if (!chatId) {
1263 | return { status: 'E22-R-2200', message: 'chatId ist erforderlich, um Chat-Informationen abzurufen.' };
1264 | }
1265 |
1266 | try {
1267 | const response = await this.axiosInstance.get(`/chats/${chatId}`, {
1268 | headers: { Authorization: `Bearer ${token}` }
1269 | });
1270 |
1271 | const chatData = response.data?.data;
1272 |
1273 | if (!chatData) {
1274 | return {
1275 | status: 'E22-R-2201',
1276 | message: t.noChatData,
1277 | };
1278 | }
1279 |
1280 | return {
1281 | data: {
1282 | chatId: chatData.chatId,
1283 | title: chatData.title || 'Unbenannter Chat',
1284 | language: chatData.language || 'Unbekannt',
1285 | groups: chatData.groups || [],
1286 | messages: chatData.messages || []
1287 | },
1288 | message: response.data?.message || 'Erfolgreich abgerufen.'
1289 | };
1290 | } catch (error) {
1291 | const fetchChatErrorMessage = error.message || error.response?.data;
1292 | console.error(t.fetchChatInfoError.replace('${error}', fetchChatErrorMessage));
1293 | return {
1294 | status: 'E22-R-2202',
1295 | message: error.response?.data?.message || 'Fehler beim Abrufen der Chat-Informationen.'
1296 | };
1297 | }
1298 | }
1299 | /* 3.0 Create Source ##############################################################################*/
1300 | case 'create_source': {
1301 | const disabledResponse = checkToolEnabled('create_source');
1302 | if (disabledResponse) return disabledResponse;
1303 |
1304 | const args = request.params.arguments;
1305 | const token = request.params.token;
1306 |
1307 | // Validierung: Erforderliche Parameter prüfen
1308 | if (!token) {
1309 | return { status: 'E30-R-3000', message: t.missingTokenError };
1310 | }
1311 | if (!args || !args.name || !args.content) {
1312 | return { status: 'E30-R-3001', message: t.missingParametersError.replace('${parameters}', 'name und content') };
1313 | }
1314 |
1315 | const { name, content, groups } = args;
1316 |
1317 | try {
1318 | // Token im Header setzen
1319 | this.axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${token}`;
1320 |
1321 | // Gruppenvalidierung vorab durchführen
1322 | if (groups && groups.length > 0) {
1323 | console.log('📤 Überprüfen der Gruppen:', groups);
1324 |
1325 | const response = await this.axiosInstance.get('/groups');
1326 | const availableGroups = response.data?.data?.assignableGroups || [];
1327 |
1328 | // Ungültige Gruppen ermitteln
1329 | const invalidGroups = groups.filter(group => !availableGroups.includes(group));
1330 | if (invalidGroups.length > 0) {
1331 | console.error('❌ Ungültige Gruppen gefunden:', invalidGroups);
1332 | return {
1333 | status: 'E30-R-3002',
1334 | message: `Ungültige Gruppen: ${invalidGroups.join(', ')}`,
1335 | };
1336 | }
1337 | }
1338 |
1339 | // API-Aufruf zur Erstellung der Quelle
1340 | const createSourceResponse = await this.axiosInstance.post(
1341 | '/sources',
1342 | { name, content, groups },
1343 | { headers: { Authorization: `Bearer ${token}` } }
1344 | );
1345 |
1346 | console.log('✔️ Quelle erfolgreich erstellt:', createSourceResponse.data);
1347 |
1348 | // Erfolgsantwort
1349 | return {
1350 | status: createSourceResponse.data?.status || 'ok',
1351 | message: createSourceResponse.data?.message || 'Quelle erfolgreich erstellt.',
1352 | data: createSourceResponse.data?.data,
1353 | };
1354 | } catch (error) {
1355 | const createSourceError = error.response?.data || error.message;
1356 | console.error(t.createSourceError.replace('${error}', createSourceError));
1357 |
1358 | // console.error('❌ Fehler beim Erstellen der Quelle:', error.response?.data || error.message);
1359 |
1360 | // Fehlerhafte Antwort
1361 | if (error.response) {
1362 | return {
1363 | status: 'E30-R-3003',
1364 | message: error.response.data?.message || 'Ein Fehler ist aufgetreten.',
1365 | details: {
1366 | status: error.response.status,
1367 | headers: error.response.headers,
1368 | data: error.response.data,
1369 | },
1370 | };
1371 | } else if (error.request) {
1372 | return {
1373 | status: 'E30-R-3004',
1374 | message: t.noServerResponse,
1375 | details: { request: error.request },
1376 | };
1377 | } else {
1378 | return {
1379 | status: 'E30-R-3005',
1380 | message: error.message || 'Ein unbekannter Fehler ist aufgetreten.',
1381 | };
1382 | }
1383 | }
1384 | }
1385 | /* 3.1 Get Source #################################################################################*/
1386 | case 'get_source': {
1387 | const disabledResponse = checkToolEnabled('get_source');
1388 | if (disabledResponse) return disabledResponse;
1389 | const args = request.params.arguments;
1390 | console.log(t.makingGetSourceRequest.replace('${args}', JSON.stringify(args, null, 2)));
1391 | const getSourceResponse = await this.axiosInstance.get(`/sources/${args.sourceId}`);
1392 | console.log(t.gotGetSourceResponse.replace('${data}', JSON.stringify(getSourceResponse.data, null, 2)));
1393 | return {
1394 | content: [
1395 | {
1396 | type: 'text',
1397 | text: JSON.stringify(getSourceResponse.data, null, 2)
1398 | }
1399 | ]
1400 | };
1401 | }
1402 | /* 3.2 List Sources ###############################################################################*/
1403 | case 'list_sources': {
1404 | const disabledResponse = checkToolEnabled('list_sources');
1405 | if (disabledResponse) return disabledResponse;
1406 | const args = request.params.arguments;
1407 | console.log(t.makingListSourcesRequest.replace('${args}', JSON.stringify(args, null, 2)));
1408 | const listSourcesResponse = await this.axiosInstance.post('/sources/groups', {
1409 | groupName: args.groupName
1410 | });
1411 | console.log(t.gotListSourcesResponse.replace('${data}', JSON.stringify(listSourcesResponse.data, null, 2)));
1412 | return {
1413 | content: [
1414 | {
1415 | type: 'text',
1416 | text: JSON.stringify(listSourcesResponse.data, null, 2)
1417 | }
1418 | ]
1419 | };
1420 | }
1421 | /* 3.3 Edit Source ################################################################################*/
1422 | case 'edit_source': {
1423 | const disabledResponse = checkToolEnabled('edit_source');
1424 | if (disabledResponse) return disabledResponse;
1425 |
1426 | const { token, arguments: args } = request.params;
1427 |
1428 | // Validierung: Token erforderlich
1429 | const tokenValidation = validateToken(token);
1430 | if (tokenValidation) return tokenValidation;
1431 |
1432 | const { sourceId, title, content, groups } = args;
1433 |
1434 | // Validierung: Pflichtfeld `sourceId`
1435 | if (!sourceId) {
1436 | return {
1437 | data: {},
1438 | message: t.missingParameterError.replace('${parameter}', 'sourceId'),
1439 | status: 'E33-R-3300', // Bad Request
1440 | };
1441 | }
1442 |
1443 | console.log(`Bearbeite Quelle mit ID: ${sourceId}, Titel: ${title || 'unverändert'}`);
1444 |
1445 | try {
1446 | // Payload dynamisch erstellen
1447 | const payload = {};
1448 | if (title) payload.title = title;
1449 | if (content) payload.content = content;
1450 | if (groups) payload.groups = groups;
1451 |
1452 | // API-Aufruf: Quelle bearbeiten
1453 | const editSourceResponse = await this.axiosInstance.patch(
1454 | `/sources/${sourceId}`,
1455 | payload,
1456 | {
1457 | headers: {
1458 | Authorization: `Bearer ${token}`, // Nutze den bereitgestellten Token
1459 | },
1460 | }
1461 | );
1462 |
1463 | console.log(t.editSourceSuccess.replace('${data}', JSON.stringify(editSourceResponse.data, null, 2)));
1464 |
1465 | // Erfolgreiche Antwort
1466 | return {
1467 | data: editSourceResponse.data?.data || {}, // Optionale Daten aus der API
1468 | message: editSourceResponse.data?.message || 'Quelle erfolgreich bearbeitet.',
1469 | status: editSourceResponse.status || 200, // OK
1470 | };
1471 | } catch (error) {
1472 | const editSourceError = error.message || JSON.stringify(error.response?.data);
1473 | console.error(t.editSourceError.replace('${error}', editSourceError));
1474 |
1475 | // console.error(`❌ Fehler beim Bearbeiten der Quelle: ${error.message || JSON.stringify(error.response?.data)}`);
1476 |
1477 | // Fehlerhafte Antwort
1478 | return {
1479 | data: {},
1480 | message: error.response?.data?.message || 'Bearbeiten der Quelle fehlgeschlagen. Bitte versuchen Sie es später erneut.',
1481 | status: error.response?.status || 'E33-R-3301', // Internal Server Error
1482 | };
1483 | }
1484 | }
1485 | /* 3.4 Delete Source ##############################################################################*/
1486 | case 'delete_source': {
1487 | const disabledResponse = checkToolEnabled('delete_source');
1488 | if (disabledResponse) return disabledResponse;
1489 |
1490 | const { token, arguments: args } = request.params.arguments;
1491 |
1492 | // Validierung: Token erforderlich
1493 | const tokenValidation = validateToken(token);
1494 | if (tokenValidation) return tokenValidation;
1495 |
1496 | const { sourceId } = args;
1497 |
1498 | // Validierung: sourceId erforderlich
1499 | if (!sourceId) {
1500 | return {
1501 | data: {},
1502 | message: t.missingParameterError.replace('${parameter}', 'sourceId'),
1503 | status: 'E34-R-3400', // Bad Request
1504 | };
1505 | }
1506 |
1507 | try {
1508 | // API-Aufruf: Quelle löschen
1509 | const deleteResponse = await this.axiosInstance.delete(`/sources/${sourceId}`, {
1510 | headers: { Authorization: `Bearer ${token}` },
1511 | });
1512 |
1513 | console.log(`Quelle erfolgreich gelöscht: ${JSON.stringify(deleteResponse.data, null, 2)}`);
1514 |
1515 | // Erfolgreiche Antwort
1516 | return {
1517 | data: deleteResponse.data?.data || {}, // Optionale Daten aus der API
1518 | message: deleteResponse.data?.message || 'Quelle erfolgreich gelöscht.',
1519 | status: deleteResponse.status || 200, // OK
1520 | };
1521 | } catch (error) {
1522 | // console.error(`❌ Fehler beim Löschen der Quelle: ${error.message || JSON.stringify(error.response?.data)}`);
1523 | const deleteSourceError = error.message || JSON.stringify(error.response?.data);
1524 | console.error(t.deleteSourceError.replace('${error}', deleteSourceError));
1525 |
1526 |
1527 | // Fehlerhafte Antwort
1528 | return {
1529 | data: {},
1530 | message: error.response?.data?.message || 'Löschen der Quelle fehlgeschlagen. Bitte versuchen Sie es später erneut.',
1531 | status: error.response?.status || 'E34-R-3401', // Internal Server Error
1532 | };
1533 | }
1534 | }
1535 | /* 4.0 List Groups ################################################################################*/
1536 | case 'list_groups': {
1537 | const disabledResponse = checkToolEnabled('list_groups');
1538 | if (disabledResponse) return disabledResponse;
1539 | console.log(t.makingListGroupsRequest);
1540 | const listGroupsResponse = await this.axiosInstance.get('/groups');
1541 | console.log(t.gotListGroupsResponse, listGroupsResponse.data);
1542 | return {
1543 | content: [
1544 | {
1545 | type: 'text',
1546 | text: JSON.stringify(listGroupsResponse.data, null, 2)
1547 | }
1548 | ]
1549 | };
1550 | }
1551 | /* 4.1 Store Group ################################################################################*/
1552 | case 'store_group': {
1553 | const disabledResponse = checkToolEnabled('store_group');
1554 | if (disabledResponse) return disabledResponse;
1555 | const args = request.params.arguments;
1556 |
1557 | if (!args || !args.groupName) {
1558 | throw new McpError(ErrorCode.InvalidRequest, 'Store: Fehlender erforderlicher Parameter: groupName.');
1559 | }
1560 |
1561 | console.log(
1562 | t.storeGroupLog
1563 | .replace('${groupName}', args.groupName)
1564 | .replace('${description}', args.description || 'Keine Beschreibung angegeben')
1565 | );
1566 |
1567 | // console.log(`Storing new group with name: ${args.groupName} and description: ${args.description || 'No description provided'}`);
1568 |
1569 | try {
1570 | const storeGroupResponse = await this.axiosInstance.post('/groups', {
1571 | groupName: args.groupName,
1572 | description: args.description || ''
1573 | });
1574 | console.log(
1575 | t.storeGroupSuccess.replace('${data}', JSON.stringify(storeGroupResponse.data, null, 2))
1576 | );
1577 | // console.log(`Group stored successfully: ${JSON.stringify(storeGroupResponse.data, null, 2)}`);
1578 |
1579 | return {
1580 | content: [
1581 | {
1582 | type: 'text',
1583 | text: `Group "${args.groupName}" successfully stored with ID: ${storeGroupResponse.data.id}`
1584 | }
1585 | ]
1586 | };
1587 | } catch (error) {
1588 | console.error(t.errorHandlingRequest.replace('${error}', error.message || JSON.stringify(error, null, 2)));
1589 | if (axios.isAxiosError(error)) {
1590 | const message = error.response?.data?.message ?? error.message;
1591 | console.error(
1592 | t.apiErrorDetails.replace('${status}', error.response?.status || 'E41-R-4100').replace('${data}', JSON.stringify(error.response?.data || {}, null, 2))
1593 | );
1594 | return {
1595 | content: [
1596 | {
1597 | type: 'text',
1598 | text: `API error: ${message}`
1599 | }
1600 | ],
1601 | isError: true
1602 | };
1603 | }
1604 | throw error;
1605 | }
1606 | };
1607 | /* 4.2 Delete Group ###############################################################################*/
1608 | case 'delete_group': {
1609 | const disabledResponse = checkToolEnabled('delete_group');
1610 | if (disabledResponse) return disabledResponse;
1611 |
1612 | const { groupName } = request.params.arguments; // Extrahiere die Gruppe
1613 | if (!groupName) {
1614 | throw new McpError(ErrorCode.InvalidRequest, 'Delete Fehlender erforderlicher Parameter: groupName.');
1615 | }
1616 |
1617 | // console.log(`Lösche Gruppe mit Name: ${groupName}`);
1618 | console.log(t.deleteGroupLog.replace('${groupName}', groupName));
1619 |
1620 |
1621 | try {
1622 | // API-Aufruf mit dem notwendigen JSON-Body
1623 | const deleteGroupResponse = await this.axiosInstance.delete('/groups', {
1624 | data: { groupName }, // JSON-Body für den DELETE-Request
1625 | });
1626 |
1627 | // console.log(t.deleteGroupSuccessLog.replace('${data}', JSON.stringify(deleteGroupResponse.data)));
1628 | console.log(t.deleteGroupSuccessLog.replace('${data}', JSON.stringify(deleteGroupResponse.data)));
1629 |
1630 |
1631 | return {
1632 | content: [
1633 | {
1634 | type: 'text',
1635 | text: `Gruppe "${groupName}" wurde erfolgreich gelöscht.`,
1636 | },
1637 | ],
1638 | };
1639 | } catch (error) {
1640 | // console.error(`Fehler bei der API-Anfrage: ${error.message || JSON.stringify(error.response?.data)}`);
1641 | const apiError = error.message || JSON.stringify(error.response?.data);
1642 | console.error(t.apiRequestError.replace('${error}', apiError));
1643 | if (axios.isAxiosError(error)) {
1644 | const message = error.response?.data?.message || 'Fehler beim Löschen der Gruppe.';
1645 | return {
1646 | content: [
1647 | {
1648 | type: 'text',
1649 | text: `API-Fehler: ${message}`,
1650 | },
1651 | ],
1652 | isError: true,
1653 | };
1654 | }
1655 | throw new McpError(ErrorCode.InternalError, 'Interner Fehler beim Löschen der Gruppe.');
1656 | }
1657 | }
1658 | /* 5.0 Store User #################################################################################*/
1659 | case 'store_user': {
1660 | const disabledResponse = checkToolEnabled('store_user');
1661 | if (disabledResponse) return disabledResponse;
1662 |
1663 | // Token und Argumente aus request.params entnehmen
1664 | const { token, arguments: args } = request.params;
1665 |
1666 | // Token validieren
1667 | const tokenValidation = validateToken(token);
1668 | if (tokenValidation) return tokenValidation;
1669 |
1670 | // Erforderliche Felder prüfen
1671 | if (!args || !args.name || !args.email || !args.password) {
1672 | return {
1673 | status: 'E50-R-5000',
1674 | message: 'Fehlende erforderliche Felder: name, email oder password.'
1675 | };
1676 | }
1677 |
1678 | try {
1679 | // Benutzer anlegen
1680 | const response = await this.axiosInstance.post(
1681 | '/users',
1682 | {
1683 | name: args.name,
1684 | email: args.email,
1685 | password: args.password,
1686 | language: args.language || 'en',
1687 | timezone: args.timezone || 'Europe/Berlin',
1688 | roles: args.roles || [],
1689 | groups: args.groups || [],
1690 | usePublic: args.usePublic || false
1691 | },
1692 | {
1693 | headers: {
1694 | Authorization: `Bearer ${token}`
1695 | }
1696 | }
1697 | );
1698 |
1699 | // Erfolgreiche Antwort
1700 | return {
1701 | status: response.data?.status || 'ok',
1702 | message: response.data?.message || 'Benutzer erfolgreich erstellt.',
1703 | data: response.data?.data
1704 | };
1705 | } catch (error) {
1706 | // console.error('❌ Fehler beim Erstellen des Benutzers:', error.response?.data || error.message);
1707 | const createUserError = error.response?.data || error.message;
1708 | console.error(t.createUserError.replace('${error}', createUserError));
1709 | return {
1710 | status: error.response?.status || 'E50-R-5001',
1711 | message: error.response?.data?.message || 'Fehler beim Erstellen des Benutzers.'
1712 | };
1713 | }
1714 | }
1715 | /* 5.1 Edit User ##################################################################################*/
1716 | case 'edit_user': {
1717 | const disabledResponse = checkToolEnabled('edit_user');
1718 | if (disabledResponse) return disabledResponse;
1719 |
1720 | const { token, arguments: args } = request.params;
1721 | const tokenValidation = validateToken(token);
1722 | if (tokenValidation) return tokenValidation;
1723 |
1724 | // Mindestens die E-Mail muss angegeben sein, um den User zu identifizieren
1725 | if (!args || !args.email) {
1726 | return {
1727 | status: 'E51-R-5100',
1728 | message: 'Die E-Mail des Benutzers ist erforderlich, um den Datensatz zu bearbeiten.'
1729 | };
1730 | }
1731 |
1732 | try {
1733 | // Nur Felder senden, die tatsächlich aktualisiert werden sollen
1734 | const payload = {};
1735 | if (args.name) payload.name = args.name;
1736 | if (args.password) payload.password = args.password;
1737 | if (args.language) payload.language = args.language;
1738 | if (args.timezone) payload.timezone = args.timezone;
1739 | if (Array.isArray(args.roles)) payload.roles = args.roles;
1740 | if (Array.isArray(args.groups)) payload.groups = args.groups;
1741 | if (typeof args.usePublic === 'boolean') payload.usePublic = args.usePublic;
1742 |
1743 | // E-Mail ist Pflicht, um den Benutzer auf dem Server zu finden
1744 | payload.email = args.email;
1745 |
1746 | const response = await this.axiosInstance.patch(
1747 | '/users',
1748 | payload,
1749 | {
1750 | headers: { Authorization: `Bearer ${token}` }
1751 | }
1752 | );
1753 |
1754 | return {
1755 | status: response.data?.status || 'ok',
1756 | message: response.data?.message || 'Benutzer erfolgreich bearbeitet.',
1757 | data: response.data?.data
1758 | };
1759 | } catch (error) {
1760 | const editUserError = error.response?.data || error.message;
1761 | console.error(t.editUserError.replace('${error}', editUserError));
1762 | // console.error('❌ Fehler beim Bearbeiten des Benutzers:', error.response?.data || error.message);
1763 | return {
1764 | status: error.response?.status || 'E51-R-5101',
1765 | message: error.response?.data?.message || 'Fehler beim Bearbeiten des Benutzers.'
1766 | };
1767 | }
1768 | }
1769 | /* 5.2 Delete User ################################################################################*/
1770 | case 'delete_user': {
1771 | const disabledResponse = checkToolEnabled('delete_user');
1772 | if (disabledResponse) return disabledResponse;
1773 |
1774 | const { token, arguments: args } = request.params;
1775 | const tokenValidation = validateToken(token);
1776 | if (tokenValidation) return tokenValidation;
1777 |
1778 | // E-Mail ist nötig, um den Benutzer zu löschen
1779 | if (!args || !args.email) {
1780 | return {
1781 | status: 'E52-R-5200',
1782 | message: 'Die E-Mail ist erforderlich, um einen Benutzer zu löschen.'
1783 | };
1784 | }
1785 |
1786 | try {
1787 | // DELETE-Anfrage mit JSON-Body
1788 | const response = await this.axiosInstance.delete(
1789 | '/users',
1790 | {
1791 | data: { email: args.email },
1792 | headers: { Authorization: `Bearer ${token}` }
1793 | }
1794 | );
1795 |
1796 | return {
1797 | status: response.data?.status || 'ok',
1798 | message: response.data?.message || 'Benutzer erfolgreich gelöscht.',
1799 | data: response.data?.data
1800 | };
1801 | } catch (error) {
1802 | // console.error('❌ Fehler beim Löschen des Benutzers:', error.response?.data || error.message);
1803 | const deleteUserError = error.response?.data || error.message;
1804 | console.error(t.deleteUserError.replace('${error}', deleteUserError));
1805 | return {
1806 | status: error.response?.status || 'E52-R-5201',
1807 | message: error.response?.data?.message || 'Fehler beim Löschen des Benutzers.'
1808 | };
1809 | }
1810 | }
1811 | default:
1812 | throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
1813 | }
1814 | }
1815 | catch (error) {
1816 | console.error(t.errorHandlingRequest.replace('${error}', error.message || JSON.stringify(error, null, 2)));
1817 | if (axios.isAxiosError(error)) {
1818 | const message = error.response?.data?.message ?? error.message;
1819 | console.error(t.apiErrorDetails.replace('${status}', error.response?.status || 'Unknown').replace('${data}', JSON.stringify(error.response?.data || {}, null, 2)));
1820 | return {
1821 | content: [
1822 | {
1823 | type: 'text',
1824 | text: `API error: ${message}`
1825 | }
1826 | ],
1827 | isError: true
1828 | };
1829 | }
1830 | throw error;
1831 | }
1832 | });
1833 | }
1834 |
1835 | /* ##################################################################################################
1836 | # MESSAGE HANDLER
1837 | ##################################################################################################*/
1838 | async run() {
1839 | const isPortInUse = (port) => new Promise((resolve, reject) => {
1840 | const tester = net.createServer()
1841 | .once('error', (err) => (err.code === 'EADDRINUSE' ? resolve(true) : reject(err)))
1842 | .once('listening', () => tester.once('close', () => resolve(false)).close())
1843 | .listen(port);
1844 | });
1845 |
1846 | const PORT = Port;
1847 | if (await isPortInUse(PORT)) {
1848 | throw new Error(t.portInUse.replace('${PORT}', PORT));
1849 | }
1850 |
1851 | const transport = new TcpServerTransport(PORT);
1852 | await transport.start(async (message) => {
1853 | try {
1854 | console.log(t.incomingMessage, message);
1855 |
1856 | // Token-Validierung nur durchführen, wenn es nicht der "login"-Befehl ist
1857 | //if (message.command !== 'login') {
1858 | // const tokenValidation = validateToken(message.token);
1859 | // if (tokenValidation) return tokenValidation;
1860 | // }
1861 |
1862 | if (!message || typeof message !== 'object') {
1863 | throw new McpError(ErrorCode.InvalidRequest, 'Ungültige Nachricht oder leere Anfrage.');
1864 | }
1865 |
1866 | // Verarbeite verschiedene Anfragen dynamisch
1867 | if (!message.command) {
1868 | throw new McpError(ErrorCode.InvalidRequest, 'Fehlender Befehlsparameter in der Nachricht.');
1869 | }
1870 | switch (message.command) {
1871 | /* 1.0 Login ######################################################################################*/
1872 | case 'login': {
1873 | const disabledResponse = checkToolEnabled('login');
1874 | if (disabledResponse) return disabledResponse;
1875 |
1876 | // Extrahiere die Argumente aus der Nachricht
1877 | const args = getArguments(message);
1878 | const { email, password: Pwd } = args;
1879 |
1880 | // Überprüfe, ob die E-Mail und das Passwort vorhanden sind
1881 | if (!email || !Pwd) {
1882 | return {
1883 | status: 'E10-M-1050',
1884 | message: 'E-Mail und Passwort sind erforderlich.',
1885 | };
1886 | }
1887 |
1888 | let password;
1889 |
1890 | // Passwort entschlüsseln, falls erforderlich
1891 | if (typeof PwEncryption !== 'undefined' && PwEncryption) {
1892 | password = decryptPassword(Pwd);
1893 | } else {
1894 | password = Pwd;
1895 | }
1896 |
1897 | try {
1898 | // Login-API aufrufen
1899 | const loginResponse = await this.axiosInstance.post('/login', { email, password });
1900 |
1901 | console.log(t.loginSuccess.replace('${data}', JSON.stringify(loginResponse.data)));
1902 |
1903 | // Token zurückgeben
1904 | return {
1905 | status: loginResponse.data?.status || 'ok', // Dynamisch, falls der API-Status einheitlich ist
1906 | message: loginResponse.data?.message || 'Login erfolgreich.', // API-Nachricht verwenden oder Standardnachricht
1907 | token: loginResponse.data?.data?.token, // Token aus API-Antwort
1908 | };
1909 | } catch (error) {
1910 | const errorMessage = error.response?.data || error.message;
1911 | console.error(t.loginError.replace('${error}', errorMessage));
1912 | // console.error('❌ Fehler beim Login:', error.response?.data || error.message);
1913 |
1914 | return {
1915 | status: error.response?.status || 'E10-M-1051', // API-Fehlerstatus oder Standardfehlerstatus,
1916 | message: error.response?.data || error.message || 'no error message'
1917 | };
1918 | }
1919 | }
1920 | /* 1.1 Logout #####################################################################################*/
1921 | case 'logout': {
1922 | const disabledResponse = checkToolEnabled('logout');
1923 | if (disabledResponse) return disabledResponse;
1924 |
1925 | const { token } = message;
1926 |
1927 | try {
1928 | const logoutResponse = await this.axiosInstance.delete('/logout', {
1929 | headers: {
1930 | Authorization: `Bearer ${token}`
1931 | }
1932 | });
1933 |
1934 | console.log(t.logoutSuccess.replace('${data}', JSON.stringify(logoutResponse.data)));
1935 | // console.log('✔️ Logout erfolgreich:', logoutResponse.data);
1936 |
1937 | return {
1938 | data: {}, // Optional: Zusätzliche Daten könnten hier eingefügt werden
1939 | status: logoutResponse.data?.status || 'no status', // Dynamisch, falls der API-Status einheitlich ist
1940 | message: logoutResponse.data?.message || 'no message', // API-Nachricht verwenden oder Standardnachricht
1941 | };
1942 | } catch (error) {
1943 | const logoutErrorMessage = error.response?.data || error.message;
1944 | console.error(t.logoutError.replace('${error}', logoutErrorMessage));
1945 | // console.error('❌ Fehler beim Logout:', error.response?.data || error.message);
1946 | return {
1947 | data: {},
1948 | message: error.response?.data || error.message || 'no error message',
1949 | status: error.response?.status || 'E11-M-1150', // Internal Server Error oder spezifischer Statuscode
1950 | };
1951 | }
1952 | }
1953 | /* 2.0 Chat #######################################################################################*/
1954 | case 'chat': {
1955 | const disabledResponse = checkToolEnabled('chat');
1956 | if (disabledResponse) return disabledResponse;
1957 |
1958 | // Extrahiere den Token und die Argumente
1959 | const token = message.token; // Token direkt extrahieren
1960 | const args = message.arguments || {}; // Sichere Extraktion der Argumente
1961 | const { question, usePublic, groups, language } = args;
1962 |
1963 | //const { token, arguments: args } = message;
1964 | // const { token, question, usePublic, groups, language } = args;
1965 |
1966 | // Argument-Validierung
1967 | if (!args || !args.question) {
1968 | return {
1969 | status: 'E20-M-2050',
1970 | message: 'Fehlende Frage in den Argumenten.',
1971 | };
1972 | }
1973 |
1974 | console.log('message Extrahierter Token:', token);
1975 |
1976 | //const { question, usePublic, groups, language } = args;
1977 |
1978 | // Konflikt zwischen `usePublic` und `groups` lösen
1979 | if (usePublic && groups && groups.length > 0) {
1980 | console.warn("⚠️ Konflikt: usePublic wurde auf false gesetzt, da Gruppen angegeben sind.");
1981 | args.usePublic = false;
1982 | }
1983 |
1984 | try {
1985 | // API-Aufruf zur Verarbeitung der Chat-Anfrage
1986 | const response = await this.axiosInstance.post(
1987 | '/chats',
1988 | {
1989 | question,
1990 | usePublic: usePublic || false,
1991 | // groups: Array.isArray(groups) ? groups : [groups],
1992 | groups: Array.isArray(groups) ? groups : groups ? [groups] : [],
1993 | language: language || 'de',
1994 | },
1995 | {
1996 | headers: { Authorization: `Bearer ${token}` },
1997 | }
1998 | );
1999 |
2000 | const data = response.data?.data || {};
2001 | console.log(t.chatResponseSuccess.replace('${data}', JSON.stringify(data)));
2002 |
2003 | // Erfolgsantwort mit Status und Daten
2004 | return {
2005 | status: response.data?.status || 'ok',
2006 | message: response.data?.message || 'Chat erfolgreich.',
2007 | content: {
2008 | chatId: data.chatId,
2009 | answer: data.answer,
2010 | sources: data.sources || [],
2011 | },
2012 | };
2013 | } catch (error) {
2014 | const chatApiErrorMessage = error.message || error.response?.data;
2015 | console.error(t.chatApiError.replace('${error}', chatApiErrorMessage));
2016 |
2017 | // Fehlerantwort mit Status und Nachricht
2018 | return {
2019 | status: error.response?.data?.status || error.message.status || 'E20-M-2051',
2020 | message: error.response?.data?.message || error.message || 'no error message',
2021 | };
2022 | }
2023 | }
2024 | /* 2.1 Continue Chat ##############################################################################*/
2025 | case 'continue_chat': {
2026 | const disabledResponse = checkToolEnabled('continue_chat');
2027 | if (disabledResponse) return disabledResponse;
2028 | //const { token, arguments: args } = message;
2029 | //const { token, chatId, question } = args;
2030 | const token = message.token; // Token direkt extrahieren
2031 | const args = message.arguments || {}; // Sichere Extraktion der Argumente
2032 |
2033 | //const { token } = message;
2034 | //const args = message.arguments || {};
2035 | const { chatId, question } = args;
2036 |
2037 |
2038 | if (!args || !args.chatId || !args.question) {
2039 | return { status: 'E21-M-2150', message: 'Fehlende erforderliche Parameter: chatId und/oder question.' };
2040 | }
2041 |
2042 | //const { chatId, question } = args;
2043 |
2044 | try {
2045 | const continueChatResponse = await this.axiosInstance.patch(
2046 | `/chats/${chatId}`,
2047 | { question },
2048 | { headers: { Authorization: `Bearer ${token}` } }
2049 | );
2050 | console.log(t.conversationSuccess.replace('${data}', JSON.stringify(continueChatResponse.data, null, 2)));
2051 | return {
2052 | content: {
2053 | chatId: continueChatResponse.data.data.chatId,
2054 | answer: continueChatResponse.data.data.answer,
2055 | sources: continueChatResponse.data.sources || [],
2056 | message: continueChatResponse.data.message,
2057 | status: continueChatResponse.data.status,
2058 | },
2059 | };
2060 | } catch (error) {
2061 | //console.error(`Fehler bei der API-Anfrage: ${error.message}`);
2062 | console.error(t.apiRequestError.replace('${error}', error.message));
2063 | return {
2064 | status: 'E21-M-2151',
2065 | message: error.response?.data?.message || error.message || 'no error message',
2066 | };
2067 | }
2068 | }
2069 | /* 2.2 Get Chat Info ##############################################################################*/
2070 | case 'get_chat_info': {
2071 | const disabledResponse = checkToolEnabled('get_chat_info');
2072 | if (disabledResponse) return disabledResponse;
2073 |
2074 | //const { token, chatId } = args;
2075 |
2076 | //const { token, arguments: args } = message;
2077 |
2078 | //const { chatId } = args;
2079 | const { token } = message; // Token direkt aus `message` extrahieren
2080 | const args = message.arguments || {}; // Argumente aus `message` extrahieren
2081 | const { chatId } = args; // chatId aus den Argumenten extrahieren
2082 |
2083 |
2084 | if (!chatId) {
2085 | return { status: 'E22-M-2250', message: 'chatId ist erforderlich, um Chat-Informationen abzurufen.' };
2086 | }
2087 |
2088 | try {
2089 | const response = await this.axiosInstance.get(`/chats/${chatId}`, {
2090 | headers: { Authorization: `Bearer ${token}` }
2091 | });
2092 |
2093 | const chatData = response.data?.data;
2094 |
2095 | if (!chatData) {
2096 | return {
2097 | status: 'E22-M-2251',
2098 | message: t.noChatData,
2099 | };
2100 | }
2101 |
2102 | // Formatiertes Ergebnis zurückgeben
2103 | return {
2104 | data: {
2105 | chatId: chatData.chatId,
2106 | title: chatData.title || 'Unbenannter Chat',
2107 | language: chatData.language || 'Unbekannt',
2108 | groups: chatData.groups || [],
2109 | messages: chatData.messages || []
2110 | },
2111 | message: response.data?.message || 'Erfolgreich abgerufen.'
2112 | };
2113 | } catch (error) {
2114 | const fetchChatErrorMessage = error.message || error.response?.data;
2115 | console.error(t.fetchChatInfoError.replace('${error}', fetchChatErrorMessage));
2116 | return {
2117 | status: 'E22-M-2252',
2118 | message: error.response?.data?.message || error.message || 'no error message'
2119 | };
2120 | }
2121 | }
2122 | /* 3.0 Create Source ##############################################################################*/
2123 | case 'create_source': {
2124 | const disabledResponse = checkToolEnabled('create_source');
2125 | if (disabledResponse) return disabledResponse;
2126 |
2127 | const args = getArguments(message);
2128 | // const args = request.params.arguments;
2129 | const token = message.token;
2130 |
2131 | // Validierung: Erforderliche Parameter prüfen
2132 | if (!token) {
2133 | return { status: 'E30-M-3050', message: t.missingTokenError };
2134 | }
2135 | if (!args || !args.name || !args.content) {
2136 | return { status: 'E30-M-3051', message: t.missingParametersError.replace('${parameters}', 'name und content') };
2137 | }
2138 |
2139 | const { name, content, groups } = args;
2140 |
2141 | try {
2142 | // Gruppenvalidierung vorab durchführen
2143 | if (groups && groups.length > 0) {
2144 | const groupValidation = await this.validateGroups(groups, token);
2145 | if (!groupValidation.isValid) {
2146 | return {
2147 | status: 'E30-M-3052',
2148 | message: t.invalidGroupsError.replace('${invalidGroups}', groupValidation.invalidGroups.join(', '))
2149 | };
2150 | }
2151 | }
2152 |
2153 | // API-Aufruf zur Erstellung der Quelle
2154 | const createSourceResponse = await this.axiosInstance.post(
2155 | '/sources',
2156 | { name, content, groups },
2157 | { headers: { Authorization: `Bearer ${token}` } }
2158 | );
2159 |
2160 | console.log('✔️ Quelle erfolgreich erstellt:', createSourceResponse.data);
2161 |
2162 | // Erfolgsantwort
2163 | return {
2164 | status: createSourceResponse.data?.status || 'ok',
2165 | message: createSourceResponse.data?.message || 'Quelle erfolgreich erstellt.',
2166 | data: createSourceResponse.data?.data,
2167 | };
2168 | } catch (error) {
2169 | // console.error('❌ Fehler beim Erstellen der Quelle:', error.response?.data || error.message);
2170 | const createSourceError = error.response?.data || error.message;
2171 | console.error(t.createSourceError.replace('${error}', createSourceError));
2172 |
2173 | // Fehlerhafte Antwort
2174 | if (error.response) {
2175 | return {
2176 | status: 'E30-M-3053',
2177 | message: error.response?.data?.message || error.message || 'no error message',
2178 | details: {
2179 | status: error.response.status,
2180 | headers: error.response.headers,
2181 | data: error.response.data,
2182 | },
2183 | };
2184 | } else if (error.request) {
2185 | return {
2186 | status: 'E30-M-3054',
2187 | message: t.noServerResponse,
2188 | details: { request: error.request },
2189 | };
2190 | } else {
2191 | return {
2192 | status: 'E30-M-3055',
2193 | message: error.message || 'Ein unbekannter Fehler ist aufgetreten.',
2194 | };
2195 | }
2196 | }
2197 | }
2198 | /* 3.1 Get Source #################################################################################*/
2199 | case 'get_source': {
2200 | const disabledResponse = checkToolEnabled('get_source');
2201 | if (disabledResponse) return disabledResponse;
2202 | const { token, arguments: args } = message; // Extrahiere den Token und die Argumente
2203 | //const { token, sourceId } = args;
2204 | const { sourceId } = args; // Extrahiere sourceId aus den Argumenten
2205 |
2206 | if (!sourceId) {
2207 | return { status: 'E31-M-3150', message: t.groupNameRequired.replace('${param}', 'sourceId') };
2208 | }
2209 |
2210 | console.log(t.makingGetSourceRequest.replace('${sourceId}', sourceId));
2211 |
2212 | try {
2213 | const sourceResponse = await this.axiosInstance.get(`/sources/${sourceId}`, {
2214 | headers: {
2215 | Authorization: `Bearer ${token}`, // Nutze den vom Client bereitgestellten Token
2216 | },
2217 | });
2218 |
2219 | console.log(t.gotGetSourceResponse.replace('${data}', JSON.stringify(sourceResponse.data, null, 2)));
2220 |
2221 | return {
2222 | content: sourceResponse.data,
2223 | };
2224 | } catch (error) {
2225 | console.error(t.errorHandlingRequest.replace('${error}', error.message || JSON.stringify(error, null, 2)));
2226 | return {
2227 | status: 'E31-M-3151',
2228 | message: t.apiErrorDetails
2229 | .replace('${status}', error.response?.status || 'E31-M-3151')
2230 | .replace('${data}', JSON.stringify(error.response?.data || {}, null, 2)),
2231 | };
2232 | }
2233 | }
2234 | /* 3.2 List Sources ###############################################################################*/
2235 | case 'list_sources': {
2236 | const disabledResponse = checkToolEnabled('list_sources');
2237 | if (disabledResponse) return disabledResponse;
2238 | const { token, attributes } = message; // Extrahiere den Token und die Attribute
2239 |
2240 | //const { token, groupName } = args;
2241 | if (!attributes || !attributes.groupName) {
2242 | return { status: 'E32-M-3250', message: 'Gruppenname erforderlich für diese Anfrage.' };
2243 | }
2244 |
2245 | const groupName = attributes.groupName; // Extrahiere den groupName aus attributes
2246 | console.log(t.fetchingSources.replace('${groupName}', groupName));
2247 |
2248 | try {
2249 | // Führe die API-Anfrage aus, um die Quellen für die Gruppe zu erhalten
2250 | const sourceResponse = await this.axiosInstance.post(
2251 | '/sources/groups',
2252 | { groupName },
2253 | {
2254 | headers: {
2255 | Authorization: `Bearer ${token}`, // Nutze den vom Client bereitgestellten Token
2256 | },
2257 | }
2258 | );
2259 |
2260 | console.log(t.sourcesRetrieved.replace('${data}', JSON.stringify(sourceResponse.data, null, 2)));
2261 |
2262 | return {
2263 | content: sourceResponse.data, // Sende die Antwort zurück
2264 | };
2265 | } catch (error) {
2266 | console.error(t.groupValidationError.replace('${error}', error.message || JSON.stringify(error)));
2267 | return {
2268 | status: 'E32-M-3251',
2269 | message: error.response?.data?.message || error.message || 'no error message',
2270 | };
2271 | // status: 'error',
2272 | //message: t.groupFetchError,
2273 | }
2274 | }
2275 | /* 3.3 Edit Source ################################################################################*/
2276 | case 'edit_source': {
2277 | const disabledResponse = checkToolEnabled('edit_source');
2278 | if (disabledResponse) return disabledResponse;
2279 |
2280 | const { token, arguments: args } = message;
2281 |
2282 | const { sourceId, title, content, groups } = args;
2283 |
2284 | // Validierung: Erforderliche Parameter
2285 | if (!sourceId) {
2286 | return {
2287 | data: {},
2288 | message: t.missingParameterError.replace('${parameter}', 'sourceId'),
2289 | status: 'E33-M-3350', // Bad Request
2290 | };
2291 | }
2292 |
2293 | // console.log(`Bearbeite Quelle mit ID: ${sourceId}, Titel: ${title || 'unverändert'}`);
2294 | console.log(
2295 | t.editSourceLog
2296 | .replace('${sourceId}', sourceId)
2297 | .replace('${title}', title || 'unverändert')
2298 | );
2299 |
2300 | try {
2301 | // API-Aufruf: Quelle bearbeiten
2302 | const payload = {};
2303 | if (title) payload.title = title;
2304 | if (content) payload.content = content;
2305 | if (groups) payload.groups = groups;
2306 |
2307 | const editSourceResponse = await this.axiosInstance.patch(
2308 | `/sources/${sourceId}`,
2309 | payload,
2310 | {
2311 | headers: {
2312 | Authorization: `Bearer ${token}`, // Nutze den bereitgestellten Token
2313 | },
2314 | }
2315 | );
2316 |
2317 | console.log(t.editSourceSuccess.replace('${data}', JSON.stringify(editSourceResponse.data, null, 2)));
2318 |
2319 | // Erfolgreiche Antwort
2320 | return {
2321 | data: editSourceResponse.data?.data || {}, // Optionale Daten aus der API
2322 | message: editSourceResponse.data?.message || 'Quelle erfolgreich bearbeitet.',
2323 | status: editSourceResponse.status || 200, // OK
2324 | };
2325 | } catch (error) {
2326 | const editSourceError = error.message || JSON.stringify(error.response?.data);
2327 | console.error(t.editSourceError.replace('${error}', editSourceError));
2328 |
2329 | // console.error(`❌ Fehler beim Bearbeiten der Quelle: ${error.message || JSON.stringify(error.response?.data)}`);
2330 |
2331 | // Fehlerhafte Antwort
2332 | return {
2333 | data: {},
2334 | message: error.response?.data?.message || 'Bearbeiten der Quelle fehlgeschlagen. Bitte versuchen Sie es später erneut.',
2335 | status: error.response?.status || 'E33-M-3351', // Internal Server Error
2336 | };
2337 | }
2338 | }
2339 | /* 3.4 Delete Source ##############################################################################*/
2340 | case 'delete_source': {
2341 | const disabledResponse = checkToolEnabled('delete_source');
2342 | if (disabledResponse) return disabledResponse;
2343 |
2344 | const { token, arguments: args } = message;
2345 | const { sourceId } = args;
2346 |
2347 | if (!sourceId) {
2348 | return { status: 'E34-M-3450', message: t.groupNameRequired.replace('${param}', 'sourceId') };
2349 | }
2350 |
2351 | try {
2352 | const deleteResponse = await this.axiosInstance.delete(`/sources/${sourceId}`, {
2353 | headers: { Authorization: `Bearer ${token}` },
2354 | });
2355 |
2356 | console.log(`Quelle erfolgreich gelöscht: ${JSON.stringify(deleteResponse.data, null, 2)}`);
2357 |
2358 | return {
2359 | content: deleteResponse.data,
2360 | };
2361 | } catch (error) {
2362 | console.error(t.errorHandlingRequest.replace('${error}', error.message || JSON.stringify(error, null, 2)));
2363 | return {
2364 | status: 'E34-M-3451',
2365 | message: t.apiErrorDetails
2366 | .replace('${status}', error.response?.status || 'E34-M-3451')
2367 | .replace('${data}', JSON.stringify(error.response?.data || {}, null, 2)),
2368 | };
2369 | }
2370 | }
2371 | /* 4.0 List Groups ################################################################################*/
2372 | case 'list_groups': {
2373 | const disabledResponse = checkToolEnabled('list_groups');
2374 | if (disabledResponse) return disabledResponse;
2375 | //const token = message.arguments?.token || message.token;
2376 | const token = message.token; // Token direkt aus `message` extrahieren
2377 |
2378 | try {
2379 | await this.ensureAuthenticated(token);
2380 |
2381 | const response = await this.axiosInstance.get('/groups');
2382 | let assignableGroups = response.data?.data?.assignableGroups || [];
2383 | const personalGroups = response.data?.data?.personalGroups || [];
2384 | const message = response.data?.message || 'no_message'; // Fallback für Nachricht
2385 | const status = response.data?.status || 'E40-M-4050'; // Fallback für Status
2386 |
2387 |
2388 | if (isRestrictedGroupsEnabled) {
2389 | // console.log('⚠️ RESTRICTED_GROUPS aktiviert. Verfügbare Gruppen werden eingeschränkt.');
2390 | console.log(t.restrictedGroupsWarning);
2391 | assignableGroups = ["NO ACCESS ALLOWED BY THE MCP-SERVER CONFIG"]; // Alle assignableGroups entfernen
2392 | }
2393 |
2394 | return {
2395 | data: {
2396 | personalGroups,
2397 | assignableGroups,
2398 | message,
2399 | status,
2400 | },
2401 | };
2402 | } catch (error) {
2403 | const fetchGroupsError = error.message || JSON.stringify(error.response?.data);
2404 | console.error(t.fetchGroupsError.replace('${error}', fetchGroupsError));
2405 |
2406 |
2407 | // Detaillierte Fehlerbehandlung
2408 | if (axios.isAxiosError(error)) {
2409 | const status = error.response?.status;
2410 | const serverMessage = error.response?.data?.message || error.message || 'no error message';
2411 | return {
2412 | status: 'E40-M-4051',
2413 | message: `Fehler beim Abrufen der Gruppen: ${serverMessage} (Status: ${status})`,
2414 | };
2415 | }
2416 |
2417 | return {
2418 | status: 'E40-M-4052',
2419 | message: 'Ein unbekannter Fehler ist aufgetreten.',
2420 | };
2421 | }
2422 | }
2423 | /* 4.1 Store Group ################################################################################*/
2424 | case 'store_group': {
2425 | const disabledResponse = checkToolEnabled('store_group');
2426 | if (disabledResponse) return disabledResponse;
2427 |
2428 | //const { groupName, description } = args; // Einheitliche Extraktion über getArguments
2429 | const { groupName, description } = message.arguments; // Extrahiere die Argumente
2430 | const clientToken = message.token; // Token aus der Anfrage
2431 |
2432 | if (!groupName || !description) {
2433 | return { status: 'E41-M-4150', message: 'Fehlende erforderliche Parameter: groupName und description.' };
2434 | }
2435 |
2436 | if (!clientToken) {
2437 | return { status: 'E41-M-4151', message: t.missingTokenError };
2438 | }
2439 |
2440 | try {
2441 | // API-Aufruf mit dem vom Client bereitgestellten Token
2442 | const createGroupResponse = await this.axiosInstance.post(
2443 | '/groups',
2444 | { groupName, description },
2445 | {
2446 | headers: {
2447 | Authorization: `Bearer ${clientToken}` // Nutze nur den Client-Token
2448 | }
2449 | }
2450 | );
2451 |
2452 | console.log(t.createGroupSuccess.replace('${data}', JSON.stringify(createGroupResponse.data)));
2453 |
2454 | return {
2455 | content: createGroupResponse.data,
2456 | };
2457 | } catch (error) {
2458 | // console.error('❌ Fehler bei der API-Anfrage:', error.response?.data || error.message);
2459 | const apiError = error.response?.data || error.message;
2460 | console.error(t.apiRequestError.replace('${error}', apiError));
2461 | return {
2462 | status: 'E41-M-4152',
2463 | message: error.response?.data?.message || error.message || 'no error message',
2464 | };
2465 | }
2466 | }
2467 | /* 4.2 Delete Group ###############################################################################*/
2468 | case 'delete_group': {
2469 | const disabledResponse = checkToolEnabled('delete_group');
2470 | if (disabledResponse) return disabledResponse;
2471 |
2472 | //const { token, groupName } = args;
2473 |
2474 | const { token, arguments: args } = message; // Extrahiere Token und Argumente
2475 | const { groupName } = args;
2476 |
2477 | if (!groupName) {
2478 | return { status: 'E42-M-4250', message: 'Fehlender erforderlicher Parameter: groupName.' };
2479 | }
2480 |
2481 | // console.log(`Lösche Gruppe mit Name: ${groupName}`);
2482 | console.log(t.deleteGroupLog.replace('${groupName}', groupName));
2483 |
2484 |
2485 | try {
2486 | // API-Aufruf mit dem Token des Clients
2487 | const deleteGroupResponse = await this.axiosInstance.delete('/groups', {
2488 | data: { groupName }, // JSON-Body für DELETE-Request
2489 | headers: {
2490 | Authorization: `Bearer ${token}`, // Nutze den vom Client bereitgestellten Token
2491 | },
2492 | });
2493 |
2494 | console.log(t.deleteGroupSuccessLog.replace('${data}', JSON.stringify(deleteGroupResponse.data)));
2495 |
2496 | return {
2497 | data: deleteGroupResponse.data?.data || {},
2498 | message: deleteGroupResponse.data?.message || 'success',
2499 | status: deleteGroupResponse.status || 200,
2500 | };
2501 | } catch (error) {
2502 | // console.error(`❌ Fehler beim Löschen der Quelle: ${error.message || JSON.stringify(error.response?.data)}`);
2503 | const deleteSourceError = error.message || JSON.stringify(error.response?.data);
2504 | console.error(t.deleteSourceError.replace('${error}', deleteSourceError));
2505 |
2506 |
2507 | // Fehlerhafte Antwort
2508 | return {
2509 | data: {},
2510 | message: error.response?.data?.message || error.message || 'no error message',
2511 | status: error.response?.status || 'E42-M-4251', // Internal Server Error oder spezifischer Statuscode
2512 | };
2513 | }
2514 | }
2515 | /* 5.0 Store User #################################################################################*/
2516 | case 'store_user': {
2517 | const disabledResponse = checkToolEnabled('store_user');
2518 | if (disabledResponse) return disabledResponse;
2519 | const { token, arguments: args } = message;
2520 |
2521 | //const { token, name, email, password } = args;
2522 |
2523 | if (!args || !args.name || !args.email || !args.password) {
2524 | return { status: 'E50-M-5050', message: 'Fehlende erforderliche Parameter: name, email oder password.' };
2525 | }
2526 |
2527 |
2528 | // Extrahiere die Argumente aus der Nachricht
2529 | //const args = getArguments(message);
2530 | const Pwd = args.password;
2531 |
2532 | // Überprüfe, ob die E-Mail und das Passwort vorhanden sind
2533 | if (!Pwd) {
2534 | return {
2535 | status: 'E10-M-1050',
2536 | message: 'Passwort ist erforderlich.',
2537 | };
2538 | }
2539 |
2540 | let password;
2541 |
2542 | // Passwort entschlüsseln, falls erforderlich
2543 | if (typeof PwEncryption !== 'undefined' && PwEncryption) {
2544 | password = decryptPassword(Pwd);
2545 | } else {
2546 | password = Pwd;
2547 | }
2548 |
2549 |
2550 | try {
2551 | // Payload für die API-Anfrage
2552 | const payload = {
2553 | name: args.name,
2554 | email: args.email,
2555 | language: args.language || 'en',
2556 | timezone: args.timezone || 'Europe/Berlin',
2557 | password: password,
2558 | usePublic: args.usePublic || false,
2559 | groups: args.groups || [],
2560 | roles: args.roles || [],
2561 | activateFtp: args.activateFtp || false,
2562 | ftpPassword: args.ftpPassword || '',
2563 | };
2564 |
2565 | console.log(t.createUserLog.replace('${payload}', JSON.stringify(payload)));
2566 |
2567 | // API-Aufruf
2568 | const createUserResponse = await this.axiosInstance.post('/users', payload, {
2569 | headers: {
2570 | Authorization: `Bearer ${token}`
2571 | }
2572 | });
2573 |
2574 | console.log(t.createUserSuccess.replace('${data}', JSON.stringify(createUserResponse.data)));
2575 |
2576 | return {
2577 | content: createUserResponse.data,
2578 | };
2579 | } catch (error) {
2580 | const createUserError = error.response?.data || error.message;
2581 | console.error(t.createUserError.replace('${error}', createUserError));
2582 |
2583 | // console.error('❌ Fehler beim Erstellen des Benutzers:', error.response?.data || error.message);
2584 |
2585 | const errors = error.response?.data?.errors;
2586 | if (errors) {
2587 | const errorMessages = [];
2588 | for (const [key, messages] of Object.entries(errors)) {
2589 | messages.forEach(message => errorMessages.push(`${key}: ${message}`));
2590 | }
2591 |
2592 | return {
2593 | status: 'E50-M-5051',
2594 | message: 'Fehler beim Erstellen des Benutzers:',
2595 | errors: errorMessages
2596 | };
2597 | }
2598 |
2599 | return {
2600 | status: 'E50-M-5052',
2601 | message: error.response?.data?.message || error.message || 'no error message',
2602 | };
2603 | }
2604 | }
2605 | /* 5.1 Edit User ##################################################################################*/
2606 | case 'edit_user': {
2607 | const disabledResponse = checkToolEnabled('edit_user');
2608 | if (disabledResponse) return disabledResponse;
2609 |
2610 | const { token, arguments: args } = message;
2611 | const tokenValidation = validateToken(token);
2612 | if (tokenValidation) return tokenValidation;
2613 |
2614 | // Mindestens die E-Mail muss angegeben sein, um den User zu identifizieren
2615 | if (!args || !args.email) {
2616 | return {
2617 | status: 'E51-R-5100',
2618 | message: 'Die E-Mail des Benutzers ist erforderlich, um den Datensatz zu bearbeiten.'
2619 | };
2620 | }
2621 |
2622 | let password = null;
2623 |
2624 | if (args.password) {
2625 | const Pwd = args.password;
2626 | if (!Pwd) {
2627 | return {
2628 | status: 'E51-M-1050',
2629 | message: 'Passwort ist erforderlich.',
2630 | };
2631 | }
2632 | if (typeof PwEncryption !== 'undefined' && PwEncryption) {
2633 | password = decryptPassword(Pwd);
2634 | } else {
2635 | password = Pwd;
2636 | }
2637 | }
2638 |
2639 | try {
2640 | // Nur Felder senden, die tatsächlich aktualisiert werden sollen
2641 | const payload = {};
2642 | if (args.name) payload.name = args.name;
2643 | if (args.password) payload.password = password;
2644 | if (args.language) payload.language = args.language;
2645 | if (args.timezone) payload.timezone = args.timezone;
2646 | if (Array.isArray(args.roles)) payload.roles = args.roles;
2647 | if (Array.isArray(args.groups)) payload.groups = args.groups;
2648 | if (typeof args.usePublic === 'boolean') payload.usePublic = args.usePublic;
2649 |
2650 | // E-Mail ist Pflicht, um den Benutzer auf dem Server zu finden
2651 | payload.email = args.email;
2652 | const response = await this.axiosInstance.patch(
2653 | '/users',
2654 | payload,
2655 | {
2656 | headers: { Authorization: `Bearer ${token}` }
2657 | }
2658 | );
2659 | console.log(t.editUserSuccess.replace('${data}', JSON.stringify(response.data)));
2660 |
2661 | return {
2662 | status: response.data?.status || 'ok',
2663 | message: response.data?.message || 'Benutzer erfolgreich bearbeitet.',
2664 | data: response.data?.data
2665 | };
2666 | } catch (error) {
2667 | const editUserError = error.response?.data || error.message;
2668 | console.error(t.editUserError.replace('${error}', editUserError));
2669 | // console.error('❌ Fehler beim Bearbeiten des Benutzers:', error.response?.data || error.message);
2670 | return {
2671 | status: error.response?.status || 'E51-M-5151',
2672 | message: error.response?.data?.message || 'Fehler beim Bearbeiten des Benutzers.'
2673 | };
2674 | }
2675 | /*
2676 | const { token, arguments: args } = message;
2677 |
2678 | //const { token, email, ...updates } = args;
2679 | const { email, ...updates } = args;
2680 |
2681 | if (!email) {
2682 | return { status: 'E51-M-5150', message: 'Email ist erforderlich, um einen Benutzer zu bearbeiten.' };
2683 | }
2684 |
2685 | try {
2686 | const response = await this.axiosInstance.patch(
2687 | '/users',
2688 | { email, ...updates },
2689 | { headers: { Authorization: `Bearer ${token}` } }
2690 | );
2691 |
2692 | console.log(t.editUserSuccess.replace('${data}', JSON.stringify(response.data)));
2693 |
2694 | return {
2695 | content: response.data,
2696 | };
2697 | } catch (error) {
2698 | const editUserError = error.response?.data || error.message;
2699 | console.error(t.editUserError.replace('${error}', editUserError));
2700 | // console.error('❌ Fehler beim Bearbeiten des Benutzers:', error.response?.data || error.message);
2701 | return {
2702 | status: 'E51-M-5151',
2703 | message: error.response?.data?.message || error.message || 'no error message',
2704 | };
2705 | }*/
2706 | }
2707 | /* 5.2 Delete User ################################################################################*/
2708 | case 'delete_user': {
2709 | const disabledResponse = checkToolEnabled('delete_user');
2710 | if (disabledResponse) return disabledResponse;
2711 | const { token, arguments: args } = message;
2712 |
2713 | const { email } = args;
2714 | //const { token, email } = args;
2715 |
2716 | if (!email) {
2717 | return { status: 'E52-M-5250', message: 'Email ist erforderlich, um einen Benutzer zu löschen.' };
2718 | }
2719 |
2720 | try {
2721 | const response = await this.axiosInstance.delete(
2722 | '/users',
2723 | {
2724 | data: { email },
2725 | headers: { Authorization: `Bearer ${token}` }
2726 | }
2727 | );
2728 |
2729 | console.log(t.deleteUserSuccess.replace('${data}', JSON.stringify(response.data)));
2730 |
2731 | return {
2732 | content: response.data,
2733 | };
2734 | } catch (error) {
2735 | const deleteUserError = error.response?.data || error.message;
2736 | console.error(t.deleteUserError.replace('${error}', deleteUserError));
2737 | // console.error('❌ Fehler beim Löschen des Benutzers:', error.response?.data || error.message);
2738 | return {
2739 | status: 'E52-M-5251',
2740 | message: error.response?.data?.message || error.message || 'no error message',
2741 | };
2742 | }
2743 | }
2744 | /* 9.0 Generate Key ###############################################################################*/
2745 | case 'keygen': {
2746 | const disabledResponse = checkToolEnabled('keygen');
2747 | if (disabledResponse) return disabledResponse;
2748 |
2749 | const { password } = message.arguments;
2750 |
2751 | try {
2752 | // Passwort verschlüsseln
2753 | const encryptedPassword = getEncryptedKey(password);
2754 |
2755 | // Schlüssel zurückgeben
2756 | return {
2757 | data: {
2758 | key: encryptedPassword
2759 | },
2760 | status: 'ok',
2761 | message: 'Keygen erfolgreich.',
2762 | };
2763 | } catch (error) {
2764 | console.error('❌ Fehler bei der Keygen-Anfrage:', error.message);
2765 | return {
2766 | data: {},
2767 | message: error.message || 'Keygen fehlgeschlagen.',
2768 | status: 'E90-M-1150',
2769 | };
2770 | }
2771 | }
2772 | }
2773 | } catch (err) {
2774 | console.error(t.tcpServerError, err.message || err);
2775 | return { status: 'E52-M-5252', message: err.message || t.internalServerError };
2776 | }
2777 | });
2778 | }
2779 | }
2780 | const server = new PrivateGPTServer();
2781 | // Server läuft
2782 | console.log(
2783 | messages[lang].serverRunning
2784 | .replace('${port}', PORT)
2785 | );
2786 | server.run().catch(console.error);
```