#
tokens: 47792/50000 10/511 files (page 14/20)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 14 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

--------------------------------------------------------------------------------
/examples/sftp_upload_with_id/language.py:
--------------------------------------------------------------------------------

```python
  1 | # Python/language.py
  2 | 
  3 | languages = {
  4 |     "en": {
  5 |         "welcome": "🎉 PGPT Agent. Type your question or 'exit' to quit.",
  6 |         "invalid_group": (
  7 |             "❌ Invalid group(s): {groups}. Please correct and restart."
  8 |         ),
  9 |         "invalid_group_error": (
 10 |             "❌ Invalid group(s) found. Terminating the agent."
 11 |         ),
 12 |         "authentication_failed": (
 13 |             "🔒 Authentication failed. Exiting."
 14 |         ),
 15 |         "goodbye": "👋 Goodbye!",
 16 |         "interrupted": "👋 Goodbye!",
 17 |         "configuration_error": "🔴 Configuration Error: {error}",
 18 |         "unexpected_error": "🔴 Unexpected Error: {error}",
 19 |         "login_attempt": "🔑 Attempting login...",
 20 |         "login_success": "✅ Login successful.",
 21 |         "login_failed": "❌ Login failed: {message}",
 22 |         "logout_attempt": "🚪 Attempting to logout...",
 23 |         "logout_success": "✅ Logout successful.",
 24 |         "logout_failed": "⚠️ Logout failed: {message}",
 25 |         "connecting_to_server": (
 26 |             "🔄 Connecting to {ip}:{port} "
 27 |             "(attempt {attempt}/{retries})..."
 28 |         ),
 29 |         "connection_established": "✅ Connection established.",
 30 |         "sending_payload": "📤 Sending payload: {payload}",
 31 |         "received_response": "📥 Received response: {response}",
 32 |         "formatted_response": "📥 Received response (formatted):",
 33 |         "personal_groups_received": (
 34 |             "📂 Personal groups from server: {groups}"
 35 |         ),
 36 |         "personal_groups": "📂 Personal groups from server: {groups}",
 37 |         "no_personal_groups": (
 38 |             "⚠️ No personal groups retrieved from the server."
 39 |         ),
 40 |         "run_failed_auth": "🔒 Authentication failed. Exiting.",
 41 |         "user_interface_started": "🗣️ User interface started.",
 42 |         "user_question": "You: ",
 43 |         "agent_answer": "Agent: {answer}",
 44 |         "agent_error": "Agent: {error}",
 45 |         "knowledge_ai": (
 46 |             "🤖 AI is a field of computer science focused "
 47 |             "on machines mimicking human intelligence."
 48 |         ),
 49 |         "knowledge_python": (
 50 |             "🐍 Python was created by Guido van Rossum and released in 1991."
 51 |         ),
 52 |         "knowledge_ml": (
 53 |             "📚 ML is a subfield of AI that aims to let machines learn "
 54 |             "from data."
 55 |         ),
 56 |         "unsupported_language_fallback": (
 57 |             "🔴 Unsupported language '{language}'. Falling back to English."
 58 |         ),
 59 |         "config_file_not_found": (
 60 |             "🔴 Config file '{config_file}' not found."
 61 |         ),
 62 |         "invalid_json_in_config": (
 63 |             "🔴 Invalid JSON in config file: {error}"
 64 |         ),
 65 |         "missing_required_fields": (
 66 |             "🔴 Missing required fields: {fields}"
 67 |         ),
 68 |         "group_validation_error": "🔴 {error}",
 69 |         "invalid_json_response": "❌ Invalid JSON response received.",
 70 |         "connection_timed_out": "⚠️ Connection timed out.",
 71 |         "connection_error": "❌ Connection error: {error}",
 72 |         "retrying_in_seconds": "🔄 Retrying in {delay} seconds...",
 73 |         "all_retries_failed": "❌ All retries failed.",
 74 |         "no_answer_received": "No answer received.",
 75 |         "unknown_error": "Unknown error.",
 76 |         "invalid_message_response": "Invalid message format received.",
 77 |         # Ergänzte Schlüssel:
 78 |         "no_server_message": "No message from server.",
 79 |         "no_data_in_response": "No data in response.",
 80 |         "list_groups_failed": "Failed to list groups: {message}",
 81 |         "knowledge_response": "Knowledge response for input: {input}",
 82 |         "session_ended": "Session ended successfully.",
 83 |         "session_interrupted": "Session interrupted.",
 84 |         "invalid_json_response": "❌ Invalid JSON response received.",
 85 |         "connection_timed_out": "⚠️ Connection timed out.",
 86 |         "connection_error": "❌ Connection error: {error}",
 87 |         "retrying_in_seconds": "🔄 Retrying in {delay} seconds...",
 88 |         "all_retries_failed": "❌ All retries failed.",
 89 |         "no_answer_received": "No answer received.",
 90 |         "unknown_error": "Unknown error.",
 91 |         "invalid_message_response": "Invalid message format received.",
 92 |         # Ergänzte Schlüssel:
 93 |         "no_server_message": "No message from server.",
 94 |         "no_data_in_response": "No data in response.",
 95 |         "list_groups_failed": "Failed to list groups: {message}",
 96 |         "knowledge_response": "Knowledge response for input: {input}",
 97 |         "session_ended": "Session ended successfully.",
 98 |         "session_interrupted": "Session interrupted.",
 99 |         "no_token_logout": "No token found for logout."
100 |     },
101 |     "de": {
102 |         "welcome": (
103 |             "🎉 PrivateGPT Agent. Bereit für Ihre Fragen "
104 |             "oder tippen Sie 'exit', um zu beenden."
105 |         ),
106 |         "invalid_group": (
107 |             "❌ Ungültige Gruppe(n): {groups}. Korrigieren und neu starten."
108 |         ),
109 |         "invalid_group_error": (
110 |             "❌ Ungültige Gruppe(n) gefunden. Beende den Agenten."
111 |         ),
112 |         "authentication_failed": (
113 |             "🔒 Authentifizierung fehlgeschlagen. Beende den Agenten."
114 |         ),
115 |         "goodbye": "👋 Auf Wiedersehen!",
116 |         "interrupted": "👋 Auf Wiedersehen!",
117 |         "configuration_error": "🔴 Konfigurationsfehler: {error}",
118 |         "unexpected_error": "🔴 Unerwarteter Fehler: {error}",
119 |         "login_attempt": (
120 |             "🔑 Versuche, mich anzumelden..."
121 |         ),
122 |         "login_success": "✅ Anmeldung erfolgreich.",
123 |         "login_failed": "❌ Anmeldung fehlgeschlagen: {message}",
124 |         "logout_attempt": (
125 |             "🚪 Versuche, mich abzumelden..."
126 |         ),
127 |         "logout_success": "✅ Abmeldung erfolgreich.",
128 |         "logout_failed": "⚠️ Abmeldung fehlgeschlagen: {message}",
129 |         "connecting_to_server": (
130 |             "🔄 Verbinde zu {ip}:{port} (Versuch {attempt}/{retries})..."
131 |         ),
132 |         "connection_established": "✅ Verbindung hergestellt.",
133 |         "sending_payload": "📤 Sende Payload: {payload}",
134 |         "received_response": "📥 Empfangene Antwort: {response}",
135 |         "formatted_response": "📥 Empfangene Antwort (formatiert):",
136 |         "personal_groups_received": (
137 |             "📂 Personal groups vom Server: {groups}"
138 |         ),
139 |         "personal_groups": "📂 Persönliche Gruppen vom Server: {groups}",
140 |         "no_personal_groups": (
141 |             "⚠️ Keine persönlichen Gruppen vom Server abgerufen."
142 |         ),
143 |         "run_failed_auth": (
144 |             "🔒 Authentifizierung fehlgeschlagen. Beende den Agenten."
145 |         ),
146 |         "user_interface_started": "🗣️ Benutzeroberfläche gestartet.",
147 |         "user_question": "Sie: ",
148 |         "agent_answer": "Agent: {answer}",
149 |         "agent_error": "Agent: {error}",
150 |         "knowledge_ai": (
151 |             "🤖 KI ist ein Bereich der Informatik, der sich "
152 |             "darauf konzentriert, Maschinen menschliche Intelligenz "
153 |             "nachzuahmen."
154 |         ),
155 |         "knowledge_python": (
156 |             "🐍 Python wurde von Guido van Rossum entwickelt "
157 |             "und 1991 veröffentlicht."
158 |         ),
159 |         "knowledge_ml": (
160 |             "📚 ML ist ein Teilbereich der KI, der darauf abzielt, "
161 |             "Maschinen das Lernen aus Daten zu ermöglichen."
162 |         ),
163 |         "unsupported_language_fallback": (
164 |             "🔴 Nicht unterstützte Sprache '{language}'. Fallback zu Englisch."
165 |         ),
166 |         "config_file_not_found": (
167 |             "🔴 Config-Datei '{config_file}' nicht gefunden."
168 |         ),
169 |         "invalid_json_in_config": (
170 |             "🔴 Ungültiges JSON in der Config-Datei: {error}"
171 |         ),
172 |         "missing_required_fields": (
173 |             "🔴 Fehlende erforderliche Felder: {fields}"
174 |         ),
175 |         "group_validation_error": "🔴 {error}",
176 |         "invalid_json_response": "❌ Ungültige JSON-Antwort empfangen.",
177 |         "connection_timed_out": "⚠️ Verbindung zeitlich begrenzt.",
178 |         "connection_error": "❌ Verbindungsfehler: {error}",
179 |         "retrying_in_seconds": "⏳ Erneuter Versuch in {delay} Sekunden...",
180 |         "all_retries_failed": "❌ Alle Wiederholungsversuche fehlgeschlagen.",
181 |         "no_answer_received": "Keine Antwort erhalten.",
182 |         "unknown_error": "Unbekannter Fehler.",
183 |         "invalid_message_response": "Ungültiges Nachrichtenformat empfangen.",
184 |         # Ergänzte Schlüssel:
185 |         "no_server_message": "Keine Nachricht vom Server erhalten.",
186 |         "no_data_in_response": "Keine Daten in der Antwort enthalten.",
187 |         "list_groups_failed": "Auflisten der Gruppen fehlgeschlagen: {message}",
188 |         "knowledge_response": "Wissensantwort für Eingabe: {input}",
189 |         "session_ended": "Sitzung erfolgreich beendet.",
190 |         "session_interrupted": "Sitzung unterbrochen.",
191 |         "no_token_logout": "Kein Token für Abmeldung gefunden."
192 |     },
193 |     # Weitere Sprachen können hier hinzugefügt werden
194 | }
195 | 
```

--------------------------------------------------------------------------------
/src/helper.js:
--------------------------------------------------------------------------------

```javascript
  1 | // helper.js
  2 | import fs from 'fs';
  3 | import path from 'path';
  4 | import os from 'os';
  5 | import crypto from 'crypto';
  6 | import { fileURLToPath } from 'url';
  7 | import { logEvent } from './logger.js';
  8 | import { messages } from './pgpt-messages.js';
  9 | 
 10 | /**
 11 |  * Lädt die Umgebungsvariablen aus der JSON-Datei.
 12 |  * @param {string} envFilePath - Der Pfad zur JSON-Umgebungsdatei.
 13 |  * @returns {object} - Das geladene Konfigurationsobjekt.
 14 |  */
 15 | function loadEnvConfig(envFilePath) {
 16 |     try {
 17 |         const config = JSON.parse(fs.readFileSync(envFilePath, 'utf-8'));
 18 |         return config;
 19 |     } catch (error) {
 20 |         logEvent('system', 'N/A', 'Env Load Err', error.message, 'error');
 21 |         process.exit(1);
 22 |     }
 23 | }
 24 | 
 25 | /**
 26 |  * Funktion zum Abrufen von Umgebungsvariablen mit optionalem verschachteltem Pfad und Fallback.
 27 |  * @param {object} envConfig - Das Konfigurationsobjekt.
 28 |  * @param {string} key - Der Schlüssel der Umgebungsvariable.
 29 |  * @param {Array<string>} [nestedPath=null] - Ein optionaler verschachtelter Pfad.
 30 |  * @param {any} [fallback=null] - Ein optionaler Fallback-Wert.
 31 |  * @param {string} lang - Die gewählte Sprache.
 32 |  * @returns {any} - Der Wert der Umgebungsvariable oder der Fallback-Wert.
 33 |  */
 34 | function getEnvVar(envConfig, key, nestedPath = null, fallback = null, lang = 'en') {
 35 |     const t = messages[lang];
 36 |     // Prüfen, ob ein verschachtelter Pfad angegeben ist
 37 |     if (nestedPath) {
 38 |         const value = nestedPath.reduce((acc, part) => acc && acc[part], envConfig);
 39 |         if (value === undefined || value === null) {
 40 |             if (fallback !== null) return fallback;
 41 |             logEvent(
 42 |                 'system',
 43 |                 'N/A',
 44 |                 'Missing Config',
 45 |                 t.missingConfigError.replace('${key}', key),
 46 |                 'error'
 47 |             );
 48 |             process.exit(1);
 49 |         }
 50 |         return value;
 51 |     }
 52 |     // Direkter Zugriff
 53 |     if (envConfig[key] === undefined || envConfig[key] === null) {
 54 |         if (fallback !== null) return fallback;
 55 |         logEvent('system', 'N/A', 'Missing Config', `Missing .json configuration variable: ${key}`, 'error');
 56 |         process.exit(1);
 57 |     }
 58 |     return envConfig[key];
 59 | }
 60 | 
 61 | /**
 62 |  * Funktion zur Pfad-Expansion.
 63 |  * @param {string} filePath - Der zu erweiternde Pfad.
 64 |  * @returns {string} - Der erweiterte Pfad.
 65 |  */
 66 | function expandPath(filePath) {
 67 |     if (filePath.startsWith('~')) {
 68 |         return path.join(os.homedir(), filePath.slice(1));
 69 |     }
 70 |     return filePath;
 71 | }
 72 | 
 73 | /**
 74 |  * Validiert eine URL und passt sie gegebenenfalls an.
 75 |  * @param {string} url - Die zu validierende URL.
 76 |  * @param {object} t - Die Übersetzungen basierend auf der Sprache.
 77 |  * @returns {string} - Die validierte und ggf. angepasste URL.
 78 |  */
 79 | function validateUrl(url, t) {
 80 |     if (!url.startsWith('https://')) {
 81 |         logEvent('system', 'N/A', 'URL Warning', t.apiUrlWarning, 'warn');
 82 |         url = url.replace(/^http:\/\//, 'https://');
 83 |     }
 84 |     url = url.replace(/([^:]\/)\/+/g, '$1'); // Doppelte Schrägstriche nach "://" entfernen
 85 |     if (!url.endsWith('/api/v1')) {
 86 |         logEvent('system', 'N/A', 'URL Warning V1', t.apiUrlWarningV1, 'warn');
 87 |         url = `${url.replace(/\/$/, '')}/api/v1`;
 88 |     }
 89 |     try {
 90 |         new URL(url);
 91 |     } catch {
 92 |         logEvent('system', 'N/A', 'URL Invalid', `${t.apiUrlInvalid} ${url}`, 'error');
 93 |         process.exit(1);
 94 |     }
 95 |     return url;
 96 | }
 97 | 
 98 | /**
 99 |  * Validiert einen Port.
100 |  * @param {string} port - Der zu validierende Port.
101 |  * @param {object} t - Die Übersetzungen basierend auf der Sprache.
102 |  * @returns {number} - Der validierte Port.
103 |  */
104 | function validatePort(port, t) {
105 |     const portNumber = parseInt(port, 10);
106 |     if (isNaN(portNumber) || portNumber < 1 || portNumber > 65535) {
107 |         logEvent('system', 'N/A', 'Port Invalid', t.portInvalid, 'error');
108 |         process.exit(1);
109 |     }
110 |     return portNumber;
111 | }
112 | 
113 | /**
114 |  * Validiert einen booleschen Wert.
115 |  * @param {string} varName - Der Name der Variable.
116 |  * @param {string} value - Der zu validierende Wert.
117 |  * @param {object} t - Die Übersetzungen basierend auf der Sprache.
118 |  * @param {boolean} [useProxy=false] - Ob eine Proxy-Verwendung erfolgt.
119 |  * @returns {boolean} - Der validierte boolesche Wert.
120 |  */
121 | function validateBoolean(varName, value, t, useProxy = false) {
122 |     if (useProxy && (varName === 'HEADER_ENCRYPTED')) {
123 |         if (value !== 'true' && value !== 'false') {
124 |             logEvent('system', 'N/A', 'Validation Err',
125 |                 t.validationError.replace('${var}', varName).replace('${value}', value), 'error');
126 |             process.exit(1);
127 |         }
128 |         return value === 'true';
129 |     }
130 |     // Allgemeine Validierung
131 |     if (value !== 'true' && value !== 'false') {
132 |         logEvent('system', 'N/A', 'Validation Err',
133 |             t.validationError.replace('${var}', varName).replace('${value}', value), 'error');
134 |         process.exit(1);
135 |     }
136 |     return value === 'true';
137 | }
138 | 
139 | /**
140 |  * Entschlüsselt eine verschlüsselte Zeichenkette mit dem privaten Schlüssel.
141 |  * @param {string} encryptedData - Die verschlüsselte Zeichenkette im Base64-Format.
142 |  * @param {string} privateKey - Der private Schlüssel.
143 |  * @param {object} t - Die Übersetzungen basierend auf der Sprache.
144 |  * @returns {string} - Das entschlüsselte Passwort.
145 |  */
146 | function decryptPassword(encryptedData, privateKey, t) {
147 |     try {
148 |         const decryptedPassword = crypto.privateDecrypt(
149 |             {
150 |                 key: privateKey,
151 |                 padding: crypto.constants.RSA_PKCS1_PADDING, // Konsistentes Padding sicherstellen
152 |             },
153 |             Buffer.from(encryptedData, 'base64')
154 |         ).toString('utf8');
155 | 
156 |         return decryptedPassword;
157 |     } catch (error) {
158 |         logEvent('system', 'N/A', 'Decryption Error', t.decryptionError, 'error');
159 |         throw new Error(t.decryptPwdError);
160 |     }
161 | }
162 | 
163 | /**
164 |  * Verschlüsselt Daten mit dem öffentlichen Schlüssel.
165 |  * @param {string} data - Die zu verschlüsselnden Daten.
166 |  * @param {string} publicKey - Der öffentliche Schlüssel.
167 |  * @param {object} t - Die Übersetzungen basierend auf der Sprache.
168 |  * @returns {string} - Die verschlüsselten Daten als Base64-String.
169 |  */
170 | function encryptWithPublicKey(data, publicKey, t) {
171 |     try {
172 |         return crypto.publicEncrypt(
173 |             {
174 |                 key: publicKey,
175 |                 padding: crypto.constants.RSA_PKCS1_PADDING, // Padding explizit setzen
176 |             },
177 |             Buffer.from(data)
178 |         ).toString('base64');
179 |     } catch (err) {
180 |         logEvent('system', 'N/A', 'Encryption Error', t.encryptionError, 'error');
181 |         throw new Error(t.encryptPwdError);
182 |     }
183 | }
184 | 
185 | /**
186 |  * Verschlüsselt ein gegebenes Passwort und gibt den verschlüsselten Schlüssel zurück.
187 |  * @param {string} password - Das zu verschlüsselnde Passwort.
188 |  * @param {string} publicKey - Der öffentliche Schlüssel.
189 |  * @param {object} t - Die Übersetzungen basierend auf der Sprache.
190 |  * @returns {string} - Das verschlüsselte Passwort als Base64-String.
191 |  */
192 | function getEncryptedKey(password, publicKey, t) {
193 |     try {
194 |         return encryptWithPublicKey(password, publicKey, t);
195 |     } catch (err) {
196 |         // Fehlerbehandlung wurde bereits in encryptWithPublicKey durchgeführt
197 |         throw err;
198 |     }
199 | }
200 | 
201 | /**
202 |  * Prüft, ob ein bestimmtes Tool aktiviert ist.
203 |  * @param {string} toolName - Der Name des Tools.
204 |  * @param {object} envConfig - Die Umgebungs-Konfigurationsdaten.
205 |  * @param {boolean} AllowKeygen - Ob Keygen erlaubt ist.
206 |  * @param {string} lang - Die ausgewählte Sprache.
207 |  * @returns {object|null} - Gibt einen Fehler zurück, wenn das Tool deaktiviert ist, sonst null.
208 |  */
209 | function checkToolEnabled(toolName, envConfig, AllowKeygen, lang) {
210 |     const t = messages[lang];
211 |     if (toolName === "keygen" && AllowKeygen) {
212 |         return null;
213 |     }
214 | 
215 |     if (!isToolEnabled(toolName, envConfig, lang)) {
216 |         logEvent(
217 |             'system', 'N/A', 'Tool Disabled', t.toolDisabledLog.replace('${toolName}', toolName), 'error'
218 |         );
219 |         return {
220 |             status: 'error',
221 |             message: messages[lang].toolDisabledError.replace('${toolName}', toolName),
222 |         };
223 |     }
224 |     return null; // Tool ist aktiviert
225 | }
226 | 
227 | /**
228 |  * Prüft, ob ein bestimmtes Tool aktiviert ist.
229 |  * @param {string} toolName - Der Name des Tools.
230 |  * @param {object} envConfig - Die Umgebungs-Konfigurationsdaten.
231 |  * @param {string} lang - Die ausgewählte Sprache.
232 |  * @returns {boolean} - Gibt true zurück, wenn das Tool aktiviert ist, sonst false.
233 |  */
234 | function isToolEnabled(toolName, envConfig, lang) {
235 |     const envKey = `ENABLE_${toolName.toUpperCase()}`;
236 |     if (!(envKey in envConfig.Functions)) {
237 |         logEvent(
238 |             'system', 'N/A', 'Tool Warn', messages[lang].toolNotDefinedInConfig.replace('${toolName}', toolName), 'warn'
239 |         );
240 |         return false;
241 |     }
242 |     return envConfig.Functions[envKey] === true;
243 | }
244 | 
245 | export {
246 |     loadEnvConfig,
247 |     getEnvVar,
248 |     expandPath,
249 |     validateUrl,
250 |     validatePort,
251 |     validateBoolean,
252 |     decryptPassword,
253 |     encryptWithPublicKey,
254 |     getEncryptedKey,
255 |     checkToolEnabled,
256 |     isToolEnabled
257 | };
258 | 
```

--------------------------------------------------------------------------------
/agents/OpenAI_Compatible_API_Agent/Python/open_ai_helper.py:
--------------------------------------------------------------------------------

```python
  1 | import asyncio
  2 | import json
  3 | import re
  4 | import time
  5 | 
  6 | import tiktoken
  7 | from pydantic import BaseModel, Field, ConfigDict
  8 | from typing import Optional, List
  9 | 
 10 | from agents.AgentInterface.Python.agent import PrivateGPTAgent
 11 | from agents.OpenAI_Compatible_API_Agent.Python.privategpt_api import PrivateGPTAPI
 12 | 
 13 | 
 14 | class ChatInstance:
 15 |     def __init__(self, api_key: str, agent: PrivateGPTAgent | PrivateGPTAPI):
 16 |         self.api_key = api_key
 17 |         self.agent = agent
 18 | 
 19 | 
 20 | # data models
 21 | class Message(BaseModel):
 22 |     role: str
 23 |     content: str | None
 24 |     tool_calls: Optional[object] = None
 25 |     name: Optional[str] = None
 26 |     tool_call_id: Optional[str] = None
 27 | 
 28 | 
 29 | class Function(BaseModel):
 30 |     arguments: str | dict
 31 |     name: str
 32 |     parsed_arguments: Optional[object] = None
 33 | 
 34 | class ChatCompletionMessageToolCall(BaseModel):
 35 |     id: str
 36 |     type: str = "function"
 37 |     function: Function
 38 | 
 39 | class ChatCompletionRequest(BaseModel):
 40 |     model: Optional[str] = "PGPT - Mistral NeMo 12B"
 41 |     messages: List[Message]
 42 |     max_tokens: Optional[int] = 64000
 43 |     temperature: Optional[float] = 0
 44 |     top_p: Optional[float] = 0
 45 |     stream: Optional[bool] = False
 46 |     response_format: Optional[object] = None
 47 |     tools: Optional[object] = None
 48 |     groups: Optional[object] = None
 49 |     newSession: Optional[bool] = False
 50 | 
 51 | 
 52 | 
 53 | 
 54 | class CompletionRequest(BaseModel):
 55 |     model: Optional[str] = "PGPT - Mistral NeMo 12B"
 56 |     max_tokens: Optional[int] = 64000
 57 |     temperature: Optional[float] = 0
 58 |     top_p: Optional[float] = 0
 59 |     stream: Optional[bool] = False
 60 |     response_format: Optional[object] = None
 61 |     tools: Optional[object] = None
 62 |     groups: Optional[object] = None
 63 |     prompt: str = ""
 64 |     messages: Optional[List[Message]] = None
 65 | 
 66 | 
 67 | 
 68 | 
 69 | def num_tokens(user_input, answer):
 70 |     """
 71 |     Calculate the number of tokens used by the user input and the assistant's answer.
 72 | 
 73 |     Args:
 74 |         user_input (str): The user's input.
 75 |         answer (str): The assistant's response.
 76 | 
 77 |     Returns:
 78 |         tuple: A tuple containing the number of tokens used by the user input,
 79 |                the assistant's answer, and the total number of tokens.
 80 |     """
 81 |     num_tokens_request = num_tokens_from_string(user_input, "o200k_base")
 82 |     num_tokens_reply = num_tokens_from_string(answer, "o200k_base")
 83 |     num_tokens_overall = num_tokens_request + num_tokens_reply
 84 | 
 85 |     return num_tokens_request, num_tokens_reply, num_tokens_overall
 86 | 
 87 | 
 88 | def num_tokens_from_string(string: str, encoding_name: str) -> int:
 89 |     """Returns the number of tokens in a text string."""
 90 |     return len(tiktoken.get_encoding(encoding_name).encode(string))
 91 | 
 92 | 
 93 | def _resp_sync(response: json, request):
 94 |     user_input = ""
 95 |     reply = {}
 96 |     for message in request.messages:
 97 |         user_input += json.dumps({'role': message.role, 'content': message.content})
 98 |     num_tokens_request, num_tokens_reply, num_tokens_overall = num_tokens(user_input, response["answer"])
 99 |     id = response.get("chatId", "0")
100 |     citations = []
101 |     if "sources" in response:
102 |         citations = response["sources"]
103 | 
104 |     tool_calls= None
105 |     if "tool_call" in response:
106 |         try:
107 |             print(response["tool_call"])
108 |             tool= json.loads(response["tool_call"])
109 |             if "arguments" in tool:
110 |                 arguments = tool["arguments"] #  '{"operation":"multiply","a":"123","b":"4324"}'
111 |                 parsed_arguments = json.loads(json.dumps(arguments).strip("\""))
112 |                 print("found arguments")
113 |                 print(parsed_arguments)
114 |             elif "params" in tool:
115 |                 parsed_arguments =  json.loads(json.dumps(tool["params"]).strip("\""))
116 |                 print("found params")
117 |                 print(parsed_arguments)
118 |             else:
119 |                 try:
120 |                     parsed_arguments = tool["params"]
121 |                 except:
122 |                     try:
123 |                         parsed_arguments = json.loads(tool)
124 |                     except:
125 |                         parsed_arguments = tool
126 |             name = "tool"
127 |             if "name" in tool:
128 |                 name = tool["name"] #'calculator'
129 |             if "method" in tool:
130 |                 name = tool["method"] #'calculator'
131 | 
132 |             function = Function(arguments=json.dumps(parsed_arguments), name=name, parsed_arguments=parsed_arguments)
133 |             tool_call = ChatCompletionMessageToolCall(id=id, function=function, type="function")
134 |             print("Tool Call: " + str(tool_call))
135 |             if tool_calls is None:
136 |                 tool_calls = []
137 |             tool_calls.append(tool_call)
138 | 
139 |         except Exception as e:
140 |             print("Tool Call error: " + str(e))
141 | 
142 | 
143 | 
144 |            
145 |     return {
146 |         "id": id,
147 |         "object": "chat.completion",
148 |         "created": time.time(),
149 |         "model": request.model,
150 |         "choices": [{"message": Message(role="assistant", content=clean_response(str(response["answer"])), tool_calls=tool_calls)}],
151 |         "citations": citations,
152 |         "usage": {
153 |             "prompt_tokens": num_tokens_request,
154 |             "completion_tokens": num_tokens_reply,
155 |             "total_tokens": num_tokens_overall
156 |         }
157 |     }
158 | 
159 | 
160 | def clean_response(response):
161 |     # Remove artefacts from reply here
162 |     response = response.replace("[TOOL_CALLS] ", "")
163 |     if "```json" in response:
164 |         response = response.replace("'''json", "").replace("'''", "")
165 |     return response
166 | 
167 | async def _resp_async_generator(response: json, request):
168 |     user_input = ""
169 |     for message in request.messages:
170 |             user_input += json.dumps({'role': message.role, 'content': message.content})
171 | 
172 | 
173 |     num_tokens_request, num_tokens_reply, num_tokens_overall = num_tokens(user_input, response["answer"])
174 | 
175 |     tokens = response["answer"].split(" ")
176 |     citations = []
177 |     if "sources" in response:
178 |         citations = response["sources"]
179 | 
180 |     for i, token in enumerate(tokens):
181 |         chunk = {
182 |             "id": i,
183 |             "object": "chat.completion.chunk",
184 |             "created": time.time(),
185 |             "model": request.model,
186 |             "choices": [{"delta": {"content": token + " "}}],
187 |             "citations": citations,
188 |             "usage": {
189 |                 "prompt_tokens": num_tokens_request,
190 |                 "completion_tokens": num_tokens_reply,
191 |                 "total_tokens": num_tokens_overall
192 |             }
193 |         }
194 |         yield f"data: {json.dumps(chunk)}\n\n"
195 |         await asyncio.sleep(0.05)
196 |     yield "data: [DONE]\n\n"
197 | 
198 | 
199 | 
200 | # Legacy Completions API
201 | def _resp_sync_completions(response: json, request):
202 |     user_input = request.prompt
203 |     reply = [{"text": response["answer"],
204 |             "index": 0,
205 |             "logprobs": None,
206 |             "finish_reason": "length"}]
207 | 
208 |     num_tokens_request, num_tokens_reply, num_tokens_overall = num_tokens(user_input, response["answer"])
209 | 
210 |     citations = []
211 |     if "sources" in response:
212 |         citations = response["sources"]
213 | 
214 | 
215 | 
216 |     return {
217 |         "id": response["chatId"],
218 |         "object": "text_completion",
219 |         "created": time.time(),
220 |         "model": request.model,
221 |         "choices": reply,
222 |         "citations": citations,
223 |         "usage": {
224 |             "prompt_tokens": num_tokens_request,
225 |             "completion_tokens": num_tokens_reply,
226 |             "total_tokens": num_tokens_overall
227 |         }
228 |     }
229 | 
230 | async def _resp_async_generator_completions(response: json, request):
231 | 
232 |     user_input = request.prompt
233 |     num_tokens_request, num_tokens_reply, num_tokens_overall = num_tokens(user_input, response["answer"])
234 | 
235 |     tokens = response["answer"].split(" ")
236 |     citations = []
237 |     if "sources" in response:
238 |         citations = response["sources"]
239 | 
240 | 
241 |     for i, token in enumerate(tokens):
242 |         chunk = {
243 |             "id": i,
244 |             "object": "text_completion",
245 |             "created": time.time(),
246 |             "model": request.model,
247 |             "choices": [
248 |                 {
249 |                   "text": token + " ",
250 |                   "index": 0,
251 |                   "logprobs": None,
252 |                   "finish_reason": None
253 |                 }
254 |             ],
255 | 
256 |             "citations": citations,
257 |             "usage": {
258 |                 "prompt_tokens": num_tokens_request,
259 |                 "completion_tokens": num_tokens_reply,
260 |                 "total_tokens": num_tokens_overall
261 |             }
262 |         }
263 |         yield f"data: {json.dumps(chunk)}\n\n"
264 |         await asyncio.sleep(0.05)
265 |     yield "data: [DONE]\n\n"
266 | 
267 | 
268 | models = [
269 |     {
270 |         "id": "/models/mistral-nemo-12b",
271 |         "object": "model",
272 |         "owned_by": "fujitsu",
273 |         "created": 1609459200,
274 |         "root": "mistral",
275 |         "parent": None,
276 |         "ready": True,
277 |         "permissions": [
278 |             {
279 |                 "id": "model-permission-1",
280 |                 "object": "model_permission",
281 |                 "created": 1612876732,
282 |                 "allow_create_engine": True,
283 |                 "allow_fine_tuning": False,
284 |                 "allow_sampling": True,
285 |                 "allow_search_indices": True,
286 |                 "allow_view": True,
287 |                 "organization": "*"
288 |             }
289 |         ]
290 |     }
291 | ]
292 | 
```

--------------------------------------------------------------------------------
/agents/MCP-Client/Python/mcp_client_sse.py:
--------------------------------------------------------------------------------

```python
  1 | import argparse
  2 | import asyncio
  3 | import json
  4 | import os
  5 | import uuid
  6 | from typing import Optional
  7 | from contextlib import AsyncExitStack
  8 | 
  9 | 
 10 | from mcp import ClientSession
 11 | from mcp.client.sse import sse_client
 12 | 
 13 | from dotenv import load_dotenv
 14 | from openai import OpenAI
 15 | 
 16 | from mcpcli.chat_handler import generate_system_prompt
 17 | 
 18 | load_dotenv()  # load environment variables from .env
 19 | 
 20 | 
 21 | class MCPClient:
 22 |     def __init__(self):
 23 | 
 24 |         self._session_context = None
 25 |         self._streams_context = None
 26 |         PGPT_API_KEY = os.getenv("PGPT_API_KEY")
 27 |         PGPT_OAI_BASE_URL = os.getenv("PGPT_OAI_BASE_URL")
 28 | 
 29 | 
 30 |         # Initialize session and client objects
 31 |         self.session: Optional[ClientSession] = None
 32 |         self.exit_stack = AsyncExitStack()
 33 |         self.client = OpenAI(
 34 |                 api_key=PGPT_API_KEY,
 35 |                 base_url=PGPT_OAI_BASE_URL  # change the default port if needed
 36 |             )
 37 | 
 38 |     async def connect_to_sse_server(self, server_url: str):
 39 |         """Connect to an MCP server running with SSE transport"""
 40 |         # Store the context managers so they stay alive
 41 |         self._streams_context = sse_client(url=server_url)
 42 |         streams = await self._streams_context.__aenter__()
 43 | 
 44 |         self._session_context = ClientSession(*streams)
 45 |         self.session: ClientSession = await self._session_context.__aenter__()
 46 | 
 47 |         # Initialize
 48 |         await self.session.initialize()
 49 | 
 50 |         # List available tools to verify connection
 51 |         print("Initialized SSE client...")
 52 |         print("Listing tools...")
 53 |         response = await self.session.list_tools()
 54 |         tools = response.tools
 55 |         print("\nConnected to server with tools:", [tool.name for tool in tools])
 56 | 
 57 |     async def cleanup(self):
 58 |         """Properly clean up the session and streams"""
 59 |         if self._session_context:
 60 |             await self._session_context.__aexit__(None, None, None)
 61 |         if self._streams_context:
 62 |             await self._streams_context.__aexit__(None, None, None)
 63 | 
 64 |     def convert_to_openai_tools(self, tools):
 65 |         """Convert tools into OpenAI-compatible function definitions."""
 66 |         openai_tools = []
 67 |         for tool in tools:
 68 | 
 69 |             inputScheme = tool.get("inputSchema", {})
 70 | 
 71 |             entry = {
 72 |                 "type": "function",
 73 |                 "function": {
 74 |                     "name": tool["name"],
 75 |                     "description": tool.get("description", ""),
 76 |                     "parameters": inputScheme
 77 |                 },
 78 |             }
 79 | 
 80 |             openai_tools.append(entry)
 81 | 
 82 |         return openai_tools
 83 | 
 84 |     async def process_query(self, query: str) -> str:
 85 |         """Process a query using PGPT and available tools"""
 86 | 
 87 |         response = await self.session.list_tools()
 88 |         available_tools = [{
 89 |             "name": tool.name,
 90 |             "description": tool.description,
 91 |             "input_schema": tool.inputSchema
 92 |         } for tool in response.tools]
 93 | 
 94 |         tools = self.convert_to_openai_tools(available_tools)
 95 | 
 96 |         #system_prompt = generate_system_prompt(tools)
 97 |         messages = []
 98 | 
 99 |         messages.append(
100 |             {
101 |                 "role": "user",
102 |                 "content": query
103 |             }
104 |         )
105 | 
106 |         # Initial PGPT API call
107 |         response = self.client.chat.completions.create(
108 |             model="pgpt-mistral-nemo-12b",
109 |             messages=messages,
110 |             tools=tools or None,
111 |             extra_body={
112 |                 "groups": [],
113 |                 "newSession": False
114 |             },
115 |             stream=False
116 | 
117 |         )
118 |         # Process response and handle tool calls
119 |         tool_results = []
120 |         final_text = []
121 | 
122 |         message = response.choices[0].message
123 |         print(message)
124 |         tool_calls = []
125 | 
126 |         # Convert Ollama tool calls to OpenAI format
127 |         if hasattr(message, "tool_calls") and message.tool_calls:
128 |             for tool in message.tool_calls:
129 |                 print(tool.function.arguments)
130 |                 tool_calls.append(
131 |                     {
132 |                         "id": str(uuid.uuid4()),  # Generate unique ID
133 |                         "type": "function",
134 |                         "function": {
135 |                             "name": tool.function.name,
136 |                             "arguments":tool.function.arguments,
137 |                         },
138 |                     }
139 |                 )
140 | 
141 | 
142 | 
143 |         if tool_calls:
144 |             for tool_call in tool_calls:
145 |                 # Extract tool_name and raw_arguments as before
146 |                 tool_call_id = str(uuid.uuid4())
147 |                 if hasattr(tool_call, "id"):
148 |                     tool_call_id = str(tool_call.id)
149 | 
150 |                 if hasattr(tool_call, "function"):
151 |                     print(tool_call.function)
152 |                     tool_name = getattr(tool_call.function, "name", "unknown tool")
153 |                     raw_arguments = getattr(tool_call.function, "arguments", {})
154 | 
155 |                 elif isinstance(tool_call, dict) and "function" in tool_call:
156 |                     fn_info = tool_call["function"]
157 |                     tool_name = fn_info.get("name", "unknown tool")
158 |                     raw_arguments = fn_info.get("arguments", {})
159 |                 else:
160 |                     tool_name = "unknown tool"
161 |                     raw_arguments = {}
162 | 
163 | 
164 | 
165 |                 # If raw_arguments is a string, try to parse it as JSON
166 |                 if isinstance(raw_arguments, str):
167 |                     try:
168 |                         raw_arguments = json.loads(raw_arguments)
169 |                     except json.JSONDecodeError:
170 |                         # If it's not valid JSON, just display as is
171 |                         pass
172 | 
173 |                 # Now raw_arguments should be a dict or something we can pretty-print as JSON
174 |                 tool_args_str = json.dumps(raw_arguments, indent=2)
175 | 
176 |                 tool_md = f"**Tool Call:** {tool_name}\n\n```json\n{tool_args_str}\n```"
177 |                 print(
178 |                    tool_md
179 |                 )
180 |                 meta = await self.session.call_tool(tool_name, raw_arguments)
181 |                 print("Tool " + tool_name + " reply: " + str(meta.content[0]))
182 | 
183 | 
184 |                 tool_results.append({"call": str(tool_name), "result": meta.content})
185 |                 #final_text.append(f"[Calling tool {tool_name} with args {raw_arguments}]")
186 | 
187 |                 messages.append(
188 |                     {
189 |                         "role": "assistant",
190 |                         "content": None,
191 |                         "tool_calls": [
192 |                             {
193 |                                 "id": tool_call_id,
194 |                                 "type": "function",
195 |                                 "function": {
196 |                                     "name": tool_name,
197 |                                     "arguments": json.dumps(raw_arguments)
198 |                                     if isinstance(raw_arguments, dict)
199 |                                     else raw_arguments,
200 |                                 },
201 |                             }
202 |                         ],
203 |                     }
204 |                 )
205 | 
206 |                 # Continue conversation with tool results
207 |                 if hasattr(meta.content[0], 'text') and meta.content[0].text:
208 |                     messages.append(
209 |                         {
210 |                             "role": "tool",
211 |                             "name": tool_name,
212 |                             "content": str(meta.content[0].text),
213 |                             "tool_call_id": tool_call_id,
214 |                         }
215 |                     )
216 | 
217 | 
218 | 
219 | 
220 |                 # Get next response from Claude
221 |                 response = self.client.chat.completions.create(
222 |                     model="pgpt-mistral-nemo-12b",
223 |                     messages=messages,
224 |                     extra_body={
225 |                         "groups": [],
226 |                         "newSession": False
227 |                     },
228 |                     stream=False
229 | 
230 |                 )
231 |                 final_text.append("LLM reply: " +response.choices[0].message.content)
232 | 
233 |             return "\n".join(final_text)
234 | 
235 |         else:
236 |             # Kein Tool-Aufruf, also gib die LLM-Antwort direkt zurück
237 |             return message.content or ""
238 | 
239 | 
240 |     async def chat_loop(self):
241 |         """Run an interactive chat loop"""
242 |         print("\nMCP Client Started!")
243 |         print("Type your queries or 'quit' to exit.")
244 | 
245 |         while True:
246 |             try:
247 |                 query = input("\nQuery: ").strip()
248 | 
249 |                 if query.lower() == 'quit':
250 |                     break
251 | 
252 |                 response = await self.process_query(query)
253 |                 print("\n" + response)
254 | 
255 |             except Exception as e:
256 |                 print(f"\nError: {str(e)}")
257 | 
258 | 
259 | async def main():
260 |     parser = argparse.ArgumentParser(description="MCP Client")
261 |     parser.add_argument(
262 |         "--server",
263 |         help=(
264 |             "SSE Server to listen to'"),
265 |     )
266 | 
267 |     args = parser.parse_args()
268 |     server_url = args.server or (
269 |          "http://127.0.0.1:3001/sse"
270 |     )
271 | 
272 |     client = MCPClient()
273 |     try:
274 |         server_url = server_url
275 |         await client.connect_to_sse_server(server_url=server_url)
276 |         await client.chat_loop()
277 |     finally:
278 |         await client.cleanup()
279 | 
280 | 
281 | if __name__ == "__main__":
282 |     import sys
283 | 
284 |     asyncio.run(main())
```

--------------------------------------------------------------------------------
/clients/PHP/5.1 mcp_edit_user/MCPEditUserClient.php:
--------------------------------------------------------------------------------

```php
  1 | <?php
  2 | /**
  3 |  * MCPEditUserClient.php
  4 |  *
  5 |  * A PHP script that acts as an Edit User Client. It connects to a server via TCP,
  6 |  * sends a request to edit an existing user, and receives the server's response.
  7 |  *
  8 |  * Usage:
  9 |  * php MCPEditUserClient.php --server-ip <IP> --server-port <Port> --token <Token> [--name <Name>] [--email <Email>] [--password <Password>] [--language <Language>] [--timezone <Timezone>] [--roles <Role1> <Role2> ...] [--groups <Group1> <Group2> ...] [--usePublic] [--activateFtp] [--ftpPassword <FtpPassword>]
 10 |  */
 11 | 
 12 | /**
 13 |  * Function to parse command line arguments
 14 |  *
 15 |  * @param array $args The command line arguments
 16 |  * @return array An associative array with the parsed arguments
 17 |  */
 18 | function parseArguments($args) {
 19 |     $parsedArgs = [];
 20 |     $argc = count($args);
 21 |     for ($i = 1; $i < $argc; $i++) {
 22 |         switch ($args[$i]) {
 23 |             case '--server-ip':
 24 |                 if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
 25 |                     $parsedArgs['serverIp'] = $args[++$i];
 26 |                 } else {
 27 |                     fwrite(STDERR, "⚠️ Warning: No value provided for --server-ip.\n");
 28 |                 }
 29 |                 break;
 30 |             case '--server-port':
 31 |                 if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
 32 |                     $parsedArgs['serverPort'] = intval($args[++$i]);
 33 |                 } else {
 34 |                     fwrite(STDERR, "⚠️ Warning: No value provided for --server-port.\n");
 35 |                 }
 36 |                 break;
 37 |             case '--token':
 38 |                 if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
 39 |                     $parsedArgs['token'] = $args[++$i];
 40 |                 } else {
 41 |                     fwrite(STDERR, "⚠️ Warning: No value provided for --token.\n");
 42 |                 }
 43 |                 break;
 44 |             case '--name':
 45 |                 if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
 46 |                     $parsedArgs['name'] = $args[++$i];
 47 |                 } else {
 48 |                     fwrite(STDERR, "⚠️ Warning: No value provided for --name.\n");
 49 |                 }
 50 |                 break;
 51 |             case '--email':
 52 |                 if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
 53 |                     $parsedArgs['email'] = $args[++$i];
 54 |                 } else {
 55 |                     fwrite(STDERR, "⚠️ Warning: No value provided for --email.\n");
 56 |                 }
 57 |                 break;
 58 |             case '--password':
 59 |                 if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
 60 |                     $parsedArgs['password'] = $args[++$i];
 61 |                 } else {
 62 |                     fwrite(STDERR, "⚠️ Warning: No value provided for --password.\n");
 63 |                 }
 64 |                 break;
 65 |             case '--language':
 66 |                 if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
 67 |                     $parsedArgs['language'] = $args[++$i];
 68 |                 } else {
 69 |                     fwrite(STDERR, "⚠️ Warning: No value provided for --language.\n");
 70 |                 }
 71 |                 break;
 72 |             case '--timezone':
 73 |                 if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
 74 |                     $parsedArgs['timezone'] = $args[++$i];
 75 |                 } else {
 76 |                     fwrite(STDERR, "⚠️ Warning: No value provided for --timezone.\n");
 77 |                 }
 78 |                 break;
 79 |             case '--roles':
 80 |                 $parsedArgs['roles'] = [];
 81 |                 while ($i + 1 < $argc && !startsWith($args[$i + 1], '--')) {
 82 |                     $parsedArgs['roles'][] = $args[++$i];
 83 |                 }
 84 |                 break;
 85 |             case '--groups':
 86 |                 $parsedArgs['groups'] = [];
 87 |                 while ($i + 1 < $argc && !startsWith($args[$i + 1], '--')) {
 88 |                     $parsedArgs['groups'][] = $args[++$i];
 89 |                 }
 90 |                 break;
 91 |             case '--usePublic':
 92 |                 $parsedArgs['usePublic'] = true;
 93 |                 break;
 94 |             case '--activateFtp':
 95 |                 $parsedArgs['activateFtp'] = true;
 96 |                 break;
 97 |             case '--ftpPassword':
 98 |                 if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
 99 |                     $parsedArgs['ftpPassword'] = $args[++$i];
100 |                 } else {
101 |                     fwrite(STDERR, "⚠️ Warning: No value provided for --ftpPassword.\n");
102 |                 }
103 |                 break;
104 |             default:
105 |                 fwrite(STDERR, "⚠️ Warning: Unknown argument: {$args[$i]}\n");
106 |         }
107 |     }
108 |     return $parsedArgs;
109 | }
110 | 
111 | /**
112 |  * Helper function to check if a string starts with a specific prefix
113 |  *
114 |  * @param string $string The string to check
115 |  * @param string $prefix The prefix
116 |  * @return bool True if the string starts with the prefix, otherwise False
117 |  */
118 | function startsWith($string, $prefix) {
119 |     return substr($string, 0, strlen($prefix)) === $prefix;
120 | }
121 | 
122 | /**
123 |  * Function to send an Edit User request over a TCP connection
124 |  *
125 |  * @param string $serverIp The server's IP address
126 |  * @param int $serverPort The server's port
127 |  * @param string $token The authentication token
128 |  * @param array $args The arguments for the user to be edited
129 |  * @return array The response received from the server as an associative array
130 |  * @throws Exception On connection errors or JSON parsing errors
131 |  */
132 | function sendEditUserRequest($serverIp, $serverPort, $token, $args) {
133 |     $payload = [
134 |         "command" => "edit_user",
135 |         "token" => $token,
136 |         "arguments" => []
137 |     ];
138 | 
139 |     // Populate 'arguments' only with the provided values
140 |     $fields = ["name", "email", "password", "language", "timezone", "roles", "groups", "usePublic", "activateFtp", "ftpPassword"];
141 |     foreach ($fields as $field) {
142 |         if (isset($args[$field])) {
143 |             $payload["arguments"][$field] = $args[$field];
144 |         }
145 |     }
146 | 
147 |     $jsonPayload = json_encode($payload);
148 |     if ($jsonPayload === false) {
149 |         throw new Exception("Error while encoding the JSON payload: " . json_last_error_msg());
150 |     }
151 | 
152 |     $errno = 0;
153 |     $errstr = '';
154 |     $timeoutDuration = 10; // Seconds (10 seconds timeout)
155 |     $client = @fsockopen($serverIp, $serverPort, $errno, $errstr, $timeoutDuration);
156 | 
157 |     if (!$client) {
158 |         throw new Exception("Connection error: $errstr ($errno)");
159 |     }
160 | 
161 |     echo "🔗 Connected to server ({$serverIp}:{$serverPort}).\n";
162 |     echo "📤 Sending Payload: {$jsonPayload}\n";
163 | 
164 |     fwrite($client, $jsonPayload);
165 | 
166 |     $responseData = '';
167 |     stream_set_timeout($client, $timeoutDuration);
168 | 
169 |     while (!feof($client)) {
170 |         $data = fread($client, 1024);
171 |         if ($data === false) {
172 |             throw new Exception("Error reading data from server.");
173 |         }
174 |         if ($data === '') {
175 |             break; // No more data
176 |         }
177 |         echo "📥 Received data: {$data}\n";
178 |         $responseData .= $data;
179 | 
180 |         // Attempt to parse the received data as JSON
181 |         $parsedData = json_decode($responseData, true);
182 |         if ($parsedData !== null) {
183 |             echo "✅ JSON response successfully parsed.\n";
184 |             fclose($client);
185 |             return $parsedData;
186 |         }
187 | 
188 |         // Check if the stream has timed out
189 |         $info = stream_get_meta_data($client);
190 |         if ($info['timed_out']) {
191 |             throw new Exception("Timeout while waiting for data from server.");
192 |         }
193 |     }
194 | 
195 |     fclose($client);
196 |     throw new Exception("Connection to server was closed before a complete response was received.");
197 | }
198 | 
199 | /**
200 |  * Main function of the script
201 |  */
202 | function main($argv) {
203 |     $parsedArgs = parseArguments($argv);
204 |     $serverIp = $parsedArgs['serverIp'] ?? null;
205 |     $serverPort = $parsedArgs['serverPort'] ?? null;
206 |     $token = $parsedArgs['token'] ?? null;
207 |     $name = $parsedArgs['name'] ?? null;
208 |     $email = $parsedArgs['email'] ?? null;
209 |     $password = $parsedArgs['password'] ?? null;
210 |     $language = $parsedArgs['language'] ?? null;
211 |     $timezone = $parsedArgs['timezone'] ?? null;
212 |     $roles = $parsedArgs['roles'] ?? [];
213 |     $groups = $parsedArgs['groups'] ?? [];
214 |     $usePublic = $parsedArgs['usePublic'] ?? false;
215 |     $activateFtp = $parsedArgs['activateFtp'] ?? false;
216 |     $ftpPassword = $parsedArgs['ftpPassword'] ?? null;
217 | 
218 |     // Check if all required parameters are present
219 |     if (!$serverIp || !$serverPort || !$token) {
220 |         fwrite(STDERR, "❌ ERROR: Missing required parameters.\n");
221 |         fwrite(STDOUT, "Usage: php MCPEditUserClient.php --server-ip <IP> --server-port <Port> --token <Token> [--name <Name>] [--email <Email>] [--password <Password>] [--language <Language>] [--timezone <Timezone>] [--roles <Role1> <Role2> ...] [--groups <Group1> <Group2> ...] [--usePublic] [--activateFtp] [--ftpPassword <FtpPassword>]\n");
222 |         exit(1);
223 |     }
224 | 
225 |     try {
226 |         echo "🧑‍💻 Sending Edit-User request...\n";
227 |         $response = sendEditUserRequest(
228 |             $serverIp,
229 |             $serverPort,
230 |             $token,
231 |             [
232 |                 'name' => $name,
233 |                 'email' => $email,
234 |                 'password' => $password,
235 |                 'language' => $language,
236 |                 'timezone' => $timezone,
237 |                 'roles' => $roles,
238 |                 'groups' => $groups,
239 |                 'usePublic' => $usePublic,
240 |                 'activateFtp' => $activateFtp,
241 |                 'ftpPassword' => $ftpPassword
242 |             ]
243 |         );
244 |         echo "✔️ Server response:\n";
245 |         echo json_encode($response, JSON_PRETTY_PRINT) . "\n";
246 |     } catch (Exception $e) {
247 |         fwrite(STDERR, "❌ Error: " . $e->getMessage() . "\n");
248 |     }
249 | }
250 | 
251 | // Check if PHP version is at least 7.1 (for better features)
252 | if (version_compare(PHP_VERSION, '7.1.0') < 0) {
253 |     fwrite(STDERR, "❌ ERROR: This script requires PHP version 7.1 or higher.\n");
254 |     exit(1);
255 | }
256 | 
257 | // Call the main function
258 | main($argv);
259 | ?>
260 | 
```

--------------------------------------------------------------------------------
/clients/JavaScript/5.0 mcp_store_user/MCPStoreUserClient.js:
--------------------------------------------------------------------------------

```javascript
  1 | const net = require('net');
  2 | const readline = require('readline');
  3 | const { argv, exit } = require('process');
  4 | 
  5 | /**
  6 |  * Funktion zum Parsen der Kommandozeilenargumente
  7 |  * @param {string[]} args - Array von Kommandozeilenargumenten
  8 |  * @returns {Object} - Objekt mit geparsten Argumenten
  9 |  */
 10 | function parseArguments(args) {
 11 |     const parsedArgs = {};
 12 |     for (let i = 2; i < args.length; i++) {
 13 |         switch (args[i]) {
 14 |             case '--server-ip':
 15 |                 if (i + 1 < args.length) {
 16 |                     parsedArgs.serverIp = args[++i];
 17 |                 } else {
 18 |                     console.warn('⚠️ Kein Wert für --server-ip angegeben.');
 19 |                 }
 20 |                 break;
 21 |             case '--server-port':
 22 |                 if (i + 1 < args.length) {
 23 |                     parsedArgs.serverPort = parseInt(args[++i], 10);
 24 |                 } else {
 25 |                     console.warn('⚠️ Kein Wert für --server-port angegeben.');
 26 |                 }
 27 |                 break;
 28 |             case '--token':
 29 |                 if (i + 1 < args.length) {
 30 |                     parsedArgs.token = args[++i];
 31 |                 } else {
 32 |                     console.warn('⚠️ Kein Wert für --token angegeben.');
 33 |                 }
 34 |                 break;
 35 |             case '--name':
 36 |                 if (i + 1 < args.length) {
 37 |                     parsedArgs.name = args[++i];
 38 |                 } else {
 39 |                     console.warn('⚠️ Kein Wert für --name angegeben.');
 40 |                 }
 41 |                 break;
 42 |             case '--email':
 43 |                 if (i + 1 < args.length) {
 44 |                     parsedArgs.email = args[++i];
 45 |                 } else {
 46 |                     console.warn('⚠️ Kein Wert für --email angegeben.');
 47 |                 }
 48 |                 break;
 49 |             case '--password':
 50 |                 if (i + 1 < args.length) {
 51 |                     parsedArgs.password = args[++i];
 52 |                 } else {
 53 |                     console.warn('⚠️ Kein Wert für --password angegeben.');
 54 |                 }
 55 |                 break;
 56 |             case '--language':
 57 |                 if (i + 1 < args.length) {
 58 |                     parsedArgs.language = args[++i];
 59 |                 } else {
 60 |                     console.warn('⚠️ Kein Wert für --language angegeben.');
 61 |                 }
 62 |                 break;
 63 |             case '--timezone':
 64 |                 if (i + 1 < args.length) {
 65 |                     parsedArgs.timezone = args[++i];
 66 |                 } else {
 67 |                     console.warn('⚠️ Kein Wert für --timezone angegeben.');
 68 |                 }
 69 |                 break;
 70 |             case '--roles':
 71 |                 parsedArgs.roles = [];
 72 |                 while (i + 1 < args.length && !args[i + 1].startsWith('--')) {
 73 |                     parsedArgs.roles.push(args[++i]);
 74 |                 }
 75 |                 break;
 76 |             case '--groups':
 77 |                 parsedArgs.groups = [];
 78 |                 while (i + 1 < args.length && !args[i + 1].startsWith('--')) {
 79 |                     parsedArgs.groups.push(args[++i]);
 80 |                 }
 81 |                 break;
 82 |             case '--usePublic':
 83 |                 parsedArgs.usePublic = true;
 84 |                 break;
 85 |             case '--activateFtp':
 86 |                 parsedArgs.activateFtp = true;
 87 |                 break;
 88 |             case '--ftpPassword':
 89 |                 if (i + 1 < args.length) {
 90 |                     parsedArgs.ftpPassword = args[++i];
 91 |                 } else {
 92 |                     console.warn('⚠️ Kein Wert für --ftpPassword angegeben.');
 93 |                 }
 94 |                 break;
 95 |             default:
 96 |                 console.warn(`⚠️ Unbekanntes Argument: ${args[i]}`);
 97 |         }
 98 |     }
 99 |     return parsedArgs;
100 | }
101 | 
102 | /**
103 |  * Funktion zum interaktiven Abfragen eines Parameters (optional)
104 |  * @param {string} query - Frage an den Benutzer
105 |  * @returns {Promise<string>} - Antwort des Benutzers
106 |  */
107 | function askQuestion(query) {
108 |     const rl = readline.createInterface({
109 |         input: process.stdin,
110 |         output: process.stdout,
111 |         terminal: true
112 |     });
113 | 
114 |     return new Promise((resolve) => {
115 |         rl.question(query, (answer) => {
116 |             rl.close();
117 |             resolve(answer);
118 |         });
119 |     });
120 | }
121 | 
122 | /**
123 |  * Sendet eine Anfrage an den MCP-Server, um einen neuen Benutzer zu erstellen.
124 |  *
125 |  * @param {string} serverIp - IP-Adresse des MCP-Servers
126 |  * @param {number} serverPort - Portnummer des MCP-Servers
127 |  * @param {string} token - Authentifizierungstoken
128 |  * @param {string} name - Name des neuen Benutzers
129 |  * @param {string} email - Email des neuen Benutzers
130 |  * @param {string} password - Passwort für den neuen Benutzer
131 |  * @param {string} language - Bevorzugte Sprache des neuen Benutzers
132 |  * @param {string} timezone - Zeitzone des neuen Benutzers
133 |  * @param {string[]} roles - Rollen des neuen Benutzers
134 |  * @param {string[]} groups - Gruppen des neuen Benutzers
135 |  * @param {boolean} usePublic - Verwendung der öffentlichen Wissensbasis
136 |  * @param {boolean} activateFtp - Aktivierung von FTP für den Benutzer
137 |  * @param {string} ftpPassword - FTP-Passwort für den Benutzer
138 |  * @returns {Promise<Object>} - Antwort vom Server
139 |  */
140 | function sendStoreUserRequest(serverIp, serverPort, token, name, email, password, language, timezone, roles, groups, usePublic, activateFtp, ftpPassword) {
141 |     return new Promise((resolve, reject) => {
142 |         const client = new net.Socket();
143 |         const payload = {
144 |             command: "store_user",
145 |             token: token,
146 |             arguments: {
147 |                 name: name,
148 |                 email: email,
149 |                 password: password,
150 |                 language: language,
151 |                 timezone: timezone,
152 |                 roles: roles,
153 |                 groups: groups,
154 |                 usePublic: usePublic,
155 |                 activateFtp: activateFtp,
156 |                 ftpPassword: ftpPassword
157 |             }
158 |         };
159 |         const payloadString = JSON.stringify(payload);
160 | 
161 |         // Timeout setzen (optional)
162 |         const TIMEOUT_DURATION = 10000; // 10 Sekunden
163 |         const timeout = setTimeout(() => {
164 |             client.destroy(); // Verbindung zerstören
165 |             reject(new Error('Verbindungs-Timeout: Der Server hat nicht rechtzeitig geantwortet.'));
166 |         }, TIMEOUT_DURATION);
167 | 
168 |         client.connect(serverPort, serverIp, () => {
169 |             console.log(`🔗 Verbindung zum Server (${serverIp}:${serverPort}) hergestellt.`);
170 |             console.log(`📤 Sende Payload: ${payloadString}`);
171 |             client.write(payloadString);
172 |         });
173 | 
174 |         let responseData = '';
175 | 
176 |         client.on('data', (data) => {
177 |             console.log(`📥 Empfangene Daten: ${data}`);
178 |             responseData += data.toString();
179 |             try {
180 |                 const parsedData = JSON.parse(responseData);
181 |                 console.log('✅ JSON-Antwort erfolgreich geparst.');
182 |                 clearTimeout(timeout);
183 |                 resolve(parsedData);
184 |                 client.destroy(); // Verbindung schließen
185 |             } catch (err) {
186 |                 console.warn('⚠️ Antwort noch nicht vollständig oder ungültiges JSON. Weitere Daten werden erwartet.');
187 |                 // Weiter empfangen
188 |             }
189 |         });
190 | 
191 |         client.on('close', () => {
192 |             console.log('🔒 Verbindung zum Server geschlossen.');
193 |             clearTimeout(timeout);
194 |         });
195 | 
196 |         client.on('error', (err) => {
197 |             console.error('❌ Verbindungsfehler:', err.message);
198 |             clearTimeout(timeout);
199 |             reject(err);
200 |         });
201 |     });
202 | }
203 | 
204 | // Hauptfunktion
205 | async function main() {
206 |     const args = argv;
207 |     const parsedArgs = parseArguments(args);
208 |     let { 
209 |         serverIp, 
210 |         serverPort, 
211 |         token, 
212 |         name, 
213 |         email, 
214 |         password, 
215 |         language, 
216 |         timezone, 
217 |         roles, 
218 |         groups, 
219 |         usePublic, 
220 |         activateFtp, 
221 |         ftpPassword 
222 |     } = parsedArgs;
223 | 
224 |     // Überprüfen, ob alle erforderlichen Parameter vorhanden sind, sonst interaktiv abfragen
225 |     if (!serverIp) {
226 |         serverIp = await askQuestion('🔗 Bitte gib die Server-IP ein: ');
227 |     }
228 |     if (!serverPort) {
229 |         const portInput = await askQuestion('🔗 Bitte gib den Server-Port ein: ');
230 |         serverPort = parseInt(portInput, 10);
231 |     }
232 |     if (!token) {
233 |         token = await askQuestion('🔒 Bitte gib dein Authentifizierungstoken ein: ');
234 |     }
235 |     if (!name) {
236 |         name = await askQuestion('👤 Bitte gib den Namen des Benutzers ein: ');
237 |     }
238 |     if (!email) {
239 |         email = await askQuestion('📧 Bitte gib die Email des Benutzers ein: ');
240 |     }
241 |     if (!password) {
242 |         password = await askQuestion('🔑 Bitte gib das Passwort des Benutzers ein: ');
243 |     }
244 |     if (!language) {
245 |         language = await askQuestion('🌐 Bitte gib die bevorzugte Sprache des Benutzers ein (z.B. en, de): ');
246 |     }
247 |     if (!timezone) {
248 |         timezone = await askQuestion('🕰️ Bitte gib die Zeitzone des Benutzers ein (z.B. Europe/Berlin): ');
249 |     }
250 |     // Rollen und Gruppen sind optional und wurden bereits mit parseArguments behandelt
251 |     // usePublic, activateFtp und ftpPassword sind ebenfalls optional
252 | 
253 |     // Standardwerte für optionale Parameter setzen, falls sie nicht vorhanden sind
254 |     roles = roles || [];
255 |     groups = groups || [];
256 |     usePublic = usePublic || false;
257 |     activateFtp = activateFtp || false;
258 |     ftpPassword = ftpPassword || '';
259 | 
260 |     try {
261 |         console.log('🧑‍💻 Sende Store-User-Anfrage...');
262 |         const response = await sendStoreUserRequest(
263 |             serverIp,
264 |             serverPort,
265 |             token,
266 |             name,
267 |             email,
268 |             password,
269 |             language,
270 |             timezone,
271 |             roles,
272 |             groups,
273 |             usePublic,
274 |             activateFtp,
275 |             ftpPassword
276 |         );
277 |         console.log('✔️ Antwort vom Server:', JSON.stringify(response, null, 2));
278 |     } catch (err) {
279 |         console.error('❌ Fehler:', err.message);
280 |     }
281 | }
282 | 
283 | main();
284 | 
```

--------------------------------------------------------------------------------
/clients/Gradio/mcp_client.py:
--------------------------------------------------------------------------------

```python
  1 | import json
  2 | import os
  3 | import sys
  4 | 
  5 | from typing import Optional
  6 | from contextlib import AsyncExitStack
  7 | 
  8 | import httpx
  9 | from mcp import ClientSession, StdioServerParameters
 10 | from mcp.client.sse import sse_client
 11 | from mcp.client.stdio import stdio_client
 12 | 
 13 | from dotenv import load_dotenv
 14 | from openai import OpenAI
 15 | 
 16 | 
 17 | load_dotenv()  # load environment variables from .env
 18 | 
 19 | 
 20 | def generate_system_prompt(tools):
 21 |     """
 22 |     Generate a concise system prompt for the assistant.
 23 | 
 24 |     This prompt is internal and not displayed to the user.
 25 |     """
 26 |     prompt_generator = SystemPromptGenerator()
 27 |     tools_json = {"tools": tools}
 28 | 
 29 |     system_prompt = prompt_generator.generate_prompt(tools_json)
 30 |     system_prompt += """
 31 | 
 32 | **GENERAL GUIDELINES:**
 33 | 
 34 | 1. Step-by-step reasoning:
 35 |    - Analyze tasks systematically.
 36 |    - Break down complex problems into smaller, manageable parts.
 37 |    - Verify assumptions at each step to avoid errors.
 38 |    - Reflect on results to improve subsequent actions.
 39 | 
 40 | 2. Effective tool usage:
 41 |    - Explore:
 42 |      - Identify available information and verify its structure.
 43 |      - Check assumptions and understand data relationships.
 44 |    - Iterate:
 45 |      - Start with simple queries or actions.
 46 |      - Build upon successes, adjusting based on observations.
 47 |    - Handle errors:
 48 |      - Carefully analyze error messages.
 49 |      - Use errors as a guide to refine your approach.
 50 |      - Document what went wrong and suggest fixes.
 51 | 
 52 | 3. Clear communication:
 53 |    - Explain your reasoning and decisions at each step.
 54 |    - Share discoveries transparently with the user.
 55 |    - Outline next steps or ask clarifying questions as needed.
 56 | 
 57 | EXAMPLES OF BEST PRACTICES:
 58 | 
 59 | - Working with databases:
 60 |   - Check schema before writing queries.
 61 |   - Verify the existence of columns or tables.
 62 |   - Start with basic queries and refine based on results.
 63 | 
 64 | - Processing data:
 65 |   - Validate data formats and handle edge cases.
 66 |   - Ensure integrity and correctness of results.
 67 | 
 68 | - Accessing resources:
 69 |   - Confirm resource availability and permissions.
 70 |   - Handle missing or incomplete data gracefully.
 71 | 
 72 | REMEMBER:
 73 | - Be thorough and systematic.
 74 | - Each tool call should have a clear and well-explained purpose.
 75 | - Make reasonable assumptions if ambiguous.
 76 | - Minimize unnecessary user interactions by providing actionable insights.
 77 | 
 78 | EXAMPLES OF ASSUMPTIONS:
 79 | - Default sorting (e.g., descending order) if not specified.
 80 | - Assume basic user intentions, such as fetching top results by a common metric.
 81 | """
 82 |     return system_prompt
 83 | 
 84 | 
 85 | class MCPClient:
 86 |     def __init__(self, vllm_url, vllm_api_key):
 87 | 
 88 |         self.stdio = None
 89 |         self.write = None
 90 |         self._session_context = None
 91 |         self._streams_context = None
 92 |         self.name = ""
 93 | 
 94 |         self.server_params = None
 95 | 
 96 |         # Initialize session and client objects
 97 |         self.session: Optional[ClientSession] = None
 98 |         self.exit_stack = AsyncExitStack()
 99 |         self.client = OpenAI(
100 |             base_url=vllm_url,
101 |             api_key=vllm_api_key,
102 |             http_client=httpx.Client(verify=False)
103 |             )
104 | 
105 |     async def connect_to_sse_server(self, server_url: str):
106 |         """Connect to an MCP server running with SSE transport"""
107 |         # Store the context managers so they stay alive
108 |         self._streams_context = sse_client(url=server_url)
109 |         streams = await self._streams_context.__aenter__()
110 | 
111 |         self._session_context = ClientSession(*streams)
112 |         self.session: ClientSession = await self._session_context.__aenter__()
113 | 
114 |         # Initialize
115 |         await self.session.initialize()
116 | 
117 |         # List available tools to verify connection
118 |         print("Initialized SSE client...")
119 |         print("Listing tools...")
120 |         response = await self.session.list_tools()
121 |         tools = response.tools
122 |         print("\nConnected to server with tools:", [tool.name for tool in tools])
123 | 
124 | 
125 |     async def connect_to_stdio_server(self, server_params, name):
126 |             """Connect to an MCP server
127 | 
128 |             Args:
129 |                 server_script_path: Path to the server script (.py or .js)
130 |             """
131 |             self.name = name
132 |             self.server_params = server_params
133 |             stdio_transport = await self.exit_stack.enter_async_context(stdio_client(self.server_params))
134 |             self.stdio, self.write = stdio_transport
135 |             self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))
136 | 
137 |             await self.session.initialize()
138 | 
139 | 
140 |             # List available tools
141 |             response = await self.session.list_tools()
142 |             tools = response.tools
143 |             print("\nConnected to server " + name + " with tools:", [tool.name for tool in tools])
144 |             return self.stdio, self.write
145 | 
146 | 
147 |     async def cleanup(self):
148 |         """Properly clean up the session and streams"""
149 |         if self._session_context:
150 |             await self._session_context.__aexit__(None, None, None)
151 |         if self._streams_context:
152 |             await self._streams_context.__aexit__(None, None, None)
153 | 
154 | 
155 | 
156 | async def load_config(config_path: str, server_name: str) -> StdioServerParameters:
157 |         """Load the server configuration from a JSON file."""
158 |         try:
159 |             # debug
160 |             print(f"Loading config from {config_path}")
161 | 
162 |             # Read the configuration file
163 |             with open(config_path, "r") as config_file:
164 |                 config = json.load(config_file)
165 | 
166 |             # Retrieve the server configuration
167 |             server_config = config.get("mcpServers", {}).get(server_name)
168 |             if not server_config:
169 |                 error_msg = f"Server '{server_name}' not found in configuration file."
170 |                 print(error_msg)
171 |                 raise ValueError(error_msg)
172 | 
173 |             # Construct the server parameters
174 |             result = StdioServerParameters(
175 |                 command=server_config["command"],
176 |                 args=server_config.get("args", []),
177 |                 env=server_config.get("env"),
178 |             )
179 | 
180 |             # debug
181 |             print(
182 |                 f"Loaded config: command='{result.command}', args={result.args}, env={result.env}"
183 |             )
184 | 
185 |             # return result
186 |             return result
187 | 
188 |         except FileNotFoundError:
189 |             # error
190 |             error_msg = f"Configuration file not found: {config_path}"
191 |             print(error_msg)
192 |             raise FileNotFoundError(error_msg)
193 |         except json.JSONDecodeError as e:
194 |             # json error
195 |             error_msg = f"Invalid JSON in configuration file: {e.msg}"
196 |             print(error_msg)
197 |             raise json.JSONDecodeError(error_msg, e.doc, e.pos)
198 |         except ValueError as e:
199 |             # error
200 |             print(str(e))
201 |             raise
202 | 
203 | class SystemPromptGenerator:
204 |     """
205 |     A class for generating system prompts dynamically based on tools JSON and user inputs.
206 |     """
207 | 
208 |     def __init__(self):
209 |         """
210 |         Initialize the SystemPromptGenerator with a default system prompt template.
211 |         """
212 |         self.template = """
213 |         In this environment you have access to a set of tools you can use to answer the user's question.
214 |         {{ FORMATTING INSTRUCTIONS }}
215 |         String and scalar parameters should be specified as is, while lists and objects should use JSON format. Note that spaces for string values are not stripped. The output is not expected to be valid XML and is parsed with regular expressions.
216 |         Here are the functions available in JSONSchema format:
217 |         {{ TOOL DEFINITIONS IN JSON SCHEMA }}
218 |         {{ USER SYSTEM PROMPT }}
219 |         {{ TOOL CONFIGURATION }}
220 |         """
221 |         self.default_user_system_prompt = "You are an intelligent assistant capable of using tools to solve user queries effectively."
222 |         self.default_tool_config = "No additional configuration is required."
223 | 
224 |     def generate_prompt(
225 |         self, tools: dict, user_system_prompt: str = None, tool_config: str = None
226 |     ) -> str:
227 |         """
228 |         Generate a system prompt based on the provided tools JSON, user prompt, and tool configuration.
229 | 
230 |         Args:
231 |             tools (dict): The tools JSON containing definitions of the available tools.
232 |             user_system_prompt (str): A user-provided description or instruction for the assistant (optional).
233 |             tool_config (str): Additional tool configuration information (optional).
234 | 
235 |         Returns:
236 |             str: The dynamically generated system prompt.
237 |         """
238 | 
239 |         # set the user system prompt
240 |         user_system_prompt = user_system_prompt or self.default_user_system_prompt
241 | 
242 |         # set the tools config
243 |         tool_config = tool_config or self.default_tool_config
244 | 
245 |         # get the tools schema
246 |         tools_json_schema = json.dumps(tools, indent=2)
247 | 
248 |         # perform replacements
249 |         prompt = self.template.replace(
250 |             "{{ TOOL DEFINITIONS IN JSON SCHEMA }}", tools_json_schema
251 |         )
252 |         prompt = prompt.replace("{{ FORMATTING INSTRUCTIONS }}", "")
253 |         prompt = prompt.replace("{{ USER SYSTEM PROMPT }}", user_system_prompt)
254 |         prompt = prompt.replace("{{ TOOL CONFIGURATION }}", tool_config)
255 | 
256 |         # return the prompt
257 |         return prompt
258 | 
259 | 
260 | # Default environment variables to inherit
261 | DEFAULT_INHERITED_ENV_VARS = (
262 |     ["HOME", "LOGNAME", "PATH", "SHELL", "TERM", "USER"]
263 |     if sys.platform != "win32"
264 |     else [
265 |         "APPDATA",
266 |         "HOMEDRIVE",
267 |         "HOMEPATH",
268 |         "LOCALAPPDATA",
269 |         "PATH",
270 |         "PROCESSOR_ARCHITECTURE",
271 |         "SYSTEMDRIVE",
272 |         "SYSTEMROOT",
273 |         "TEMP",
274 |         "USERNAME",
275 |         "USERPROFILE",
276 |     ]
277 | )
278 | 
279 | 
280 | def get_default_environment() -> dict[str, str]:
281 |     """
282 |     Retrieve a dictionary of default environment variables to inherit.
283 |     """
284 | 
285 |     # get the current environment
286 |     env = {
287 |         key: value
288 |         for key in DEFAULT_INHERITED_ENV_VARS
289 |         if (value := os.environ.get(key)) and not value.startswith("()")
290 |     }
291 | 
292 |     # return the dictionary
293 |     return env
294 | 
295 | 
296 | def clean_response(response):
297 |     # Remove artefacts from reply here
298 |     response = response.replace("[TOOL_CALLS]", "")
299 |     if "```json" in response:
300 |         response = response.replace("'''json", "").replace("'''", "")
301 |     return response
302 | 
```

--------------------------------------------------------------------------------
/agents/AgentMonitoring/OpenAI compatible API - Agent Dashboard Example - Grafana.json:
--------------------------------------------------------------------------------

```json
  1 | {
  2 |   "annotations": {
  3 |     "list": [
  4 |       {
  5 |         "builtIn": 1,
  6 |         "datasource": "-- Grafana --",
  7 |         "enable": true,
  8 |         "hide": true,
  9 |         "iconColor": "rgba(0, 211, 255, 1)",
 10 |         "name": "Annotations & Alerts",
 11 |         "type": "dashboard"
 12 |       }
 13 |     ]
 14 |   },
 15 |   "editable": true,
 16 |   "fiscalYearStartMonth": 0,
 17 |   "graphTooltip": 0,
 18 |   "id": 2,
 19 |   "links": [],
 20 |   "panels": [
 21 |     {
 22 |       "fieldConfig": {
 23 |         "defaults": {
 24 |           "color": {
 25 |             "mode": "palette-classic"
 26 |           },
 27 |           "custom": {
 28 |             "axisBorderShow": false,
 29 |             "axisCenteredZero": false,
 30 |             "axisColorMode": "text",
 31 |             "axisLabel": "",
 32 |             "axisPlacement": "auto",
 33 |             "barAlignment": 0,
 34 |             "barWidthFactor": 0.6,
 35 |             "drawStyle": "line",
 36 |             "fillOpacity": 0,
 37 |             "gradientMode": "none",
 38 |             "hideFrom": {
 39 |               "legend": false,
 40 |               "tooltip": false,
 41 |               "viz": false
 42 |             },
 43 |             "insertNulls": false,
 44 |             "lineInterpolation": "linear",
 45 |             "lineWidth": 1,
 46 |             "pointSize": 5,
 47 |             "scaleDistribution": {
 48 |               "type": "linear"
 49 |             },
 50 |             "showPoints": "auto",
 51 |             "spanNulls": false,
 52 |             "stacking": {
 53 |               "group": "A",
 54 |               "mode": "none"
 55 |             },
 56 |             "thresholdsStyle": {
 57 |               "mode": "off"
 58 |             }
 59 |           },
 60 |           "mappings": [],
 61 |           "thresholds": {
 62 |             "mode": "absolute",
 63 |             "steps": [
 64 |               {
 65 |                 "color": "green",
 66 |                 "value": null
 67 |               },
 68 |               {
 69 |                 "color": "red",
 70 |                 "value": 80
 71 |               }
 72 |             ]
 73 |           },
 74 |           "unit": "req/s"
 75 |         },
 76 |         "overrides": []
 77 |       },
 78 |       "gridPos": {
 79 |         "h": 8,
 80 |         "w": 12,
 81 |         "x": 0,
 82 |         "y": 0
 83 |       },
 84 |       "id": 1,
 85 |       "options": {
 86 |         "legend": {
 87 |           "calcs": [],
 88 |           "displayMode": "list",
 89 |           "placement": "bottom",
 90 |           "showLegend": true
 91 |         },
 92 |         "tooltip": {
 93 |           "hideZeros": false,
 94 |           "mode": "single",
 95 |           "sort": "none"
 96 |         }
 97 |       },
 98 |       "pluginVersion": "11.5.2",
 99 |       "targets": [
100 |         {
101 |           "datasource": {
102 |             "name": "Prometheus",
103 |             "type": "prometheus"
104 |           },
105 |           "editorMode": "code",
106 |           "expr": "rate(request_count[1m])",
107 |           "interval": "",
108 |           "legendFormat": "{{method}} {{endpoint}}",
109 |           "range": true,
110 |           "refId": "A"
111 |         }
112 |       ],
113 |       "title": "Request Count (rate)",
114 |       "type": "timeseries"
115 |     },
116 |     {
117 |       "fieldConfig": {
118 |         "defaults": {
119 |           "color": {
120 |             "mode": "palette-classic"
121 |           },
122 |           "custom": {
123 |             "axisBorderShow": false,
124 |             "axisCenteredZero": false,
125 |             "axisColorMode": "text",
126 |             "axisLabel": "",
127 |             "axisPlacement": "auto",
128 |             "barAlignment": 0,
129 |             "barWidthFactor": 0.6,
130 |             "drawStyle": "line",
131 |             "fillOpacity": 0,
132 |             "gradientMode": "none",
133 |             "hideFrom": {
134 |               "legend": false,
135 |               "tooltip": false,
136 |               "viz": false
137 |             },
138 |             "insertNulls": false,
139 |             "lineInterpolation": "linear",
140 |             "lineWidth": 1,
141 |             "pointSize": 5,
142 |             "scaleDistribution": {
143 |               "type": "linear"
144 |             },
145 |             "showPoints": "auto",
146 |             "spanNulls": false,
147 |             "stacking": {
148 |               "group": "A",
149 |               "mode": "none"
150 |             },
151 |             "thresholdsStyle": {
152 |               "mode": "off"
153 |             }
154 |           },
155 |           "mappings": [],
156 |           "thresholds": {
157 |             "mode": "absolute",
158 |             "steps": [
159 |               {
160 |                 "color": "green",
161 |                 "value": null
162 |               },
163 |               {
164 |                 "color": "red",
165 |                 "value": 80
166 |               }
167 |             ]
168 |           },
169 |           "unit": "s"
170 |         },
171 |         "overrides": []
172 |       },
173 |       "gridPos": {
174 |         "h": 8,
175 |         "w": 12,
176 |         "x": 12,
177 |         "y": 0
178 |       },
179 |       "id": 2,
180 |       "options": {
181 |         "legend": {
182 |           "calcs": [],
183 |           "displayMode": "list",
184 |           "placement": "bottom",
185 |           "showLegend": true
186 |         },
187 |         "tooltip": {
188 |           "hideZeros": false,
189 |           "mode": "single",
190 |           "sort": "none"
191 |         }
192 |       },
193 |       "pluginVersion": "11.5.2",
194 |       "targets": [
195 |         {
196 |           "datasource": {
197 |             "name": "Prometheus",
198 |             "type": "prometheus"
199 |           },
200 |           "editorMode": "code",
201 |           "expr": "histogram_quantile(0.95, sum(rate(request_latency_seconds_bucket[1m])) by (le, method, endpoint))",
202 |           "interval": "",
203 |           "legendFormat": "p95 latency: {{method}} {{endpoint}}",
204 |           "refId": "A"
205 |         }
206 |       ],
207 |       "title": "Request Latency (Histogram)",
208 |       "type": "timeseries"
209 |     },
210 |     {
211 |       "fieldConfig": {
212 |         "defaults": {
213 |           "mappings": [],
214 |           "thresholds": {
215 |             "mode": "absolute",
216 |             "steps": [
217 |               {
218 |                 "color": "green",
219 |                 "value": null
220 |               },
221 |               {
222 |                 "color": "red",
223 |                 "value": 80
224 |               }
225 |             ]
226 |           },
227 |           "unit": "none"
228 |         },
229 |         "overrides": []
230 |       },
231 |       "gridPos": {
232 |         "h": 5,
233 |         "w": 6,
234 |         "x": 0,
235 |         "y": 8
236 |       },
237 |       "id": 3,
238 |       "options": {
239 |         "colorMode": "value",
240 |         "graphMode": "none",
241 |         "justifyMode": "auto",
242 |         "orientation": "auto",
243 |         "percentChangeColorMode": "standard",
244 |         "reduceOptions": {
245 |           "calcs": [
246 |             "lastNotNull"
247 |           ],
248 |           "fields": "",
249 |           "values": false
250 |         },
251 |         "showPercentChange": false,
252 |         "textMode": "auto",
253 |         "wideLayout": true
254 |       },
255 |       "pluginVersion": "11.5.2",
256 |       "targets": [
257 |         {
258 |           "datasource": {
259 |             "name": "Prometheus",
260 |             "type": "prometheus"
261 |           },
262 |           "editorMode": "code",
263 |           "expr": "chat_completion_count",
264 |           "interval": "",
265 |           "refId": "A"
266 |         }
267 |       ],
268 |       "title": "Chat Completion Count",
269 |       "type": "stat"
270 |     },
271 |     {
272 |       "fieldConfig": {
273 |         "defaults": {
274 |           "mappings": [],
275 |           "thresholds": {
276 |             "mode": "absolute",
277 |             "steps": [
278 |               {
279 |                 "color": "green",
280 |                 "value": null
281 |               },
282 |               {
283 |                 "color": "red",
284 |                 "value": 80
285 |               }
286 |             ]
287 |           },
288 |           "unit": "none"
289 |         },
290 |         "overrides": []
291 |       },
292 |       "gridPos": {
293 |         "h": 5,
294 |         "w": 6,
295 |         "x": 6,
296 |         "y": 8
297 |       },
298 |       "id": 4,
299 |       "options": {
300 |         "colorMode": "value",
301 |         "graphMode": "none",
302 |         "justifyMode": "auto",
303 |         "orientation": "auto",
304 |         "percentChangeColorMode": "standard",
305 |         "reduceOptions": {
306 |           "calcs": [
307 |             "lastNotNull"
308 |           ],
309 |           "fields": "",
310 |           "values": false
311 |         },
312 |         "showPercentChange": false,
313 |         "textMode": "auto",
314 |         "wideLayout": true
315 |       },
316 |       "pluginVersion": "11.5.2",
317 |       "targets": [
318 |         {
319 |           "datasource": {
320 |             "name": "Prometheus",
321 |             "type": "prometheus"
322 |           },
323 |           "editorMode": "code",
324 |           "expr": "completion_count",
325 |           "interval": "",
326 |           "refId": "A"
327 |         }
328 |       ],
329 |       "title": "Completion Count",
330 |       "type": "stat"
331 |     },
332 |     {
333 |       "fieldConfig": {
334 |         "defaults": {
335 |           "mappings": [],
336 |           "thresholds": {
337 |             "mode": "absolute",
338 |             "steps": [
339 |               {
340 |                 "color": "green",
341 |                 "value": null
342 |               },
343 |               {
344 |                 "color": "red",
345 |                 "value": 80
346 |               }
347 |             ]
348 |           },
349 |           "unit": "none"
350 |         },
351 |         "overrides": []
352 |       },
353 |       "gridPos": {
354 |         "h": 5,
355 |         "w": 6,
356 |         "x": 12,
357 |         "y": 8
358 |       },
359 |       "id": 5,
360 |       "options": {
361 |         "colorMode": "value",
362 |         "graphMode": "none",
363 |         "justifyMode": "auto",
364 |         "orientation": "auto",
365 |         "percentChangeColorMode": "standard",
366 |         "reduceOptions": {
367 |           "calcs": [
368 |             "lastNotNull"
369 |           ],
370 |           "fields": "",
371 |           "values": false
372 |         },
373 |         "showPercentChange": false,
374 |         "textMode": "auto",
375 |         "wideLayout": true
376 |       },
377 |       "pluginVersion": "11.5.2",
378 |       "targets": [
379 |         {
380 |           "datasource": {
381 |             "name": "Prometheus",
382 |             "type": "prometheus"
383 |           },
384 |           "editorMode": "code",
385 |           "expr": "active_worker",
386 |           "interval": "",
387 |           "refId": "A"
388 |         }
389 |       ],
390 |       "title": "Active Worker",
391 |       "type": "stat"
392 |     },
393 |     {
394 |       "fieldConfig": {
395 |         "defaults": {
396 |           "mappings": [],
397 |           "thresholds": {
398 |             "mode": "absolute",
399 |             "steps": [
400 |               {
401 |                 "color": "green",
402 |                 "value": null
403 |               },
404 |               {
405 |                 "color": "red",
406 |                 "value": 80
407 |               }
408 |             ]
409 |           },
410 |           "unit": "none"
411 |         },
412 |         "overrides": []
413 |       },
414 |       "gridPos": {
415 |         "h": 5,
416 |         "w": 6,
417 |         "x": 18,
418 |         "y": 8
419 |       },
420 |       "id": 6,
421 |       "options": {
422 |         "colorMode": "value",
423 |         "graphMode": "none",
424 |         "justifyMode": "auto",
425 |         "orientation": "auto",
426 |         "percentChangeColorMode": "standard",
427 |         "reduceOptions": {
428 |           "calcs": [
429 |             "lastNotNull"
430 |           ],
431 |           "fields": "",
432 |           "values": false
433 |         },
434 |         "showPercentChange": false,
435 |         "textMode": "auto",
436 |         "wideLayout": true
437 |       },
438 |       "pluginVersion": "11.5.2",
439 |       "targets": [
440 |         {
441 |           "datasource": {
442 |             "name": "Prometheus",
443 |             "type": "prometheus"
444 |           },
445 |           "editorMode": "code",
446 |           "expr": "sum(token_usage)",
447 |           "interval": "",
448 |           "legendFormat": "",
449 |           "refId": "A"
450 |         }
451 |       ],
452 |       "title": "Token Usage (gesamt)",
453 |       "type": "stat"
454 |     }
455 |   ],
456 |   "preload": false,
457 |   "refresh": "5s",
458 |   "schemaVersion": 40,
459 |   "tags": [
460 |     "privategpt",
461 |     "agent",
462 |     "prometheus"
463 |   ],
464 |   "templating": {
465 |     "list": []
466 |   },
467 |   "time": {
468 |     "from": "now-15m",
469 |     "to": "now"
470 |   },
471 |   "timepicker": {},
472 |   "timezone": "",
473 |   "title": "OpenAI compatible API - Agent Monitoring",
474 |   "uid": "eeej52phyxbswb",
475 |   "version": 1,
476 |   "weekStart": ""
477 | }
```

--------------------------------------------------------------------------------
/agents/OpenAI_Compatible_API_Agent/Python/openai_mcp_api.py:
--------------------------------------------------------------------------------

```python
  1 | import asyncio
  2 | import logging
  3 | import time
  4 | from pathlib import Path
  5 | from typing import Optional, List
  6 | 
  7 | from fastapi import FastAPI, Request, HTTPException, Header, Depends
  8 | from fastapi.responses import StreamingResponse, Response
  9 | from pydantic import BaseModel
 10 | 
 11 | # Prometheus-Client importieren
 12 | from prometheus_client import (
 13 |     Counter, Histogram, Gauge,
 14 |     generate_latest, CONTENT_TYPE_LATEST
 15 | )
 16 | 
 17 | # ------------------------------------------------------------------
 18 | #   1) Logging: Log-Level konfigurierbar, Minimalkonfiguration
 19 | # ------------------------------------------------------------------
 20 | logging.basicConfig(
 21 |     level=logging.INFO,  # Für Produktion ggf. WARNING oder ERROR
 22 |     format="%(asctime)s [%(levelname)s] %(name)s - %(message)s",
 23 | )
 24 | logger = logging.getLogger(__name__)
 25 | 
 26 | # ------------------------------------------------------------------
 27 | #   2) Konfiguration laden
 28 | # ------------------------------------------------------------------
 29 | try:
 30 |     from ...AgentInterface.Python.config import Config, ConfigError
 31 | 
 32 |     config_file = Path(__file__).parent.parent / "pgpt_openai_api_mcp.json"
 33 |     config_file = Path.absolute(config_file)
 34 |     config = Config(config_file=config_file, required_fields=["email", "password", "mcp_server"])
 35 |     logger.info(f"Configuration loaded: {config}")
 36 | except ConfigError as e:
 37 |     logger.error(f"Configuration Error: {e}")
 38 |     exit(1)
 39 | 
 40 | # ------------------------------------------------------------------
 41 | #   3) Globaler Agent (nur eine Instanz)
 42 | # ------------------------------------------------------------------
 43 | try:
 44 |     from ...AgentInterface.Python.agent import PrivateGPTAgent
 45 |     GLOBAL_AGENT = PrivateGPTAgent(config)
 46 |     logger.info("Global PrivateGPTAgent instance initialized.")
 47 | except Exception as e:
 48 |     logger.error(f"Error initializing global agent: {e}")
 49 |     exit(1)
 50 | 
 51 | # ------------------------------------------------------------------
 52 | #   4) Benötigte Klassen/Modelle
 53 | # ------------------------------------------------------------------
 54 | class Message(BaseModel):
 55 |     role: str
 56 |     content: str
 57 | 
 58 | class ChatCompletionRequest(BaseModel):
 59 |     model: Optional[str] = "PGPT - Mistral NeMo 12B"
 60 |     messages: List[Message]
 61 |     max_tokens: Optional[int] = 2048
 62 |     temperature: Optional[float] = 0.1
 63 |     stream: Optional[bool] = False
 64 | 
 65 | # (Optional) CompletionRequest, falls benötigt
 66 | from agents.OpenAI_Compatible_API_Agent.Python.open_ai_helper import (
 67 |     CompletionRequest,
 68 |     _resp_sync,
 69 |     _resp_async_generator,
 70 |     _resp_async_generator_completions,
 71 |     _resp_sync_completions,
 72 |     models
 73 | )
 74 | 
 75 | # ------------------------------------------------------------------
 76 | #   5) Asynchroner Aufruf des Agenten via Thread-Pool
 77 | # ------------------------------------------------------------------
 78 | from concurrent.futures import ThreadPoolExecutor
 79 | 
 80 | executor = ThreadPoolExecutor(max_workers=4)
 81 | 
 82 | async def async_respond(agent: PrivateGPTAgent, messages: List[Message]) -> dict:
 83 |     """
 84 |     Führt den blockierenden respond_with_context-Aufruf in einem Threadpool aus,
 85 |     um den Haupt-Eventloop nicht zu blockieren.
 86 |     """
 87 |     loop = asyncio.get_event_loop()
 88 |     return await loop.run_in_executor(executor, agent.respond_with_context, messages)
 89 | 
 90 | # ------------------------------------------------------------------
 91 | #   6) FastAPI-App erstellen
 92 | # ------------------------------------------------------------------
 93 | app = FastAPI(title="OpenAI-Compatible API for PrivateGPT using MCP")
 94 | 
 95 | # ------------------------------------------------------------------
 96 | #   7) Prometheus-Metriken definieren
 97 | # ------------------------------------------------------------------
 98 | 
 99 | # Anzahl eingehender Requests pro Method + Endpoint
100 | REQUEST_COUNT = Counter(
101 |     "request_count",
102 |     "Number of requests received",
103 |     ["method", "endpoint"]
104 | )
105 | 
106 | # Latenz der Requests (Histogram)
107 | REQUEST_LATENCY = Histogram(
108 |     "request_latency_seconds",
109 |     "Request latency in seconds",
110 |     ["method", "endpoint"]
111 | )
112 | 
113 | # Zähler, wie oft Chat-/Completion-Aufrufe erfolgreich waren
114 | CHAT_COMPLETION_COUNT = Counter(
115 |     "chat_completion_count",
116 |     "Number of successful ChatCompletion requests"
117 | )
118 | 
119 | COMPLETION_COUNT = Counter(
120 |     "completion_count",
121 |     "Number of successful Completions requests"
122 | )
123 | 
124 | # Ggf. ein Gauge für "laufende Threads" oder "Queue-Länge", falls relevant
125 | # (Beispiel: wir nehmen hier einen Dummy-Gauge für aktive Worker)
126 | ACTIVE_WORKER = Gauge(
127 |     "active_worker",
128 |     "Number of active threads in the ThreadPoolExecutor"
129 | )
130 | 
131 | # (Optional) Counter für Token, wenn du das aus dem Agent extrahieren kannst:
132 | TOKEN_USAGE = Counter(
133 |     "token_usage",
134 |     "Count of tokens used",
135 |     ["model"]
136 | )
137 | 
138 | # ------------------------------------------------------------------
139 | #   8) Middleware zum Messen und Zählen der Requests
140 | # ------------------------------------------------------------------
141 | @app.middleware("http")
142 | async def prometheus_middleware(request: Request, call_next):
143 |     start_time = time.time()
144 |     
145 |     # Zähle Request
146 |     REQUEST_COUNT.labels(request.method, request.url.path).inc()
147 |     
148 |     # Schätze aktive Worker
149 |     #   (Im ThreadPool ist das nicht exakt; man könnte hier "max_workers - free" ermitteln.)
150 |     ACTIVE_WORKER.set(executor._work_queue.qsize())
151 | 
152 |     try:
153 |         response = await call_next(request)
154 |     except Exception as exc:
155 |         raise exc
156 |     finally:
157 |         resp_time = time.time() - start_time
158 |         # Latenz messen
159 |         REQUEST_LATENCY.labels(request.method, request.url.path).observe(resp_time)
160 | 
161 |     return response
162 | 
163 | # ------------------------------------------------------------------
164 | #   9) Whitelist-Prüfung via Dependency
165 | #       -> Gibt bei invalidem Key sofort HTTPException (401) zurück
166 | # ------------------------------------------------------------------
167 | def verify_api_key(authorization: str = Header(None)) -> str:
168 |     if not authorization:
169 |         # Kein Authorization-Header
170 |         raise HTTPException(status_code=401, detail="Missing Authorization header")
171 | 
172 |     try:
173 |         scheme, token = authorization.split(" ")
174 |         if scheme.lower() != "bearer":
175 |             raise HTTPException(status_code=401, detail="Authorization scheme must be 'Bearer'")
176 |     except ValueError:
177 |         raise HTTPException(status_code=401, detail="Invalid Authorization header format")
178 | 
179 |     # Ggf. Whitelisting
180 |     whitelist_keys = config.get("whitelist_keys", [])
181 |     if len(whitelist_keys) > 0 and token not in whitelist_keys:
182 |         # Key ist nicht in der Whitelist
183 |         logger.warning(f"Invalid API key: {token}")
184 |         raise HTTPException(status_code=401, detail="API Key not valid")
185 | 
186 |     return token
187 | 
188 | # ------------------------------------------------------------------
189 | #   10) Chat-Completions Endpoint
190 | # ------------------------------------------------------------------
191 | @app.post("/chat/completions")
192 | async def chat_completions(
193 |     request: ChatCompletionRequest,
194 |     client_api_key: str = Depends(verify_api_key)
195 | ):
196 |     """
197 |     Beispielhafter Endpoint für Chat Completion.
198 |     Nutzt GLOBAL_AGENT und führt die Logik asynchron aus.
199 |     """
200 |     logger.info(f"[/chat/completions] Request received with API key: {client_api_key}")
201 | 
202 |     # Kein messages-Array => Fehler/Leere Antwort
203 |     if not request.messages:
204 |         response = {"chatId": "0", "answer": "No input provided"}
205 |         logger.warning("No messages provided.")
206 |         return _resp_sync(response, request)
207 | 
208 |     # Asynchrone Agent-Antwort
209 |     response = await async_respond(GLOBAL_AGENT, request.messages)
210 |     if "answer" not in response:
211 |         response["answer"] = "No Response received"
212 | 
213 |     # Metrik hochzählen
214 |     CHAT_COMPLETION_COUNT.inc()
215 | 
216 |     # (Optional) Token-Usage-Tracking, falls du im response-Dict Token-Infos hast
217 |     # Hier beispielhaft: response["usage"]["tokens"] (falls existiert)
218 |     # if "usage" in response and "tokens" in response["usage"]:
219 |     #     TOKEN_USAGE.labels(request.model or "unknown_model").inc(response["usage"]["tokens"])
220 | 
221 |     preview_len = 80
222 |     logger.info(f"💡 Response (preview): {response['answer'][:preview_len]}...")
223 | 
224 |     # Streaming?
225 |     if request.stream:
226 |         return StreamingResponse(
227 |             _resp_async_generator(response, request),
228 |             media_type="application/x-ndjson"
229 |         )
230 |     else:
231 |         return _resp_sync(response, request)
232 | 
233 | # ------------------------------------------------------------------
234 | #   11) Text-Completions Endpoint
235 | # ------------------------------------------------------------------
236 | @app.post("/completions")
237 | async def completions(
238 |     request: CompletionRequest,
239 |     client_api_key: str = Depends(verify_api_key)
240 | ):
241 |     logger.info(f"[/completions] Request received with API key: {client_api_key}")
242 | 
243 |     if not request.prompt:
244 |         response = {"chatId": "0", "answer": "No input provided"}
245 |         logger.warning("No prompt provided.")
246 |         return _resp_sync(response, request)
247 | 
248 |     # Asynchrone Agent-Antwort
249 |     response = await async_respond(GLOBAL_AGENT, [Message(role="user", content=request.prompt)])
250 |     if "answer" not in response:
251 |         response["answer"] = "No Response received"
252 | 
253 |     # Completion-Metrik hochzählen
254 |     COMPLETION_COUNT.inc()
255 | 
256 |     # (Optional) Token-Usage-Tracking
257 |     # if "usage" in response and "tokens" in response["usage"]:
258 |     #     TOKEN_USAGE.labels("some_model").inc(response["usage"]["tokens"])
259 | 
260 |     logger.info(f"💡 Response (preview): {response['answer'][:80]}...")
261 | 
262 |     if request.stream:
263 |         return StreamingResponse(
264 |             _resp_async_generator_completions(response, request),
265 |             media_type="application/x-ndjson"
266 |         )
267 |     else:
268 |         return _resp_sync_completions(response, request)
269 | 
270 | # ------------------------------------------------------------------
271 | #   12) Modelle abfragen
272 | # ------------------------------------------------------------------
273 | @app.get("/models")
274 | def return_models():
275 |     return {"object": "list", "data": models}
276 | 
277 | @app.get("/models/{model_id}")
278 | async def get_model(model_id: str):
279 |     filtered_entries = [m for m in models if m["id"] == model_id]
280 |     if not filtered_entries:
281 |         raise HTTPException(status_code=404, detail="Model not found")
282 |     return filtered_entries[0]
283 | 
284 | # ------------------------------------------------------------------
285 | #   13) /metrics Endpoint für Prometheus
286 | # ------------------------------------------------------------------
287 | @app.get("/metrics")
288 | def metrics():
289 |     """
290 |     Endpoint, der die Prometheus-Metriken zurückgibt.
291 |     Von Prometheus unter http://<host>:<port>/metrics abgefragt.
292 |     """
293 |     return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)
294 | 
295 | # ------------------------------------------------------------------
296 | #   14) App-Start via uvicorn.run()
297 | # ------------------------------------------------------------------
298 | if __name__ == "__main__":
299 |     import uvicorn
300 |     api_ip = config.get("api_ip", "0.0.0.0")
301 |     api_port = config.get("api_port", 8002)
302 |     logger.info(f"Starting API on http://{api_ip}:{api_port}")
303 |     # workers=4, wenn man mehrere Prozesse möchte (Skalierung)
304 |     uvicorn.run(app, host=api_ip, port=int(api_port))
305 | 
```

--------------------------------------------------------------------------------
/agents/AgentInterface/Python/agent.py:
--------------------------------------------------------------------------------

```python
  1 | # agent.py
  2 | 
  3 | import logging
  4 | import json
  5 | import atexit
  6 | from .network import NetworkClient, NetworkError
  7 | from .color import Color
  8 | from .language import languages
  9 | 
 10 | class GroupValidationError(Exception):
 11 |     """Exception raised for errors in the group validation process."""
 12 |     pass
 13 | 
 14 | class PrivateGPTAgent:
 15 |     def __init__(self, config):
 16 |         # mcp_server-Daten aus dem config-Objekt lesen
 17 |         self.mcp_config = config.get("mcp_server")
 18 |         # Lese host und port
 19 |         self.mcp_host = self.mcp_config.get("host")
 20 |         self.mcp_port = self.mcp_config.get("port")
 21 |         self.server_ip = self.mcp_host
 22 |         self.server_port = self.mcp_port
 23 |         self.email = config.get("email")
 24 |         self.password = config.get("password")
 25 |         self.chosen_groups = config.get("groups", [])
 26 |         self.language = config.get("language", "en")  # Standard ist Englisch
 27 | 
 28 |         if self.language not in languages:
 29 |             self.language = "en"
 30 |             logging.warning(f"Unsupported language '{config.get('language')}'. Falling back to English.")
 31 | 
 32 |         self.lang = languages[self.language]
 33 | 
 34 |         self.network_client = NetworkClient(self.server_ip, self.server_port, language=self.language)
 35 |         self.token = None
 36 | 
 37 |         atexit.register(self.logout)
 38 | 
 39 |         # Initialer Login
 40 |         self.login()
 41 | 
 42 |         # Personalisierte Gruppen abholen
 43 |         if self.token:
 44 |             self.allowed_groups = self.list_personal_groups()
 45 |             if not self.allowed_groups:
 46 |                 logging.warning(self.lang["no_personal_groups"])
 47 |                 print(self.lang["no_personal_groups"], flush=True)
 48 |                 self.allowed_groups = []
 49 | 
 50 |             # Validierung der Gruppen
 51 |             invalid = self.validate_groups(self.chosen_groups)
 52 |             if invalid:
 53 |                 print(self.lang["invalid_group"].format(groups=invalid), flush=True)
 54 |                 logging.error(self.lang["invalid_group_error"])
 55 |                 raise GroupValidationError(self.lang["invalid_group"].format(groups=invalid))
 56 |         else:
 57 |             self.allowed_groups = []
 58 | 
 59 |         # Lokale Wissensbasis (Beispiel)
 60 |         self.knowledge_base = {
 61 |             "What is AI?": self.lang["knowledge_ai"],
 62 |             "Who created Python?": self.lang["knowledge_python"],
 63 |             "What is Machine Learning?": self.lang["knowledge_ml"]
 64 |         }
 65 | 
 66 |     def get_lang_message(self, key, **kwargs):
 67 |         message = self.lang.get(key, "Message not defined.")
 68 |         try:
 69 |             return message.format(**kwargs)
 70 |         except KeyError as e:
 71 |             logging.error(f"Missing placeholder in language file for key '{key}': {e}")
 72 |             return message
 73 | 
 74 |     def validate_groups(self, groups):
 75 |         if groups is None:
 76 |             return []
 77 |         invalid = [g for g in groups if g not in self.allowed_groups]
 78 |         if invalid:
 79 |             logging.error(self.get_lang_message("group_validation_error", error=invalid))
 80 |             return invalid
 81 |         return []
 82 | 
 83 |     def login(self):
 84 |         payload = {
 85 |             "command": "login",
 86 |             "arguments": {
 87 |                 "email": self.email,
 88 |                 "password": self.password
 89 |             }
 90 |         }
 91 |         logging.info(self.get_lang_message("login_attempt"))
 92 |         try:
 93 |             resp = self.network_client.send_request(payload)
 94 |             #logging.info(self.get_lang_message("received_response", response=resp))
 95 | 
 96 |             if resp.get("status") == 200 and resp.get("message") == "success":
 97 |                 self.token = resp.get("token")
 98 |                 logging.info(self.get_lang_message("login_success"))
 99 |                 return True
100 |             else:
101 |                 msg = resp.get("message", self.get_lang_message("no_server_message"))
102 |                 logging.error(self.get_lang_message("login_failed", message=msg))
103 |                 return False
104 |         except NetworkError as e:
105 |             logging.error(self.get_lang_message("login_failed", message=str(e)))
106 |             return False
107 | 
108 |     def list_personal_groups(self):
109 |         if not self.token:
110 |             logging.error(self.get_lang_message("authentication_failed"))
111 |             return []
112 | 
113 |         payload = {
114 |             "command": "list_groups",
115 |             "token": self.token
116 |         }
117 |         try:
118 |             resp = self.network_client.send_request(payload)
119 |             data_block = resp.get("data")
120 |             if not data_block:
121 |                 logging.warning(self.lang["no_data_in_response"].format(response=resp))
122 |                 return []
123 | 
124 |             if data_block.get("status") == 200 and data_block.get("message") == "success":
125 |                 personal = data_block.get("personalGroups", [])
126 |                 logging.info(self.lang["personal_groups"].format(groups=personal))
127 |                 return personal
128 |             else:
129 |                 logging.warning(self.lang["list_groups_failed"].format(
130 |                     message=data_block.get("message", self.lang["no_server_message"])))
131 |                 return []
132 |         except NetworkError as e:
133 |             logging.error(self.lang["list_groups_failed"].format(message=str(e)))
134 |             return []
135 | 
136 |     def query_private_gpt(self, prompt, use_public=False, language="en", groups=None, _retry_on_token_expired=True):
137 |         if not self.token:
138 |             error_msg = self.get_lang_message("authentication_failed")
139 |             logging.error(error_msg)
140 |             return json.dumps({"error": error_msg})
141 | 
142 |         if language not in languages:
143 |             language = 'en'
144 |             logging.warning(f"Unsupported language '{language}'. Falling back to English.")
145 | 
146 |         lang = languages[language]
147 | 
148 |         if groups is None:
149 |             groups = self.chosen_groups
150 |         else:
151 |             groups = [g.strip() for g in groups if g.strip()]
152 |         relevant_groups = [g for g in groups if g in self.allowed_groups]
153 | 
154 |         payload = {
155 |             "command": "chat",
156 |             "token": self.token,
157 |             "arguments": {
158 |                 "question": prompt,
159 |                 "usePublic": use_public,
160 |                 "groups": relevant_groups,
161 |                 "language": language
162 |             }
163 |         }
164 |         #logging.info(lang["sending_payload"].format(payload=json.dumps(payload)))
165 | 
166 |         try:
167 |             resp = self.network_client.send_request(payload)
168 |             #logging.info(lang["received_response"].format(response=resp))
169 | 
170 |             # ─────────────────────────────────────────────────
171 |             # Token abgelaufen/ungültig => Re-Login
172 |             # ─────────────────────────────────────────────────
173 |             if (
174 |                 (resp.get("status") in [401, 403])
175 |                 or (resp.get("message") in ["token expired", "token invalid"])
176 |             ):
177 |                 if not _retry_on_token_expired:
178 |                     return json.dumps({"error": "Token ungültig, Re-Login fehlgeschlagen."})
179 | 
180 |                 # Zusätzlicher Log-Eintrag, um sicher zu sehen, dass der Refresh hier wirklich passiert:
181 |                 logging.warning("TOKEN REFRESH TRIGGERED! (401/403 or token expired/invalid recognized)")
182 | 
183 |                 old_token = self.token
184 |                 self.token = None
185 | 
186 |                 if self.login():
187 |                     return self.query_private_gpt(
188 |                         prompt, use_public, language, groups,
189 |                         _retry_on_token_expired=False
190 |                     )
191 |                 else:
192 |                     return json.dumps({"error": "Automatischer Re-Login ist fehlgeschlagen."})
193 | 
194 |             # Normaler Erfolgsfall
195 |             if resp.get("status") == 200 and resp.get("message") == "success":
196 |                 content = resp.get("content", {})
197 |                 answer = content.get("answer", lang["agent_error"].format(error=lang["no_answer_received"]))
198 |                 return json.dumps({"answer": answer})
199 |             else:
200 |                 return json.dumps({"error": resp.get("message", lang["agent_error"].format(error=lang["unknown_error"]))})
201 | 
202 |         except NetworkError as e:
203 |             error_msg = lang["agent_error"].format(error=str(e))
204 |             logging.error(f"❌ {error_msg}")
205 |             return json.dumps({"error": error_msg})
206 | 
207 |     def respond(self, user_input, groups=None):
208 |         response = self.knowledge_base.get(user_input, None)
209 |         if response:
210 |             #logging.info(self.get_lang_message("knowledge_response", input=user_input))
211 |             return json.dumps({"answer": response})
212 |         else:
213 |             return self.query_private_gpt(user_input, groups=groups)
214 | 
215 |     def respond_with_context(self, messages):
216 |         user_input = f'{messages[-1].content}'
217 |         add_context = False
218 |         if add_context:
219 |             messages.pop()
220 |             user_input += "\nHere is some context about the previous conversation:\n"
221 |             for message in messages:
222 |                 user_input += f"{message.role}: {message.content}\n"
223 | 
224 |         result = self.query_private_gpt(user_input)
225 |         return json.loads(result)
226 | 
227 |     def logout(self):
228 |         if not self.token:
229 |             logging.info(self.get_lang_message("no_token_logout"))
230 |             return
231 | 
232 |         payload = {
233 |             "command": "logout",
234 |             "token": self.token
235 |         }
236 |         logging.info(self.get_lang_message("logout_attempt"))
237 |         try:
238 |             resp = self.network_client.send_request(payload)
239 |             logging.info(self.get_lang_message("received_response", response=resp))
240 | 
241 |             if resp.get("status") == 200 and resp.get("message") == "success":
242 |                 logging.info(self.get_lang_message("logout_success"))
243 |                 self.token = None
244 |             else:
245 |                 msg = resp.get("message", self.get_lang_message("no_server_message"))
246 |                 logging.warning(self.get_lang_message("logout_failed", message=msg))
247 |         except NetworkError as e:
248 |             logging.error(self.get_lang_message("logout_failed", message=str(e)))
249 | 
250 |     def run(self):
251 |         if not self.token:
252 |             logging.error(self.get_lang_message("authentication_failed"))
253 |             print(self.get_lang_message("authentication_failed"), flush=True)
254 |             return
255 | 
256 |         welcome_msg = f"{Color.OKGREEN}{self.get_lang_message('welcome')}{Color.ENDC}"
257 |         print(welcome_msg, flush=True)
258 |         logging.info(self.get_lang_message("user_interface_started"))
259 | 
260 |         while True:
261 |             try:
262 |                 user_input = input(f"{Color.OKBLUE}{self.get_lang_message('user_question')}{Color.ENDC}")
263 |                 if user_input.strip().lower() == "exit":
264 |                     goodbye_msg = f"{Color.OKGREEN}{self.get_lang_message('goodbye')}{Color.ENDC}"
265 |                     print(goodbye_msg, flush=True)
266 |                     logging.info(self.get_lang_message("session_ended"))
267 |                     break
268 |                 elif not user_input.strip():
269 |                     continue
270 | 
271 |                 result = self.respond(user_input)
272 |                 parsed_result = json.loads(result)
273 |                 if "answer" in parsed_result:
274 |                     answer = parsed_result["answer"]
275 |                     print(f"{Color.OKGREEN}{self.get_lang_message('agent_answer', answer=answer)}{Color.ENDC}", flush=True)
276 |                 else:
277 |                     error = parsed_result["error"]
278 |                     print(f"{Color.FAIL}{self.get_lang_message('agent_error', error=error)}{Color.ENDC}", flush=True)
279 |             except (KeyboardInterrupt, EOFError):
280 |                 goodbye_msg = f"{Color.OKGREEN}{self.get_lang_message('goodbye')}{Color.ENDC}"
281 |                 print(goodbye_msg, flush=True)
282 |                 logging.info(self.get_lang_message("session_interrupted"))
283 |                 break
284 | 
```
Page 14/20FirstPrevNextLast