#
tokens: 49403/50000 10/501 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
│   ├── 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

--------------------------------------------------------------------------------
/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 | 
```

--------------------------------------------------------------------------------
/clients/PHP/5.0 mcp_store_user/MCPStoreUserClient.php:
--------------------------------------------------------------------------------

```php
  1 | <?php
  2 | /**
  3 |  * MCPStoreUserClient.php
  4 |  *
  5 |  * A PHP script that acts as a Store User Client. It connects to a server via TCP,
  6 |  * sends a request to store a new user, and receives the server's response.
  7 |  *
  8 |  * Usage:
  9 |  * php MCPStoreUserClient.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 interactively prompt for a parameter (optional)
124 |  *
125 |  * @param string $prompt The input prompt
126 |  * @return string The user input
127 |  */
128 | function askQuestionPrompt($prompt) {
129 |     if (preg_match('/^win/i', PHP_OS)) {
130 |         // Windows specific input prompt
131 |         $vbscript = sys_get_temp_dir() . 'prompt_input.vbs';
132 |         file_put_contents($vbscript, 'wscript.echo(InputBox("' . addslashes($prompt) . '", "", ""))');
133 |         $response = shell_exec("cscript //nologo " . escapeshellarg($vbscript));
134 |         unlink($vbscript);
135 |         return trim($response);
136 |     } else {
137 |         // Unix/Linux input prompt
138 |         echo $prompt;
139 |         $handle = fopen("php://stdin", "r");
140 |         $response = trim(fgets($handle));
141 |         fclose($handle);
142 |         return $response;
143 |     }
144 | }
145 | 
146 | /**
147 |  * Function to send a Store User request over a TCP connection
148 |  *
149 |  * @param string $serverIp The server's IP address
150 |  * @param int $serverPort The server's port
151 |  * @param string $token The authentication token
152 |  * @param array $args The arguments for the user to be processed
153 |  * @return array The response received from the server as an associative array
154 |  * @throws Exception On connection errors or JSON parsing errors
155 |  */
156 | function sendStoreUserRequest($serverIp, $serverPort, $token, $args) {
157 |     $payload = [
158 |         "command" => "store_user",
159 |         "token" => $token,
160 |         "arguments" => [
161 |             "name" => $args['name'] ?? null,
162 |             "email" => $args['email'] ?? null,
163 |             "password" => $args['password'] ?? null,
164 |             "language" => $args['language'] ?? null,
165 |             "timezone" => $args['timezone'] ?? null,
166 |             "roles" => $args['roles'] ?? [],
167 |             "groups" => $args['groups'] ?? [],
168 |             "usePublic" => $args['usePublic'] ?? false,
169 |             "activateFtp" => $args['activateFtp'] ?? false,
170 |             "ftpPassword" => $args['ftpPassword'] ?? null
171 |         ]
172 |     ];
173 | 
174 |     // Remove null or empty values from the arguments
175 |     $payload['arguments'] = array_filter($payload['arguments'], function($value) {
176 |         if (is_array($value)) {
177 |             return !empty($value);
178 |         }
179 |         return $value !== null;
180 |     });
181 | 
182 |     $jsonPayload = json_encode($payload);
183 |     if ($jsonPayload === false) {
184 |         throw new Exception("Error while encoding the JSON payload: " . json_last_error_msg());
185 |     }
186 | 
187 |     $errno = 0;
188 |     $errstr = '';
189 |     $timeoutDuration = 10; // Seconds (10 seconds timeout)
190 |     $client = @fsockopen($serverIp, $serverPort, $errno, $errstr, $timeoutDuration);
191 | 
192 |     if (!$client) {
193 |         throw new Exception("Connection error: $errstr ($errno)");
194 |     }
195 | 
196 |     echo "🔗 Connected to server ({$serverIp}:{$serverPort}).\n";
197 |     echo "📤 Sending Payload: {$jsonPayload}\n";
198 | 
199 |     fwrite($client, $jsonPayload);
200 | 
201 |     $responseData = '';
202 |     stream_set_timeout($client, $timeoutDuration);
203 | 
204 |     while (!feof($client)) {
205 |         $data = fread($client, 1024);
206 |         if ($data === false) {
207 |             throw new Exception("Error reading data from server.");
208 |         }
209 |         if ($data === '') {
210 |             break; // No more data
211 |         }
212 |         echo "📥 Received data: {$data}\n";
213 |         $responseData .= $data;
214 | 
215 |         // Attempt to parse the received data as JSON
216 |         $parsedData = json_decode($responseData, true);
217 |         if ($parsedData !== null) {
218 |             echo "✅ JSON response successfully parsed.\n";
219 |             fclose($client);
220 |             return $parsedData;
221 |         }
222 | 
223 |         // Check if the stream has timed out
224 |         $info = stream_get_meta_data($client);
225 |         if ($info['timed_out']) {
226 |             throw new Exception("Timeout while waiting for data from server.");
227 |         }
228 |     }
229 | 
230 |     fclose($client);
231 |     throw new Exception("Connection to server was closed before a complete response was received.");
232 | }
233 | 
234 | /**
235 |  * Main function of the script
236 |  */
237 | function main($argv) {
238 |     $parsedArgs = parseArguments($argv);
239 |     $serverIp = $parsedArgs['serverIp'] ?? null;
240 |     $serverPort = $parsedArgs['serverPort'] ?? null;
241 |     $token = $parsedArgs['token'] ?? null;
242 |     $name = $parsedArgs['name'] ?? null;
243 |     $email = $parsedArgs['email'] ?? null;
244 |     $password = $parsedArgs['password'] ?? null;
245 |     $language = $parsedArgs['language'] ?? null;
246 |     $timezone = $parsedArgs['timezone'] ?? null;
247 |     $roles = $parsedArgs['roles'] ?? [];
248 |     $groups = $parsedArgs['groups'] ?? [];
249 |     $usePublic = $parsedArgs['usePublic'] ?? false;
250 |     $activateFtp = $parsedArgs['activateFtp'] ?? false;
251 |     $ftpPassword = $parsedArgs['ftpPassword'] ?? null;
252 | 
253 |     // Check if all required parameters are present, otherwise prompt interactively
254 |     if (!$serverIp) {
255 |         $serverIp = askQuestionPrompt('🔗 Please enter the server IP: ');
256 |     }
257 |     if (!$serverPort) {
258 |         $portInput = askQuestionPrompt('🔗 Please enter the server port: ');
259 |         $serverPort = intval($portInput);
260 |         if ($serverPort <= 0) {
261 |             fwrite(STDERR, "❌ ERROR: Invalid server port.\n");
262 |             exit(1);
263 |         }
264 |     }
265 |     if (!$token) {
266 |         $token = askQuestionPrompt('🔒 Please enter your authentication token: ');
267 |     }
268 |     if (!$name) {
269 |         $name = askQuestionPrompt('👤 Please enter the user\'s name: ');
270 |     }
271 |     if (!$email) {
272 |         $email = askQuestionPrompt('📧 Please enter the user\'s email: ');
273 |     }
274 |     if (!$password) {
275 |         $password = askQuestionPrompt('🔑 Please enter the user\'s password: ');
276 |     }
277 |     if (!$language) {
278 |         $language = askQuestionPrompt('🌐 Please enter the user\'s preferred language (e.g., en, de): ');
279 |     }
280 |     if (!$timezone) {
281 |         $timezone = askQuestionPrompt('🕰️ Please enter the user\'s timezone (e.g., Europe/Berlin): ');
282 |     }
283 |     // Roles and groups are optional and have already been handled by parseArguments
284 |     // usePublic, activateFtp, and ftpPassword are also optional
285 | 
286 |     // Set default values for optional parameters if they are not present
287 |     $roles = $roles ?: [];
288 |     $groups = $groups ?: [];
289 |     $usePublic = $usePublic ? true : false;
290 |     $activateFtp = $activateFtp ? true : false;
291 |     $ftpPassword = $ftpPassword ?: '';
292 | 
293 |     // Check if all required parameters are now present
294 |     if (!$serverIp || !$serverPort || !$token || !$name || !$email || !$password || !$language || !$timezone) {
295 |         fwrite(STDERR, "❌ ERROR: Missing required parameters.\n");
296 |         fwrite(STDOUT, "Usage: php MCPStoreUserClient.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");
297 |         exit(1);
298 |     }
299 | 
300 |     try {
301 |         echo "🧑‍💻 Sending Store-User request...\n";
302 |         $response = sendStoreUserRequest(
303 |             $serverIp,
304 |             $serverPort,
305 |             $token,
306 |             [
307 |                 'name' => $name,
308 |                 'email' => $email,
309 |                 'password' => $password,
310 |                 'language' => $language,
311 |                 'timezone' => $timezone,
312 |                 'roles' => $roles,
313 |                 'groups' => $groups,
314 |                 'usePublic' => $usePublic,
315 |                 'activateFtp' => $activateFtp,
316 |                 'ftpPassword' => $ftpPassword
317 |             ]
318 |         );
319 |         echo "✔️ Server response:\n";
320 |         echo json_encode($response, JSON_PRETTY_PRINT) . "\n";
321 |     } catch (Exception $e) {
322 |         fwrite(STDERR, "❌ Error: " . $e->getMessage() . "\n");
323 |     }
324 | }
325 | 
326 | // Check if PHP version is at least 7.1 (for better features)
327 | if (version_compare(PHP_VERSION, '7.1.0') < 0) {
328 |     fwrite(STDERR, "❌ ERROR: This script requires PHP version 7.1 or higher.\n");
329 |     exit(1);
330 | }
331 | 
332 | // Call the main function
333 | main($argv);
334 | ?>
335 | 
```

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

```python
  1 | import json
  2 | import re
  3 | from pathlib import Path
  4 | 
  5 | import requests
  6 | import urllib3
  7 | import base64
  8 | 
  9 | from ...AgentInterface.Python.config import Config
 10 | 
 11 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
 12 | 
 13 | 
 14 | def initialize_session(proxy_user, proxy_password, access_header):
 15 |     """Set up the session with proxy authentication."""
 16 |     session = requests.Session()
 17 |     session.verify = False
 18 |     headers = {
 19 |         'Accept': 'application/json',
 20 |         'Content-Type': 'application/json',
 21 |     }
 22 |     if access_header is not None:
 23 |         headers['X-Custom-Header'] = access_header
 24 |     elif proxy_user is not None and proxy_password is not None:
 25 |             auth = base64.b64encode(f"{proxy_user}:{proxy_password}".encode()).decode()
 26 |             headers['Authorization'] = f'Basic {auth}'
 27 |     session.headers.update(headers)
 28 |     return session
 29 | 
 30 | 
 31 | class PrivateGPTAPI:
 32 |     def __init__(self, config, client_api_key=None):
 33 |         """Initialize the chat client with proxy authentication."""
 34 |         self.token = None
 35 |         self.chat_id = None
 36 | 
 37 |         self.base_url = config.get("base_url")
 38 |         self.proxy_user = config.get("proxy_user", None)
 39 |         if self.proxy_user == "":
 40 |             self.proxy_user = None
 41 |         self.proxy_password = config.get("proxy_password", None)
 42 |         if self.proxy_password == "":
 43 |             self.proxy_password = None
 44 |         self.access_header = config.get("access_header", None)
 45 |         if self.access_header == "":
 46 |             self.access_header = None
 47 | 
 48 |         self.chosen_groups = config.data["groups"] or []
 49 |         self.language = config.get("language", "en")
 50 |         self.use_public = config.get("use_public", True)
 51 |         self.whitelist_keys = config.get("whitelist_keys", [])
 52 |         self.logged_in = False
 53 | 
 54 | 
 55 |         if client_api_key is not None:
 56 |             self.email, self.password = decrypt_api_key(client_api_key)
 57 |             if len(self.whitelist_keys) > 0:
 58 |                 if client_api_key not in self.whitelist_keys:
 59 |                     print("not authorized")
 60 | 
 61 |         self.session = initialize_session(self.proxy_user, self.proxy_password, self.access_header)
 62 |         if self.login():
 63 |             self.logged_in = True
 64 | 
 65 | 
 66 |     def login(self):
 67 |         """Authenticate the user and retrieve the token."""
 68 |         url = f"{self.base_url}/login"
 69 |         payload = {"email": self.email, "password": self.password}
 70 |         try:
 71 |             response = self.session.post(url, json=payload)
 72 |             print(response.content)
 73 |             response.raise_for_status()
 74 |             data = response.json()
 75 |             self.token = data['data']['token']
 76 |             
 77 |             # Prüfen, ob der Header bereits existiert
 78 |             if 'Authorization' in self.session.headers:
 79 |                 self.session.headers['Authorization'] += f', Bearer {self.token}'
 80 |             else:
 81 |                 self.session.headers['Authorization'] = f'Bearer {self.token}'
 82 |             self.chat_id = None
 83 |             print("✅ Login successful.")
 84 |             return True
 85 |         except requests.exceptions.RequestException as e:
 86 |             print(f"❌ Login failed: {e}")
 87 |         return False
 88 | 
 89 |     def create_chat(self, user_input):
 90 |         """Start a new chat session.
 91 | 
 92 |         This method sends a POST request to the '/chats' endpoint with the provided parameters.
 93 |         It initializes a new chat session and stores the chat ID for future use.
 94 |         """
 95 |         url = f"{self.base_url}/chats"
 96 |         payload = {
 97 |             "language": self.language,
 98 |             "question": user_input,  # Initial question to start the chat
 99 |             "usePublic": self.use_public,
100 |             "groups": self.chosen_groups
101 |         }
102 |         try:
103 |             response = self.session.post(url, json=payload)
104 |             response.raise_for_status()  # Raise an exception if the response was not successful
105 |             data = response.json()
106 |             self.chat_id = data['data']['chatId']  # Store the chat ID for future use
107 |             print("✅ Chat initialized.")
108 |             resp = response.json()
109 |             try:
110 |                 answer = resp.get('data', None).get('answer', "error")
111 |             except:
112 |                 print(response.json())
113 |                 resp = {"data":
114 |                             {"answer": "error"}
115 |                         }
116 |                 answer = "error"
117 | 
118 |             if answer.startswith("{\"role\":"):
119 |                 answerj = json.loads(answer)
120 |                 resp["data"]["answer"] = answerj["content"]
121 |                 resp["data"]["chatId"] = "0"
122 | 
123 |             print(f"💡 Response: {answer}")
124 |             return resp
125 |         except requests.exceptions.RequestException as e:
126 |             # It seems we get disconnections from time to time..
127 |             # print(f"⚠️ Failed to get response on first try, trying again..: {e}")
128 |             try:
129 |                 response = self.session.patch(url, json=payload)
130 |                 response.raise_for_status()
131 |                 data = response.json()
132 |                 answer = data.get('data', {}).get('answer', "No answer provided.")
133 |                 print(f"💡 Response: {answer}")
134 |                 return data
135 |             except:
136 |                 print(f"❌ Failed to get response: {e}")
137 |                 return {"error": f"❌ Failed to get response: {e}"}
138 | 
139 |     def query_private_gpt(self, user_input) -> json:
140 |         """Send a question to the chat and retrieve the response."""
141 |         if not self.chat_id:
142 |             print("❌ Chat session not initialized.")
143 |             return False
144 |         url = f"{self.base_url}/chats/{self.chat_id}"
145 |         payload = {"question": user_input}
146 |         try:
147 |             response = self.session.patch(url, json=payload)
148 |             #response.raise_for_status()
149 |             resp = response.json()
150 |             try:
151 |                 answer = resp.get('data', None).get('answer', "error")
152 |             except:
153 |                 print(response.json())
154 |                 resp = {"data" :
155 |                         {"answer": "error"}
156 |                         }
157 |                 answer = "error"
158 | 
159 |             if answer.startswith("{\"role\":"):
160 |                  answerj = json.loads(answer)
161 |                  resp["data"]["answer"] = answerj["content"]
162 |                  resp["data"]["chatId"] = "0"
163 | 
164 |             print(f"💡 Response: {answer}")
165 |             return resp
166 |         except requests.exceptions.RequestException as e:
167 |             # It seems we get disconnections from time to time..
168 |             #print(f"⚠️ Failed to get response on first try, trying again..: {e}")
169 |             try:
170 |                 response = self.session.patch(url, json=payload)
171 |                 response.raise_for_status()
172 |                 data = response.json()
173 |                 answer = data.get('data', {}).get('answer', "No answer provided.")
174 |                 print(f"💡 Response: {answer}")
175 |                 return data
176 |             except:
177 |                 print(f"❌ Failed to get response: {e}")
178 |                 return {"error": f"❌ Failed to get response: {e}"}
179 | 
180 | 
181 |     def get_document_info(self, source_id):
182 |         """Send a source id to retrieve details. Working with version 1.3.3 and newer"""
183 |         url = f"{self.base_url}/sources/{source_id}"
184 |         try:
185 |             response = self.session.get(url)
186 |             data = response.json()
187 |             info = data.get('data', {})
188 |             print(f"💡 Response: {str(info)}")
189 |             return data
190 |         except requests.exceptions.RequestException as e:
191 |             print(f"❌ Failed to get response: {e}")
192 |             return {"error": f"❌ Failed to get response: {e}"}
193 | 
194 | 
195 |     def respond_with_context(self, messages, response_format=None, request_tools=None):
196 |         last_user_message = next((p for p in reversed(messages) if p.role == "user"), None)
197 |         user_input = ""
198 | 
199 | 
200 |         for message in messages:
201 |             if message.role == "system":
202 |                 user_input = str(message) + "\n"
203 | 
204 |         if last_user_message is not None:
205 |             user_input += last_user_message.content
206 | 
207 |         last_assistant_message = next((p for p in reversed(messages) if p.role == "assistant"), None)
208 |         last_tool_message = next((p for p in reversed(messages) if p.role == "tool"), None)
209 | 
210 |         hastoolresult = False
211 |         if last_tool_message is not None and last_assistant_message is not None and last_assistant_message.tool_calls is not None and len(last_assistant_message.tool_calls) > 0:
212 |             user_input += "\nYou called the tool: " + str(last_assistant_message.tool_calls[0]) + ". The result was: " + last_tool_message.content
213 |             hastoolresult = True
214 | 
215 | 
216 |         print(f"💁 Request: " + user_input)
217 | 
218 |         # PGPT manages history and context itself so we don't need to forward the history.
219 |         add_context = False
220 |         if add_context:
221 |             messages.pop()
222 |             user_input += "\nHere is some context about the previous conversation:\n"
223 |             for message in messages:
224 |                 user_input += f"{message.role}: {message.content}\n"
225 | 
226 |         if response_format is not None:
227 |             print("Response format: " + str(response_format))
228 |             user_input += add_response_format(response_format)
229 | 
230 |         if request_tools is not None and not hastoolresult:
231 |             user_input += add_tools(request_tools, last_tool_message)
232 | 
233 |         if not self.logged_in:
234 |             self.login()
235 |         else:
236 |             if self.chat_id is None:
237 |                 result = self.create_chat(user_input)
238 |             else:
239 |                 result = self.query_private_gpt(user_input)
240 | 
241 |             if 'data' in result:
242 |                 response_data = result.get("data")
243 |                 if request_tools is not None and not hastoolresult and is_json(clean_response(response_data.get("answer"))):
244 |                     response_data["tool_call"] = clean_response(response_data.get("answer", ""))
245 |                 return response_data
246 |             elif 'error' in result:
247 |                 # Try to login again and send the query once more on error.
248 |                 if self.login():
249 |                     if self.chat_id is None:
250 |                         result = self.create_chat(user_input)
251 |                     else:
252 |                         result = self.query_private_gpt(user_input)
253 | 
254 |                     if 'data' in result:
255 |                         return result['data']
256 |                     else:
257 |                         return result
258 | 
259 |             else:
260 |                 return result
261 | 
262 | def is_json(myjson):
263 |   try:
264 |     json.loads(myjson)
265 |   except ValueError as e:
266 |     return False
267 |   return True
268 | 
269 | def add_response_format(response_format):
270 |     #prompt = "\nPlease fill in the following template with realistic and appropriate information. Be creative. The field 'type' defines the output format. In your reply, only return the generated json\n"
271 |     prompt = "\nPlease fill in the following json template with realistic and appropriate information. In your reply, only return the generated json. If you can't answer return an empty json.\n"
272 |     prompt += json.dumps(response_format)
273 |     return prompt
274 | 
275 | 
276 | def add_tools(response_tools, last_tool_message):
277 | 
278 |     prompt = "\nPlease select the fitting provided tool to create your answer. Only return the generated result of the tool. Do not describe what you are doing, just return the json.\n"
279 |     index = 1
280 |     for tool in response_tools:
281 |         prompt += "\n" + json.dumps(tool) + "\n"
282 |         index += 1
283 | 
284 |     return prompt
285 | 
286 | def clean_response(response):
287 |     # Remove artefacts from reply here
288 |     response = response.replace("[TOOL_CALLS]", "")
289 |     return response
290 | 
291 | def decrypt_api_key(api_key):
292 |     """
293 |     This is PoC code and methods should be replaced with a more secure way to deal with credentials (e.g. in a db)
294 |     """
295 |     try:
296 |         base64_bytes = api_key.encode("ascii")
297 |         decoded_string_bytes = base64.b64decode(base64_bytes)
298 |         decoded_key = decoded_string_bytes.decode("ascii")
299 |     except Exception as e:
300 |         print(e)
301 |         decoded_key = "invalid:invalid"
302 | 
303 |     return decoded_key.split(":")[0], decoded_key.split(":")[1]
304 | 
305 | 
306 | def main():
307 |     """Main function to run the chat application."""
308 |     config_file = Path.absolute(Path(__file__).parent.parent / "pgpt_openai_api_proxy.json")
309 |     config = Config(config_file=config_file, required_fields=["base_url"])
310 |     chat = PrivateGPTAPI(config)
311 | 
312 |     print("Type your questions below. Type 'quit' to exit.")
313 |     while True:
314 |         try:
315 |             question = input("❓ Question: ").strip()
316 |             if question.lower() == 'quit':
317 |                 break
318 |             if question:
319 |                  chat.query_private_gpt(question)
320 |         except KeyboardInterrupt:
321 |             print("\nExiting chat...")
322 |             break
323 |         except Exception as e:
324 |             print(f"❌ Error: {str(e)}")
325 |             break
326 | 
327 | 
328 | if __name__ == "__main__":
329 |     main()
```
Page 14/20FirstPrevNextLast