This is page 8 of 16. Use http://codebase.md/fujitsu-ai/mcp-server-for-mas-developments?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 -------------------------------------------------------------------------------- /clients/PHP/1.0 mcp_login/MCPLoginClient.php: -------------------------------------------------------------------------------- ```php <?php // Functions for parsing command line arguments function parseArguments($args) { $parsedArgs = []; $argc = count($args); for ($i = 1; $i < $argc; $i++) { switch ($args[$i]) { case '--server-ip': if (isset($args[$i + 1])) { $parsedArgs['serverIp'] = $args[++$i]; } else { fwrite(STDERR, "Error: --server-ip expects a value.\n"); exit(1); } break; case '--server-port': if (isset($args[$i + 1])) { $parsedArgs['serverPort'] = intval($args[++$i]); } else { fwrite(STDERR, "Error: --server-port expects a value.\n"); exit(1); } break; case '--email': if (isset($args[$i + 1])) { $parsedArgs['email'] = $args[++$i]; } else { fwrite(STDERR, "Error: --email expects a value.\n"); exit(1); } break; case '--password': if (isset($args[$i + 1])) { $parsedArgs['password'] = $args[++$i]; } else { fwrite(STDERR, "Error: --password expects a value.\n"); exit(1); } break; default: fwrite(STDERR, "Warning: Unknown argument: {$args[$i]}\n"); } } return $parsedArgs; } // Function for sending a request over a TCP connection function sendRequest($serverIp, $serverPort, $payload) { $jsonPayload = json_encode($payload); if ($jsonPayload === false) { throw new Exception("Error encoding JSON payload."); } $errno = 0; $errstr = ''; $timeout = 30; // seconds $client = fsockopen($serverIp, $serverPort, $errno, $errstr, $timeout); if (!$client) { throw new Exception("Connection error: $errstr ($errno)"); } echo "🔗 Connection to server established.\n"; fwrite($client, $jsonPayload); $responseData = ''; stream_set_timeout($client, $timeout); while (!feof($client)) { $data = fread($client, 1024); if ($data === false) { throw new Exception("Error reading data from server."); } $responseData .= $data; // Attempt to parse the received data as JSON $parsedData = json_decode($responseData, true); if ($parsedData !== null) { fclose($client); return $parsedData; } // Check if the stream timed out $info = stream_get_meta_data($client); if ($info['timed_out']) { throw new Exception("Timeout waiting for data from server."); } } fclose($client); throw new Exception("Connection to the server was closed before a complete response was received."); } // Function for interactively asking for a password (optional) function askPassword($prompt) { if (preg_match('/^win/i', PHP_OS)) { // Windows-specific password prompt $vbscript = sys_get_temp_dir() . 'prompt_password.vbs'; file_put_contents($vbscript, 'wscript.echo(InputBox("' . addslashes($prompt) . '", "", "password here"))'); $password = shell_exec("cscript //nologo " . escapeshellarg($vbscript)); unlink($vbscript); return trim($password); } else { // Unix/Linux password prompt echo $prompt; system('stty -echo'); $password = rtrim(fgets(STDIN), "\n"); system('stty echo'); echo "\n"; return $password; } } // Main function function main($argv) { $args = parseArguments($argv); $serverIp = $args['serverIp'] ?? null; $serverPort = $args['serverPort'] ?? null; $email = $args['email'] ?? null; $password = $args['password'] ?? null; // Check if all required parameters are present if (!$serverIp || !$serverPort || !$email || !$password) { fwrite(STDERR, "❌ ERROR: Missing required parameters.\n"); fwrite(STDOUT, "Usage: php MCPLoginClient.php --server-ip <IP> --server-port <Port> --email <Email> --password <Password>\n"); exit(1); } $payload = [ "command" => "login", "arguments" => [ "email" => $email, "password" => $password ] ]; try { echo "🔐 Logging in...\n"; $response = sendRequest($serverIp, $serverPort, $payload); echo "✅ Server Response:\n"; echo json_encode($response, JSON_PRETTY_PRINT) . "\n"; } catch (Exception $e) { fwrite(STDERR, "❌ ERROR: " . $e->getMessage() . "\n"); } } main($argv); ?> ``` -------------------------------------------------------------------------------- /clients/PHP/1.1 mcp_logout/MCPLogoutClient.php: -------------------------------------------------------------------------------- ```php <?php // Functions for parsing command line arguments function parseArguments($args) { $parsedArgs = []; $argc = count($args); for ($i = 1; $i < $argc; $i++) { switch ($args[$i]) { case '--server-ip': if (isset($args[$i + 1])) { $parsedArgs['serverIp'] = $args[++$i]; } else { fwrite(STDERR, "Error: --server-ip expects a value.\n"); exit(1); } break; case '--server-port': if (isset($args[$i + 1])) { $parsedArgs['serverPort'] = intval($args[++$i]); } else { fwrite(STDERR, "Error: --server-port expects a value.\n"); exit(1); } break; case '--token': if (isset($args[$i + 1])) { $parsedArgs['token'] = $args[++$i]; } else { fwrite(STDERR, "Error: --token expects a value.\n"); exit(1); } break; default: fwrite(STDERR, "Warning: Unknown argument: {$args[$i]}\n"); } } return $parsedArgs; } // Function for interactively asking for a token (optional) function askToken($prompt) { if (preg_match('/^win/i', PHP_OS)) { // Windows-specific token prompt $vbscript = sys_get_temp_dir() . 'prompt_token.vbs'; file_put_contents($vbscript, 'wscript.echo(InputBox("' . addslashes($prompt) . '", "", "token here"))'); $token = shell_exec("cscript //nologo " . escapeshellarg($vbscript)); unlink($vbscript); return trim($token); } else { // Unix/Linux token prompt echo $prompt; // Token input typically without echo if (shell_exec('which stty')) { system('stty -echo'); $token = rtrim(fgets(STDIN), "\n"); system('stty echo'); echo "\n"; return $token; } else { // Fallback if stty is unavailable return rtrim(fgets(STDIN), "\n"); } } } // Function for sending a logout request over a TCP connection function sendLogoutRequest($serverIp, $serverPort, $payload) { $jsonPayload = json_encode($payload); if ($jsonPayload === false) { throw new Exception("Error encoding JSON payload."); } $errno = 0; $errstr = ''; $timeout = 30; // seconds $client = fsockopen($serverIp, $serverPort, $errno, $errstr, $timeout); if (!$client) { throw new Exception("Connection error: $errstr ($errno)"); } echo "🔗 Connection to server established.\n"; fwrite($client, $jsonPayload); $responseData = ''; stream_set_timeout($client, $timeout); while (!feof($client)) { $data = fread($client, 1024); if ($data === false) { throw new Exception("Error reading data from server."); } $responseData .= $data; // Attempt to parse the received data as JSON $parsedData = json_decode($responseData, true); if ($parsedData !== null) { fclose($client); return $parsedData; } // Check if the stream timed out $info = stream_get_meta_data($client); if ($info['timed_out']) { throw new Exception("Timeout waiting for data from server."); } } fclose($client); throw new Exception("Connection to the server was closed before a complete response was received."); } // Main function function main($argv) { $args = parseArguments($argv); $serverIp = $args['serverIp'] ?? null; $serverPort = $args['serverPort'] ?? null; $token = $args['token'] ?? null; // Check if all required parameters except token are present if (!$serverIp || !$serverPort) { fwrite(STDERR, "❌ ERROR: Missing required parameters.\n"); fwrite(STDOUT, "Usage: php MCPLogoutClient.php --server-ip <IP> --server-port <Port> --token <Token>\n"); exit(1); } // Interactively ask for token if not provided in arguments $authToken = $token; if (!$authToken) { $authToken = askToken('🔒 Please enter your authentication token: '); } if (empty($authToken)) { fwrite(STDERR, "❌ ERROR: Authentication token must not be empty.\n"); exit(1); } $payload = [ "command" => "logout", "token" => $authToken ]; try { echo "🚪 Logging out...\n"; $response = sendLogoutRequest($serverIp, $serverPort, $payload); echo "✅ Server Response:\n"; echo json_encode($response, JSON_PRETTY_PRINT) . "\n"; } catch (Exception $e) { fwrite(STDERR, "❌ ERROR: " . $e->getMessage() . "\n"); } } main($argv); ?> ``` -------------------------------------------------------------------------------- /clients/C++/5.0 mcp_store_user/MCPStoreUserClient.cpp: -------------------------------------------------------------------------------- ```cpp #include <iostream> #include <string> #include <map> #include <vector> #include <sstream> #include <stdexcept> #include <json/json.h> #include <winsock2.h> #include <ws2tcpip.h> #pragma comment(lib, "ws2_32.lib") // Verlinkung mit der Winsock-Bibliothek // Funktion zum Parsen von Argumenten std::map<std::string, std::string> parseArguments(int argc, char* argv[]) { std::map<std::string, std::string> args; for (int i = 1; i < argc; ++i) { std::string key = argv[i]; if (i + 1 < argc && key.rfind("--", 0) == 0) { args[key] = argv[++i]; } } return args; } // Funktion zum Parsen von Listen-Argumenten std::vector<std::string> parseListArgument(int argc, char* argv[], const std::string& key) { std::vector<std::string> values; for (int i = 1; i < argc; ++i) { if (argv[i] == key && i + 1 < argc) { for (int j = i + 1; j < argc && std::string(argv[j]).rfind("--", 0) != 0; ++j) { values.push_back(argv[j]); } } } return values; } // Funktion zum Senden der Anfrage std::string sendRequest(const std::string& serverIp, int serverPort, const Json::Value& payload) { Json::StreamWriterBuilder writer; std::string payloadJson = Json::writeString(writer, payload); // Winsock initialisieren WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { throw std::runtime_error("Failed to initialize Winsock."); } // Socket erstellen SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { WSACleanup(); throw std::runtime_error("Failed to create socket."); } // Server-Adresse konfigurieren sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(serverPort); if (inet_pton(AF_INET, serverIp.c_str(), &serverAddr.sin_addr) <= 0) { closesocket(sock); WSACleanup(); throw std::runtime_error("Invalid server IP address."); } // Verbindung herstellen if (connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { closesocket(sock); WSACleanup(); throw std::runtime_error("Connection failed."); } // Daten senden if (send(sock, payloadJson.c_str(), payloadJson.size(), 0) < 0) { closesocket(sock); WSACleanup(); throw std::runtime_error("Failed to send data."); } // Antwort empfangen char buffer[4096]; int bytesRead; std::ostringstream response; do { bytesRead = recv(sock, buffer, sizeof(buffer) - 1, 0); if (bytesRead > 0) { buffer[bytesRead] = '\0'; // Null-terminieren response << buffer; } } while (bytesRead == sizeof(buffer) - 1); // Socket schließen closesocket(sock); WSACleanup(); return response.str(); } int main(int argc, char* argv[]) { try { auto args = parseArguments(argc, argv); // Argumente auslesen std::string serverIp = args["--server-ip"]; int serverPort = std::stoi(args["--server-port"]); std::string token = args["--token"]; std::string name = args["--name"]; std::string email = args["--email"]; std::string password = args["--password"]; std::string language = args.count("--language") ? args["--language"] : "en"; std::string timezone = args.count("--timezone") ? args["--timezone"] : "Europe/Berlin"; auto roles = parseListArgument(argc, argv, "--roles"); auto groups = parseListArgument(argc, argv, "--groups"); bool usePublic = args.count("--usePublic"); bool activateFtp = args.count("--activateFtp"); std::string ftpPassword = args.count("--ftpPassword") ? args["--ftpPassword"] : ""; // JSON-Payload erstellen Json::Value payload; payload["command"] = "store_user"; payload["token"] = token; payload["arguments"]["name"] = name; payload["arguments"]["email"] = email; payload["arguments"]["password"] = password; payload["arguments"]["language"] = language; payload["arguments"]["timezone"] = timezone; for (const auto& role : roles) { payload["arguments"]["roles"].append(role); } for (const auto& group : groups) { payload["arguments"]["groups"].append(group); } payload["arguments"]["usePublic"] = usePublic; payload["arguments"]["activateFtp"] = activateFtp; payload["arguments"]["ftpPassword"] = ftpPassword; std::cout << "📤 Sending store user request...\n"; // Anfrage senden und Antwort erhalten std::string response = sendRequest(serverIp, serverPort, payload); std::cout << "✔️ Response from server:\n" << response << "\n"; } catch (const std::exception& e) { std::cerr << "❌ ERROR: " << e.what() << "\n"; return 1; } return 0; } ``` -------------------------------------------------------------------------------- /agents/IoTAgent/Python/language.py: -------------------------------------------------------------------------------- ```python # language.py languages = { "en": { "configuration_loaded": "Configuration loaded from {config_path}.", "error_loading_config": "Error loading configuration: {e}", "welcome": "Connected to MQTT broker successfully.", "chatbot_error_status": "Chatbot returned error status {status_code}.", "start_uploading_file": "Starting upload for file: {file_path}.", "error_sftp_upload": "Error uploading file {file_path}: {e}", "file_archived": "File {file_path} archived as {archive_name}.", "error_archiving_file": "Error archiving file {file_path}: {e}", "file_size": "File {file_path} size: {file_size} bytes.", "file_limit_reached": "File {file_path} reached size limit of {size_limit} bytes.", "new_file_created": "New file created at {file_path}.", "cannot_create_new_file": "Cannot create new file of type {file_type} for language {language}.", "error_getting_suffixes": "Error getting suffixes: {e}", "record_added": "Record added to {file_path}.", "invalid_group": "Invalid group type: {groups}.", "error_writing_file": "Error writing to file {file_path}: {e}", "file_empty_or_corrupted": "File {file_path} is empty or corrupted.", "language_sentence_generated": "Language: {language_full} | Sentence: {sentence}", "no_translation_file_config": "No translation file configured for language {language}.", "no_file_handler_found": "No file handler found for language {language}.", "no_translation_file_in_config": "No translation file configured in config for language {language}.", "empty_answer_field": "Warning: 'answer' field is empty in the chatbot response.", "max_retries_reached": "Maximum retry attempts reached.", "communication_error": "Communication error: {e} | Attempt {attempt} of {max_retries}.", "waiting_before_retry": "Waiting {wait_seconds} seconds before retrying...", "error_in_interpret_and_output": "Error in interpret_and_output: {e}", "sending_request_to_chatbot": "Sending request to chatbot (Attempt {attempt}).", "chatbot_response": "Chatbot response: {response}", "unknown_language": "Unknown language: {language}.", "no_sentence_generated": "No sentence generated for language {language_full}.", "user_exit": "User initiated exit." }, "de": { "configuration_loaded": "Konfiguration geladen von {config_path}.", "error_loading_config": "Fehler beim Laden der Konfiguration: {e}", "welcome": "Erfolgreich mit dem MQTT-Broker verbunden.", "chatbot_error_status": "Chatbot hat Fehlerstatus {status_code} zurückgegeben.", "start_uploading_file": "Starte Upload für Datei: {file_path}.", "error_sftp_upload": "Fehler beim Hochladen der Datei {file_path}: {e}", "file_archived": "Datei {file_path} archiviert als {archive_name}.", "error_archiving_file": "Fehler beim Archivieren der Datei {file_path}: {e}", "file_size": "Datei {file_path} Größe: {file_size} Bytes.", "file_limit_reached": "Datei {file_path} hat das Größenlimit von {size_limit} Bytes erreicht.", "new_file_created": "Neue Datei erstellt unter {file_path}.", "cannot_create_new_file": "Kann keine neue Datei vom Typ {file_type} für Sprache {language} erstellen.", "error_getting_suffixes": "Fehler beim Abrufen der Suffixe: {e}", "record_added": "Datensatz hinzugefügt zu {file_path}.", "invalid_group": "Ungültiger Gruppentyp: {groups}.", "error_writing_file": "Fehler beim Schreiben in die Datei {file_path}: {e}", "file_empty_or_corrupted": "Datei {file_path} ist leer oder beschädigt.", "language_sentence_generated": "Sprache: {language_full} | Satz: {sentence}", "no_translation_file_config": "Keine Übersetzungsdatei für Sprache {language} konfiguriert.", "no_file_handler_found": "Kein Dateihandler für Sprache {language} gefunden.", "no_translation_file_in_config": "Keine Übersetzungsdatei in der Konfiguration für Sprache {language} konfiguriert.", "empty_answer_field": "Warnung: 'answer'-Feld ist in der Chatbot-Antwort leer.", "max_retries_reached": "Maximale Anzahl an Wiederholungsversuchen erreicht.", "communication_error": "Kommunikationsfehler: {e} | Versuch {attempt} von {max_retries}.", "waiting_before_retry": "Warte {wait_seconds} Sekunden bevor erneut versucht wird...", "error_in_interpret_and_output": "Fehler in interpret_and_output: {e}", "sending_request_to_chatbot": "Sende Anfrage an Chatbot (Versuch {attempt}).", "chatbot_response": "Chatbot-Antwort: {response}", "unknown_language": "Unbekannte Sprache: {language}.", "no_sentence_generated": "Kein Satz für Sprache {language_full} generiert.", "user_exit": "Benutzer hat die Anwendung beendet." } } ``` -------------------------------------------------------------------------------- /clients/Java/3.0 mcp_create_source/MCPCreateSourceClient.java: -------------------------------------------------------------------------------- ```java import org.json.JSONArray; import org.json.JSONObject; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; public class MCPCreateSourceClient { public static void main(String[] args) { // Entspricht dem Minimalcheck (8 Parameter) wie im C#-Code. if (args.length < 8) { printUsage(); return; } String serverIp = getArgument(args, "--server-ip"); String portStr = getArgument(args, "--server-port"); String token = getArgument(args, "--token"); String name = getArgument(args, "--name"); String content = getArgument(args, "--content"); List<String> groups = getArgumentList(args, "--groups"); // Falls wichtige Argumente fehlen, direkt Usage anzeigen if (serverIp == null || portStr == null || token == null || name == null || content == null) { printUsage(); return; } int serverPort = Integer.parseInt(portStr); System.out.println("📤 Sending request to create a new source..."); // JSON-Payload erstellen JSONObject payload = new JSONObject(); payload.put("command", "create_source"); payload.put("token", token); // "arguments" Objekt JSONObject arguments = new JSONObject(); arguments.put("name", name); arguments.put("content", content); // "groups" als JSONArray hinzufügen JSONArray groupsJsonArray = new JSONArray(groups); arguments.put("groups", groupsJsonArray); payload.put("arguments", arguments); // Request an den MCP-Server senden String response = sendRequest(serverIp, serverPort, payload); System.out.println("✔️ Response from server:"); System.out.println(response); } /** * Gibt einen einzelnen Argumentwert für das gegebene Schlüsselwort zurück, * oder null, wenn keiner gefunden wurde. */ private static String getArgument(String[] args, String key) { for (int i = 0; i < args.length - 1; i++) { if (args[i].equals(key)) { return args[i + 1]; } } return null; } /** * Sucht im args-Array nach dem Schlüssel 'key' und liest dann solange * weiter, bis das nächste Argument wieder mit "--" beginnt (oder das Array endet). * So können mehrere Gruppenwerte nacheinander gelesen werden. */ private static List<String> getArgumentList(String[] args, String key) { List<String> values = new ArrayList<>(); for (int i = 0; i < args.length; i++) { if (args[i].equals(key)) { // Ab hier die folgenden Einträge sammeln, bis "--" oder Ende for (int j = i + 1; j < args.length; j++) { if (args[j].startsWith("--")) { break; } values.add(args[j]); } break; // Suche beenden, sobald wir die Liste gefunden haben } } return values; } /** * Baut eine Socket-Verbindung zum Server auf, sendet das JSON-Payload * und empfängt die Antwort. */ private static String sendRequest(String serverIp, int serverPort, JSONObject payload) { String payloadJson = payload.toString(); try (Socket client = new Socket(serverIp, serverPort)) { // Daten senden OutputStream out = client.getOutputStream(); byte[] data = payloadJson.getBytes(StandardCharsets.UTF_8); out.write(data); out.flush(); // Antwort empfangen InputStream in = client.getInputStream(); byte[] buffer = new byte[4096]; StringBuilder responseBuilder = new StringBuilder(); int bytesRead; do { bytesRead = in.read(buffer); if (bytesRead > 0) { responseBuilder.append(new String(buffer, 0, bytesRead, StandardCharsets.UTF_8)); } } while (bytesRead == buffer.length); return responseBuilder.toString(); } catch (IOException e) { return "Error: " + e.getMessage(); } } private static void printUsage() { System.out.println("Usage:"); System.out.println(" --server-ip <IP> --server-port <PORT> --token <TOKEN> " + "--name <NAME> --content <CONTENT> [--groups <GROUP1 GROUP2 ...>]"); System.out.println(); System.out.println("Example:"); System.out.println(" java -cp .;json-20241224.jar MCPCreateSourceClient " + "--server-ip 127.0.0.1 --server-port 1234 --token MyToken " + "--name \"Test Source\" --content \"This is some content\" " + "--groups dev hr admin"); } } ``` -------------------------------------------------------------------------------- /WORKLOG.md: -------------------------------------------------------------------------------- ```markdown # PrivateGPT MCP Server Development Log ## ⚠️ Warning: User Management Implementation **HANDLE WITH CARE**: The user management endpoints have significant impact and can potentially delete all users if not handled properly. While the API functionality has been tested successfully, implementation in the pgpt-mcp-server is pending due to these security considerations. The following user management endpoints require careful implementation: ### Create User (POST /api/v1/users) Required functionality: - Create new user with name, email, and password - Set optional language and timezone - Configure public access and group assignments - Assign user roles - Set up FTP access if needed - Handle all required fields: ```json { "name": "User Name", "email": "[email protected]", "password": "UserPassword123", "language": "en", "timezone": "UTC", "usePublic": true, "groups": ["Group A"], "roles": ["Sources"], "activateFtp": true, "ftpPassword": "FTPPassword!" } ``` ### Edit User (PATCH /api/v1/users) Required functionality: - Update user details by email - Modify name, language, and group assignments - Handle partial updates - Fields that can be updated: ```json { "email": "[email protected]", "name": "Updated Name", "language": "en", "groups": ["Updated Group"] } ``` ### Delete User (DELETE /api/v1/users) ⚠️ **Critical Operation** Required functionality: - Remove user by email - Clean up associated data - Handle dependencies: ```json { "email": "[email protected]" } ``` ## Implementation Status ### Core Server Structure - ✅ Basic MCP server setup with stdio transport - ✅ Error handling and graceful shutdown - ✅ Type-safe request handling - ✅ Input validation for all tools ### API Integration - ✅ Authentication with Bearer tokens - ✅ Automatic token refresh - ✅ Error mapping to MCP error codes - ✅ JSON response formatting ### Tools Implementation 1. Chat Tool - ✅ Chat creation with knowledge base selection - ✅ Support for public and document knowledge bases - ✅ Group-based access control - ✅ Language support - ✅ Chat continuation support 2. Source Management - ✅ Source creation with markdown formatting - ✅ Group assignment for private sources - ✅ Source listing by group - ✅ Source details retrieval - ✅ Source deletion - ✅ Source editing 3. Group Management - ✅ List personal and assignable groups - ✅ Group-based visibility control - ✅ Personal group handling - ✅ Group creation - ✅ Group deletion ## API Behavior Notes ### Authentication - Uses Bearer token authentication via `/api/v1/login` - Token required for all authenticated endpoints - Token invalidation via `/api/v1/logout` ### Group Management - GET `/api/v1/groups` returns personalGroups and assignableGroups arrays - Personal group appears in both arrays - Groups control access to sources and knowledge base - Full CRUD operations implemented and tested ### Source Management - Sources can be public or private - Private sources require group assignment - Sources are vectorized asynchronously - Source states: creation → vectorized - Source operations: - POST `/api/v1/sources` for creation - DELETE `/api/v1/sources/{sourceId}` for removal - PATCH `/api/v1/sources/{sourceId}` for editing - Can list sources by group - Can verify source state and visibility - All operations tested and verified ### Chat System - Two knowledge base types: - Public (usePublic: true) - Document (specific groups) - Chat operations: - Initial creation: POST `/api/v1/chats` - Continuation: PATCH `/api/v1/chats/{chatId}` - Details: GET `/api/v1/chats/{chatId}` - Chat features: - Preserves complete message history - Context-aware responses - Group-based access control - Language support ## Implementation Details ### Type Safety - Comprehensive TypeScript interfaces for all API interactions - Runtime validation for all tool inputs - Error type mapping between API and MCP ### Error Handling - API errors mapped to appropriate MCP error codes - Detailed error messages preserved - Authentication errors handled gracefully ### Resource Management - No direct resource exposure currently - All data access through tools - Future potential for direct resource access ## Future Improvements 1. Performance Optimizations: - Add caching layer - Optimize API requests - Improve response times 2. Monitoring and Observability: - Add comprehensive logging - Add metrics collection - Add performance tracking 3. Documentation: - Add API reference documentation - Add deployment guides - Add troubleshooting guides 4. Security Enhancements: - Add rate limiting - Implement request validation - Add security headers - Enhance token management - Add user session management ## Testing Notes - ✅ All major API endpoints tested - ✅ Group-based access control verified - ✅ Chat system behavior documented - ✅ Source visibility rules confirmed - ✅ Error handling validated - ✅ Source CRUD operations verified - ✅ Group CRUD operations verified - ✅ User management API functionality tested ``` -------------------------------------------------------------------------------- /clients/C++/1.0 mcp_login/MCPLoginClient.cpp: -------------------------------------------------------------------------------- ```cpp #include <iostream> #include <string> #include <map> #include <cstring> #include <cstdlib> #include <sstream> #include <stdexcept> #include <json/json.h> #include <openssl/ssl.h> #include <openssl/err.h> #ifdef _WIN32 #include <winsock2.h> #include <ws2tcpip.h> #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "libssl.lib") #pragma comment(lib, "libcrypto.lib") #else #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #endif // Function to parse command-line arguments std::map<std::string, std::string> parseArguments(int argc, char* argv[]) { std::map<std::string, std::string> args; for (int i = 1; i < argc; i++) { std::string key = argv[i]; if (i + 1 < argc) { args[key] = argv[++i]; } } return args; } void init_openssl() { SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); } void cleanup_openssl() { EVP_cleanup(); } SSL_CTX* create_context() { const SSL_METHOD* method; SSL_CTX* ctx; method = TLS_client_method(); ctx = SSL_CTX_new(method); if (!ctx) { perror("Unable to create SSL context"); ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } return ctx; } std::string sendRequest(const std::string& serverIp, int serverPort, const Json::Value& payload) { init_openssl(); SSL_CTX* ctx = create_context(); #ifdef _WIN32 WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); #endif int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { SSL_CTX_free(ctx); #ifdef _WIN32 WSACleanup(); #endif throw std::runtime_error("Failed to create socket"); } struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(serverPort); if (inet_pton(AF_INET, serverIp.c_str(), &serverAddr.sin_addr) <= 0) { #ifdef _WIN32 closesocket(sock); WSACleanup(); #else close(sock); #endif SSL_CTX_free(ctx); throw std::runtime_error("Invalid server IP address"); } if (connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { #ifdef _WIN32 closesocket(sock); WSACleanup(); #else close(sock); #endif SSL_CTX_free(ctx); throw std::runtime_error("Connection failed"); } SSL* ssl = SSL_new(ctx); SSL_set_fd(ssl, sock); if (SSL_connect(ssl) <= 0) { ERR_print_errors_fp(stderr); #ifdef _WIN32 closesocket(sock); WSACleanup(); #else close(sock); #endif SSL_free(ssl); SSL_CTX_free(ctx); throw std::runtime_error("Failed to create SSL connection"); } // Serialize the JSON payload to a string Json::StreamWriterBuilder writer; std::string payloadJson = Json::writeString(writer, payload); // Send the payload if (SSL_write(ssl, payloadJson.c_str(), payloadJson.size()) <= 0) { #ifdef _WIN32 closesocket(sock); WSACleanup(); #else close(sock); #endif SSL_free(ssl); SSL_CTX_free(ctx); throw std::runtime_error("Failed to send data"); } // Receive the response char buffer[4096]; int bytesRead = SSL_read(ssl, buffer, sizeof(buffer) - 1); if (bytesRead < 0) { #ifdef _WIN32 closesocket(sock); WSACleanup(); #else close(sock); #endif SSL_free(ssl); SSL_CTX_free(ctx); throw std::runtime_error("Failed to receive data"); } buffer[bytesRead] = '\0'; // Null-terminate the received data SSL_free(ssl); #ifdef _WIN32 closesocket(sock); WSACleanup(); #else close(sock); #endif SSL_CTX_free(ctx); cleanup_openssl(); return std::string(buffer); } int main(int argc, char* argv[]) { try { auto args = parseArguments(argc, argv); // Extract required parameters std::string serverIp = args["--server-ip"]; int serverPort = std::stoi(args["--server-port"]); std::string email = args["--email"]; std::string password = args["--password"]; if (serverIp.empty() || serverPort == 0 || email.empty() || password.empty()) { std::cerr << "❌ ERROR: Missing required parameters.\n"; return 1; } std::cout << "🔐 Logging in...\n"; // Build the payload Json::Value payload; payload["command"] = "login"; payload["arguments"]["email"] = email; payload["arguments"]["password"] = password; // Send request and get response std::string responseJson = sendRequest(serverIp, serverPort, payload); // Parse and print the server response Json::CharReaderBuilder reader; Json::Value response; std::istringstream responseStream(responseJson); std::string errs; if (!Json::parseFromStream(reader, responseStream, &response, &errs)) { throw std::runtime_error("Failed to parse server response: " + errs); } std::cout << "✅ Server Response:\n" << response.toStyledString(); } catch (const std::exception& e) { std::cerr << "❌ ERROR: " << e.what() << '\n'; return 1; } return 0; } ``` -------------------------------------------------------------------------------- /src/logger.js: -------------------------------------------------------------------------------- ```javascript // logger.js import winston from 'winston'; import chalk from 'chalk'; import stripAnsi from 'strip-ansi'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; // ESM-Äquivalent von __dirname const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Bestimmen Sie den Pfad zur Log-Datei relativ zu `logger.js` const LOG_FILE_PATH = path.join(__dirname, '../logs/server.log'); // Passen Sie den Pfad nach Bedarf an // Hilfsfunktionen für Symbole und Farben function getLevelSymbol(level) { const symbols = { info: 'ℹ️', warn: '⚠️', error: '❌', debug: '🐞', }; return symbols[level] || ''; } function chalkForLevel(level) { const levels = { info: chalk.blue, warn: chalk.yellow, error: chalk.red, debug: chalk.green, }; return levels[level] || chalk.white; } // Variable zur Steuerung der Dateiausgabe let allowWrittenLogfile = false; // Initialisieren der Transports mit nur der Konsolenausgabe const transports = [ new winston.transports.Console({ format: winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf(({ timestamp, level, message }) => { const symbol = getLevelSymbol(level); const coloredMessage = `${chalkForLevel(level)(symbol)} ${message}`; return `${timestamp} | ${coloredMessage}`; }) ), }), ]; // Erstellen des Winston-Loggers const logger = winston.createLogger({ level: 'info', transports: transports, }); /** * Funktion zum Hinzufügen des File-Transports */ function addFileTransport() { const logDir = path.dirname(LOG_FILE_PATH); if (!fs.existsSync(logDir)) { fs.mkdirSync(logDir, { recursive: true }); } const fileTransport = new winston.transports.File({ filename: LOG_FILE_PATH, level: 'info', // Stellen Sie sicher, dass der Level ausreichend niedrig ist maxsize: 10485760, // 10 MB pro Datei maxFiles: 5, // Maximal 5 Dateien format: winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf(({ timestamp, level, message }) => { const symbol = getLevelSymbol(level); const plainMessage = stripAnsi(`${symbol} ${message}`); // ANSI-Codes entfernen return `${timestamp} | ${plainMessage}`; }) ), }); // Fehler-Handler hinzufügen fileTransport.on('error', (error) => { console.error(chalk.red('File-Transport Fehler:'), error); }); // Prüfen, ob der Transport bereits hinzugefügt wurde, um Duplikate zu vermeiden if (!logger.transports.some(t => t instanceof winston.transports.File)) { logger.add(fileTransport); } } /** * Funktion zum Entfernen des File-Transports */ function removeFileTransport() { const fileTransport = logger.transports.find( (t) => t instanceof winston.transports.File ); if (fileTransport) { logger.remove(fileTransport); } } /** * Funktion zum Setzen von allowWrittenLogfile * @param {boolean} value - true, um Dateilogs zu erlauben; false, um sie zu deaktivieren */ function setAllowWrittenLogfile(value) { allowWrittenLogfile = value; if (allowWrittenLogfile) { addFileTransport(); logEvent('system', 'wrlog', 'File logs activated.', 'File logs are now activated.', 'info'); // Überprüfen, ob der File-Transport hinzugefügt wurde const fileTransport = logger.transports.find(t => t instanceof winston.transports.File); if (fileTransport) { // console.log(chalk.green('File-Transport erfolgreich hinzugefügt.')); } else { console.log(chalk.red('Error: File transport could not be added.')); } } else { removeFileTransport(); logEvent('system', 'wrlog', 'File logs deactivated.', 'File logs are now deactivated.', 'info'); } } /** * Zentrale Logging-Funktion * @param {string} clientIP - IP-Adresse des Clients * @param {number|string} clientPort - Port des Clients * @param {string} functionName - Name der aufgerufenen Funktion * @param {string|object} status - Status der Rückmeldung * @param {string} level - Log-Level ('info', 'warn', 'error', 'debug') */ function logEvent(clientIP, clientPort, functionName, status, level = 'info') { // Kürzen und formatieren der Felder const ip = String(clientIP || 'N/A').padEnd(23).substring(0, 23); // Mindestens 8 Zeichen für die IP const port = String(clientPort || 'N/A').padEnd(5).substring(0, 5); // 5 Zeichen für den Port const func = String(functionName || 'N/A').padEnd(26).substring(0, 26); // 20 Zeichen für den Funktionsnamen const stat = String(status || '').padEnd(120).substring(0, 120); // 100 Zeichen für den Status // Formatierte Logzeile const logLine = `${ip}:${port} | ${func} | ${stat}`; // Log-Ausgabe basierend auf dem Level logger.log({ level, message: logLine }); } export { logger, logEvent, setAllowWrittenLogfile, LOG_FILE_PATH }; ``` -------------------------------------------------------------------------------- /clients/C++/5.1 mcp_edit_user/MCPEditUserClient.cpp: -------------------------------------------------------------------------------- ```cpp #include <iostream> #include <string> #include <map> #include <vector> #include <sstream> #include <stdexcept> #include <json/json.h> #include <winsock2.h> #include <ws2tcpip.h> #pragma comment(lib, "ws2_32.lib") // Verlinkung mit der Winsock-Bibliothek // Funktion zum Parsen von Argumenten std::map<std::string, std::string> parseArguments(int argc, char* argv[]) { std::map<std::string, std::string> args; for (int i = 1; i < argc; ++i) { std::string key = argv[i]; if (i + 1 < argc && key.rfind("--", 0) == 0) { args[key] = argv[++i]; } } return args; } // Funktion zum Parsen von Listen-Argumenten std::vector<std::string> parseListArgument(int argc, char* argv[], const std::string& key) { std::vector<std::string> values; for (int i = 1; i < argc; ++i) { if (argv[i] == key && i + 1 < argc) { for (int j = i + 1; j < argc && std::string(argv[j]).rfind("--", 0) != 0; ++j) { values.push_back(argv[j]); } } } return values; } // Funktion zum Senden der Anfrage std::string sendRequest(const std::string& serverIp, int serverPort, const Json::Value& payload) { Json::StreamWriterBuilder writer; std::string payloadJson = Json::writeString(writer, payload); // Winsock initialisieren WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { throw std::runtime_error("Failed to initialize Winsock."); } // Socket erstellen SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { WSACleanup(); throw std::runtime_error("Failed to create socket."); } // Server-Adresse konfigurieren sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(serverPort); if (inet_pton(AF_INET, serverIp.c_str(), &serverAddr.sin_addr) <= 0) { closesocket(sock); WSACleanup(); throw std::runtime_error("Invalid server IP address."); } // Verbindung herstellen if (connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { closesocket(sock); WSACleanup(); throw std::runtime_error("Connection failed."); } // Daten senden if (send(sock, payloadJson.c_str(), payloadJson.size(), 0) < 0) { closesocket(sock); WSACleanup(); throw std::runtime_error("Failed to send data."); } // Antwort empfangen char buffer[4096]; int bytesRead; std::ostringstream response; do { bytesRead = recv(sock, buffer, sizeof(buffer) - 1, 0); if (bytesRead > 0) { buffer[bytesRead] = '\0'; // Null-terminieren response << buffer; } } while (bytesRead == sizeof(buffer) - 1); // Socket schließen closesocket(sock); WSACleanup(); return response.str(); } int main(int argc, char* argv[]) { try { auto args = parseArguments(argc, argv); // Pflichtargumente überprüfen if (args["--server-ip"].empty() || args["--server-port"].empty() || args["--token"].empty() || args["--email"].empty() || args["--name"].empty()) { std::cerr << "Usage: --server-ip <IP> --server-port <PORT> --token <TOKEN> --email <EMAIL> --name <NAME> [optional parameters]\n"; return 1; } // Argumente auslesen std::string serverIp = args["--server-ip"]; int serverPort = std::stoi(args["--server-port"]); std::string token = args["--token"]; std::string email = args["--email"]; std::string name = args["--name"]; std::string language = args.count("--language") ? args["--language"] : "en"; std::string timezone = args.count("--timezone") ? args["--timezone"] : "UTC"; std::string password = args["--password"]; bool publicUpload = args.count("--publicUpload") > 0; auto groups = parseListArgument(argc, argv, "--groups"); auto roles = parseListArgument(argc, argv, "--roles"); bool activateFtp = args.count("--activateFtp") > 0; std::string ftpPassword = args["--ftpPassword"]; // JSON-Payload erstellen Json::Value payload; payload["command"] = "edit_user"; payload["token"] = token; payload["arguments"]["email"] = email; payload["arguments"]["name"] = name; payload["arguments"]["language"] = language; payload["arguments"]["timezone"] = timezone; if (!password.empty()) payload["arguments"]["password"] = password; payload["arguments"]["publicUpload"] = publicUpload; for (const auto& group : groups) { payload["arguments"]["groups"].append(group); } for (const auto& role : roles) { payload["arguments"]["roles"].append(role); } payload["arguments"]["activateFtp"] = activateFtp; if (!ftpPassword.empty()) payload["arguments"]["ftpPassword"] = ftpPassword; std::cout << "📤 Sending edit user request...\n"; // Anfrage senden und Antwort erhalten std::string response = sendRequest(serverIp, serverPort, payload); std::cout << "✔️ Response from server:\n" << response << "\n"; } catch (const std::exception& e) { std::cerr << "❌ ERROR: " << e.what() << "\n"; return 1; } return 0; } ``` -------------------------------------------------------------------------------- /clients/JavaScript/3.3 mcp_edit_source/MCPEditSourceClient.js: -------------------------------------------------------------------------------- ```javascript const net = require('net'); const readline = require('readline'); const { argv, exit } = require('process'); // Funktion zum Parsen der Kommandozeilenargumente function parseArguments(args) { const parsedArgs = {}; for (let i = 2; i < args.length; i++) { switch (args[i]) { case '--server-ip': parsedArgs.serverIp = args[++i]; break; case '--server-port': parsedArgs.serverPort = parseInt(args[++i], 10); break; case '--token': parsedArgs.token = args[++i]; break; case '--source-id': parsedArgs.sourceId = args[++i]; break; case '--title': parsedArgs.title = args[++i]; break; case '--content': parsedArgs.content = args[++i]; break; case '--groups': // Sammle alle Gruppenargumente bis zum nächsten Flag oder Ende parsedArgs.groups = []; while (i + 1 < args.length && !args[i + 1].startsWith('--')) { parsedArgs.groups.push(args[++i]); } break; default: console.warn(`⚠️ Unbekanntes Argument: ${args[i]}`); } } return parsedArgs; } // Funktion zum interaktiven Abfragen eines Parameters (optional) function askQuestion(query) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true }); return new Promise((resolve) => { rl.question(query, (answer) => { rl.close(); resolve(answer); }); }); } // Funktion zum Senden einer Edit-Source-Anfrage über eine TCP-Verbindung function sendEditSourceRequest(serverIp, serverPort, payload) { return new Promise((resolve, reject) => { const client = new net.Socket(); let responseData = ''; client.connect(serverPort, serverIp, () => { console.log(`🔗 Verbindung zum Server (${serverIp}:${serverPort}) hergestellt.`); const payloadString = JSON.stringify(payload); console.log(`📤 Sende Payload: ${payloadString}`); client.write(payloadString); }); client.on('data', (data) => { console.log(`📥 Empfangene Daten: ${data}`); responseData += data.toString(); try { const parsedData = JSON.parse(responseData); console.log('✅ JSON-Antwort erfolgreich geparst.'); resolve(parsedData); client.destroy(); // Verbindung schließen } catch (err) { console.warn('⚠️ Antwort noch nicht vollständig oder ungültiges JSON. Weitere Daten werden erwartet.'); // Antwort noch nicht vollständig, weiter empfangen } }); client.on('close', () => { console.log('🔒 Verbindung zum Server geschlossen.'); }); client.on('error', (err) => { console.error('❌ Verbindungsfehler:', err.message); reject(err); }); }); } // Hauptfunktion async function main() { const args = argv; const parsedArgs = parseArguments(args); let { serverIp, serverPort, token, sourceId, title, content, groups } = parsedArgs; // Überprüfen, ob alle erforderlichen Parameter vorhanden sind, sonst interaktiv abfragen if (!serverIp) { serverIp = await askQuestion('🔗 Bitte gib die Server-IP ein: '); } if (!serverPort) { const portInput = await askQuestion('🔗 Bitte gib den Server-Port ein: '); serverPort = parseInt(portInput, 10); } if (!token) { token = await askQuestion('🔒 Bitte gib dein Authentifizierungstoken ein: '); } if (!sourceId) { sourceId = await askQuestion('📁 Bitte gib die Source-ID ein: '); } // Überprüfen, ob mindestens eines der optionalen Parameter vorhanden ist if (title === undefined && content === undefined && (groups === undefined || groups.length === 0)) { console.warn('⚠️ Keine Änderungsparameter angegeben. Es werden mindestens eines der folgenden benötigt: --title, --content, --groups.'); exit(1); } // Optional: Abfrage fehlender optionaler Parameter, wenn entsprechende Flags gesetzt sind // Hier gehen wir davon aus, dass --title, --content und --groups bereits korrekt geparst wurden // und entweder definiert sind oder nicht angegeben wurden. // Entferne unerwünschte Schlüssel mit undefined oder null Werten const filteredArguments = {}; if (sourceId) filteredArguments.sourceId = sourceId; if (title) filteredArguments.title = title; if (content) filteredArguments.content = content; if (groups && groups.length > 0) filteredArguments.groups = groups; const payload = { command: "edit_source", token: token, arguments: filteredArguments }; try { console.log('🛠️ Sende Edit-Source-Anfrage...'); const response = await sendEditSourceRequest(serverIp, serverPort, payload); console.log('✅ Server Response:'); console.log(JSON.stringify(response, null, 2)); } catch (err) { console.error('❌ ERROR:', err.message); } } main(); ``` -------------------------------------------------------------------------------- /clients/JavaScript/4.1 mcp_store_group/MCPStoreGroupClient.js: -------------------------------------------------------------------------------- ```javascript const net = require('net'); const readline = require('readline'); const { argv, exit } = require('process'); /** * Funktion zum Parsen der Kommandozeilenargumente * @param {string[]} args - Array von Kommandozeilenargumenten * @returns {Object} - Objekt mit geparsten Argumenten */ function parseArguments(args) { const parsedArgs = {}; for (let i = 2; i < args.length; i++) { switch (args[i]) { case '--server-ip': parsedArgs.serverIp = args[++i]; break; case '--server-port': parsedArgs.serverPort = parseInt(args[++i], 10); break; case '--group-name': parsedArgs.groupName = args[++i]; break; case '--token': parsedArgs.token = args[++i]; break; case '--description': parsedArgs.description = args[++i]; break; default: console.warn(`⚠️ Unbekanntes Argument: ${args[i]}`); } } return parsedArgs; } /** * Funktion zum interaktiven Abfragen eines Parameters (optional) * @param {string} query - Frage an den Benutzer * @returns {Promise<string>} - Antwort des Benutzers */ function askQuestion(query) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true }); return new Promise((resolve) => { rl.question(query, (answer) => { rl.close(); resolve(answer); }); }); } /** * Sendet eine Anfrage an den MCP-Server, um eine neue Gruppe zu speichern. * * @param {string} serverIp - IP-Adresse des MCP-Servers * @param {number} serverPort - Portnummer des MCP-Servers * @param {string} groupName - Name der zu speichernden Gruppe * @param {string} token - Authentifizierungstoken * @param {string} description - Beschreibung der Gruppe (optional) * @returns {Promise<Object>} - Antwort vom Server */ function sendStoreGroupRequest(serverIp, serverPort, groupName, token, description) { return new Promise((resolve, reject) => { const client = new net.Socket(); const payload = { command: "store_group", token: token, arguments: { groupName: groupName, description: description } }; const payloadString = JSON.stringify(payload); // Timeout setzen (optional) const TIMEOUT_DURATION = 10000; // 10 Sekunden const timeout = setTimeout(() => { client.destroy(); // Verbindung zerstören reject(new Error('Verbindungs-Timeout: Der Server hat nicht rechtzeitig geantwortet.')); }, TIMEOUT_DURATION); client.connect(serverPort, serverIp, () => { console.log(`🔗 Verbindung zum Server (${serverIp}:${serverPort}) hergestellt.`); console.log(`📤 Sende Payload: ${payloadString}`); client.write(payloadString); }); let responseData = ''; client.on('data', (data) => { console.log(`📥 Empfangene Daten: ${data}`); responseData += data.toString(); try { const parsedData = JSON.parse(responseData); console.log('✅ JSON-Antwort erfolgreich geparst.'); clearTimeout(timeout); resolve(parsedData); client.destroy(); // Verbindung schließen } catch (err) { console.warn('⚠️ Antwort noch nicht vollständig oder ungültiges JSON. Weitere Daten werden erwartet.'); // Weiter empfangen } }); client.on('close', () => { console.log('🔒 Verbindung zum Server geschlossen.'); clearTimeout(timeout); }); client.on('error', (err) => { console.error('❌ Verbindungsfehler:', err.message); clearTimeout(timeout); reject(err); }); }); } // Hauptfunktion async function main() { const args = argv; const parsedArgs = parseArguments(args); let { serverIp, serverPort, groupName, token, description } = parsedArgs; // Überprüfen, ob alle erforderlichen Parameter vorhanden sind, sonst interaktiv abfragen if (!serverIp) { serverIp = await askQuestion('🔗 Bitte gib die Server-IP ein: '); } if (!serverPort) { const portInput = await askQuestion('🔗 Bitte gib den Server-Port ein: '); serverPort = parseInt(portInput, 10); } if (!groupName) { groupName = await askQuestion('📛 Bitte gib den Gruppennamen ein: '); } if (!token) { token = await askQuestion('🔒 Bitte gib dein Authentifizierungstoken ein: '); } // Beschreibung ist optional, kein Abfrage notwendig const payload = { command: "store_group", token: token, arguments: { groupName: groupName, description: description || "" } }; try { console.log('🗃️ Sende Store-Group-Anfrage...'); const response = await sendStoreGroupRequest(serverIp, serverPort, groupName, token, description); console.log('✔️ Antwort vom Server:', JSON.stringify(response, null, 2)); } catch (err) { console.error('❌ Fehler:', err.message); } } main(); ``` -------------------------------------------------------------------------------- /clients/JavaScript/5.1 mcp_edit_user/MCPEditUserClient.js: -------------------------------------------------------------------------------- ```javascript const net = require('net'); const readline = require('readline'); const { argv } = require('process'); /** * Funktion zum Parsen der Kommandozeilenargumente * @param {string[]} args - Array von Kommandozeilenargumenten * @returns {Object} - Objekt mit geparsten Argumenten */ function parseArguments(args) { const parsedArgs = {}; for (let i = 2; i < args.length; i++) { switch (args[i]) { case '--server-ip': parsedArgs.serverIp = args[++i]; break; case '--server-port': parsedArgs.serverPort = parseInt(args[++i], 10); break; case '--token': parsedArgs.token = args[++i]; break; case '--name': parsedArgs.name = args[++i]; break; case '--email': parsedArgs.email = args[++i]; break; case '--password': parsedArgs.password = args[++i]; break; case '--language': parsedArgs.language = args[++i]; break; case '--timezone': parsedArgs.timezone = args[++i]; break; case '--roles': parsedArgs.roles = []; while (i + 1 < args.length && !args[i + 1].startsWith('--')) { parsedArgs.roles.push(args[++i]); } break; case '--groups': parsedArgs.groups = []; while (i + 1 < args.length && !args[i + 1].startsWith('--')) { parsedArgs.groups.push(args[++i]); } break; case '--usePublic': parsedArgs.usePublic = true; break; case '--activateFtp': parsedArgs.activateFtp = true; break; case '--ftpPassword': parsedArgs.ftpPassword = args[++i]; break; default: console.warn(`⚠️ Unbekanntes Argument: ${args[i]}`); } } return parsedArgs; } /** * Sendet eine Anfrage an den MCP-Server, um einen Benutzer zu bearbeiten. * * @param {string} serverIp - IP-Adresse des MCP-Servers * @param {number} serverPort - Portnummer des MCP-Servers * @param {string} token - Authentifizierungstoken * @param {Object} args - Argumente für den zu bearbeitenden Benutzer * @returns {Promise<string>} - Antwort vom Server */ function sendEditUserRequest(serverIp, serverPort, token, args) { return new Promise((resolve, reject) => { const client = new net.Socket(); const payload = { command: "edit_user", token: token, arguments: { name: args.name, email: args.email, password: args.password, language: args.language, timezone: args.timezone, roles: args.roles || [], groups: args.groups || [], usePublic: args.usePublic || false, activateFtp: args.activateFtp || false, ftpPassword: args.ftpPassword } }; // Entferne Null- oder undefined-Werte payload.arguments = Object.fromEntries(Object.entries(payload.arguments).filter(([_, v]) => v != null)); const payloadString = JSON.stringify(payload); // Timeout setzen const TIMEOUT_DURATION = 10000; // 10 Sekunden const timeout = setTimeout(() => { client.destroy(); reject(new Error('Verbindungs-Timeout: Der Server hat nicht rechtzeitig geantwortet.')); }, TIMEOUT_DURATION); client.connect(serverPort, serverIp, () => { console.log(`🔗 Verbindung zum Server (${serverIp}:${serverPort}) hergestellt.`); console.log(`📤 Sende Payload: ${payloadString}`); client.write(payloadString); }); let responseData = ''; client.on('data', (data) => { responseData += data.toString(); try { const parsedData = JSON.parse(responseData); clearTimeout(timeout); resolve(parsedData); client.destroy(); } catch (e) { // Weiter empfangen, falls JSON unvollständig ist } }); client.on('close', () => { console.log('🔒 Verbindung zum Server geschlossen.'); }); client.on('error', (err) => { clearTimeout(timeout); reject(err); }); }); } // Hauptfunktion async function main() { const args = parseArguments(argv); if (!args.serverIp || !args.serverPort || !args.token) { console.error('❌ Fehler: --server-ip, --server-port und --token sind erforderlich.'); console.log('📖 Beispiel: node MCPEditUserClient.js --server-ip 192.168.0.1 --server-port 5000 --token YOUR_AUTH_TOKEN'); process.exit(1); } try { console.log('🧑💻 Sende Edit-User-Anfrage...'); const response = await sendEditUserRequest( args.serverIp, args.serverPort, args.token, args ); console.log('✔️ Antwort vom Server:', JSON.stringify(response, null, 2)); } catch (err) { console.error('❌ Fehler beim Bearbeiten des Benutzers:', err.message); } } main(); ``` -------------------------------------------------------------------------------- /clients/Java/2.0 mcp_chat/MCPChatClient.java: -------------------------------------------------------------------------------- ```java import org.json.JSONArray; import org.json.JSONObject; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class MCPChatClient { public static void main(String[] args) { // Minimalprüfung, ob genug Argumente für --server-ip, --server-port, --token, --question vorliegen. // (Die eigentliche Prüfung machen wir etwas weiter unten ausführlicher.) if (args.length < 5) { printUsage(); return; } // Argumente auslesen String serverIp = getArgument(args, "--server-ip"); String serverPortStr = getArgument(args, "--server-port"); String token = getArgument(args, "--token"); String question = getArgument(args, "--question"); boolean usePublic = Arrays.asList(args).contains("--use-public"); String language = getArgument(args, "--language"); if (language == null) { language = "de"; // Defaultwert wie im Original } // Groups (kommagetrennt) List<String> groups = new ArrayList<>(); String groupsArgument = getArgument(args, "--groups"); if (groupsArgument != null) { // Zerlege den String an Kommas String[] groupArray = groupsArgument.split(","); groups.addAll(Arrays.asList(groupArray)); } // Vollständige Prüfung if (serverIp == null || serverPortStr == null || token == null || question == null) { printUsage(); return; } int serverPort = Integer.parseInt(serverPortStr); // Anfrage an den Server stellen String response = sendMCPRequest(serverIp, serverPort, token, question, usePublic, groups, language); System.out.println("Response from server:"); System.out.println(response); } /** * Liest den Wert eines Arguments aus (z.B. --server-ip 127.0.0.1). * Gibt null zurück, wenn der Schlüssel nicht gefunden wurde. */ private static String getArgument(String[] args, String key) { for (int i = 0; i < args.length - 1; i++) { if (args[i].equals(key)) { // Gib das nächste Element zurück, sofern vorhanden return args[i + 1]; } } return null; } /** * Stellt eine Socket-Verbindung her, sendet das JSON-Payload und empfängt die Antwort. */ private static String sendMCPRequest(String serverIp, int serverPort, String token, String question, boolean usePublic, List<String> groups, String language) { // Payload aufbauen JSONObject payload = new JSONObject(); payload.put("command", "chat"); payload.put("token", token); // arguments JSONObject arguments = new JSONObject(); arguments.put("question", question); arguments.put("usePublic", usePublic); arguments.put("language", language); // Falls du lieber ein reines Array statt List speichern möchtest, // kannst du direkt new JSONArray(groups) verwenden. // Hier konvertieren wir die Java-Liste in ein JSONArray: JSONArray groupsArray = new JSONArray(groups); arguments.put("groups", groupsArray); payload.put("arguments", arguments); // Konvertiere das JSON-Objekt in einen String String payloadJson = payload.toString(); try (Socket client = new Socket(serverIp, serverPort)) { // Sende das JSON-Payload OutputStream outputStream = client.getOutputStream(); byte[] data = payloadJson.getBytes(StandardCharsets.UTF_8); outputStream.write(data); outputStream.flush(); // Antwort empfangen InputStream inputStream = client.getInputStream(); byte[] buffer = new byte[4096]; StringBuilder responseBuilder = new StringBuilder(); int bytesRead; do { bytesRead = inputStream.read(buffer); if (bytesRead > 0) { responseBuilder.append(new String(buffer, 0, bytesRead, StandardCharsets.UTF_8)); } } while (bytesRead == buffer.length); return responseBuilder.toString(); } catch (IOException e) { // Fehler in ein JSON-Objekt packen, wie im Original JSONObject errorResponse = new JSONObject(); errorResponse.put("status", "error"); errorResponse.put("message", e.getMessage()); return errorResponse.toString(); } } private static void printUsage() { System.out.println("Usage: "); System.out.println(" --server-ip <IP> --server-port <PORT> --token <TOKEN> --question <QUESTION>"); System.out.println(" [--use-public] [--groups <GROUPS>] [--language <LANGUAGE>]"); System.out.println(); System.out.println("Example:"); System.out.println(" java -cp .;json-20241224.jar MCPChatClient --server-ip 127.0.0.1 --server-port 1234 \\"); System.out.println(" --token 12345 --question \"Hallo Welt?\" --use-public --groups \"devops,hr\""); } } ``` -------------------------------------------------------------------------------- /clients/Gradio/transport/stdio/stdio_client.py: -------------------------------------------------------------------------------- ```python # transport/stdio/stdio_client.py import json import logging import sys import traceback from contextlib import asynccontextmanager import anyio from anyio.streams.text import TextReceiveStream from ...mcp_client import get_default_environment from ...messages.message_types.json_rpc_message import JSONRPCMessage from ...transport.stdio.stdio_server_parameters import StdioServerParameters @asynccontextmanager async def stdio_client(server: StdioServerParameters): # ensure we have a server command if not server.command: raise ValueError("Server command must not be empty.") # ensure we have server arguments as a list or tuple if not isinstance(server.args, (list, tuple)): raise ValueError("Server arguments must be a list or tuple.") # create the the read and write streams read_stream_writer, read_stream = anyio.create_memory_object_stream(0) write_stream, write_stream_reader = anyio.create_memory_object_stream(0) # start the subprocess process = await anyio.open_process( [server.command, *server.args], env={**get_default_environment(), **(server.env or {})}, stderr=sys.stderr, ) # started server logging.debug( f"Subprocess started with PID {process.pid}, command: {server.command}" ) # create a task to read from the subprocess' stdout async def process_json_line(line: str, writer): try: logging.debug(f"Processing line: {line.strip()}") data = json.loads(line) # parse the json logging.debug(f"Parsed JSON data: {data}") # validate the jsonrpc message message = JSONRPCMessage.model_validate(data) logging.debug(f"Validated JSONRPCMessage: {message}") # send the message await writer.send(message) except json.JSONDecodeError as exc: # not valid json logging.error(f"JSON decode error: {exc}. Line: {line.strip()}") except Exception as exc: # other exception logging.error(f"Error processing message: {exc}. Line: {line.strip()}") logging.debug(f"Traceback:\n{traceback.format_exc()}") async def stdout_reader(): """Read JSON-RPC messages from the server's stdout.""" assert process.stdout, "Opened process is missing stdout" buffer = "" logging.debug("Starting stdout_reader") try: async with read_stream_writer: async for chunk in TextReceiveStream(process.stdout): lines = (buffer + chunk).split("\n") buffer = lines.pop() for line in lines: if line.strip(): await process_json_line(line, read_stream_writer) if buffer.strip(): await process_json_line(buffer, read_stream_writer) except anyio.ClosedResourceError: logging.debug("Read stream closed.") except Exception as exc: logging.error(f"Unexpected error in stdout_reader: {exc}") logging.debug(f"Traceback:\n{traceback.format_exc()}") raise finally: logging.debug("Exiting stdout_reader") async def stdin_writer(): """Send JSON-RPC messages from the write stream to the server's stdin.""" assert process.stdin, "Opened process is missing stdin" logging.debug("Starting stdin_writer") try: async with write_stream_reader: async for message in write_stream_reader: json_str = message.model_dump_json(exclude_none=True) logging.debug(f"Sending: {json_str}") await process.stdin.send((json_str + "\n").encode()) except anyio.ClosedResourceError: logging.debug("Write stream closed.") except Exception as exc: logging.error(f"Unexpected error in stdin_writer: {exc}") logging.debug(f"Traceback:\n{traceback.format_exc()}") raise finally: logging.debug("Exiting stdin_writer") async def terminate_process(): """Gracefully terminate the subprocess.""" try: if process.returncode is None: # Process is still running logging.debug("Terminating subprocess...") process.terminate() with anyio.fail_after(5): await process.wait() else: logging.info("Process already terminated.") except TimeoutError: logging.warning( "Process did not terminate gracefully. Forcefully killing it." ) try: process.kill() except Exception as kill_exc: logging.error(f"Error killing process: {kill_exc}") except Exception as exc: logging.error(f"Error during process termination: {exc}") try: async with anyio.create_task_group() as tg, process: tg.start_soon(stdout_reader) tg.start_soon(stdin_writer) yield read_stream, write_stream # exit the task group exit_code = await process.wait() logging.info(f"Process exited with code {exit_code}") except Exception as exc: # other exception logging.error(f"Unhandled error in TaskGroup: {exc}") logging.debug(f"Traceback:\n{traceback.format_exc()}") if hasattr(exc, "__cause__") and exc.__cause__: logging.debug(f"TaskGroup exception cause: {exc.__cause__}") raise finally: await terminate_process() ``` -------------------------------------------------------------------------------- /agents/MCP-Client/Python/transport/stdio/stdio_client.py: -------------------------------------------------------------------------------- ```python # transport/stdio/stdio_client.py import json import logging import sys import traceback from contextlib import asynccontextmanager import anyio from anyio.streams.text import TextReceiveStream from ...environment import get_default_environment from ...messages.message_types.json_rpc_message import JSONRPCMessage from ...transport.stdio.stdio_server_parameters import StdioServerParameters @asynccontextmanager async def stdio_client(server: StdioServerParameters): # ensure we have a server command if not server.command: raise ValueError("Server command must not be empty.") # ensure we have server arguments as a list or tuple if not isinstance(server.args, (list, tuple)): raise ValueError("Server arguments must be a list or tuple.") # create the the read and write streams read_stream_writer, read_stream = anyio.create_memory_object_stream(0) write_stream, write_stream_reader = anyio.create_memory_object_stream(0) # start the subprocess process = await anyio.open_process( [server.command, *server.args], env={**get_default_environment(), **(server.env or {})}, stderr=sys.stderr, ) # started server logging.debug( f"Subprocess started with PID {process.pid}, command: {server.command}" ) # create a task to read from the subprocess' stdout async def process_json_line(line: str, writer): try: logging.debug(f"Processing line: {line.strip()}") data = json.loads(line) # parse the json logging.debug(f"Parsed JSON data: {data}") # validate the jsonrpc message message = JSONRPCMessage.model_validate(data) logging.debug(f"Validated JSONRPCMessage: {message}") # send the message await writer.send(message) except json.JSONDecodeError as exc: # not valid json logging.error(f"JSON decode error: {exc}. Line: {line.strip()}") except Exception as exc: # other exception logging.error(f"Error processing message: {exc}. Line: {line.strip()}") logging.debug(f"Traceback:\n{traceback.format_exc()}") async def stdout_reader(): """Read JSON-RPC messages from the server's stdout.""" assert process.stdout, "Opened process is missing stdout" buffer = "" logging.debug("Starting stdout_reader") try: async with read_stream_writer: async for chunk in TextReceiveStream(process.stdout): lines = (buffer + chunk).split("\n") buffer = lines.pop() for line in lines: if line.strip(): await process_json_line(line, read_stream_writer) if buffer.strip(): await process_json_line(buffer, read_stream_writer) except anyio.ClosedResourceError: logging.debug("Read stream closed.") except Exception as exc: logging.error(f"Unexpected error in stdout_reader: {exc}") logging.debug(f"Traceback:\n{traceback.format_exc()}") raise finally: logging.debug("Exiting stdout_reader") async def stdin_writer(): """Send JSON-RPC messages from the write stream to the server's stdin.""" assert process.stdin, "Opened process is missing stdin" logging.debug("Starting stdin_writer") try: async with write_stream_reader: async for message in write_stream_reader: json_str = message.model_dump_json(exclude_none=True) logging.debug(f"Sending: {json_str}") await process.stdin.send((json_str + "\n").encode()) except anyio.ClosedResourceError: logging.debug("Write stream closed.") except Exception as exc: logging.error(f"Unexpected error in stdin_writer: {exc}") logging.debug(f"Traceback:\n{traceback.format_exc()}") raise finally: logging.debug("Exiting stdin_writer") async def terminate_process(): """Gracefully terminate the subprocess.""" try: if process.returncode is None: # Process is still running logging.debug("Terminating subprocess...") process.terminate() with anyio.fail_after(5): await process.wait() else: logging.info("Process already terminated.") except TimeoutError: logging.warning( "Process did not terminate gracefully. Forcefully killing it." ) try: process.kill() except Exception as kill_exc: logging.error(f"Error killing process: {kill_exc}") except Exception as exc: logging.error(f"Error during process termination: {exc}") try: async with anyio.create_task_group() as tg, process: tg.start_soon(stdout_reader) tg.start_soon(stdin_writer) yield read_stream, write_stream # exit the task group exit_code = await process.wait() logging.info(f"Process exited with code {exit_code}") except Exception as exc: # other exception logging.error(f"Unhandled error in TaskGroup: {exc}") logging.debug(f"Traceback:\n{traceback.format_exc()}") if hasattr(exc, "__cause__") and exc.__cause__: logging.debug(f"TaskGroup exception cause: {exc.__cause__}") raise finally: await terminate_process() ``` -------------------------------------------------------------------------------- /clients/JavaScript/4.2 mcp_delete_group/MCPDeleteGroupClient.js: -------------------------------------------------------------------------------- ```javascript const net = require('net'); const readline = require('readline'); const { argv, exit } = require('process'); /** * Funktion zum Parsen der Kommandozeilenargumente * @param {string[]} args - Array von Kommandozeilenargumenten * @returns {Object} - Objekt mit geparsten Argumenten */ function parseArguments(args) { const parsedArgs = {}; for (let i = 2; i < args.length; i++) { switch (args[i]) { case '--server-ip': if (i + 1 < args.length) { parsedArgs.serverIp = args[++i]; } else { console.warn('⚠️ Kein Wert für --server-ip angegeben.'); } break; case '--server-port': if (i + 1 < args.length) { parsedArgs.serverPort = parseInt(args[++i], 10); } else { console.warn('⚠️ Kein Wert für --server-port angegeben.'); } break; case '--token': if (i + 1 < args.length) { parsedArgs.token = args[++i]; } else { console.warn('⚠️ Kein Wert für --token angegeben.'); } break; case '--group-name': if (i + 1 < args.length) { parsedArgs.groupName = args[++i]; } else { console.warn('⚠️ Kein Wert für --group-name angegeben.'); } break; default: console.warn(`⚠️ Unbekanntes Argument: ${args[i]}`); } } return parsedArgs; } /** * Funktion zum interaktiven Abfragen eines Parameters (optional) * @param {string} query - Frage an den Benutzer * @returns {Promise<string>} - Antwort des Benutzers */ function askQuestion(query) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true }); return new Promise((resolve) => { rl.question(query, (answer) => { rl.close(); resolve(answer); }); }); } /** * Sendet eine Anfrage an den MCP-Server, um eine bestehende Gruppe zu löschen. * * @param {string} serverIp - IP-Adresse des MCP-Servers * @param {number} serverPort - Portnummer des MCP-Servers * @param {string} token - Authentifizierungstoken * @param {string} groupName - Name der zu löschenden Gruppe * @returns {Promise<Object>} - Antwort vom Server */ function sendDeleteGroupRequest(serverIp, serverPort, token, groupName) { return new Promise((resolve, reject) => { const client = new net.Socket(); const payload = { command: "delete_group", token: token, arguments: { groupName: groupName } }; const payloadString = JSON.stringify(payload); // Timeout setzen (optional) const TIMEOUT_DURATION = 10000; // 10 Sekunden const timeout = setTimeout(() => { client.destroy(); // Verbindung zerstören reject(new Error('Verbindungs-Timeout: Der Server hat nicht rechtzeitig geantwortet.')); }, TIMEOUT_DURATION); client.connect(serverPort, serverIp, () => { console.log(`🔗 Verbindung zum Server (${serverIp}:${serverPort}) hergestellt.`); console.log(`📤 Sende Payload: ${payloadString}`); client.write(payloadString); }); let responseData = ''; client.on('data', (data) => { console.log(`📥 Empfangene Daten: ${data}`); responseData += data.toString(); try { const parsedData = JSON.parse(responseData); console.log('✅ JSON-Antwort erfolgreich geparst.'); clearTimeout(timeout); resolve(parsedData); client.destroy(); // Verbindung schließen } catch (err) { console.warn('⚠️ Antwort noch nicht vollständig oder ungültiges JSON. Weitere Daten werden erwartet.'); // Weiter empfangen } }); client.on('close', () => { console.log('🔒 Verbindung zum Server geschlossen.'); clearTimeout(timeout); }); client.on('error', (err) => { console.error('❌ Verbindungsfehler:', err.message); clearTimeout(timeout); reject(err); }); }); } // Hauptfunktion async function main() { const args = argv; const parsedArgs = parseArguments(args); let { serverIp, serverPort, token, groupName } = parsedArgs; // Überprüfen, ob alle erforderlichen Parameter vorhanden sind, sonst interaktiv abfragen if (!serverIp) { serverIp = await askQuestion('🔗 Bitte gib die Server-IP ein: '); } if (!serverPort) { const portInput = await askQuestion('🔗 Bitte gib den Server-Port ein: '); serverPort = parseInt(portInput, 10); } if (!token) { token = await askQuestion('🔒 Bitte gib dein Authentifizierungstoken ein: '); } if (!groupName) { groupName = await askQuestion('👥 Bitte gib den Namen der Gruppe ein: '); } const payload = { command: "delete_group", token: token, arguments: { groupName: groupName } }; try { console.log('🗑️ Sende Delete-Group-Anfrage...'); const response = await sendDeleteGroupRequest(serverIp, serverPort, token, groupName); console.log('✔️ Antwort vom Server:', JSON.stringify(response, null, 2)); } catch (err) { console.error('❌ Fehler:', err.message); } } main(); ``` -------------------------------------------------------------------------------- /agents/OpenAI_Compatible_API_Agent/Python/openai_compatible_api.py: -------------------------------------------------------------------------------- ```python import json from pathlib import Path from starlette.responses import StreamingResponse from fastapi import FastAPI, Request, HTTPException from threading import local from agents.OpenAI_Compatible_API_Agent.Python.open_ai_helper import ChatInstance, \ ChatCompletionRequest, CompletionRequest, _resp_sync, _resp_async_generator, models, Message, _resp_async_generator_completions, _resp_sync_completions from .privategpt_api import PrivateGPTAPI from ...AgentInterface.Python.config import Config, ConfigError import uvicorn app = FastAPI(title="OpenAI-compatible API for PrivateGPT") request_context = local() instances = [] # Konfiguration laden try: config_file = Path.absolute(Path(__file__).parent.parent / "pgpt_openai_api_proxy.json") config = Config(config_file=config_file, required_fields=["base_url"]) default_groups = config.get("groups", []) except ConfigError as e: print(f"Configuration Error: {e}") exit(1) @app.middleware("http") async def store_request_headers(request: Request, call_next): request_context.headers = dict(request.headers) response = await call_next(request) return response @app.post("/chat/completions") async def chat_completions(request: ChatCompletionRequest): headers = getattr(request_context, "headers", {}) client_api_key = str(headers['authorization']).split(" ")[1] groups = default_groups force_new_session = False if request.groups: groups = request.groups if request.newSession: force_new_session = True print("Groups: " + str(groups)) if request.messages: #Check if this api-key already has a running instance indices = [i for i, x in enumerate(instances) if x.api_key == client_api_key] index = -1 if len(indices) > 0: index = indices[0] if index > -1: # if we already have an instance, just reuse it. No need to open new connection if instances[index].agent.chosen_groups != groups: print("⚠️ New Groups requested, switching to new Chat..") config.set_value("groups", groups) instances[index].agent.chat_id = None elif force_new_session: print("⚠️ New Session Requested, switching to new Chat..") config.set_value("groups", groups) instances[index].agent.chat_id = None pgpt = instances[index].agent else: #otherwise connect via api-key config.set_value("groups", groups) pgpt = PrivateGPTAPI(config, client_api_key=client_api_key) # remember that we already have an instance for the api key instance = ChatInstance(client_api_key, pgpt) instances.append(instance) if pgpt.logged_in: response = pgpt.respond_with_context(request.messages, request.response_format, request.tools) if response is not None: if "answer" not in response: response["answer"] = "No Response received" if response is None or ("answer" in response and response["answer"] == "error"): pgpt.login() else: response = { "chatId": "0", "answer": "API Key not valid", } else: response = { "chatId": "0", "answer": "No Input given", } if request.stream: return StreamingResponse( _resp_async_generator(response, request), media_type="application/x-ndjson" ) else: return _resp_sync(response, request) # legacy completions API @app.post("/completions") async def completions(request: CompletionRequest): headers = getattr(request_context, "headers", {}) client_api_key = str(headers['authorization']).split(" ")[1] groups = default_groups if request.groups: groups = request.groups print("Groups: " + str(groups)) if request.prompt: #otherwise connect via api-key config.set_value("groups", groups) pgpt = PrivateGPTAPI(config, client_api_key=client_api_key) # remember that we already have an instance for the api key if pgpt.logged_in: response = pgpt.respond_with_context([Message(role="user", content=request.prompt)], request.response_format, request.tools) if "answer" not in response: response["answer"] = "No Response received" if "answer" in response and response["answer"] == "error": if pgpt.login(): pgpt.create_chat() else: response = { "chatId": "0", "answer": "API Key not valid", } else: response = { "chatId": "0", "answer": "No Input given", } if request.stream : return StreamingResponse( _resp_async_generator_completions(response, request), media_type="application/x-ndjson" ) else: return _resp_sync_completions(response, request) @app.get("/models") def return_models(): return { "object": "list", "data": models } @app.get('/models/{model_id}') async def get_model(model_id: str): filtered_entries = list(filter(lambda item: item["id"] == model_id, models)) entry = filtered_entries[0] if filtered_entries else None print(entry) if entry is None: raise HTTPException(status_code=404, detail="Model not found") return entry if __name__ == "__main__": api_ip = config.get("api_ip", "0.0.0.0") api_port = config.get("api_port", 8001) uvicorn.run(app, host=api_ip, port=int(api_port)) ``` -------------------------------------------------------------------------------- /agents/ChatBotAgent/html/index.html: -------------------------------------------------------------------------------- ```html <!DOCTYPE html> <html lang="de"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ChatBot Agent Interface</title> <style> body { font-family: Arial, sans-serif; margin: 20px; padding: 0; background-color: #f4f4f9; } .container { max-width: 600px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); text-align: center; /* Zentriert den Inhalt */ } .logo { display: block; margin: 0 auto 20px; /* Zentriert das Logo und fügt Abstand ein */ width: 150px; height: auto; } h1 { text-align: center; color: #333; } textarea, select, input, button { width: 100%; margin: 10px 0; padding: 10px; font-size: 16px; border: 1px solid #ccc; border-radius: 5px; box-sizing: border-box; } button { background-color: #007BFF; color: white; border: none; cursor: pointer; font-size: 16px; } button:hover { background-color: #0056b3; } .response-box { margin-top: 20px; padding: 15px; border: 1px solid #ccc; border-radius: 5px; background-color: #f9f9f9; white-space: pre-wrap; font-family: monospace; } </style> </head> <body> <div class="container"> <!-- Logo einfügen --> <img src="Logo_light.svg" alt="Logo" class="logo"> <h1>ChatBot Agent</h1> <form id="queryForm"> <label for="question">Question:</label> <textarea id="question" rows="3" placeholder="Enter your question here..." required></textarea> <label for="language">Language:</label> <select id="language"> <option value="en" selected>English</option> <option value="de">German</option> </select> <label for="groups">Groups (optional, separated by commas):</label> <input type="text" id="groups" placeholder="Example: Group1, Group2"> <label> <input type="checkbox" id="usePublic" checked> Use general knowledge </label> <button type="submit">Send Request</button> </form> <div class="response-box" id="responseBox"> The response will be displayed here... </div> </div> <script> const apiUrl = "http://127.0.0.1:5001/ask"; // URL der API const apiKey = "IhrSichererAPIKey123"; // API-Key document.getElementById("queryForm").addEventListener("submit", async function(event) { event.preventDefault(); // Eingaben aus dem Formular abrufen const question = document.getElementById("question").value.trim(); const language = document.getElementById("language").value; const groupsInput = document.getElementById("groups").value; const groups = groupsInput .split(",") .map(group => group.trim()) .filter(group => group); // Leere Gruppen entfernen const usePublic = document.getElementById("usePublic").checked; if (!question) { alert("Please enter a question."); return; } // JSON-Body für die Anfrage erstellen const body = { question: question, usePublic: usePublic, groups: groups, language: language }; // Anzeige der Anfrage im Response-Box (optional) document.getElementById("responseBox").textContent = "Sending request..."; // Anfrage senden try { const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json", "X-API-KEY": apiKey // Korrigierter Header }, body: JSON.stringify(body) }); if (response.ok) { const data = await response.json(); // Extrahiere das 'answer'-Feld und entferne mögliche Anführungszeichen let answer = data.answer || ""; if (answer.startsWith('"') && answer.endsWith('"')) { answer = answer.substring(1, answer.length - 1); } // Optional: Entschlüsselung von Unicode-Zeichen try { answer = decodeURIComponent(escape(answer)); } catch (e) { console.warn("Unicode decoding failed:", e); } // Anzeige der Antwort document.getElementById("responseBox").textContent = answer; } else { // Fehlerbehandlung bei HTTP-Fehlern const errorText = await response.text(); document.getElementById("responseBox").textContent = `Error: ${response.status} ${response.statusText}\n${errorText}`; } } catch (error) { // Fehlerbehandlung bei Netzwerk- oder anderen Fehlern document.getElementById("responseBox").textContent = `Request failed: ${error.message}`; } }); </script> </body> </html> ``` -------------------------------------------------------------------------------- /agents/ChatBotAgent/html/index_de.html: -------------------------------------------------------------------------------- ```html <!DOCTYPE html> <html lang="de"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ChatBot Agent Interface</title> <style> body { font-family: Arial, sans-serif; margin: 20px; padding: 0; background-color: #f4f4f9; } .container { max-width: 600px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); text-align: center; /* Zentriert den Inhalt */ } .logo { display: block; margin: 0 auto 20px; /* Zentriert das Logo und fügt Abstand ein */ width: 150px; height: auto; } h1 { text-align: center; color: #333; } textarea, select, input, button { width: 100%; margin: 10px 0; padding: 10px; font-size: 16px; border: 1px solid #ccc; border-radius: 5px; box-sizing: border-box; } button { background-color: #007BFF; color: white; border: none; cursor: pointer; font-size: 16px; } button:hover { background-color: #0056b3; } .response-box { margin-top: 20px; padding: 15px; border: 1px solid #ccc; border-radius: 5px; background-color: #f9f9f9; white-space: pre-wrap; font-family: monospace; } </style> </head> <body> <div class="container"> <!-- Logo einfügen --> <img src="Logo_light.svg" alt="Logo" class="logo"> <h1>ChatBot Agent</h1> <form id="queryForm"> <label for="question">Frage:</label> <textarea id="question" rows="3" placeholder="Geben Sie Ihre Frage ein..." required></textarea> <label for="language">Sprache:</label> <select id="language"> <option value="de" selected>Deutsch</option> <option value="en">Englisch</option> </select> <label for="groups">Gruppen (optional, getrennt durch Kommas):</label> <input type="text" id="groups" placeholder="Beispiel: Gruppe1, Gruppe2"> <label> <input type="checkbox" id="usePublic" checked> Öffentliche Daten verwenden </label> <button type="submit">Anfrage senden</button> </form> <div class="response-box" id="responseBox"> Antwort wird hier angezeigt... </div> </div> <script> const apiUrl = "http://192.168.100.185:5001/ask"; // URL der API const apiKey = "IhrSichererAPIKey123"; // API-Key document.getElementById("queryForm").addEventListener("submit", async function(event) { event.preventDefault(); // Eingaben aus dem Formular abrufen const question = document.getElementById("question").value.trim(); const language = document.getElementById("language").value; const groupsInput = document.getElementById("groups").value; const groups = groupsInput .split(",") .map(group => group.trim()) .filter(group => group); // Leere Gruppen entfernen const usePublic = document.getElementById("usePublic").checked; if (!question) { alert("Bitte geben Sie eine Frage ein."); return; } // JSON-Body für die Anfrage erstellen const body = { question: question, usePublic: usePublic, groups: groups, language: language }; // Anzeige der Anfrage im Response-Box (optional) document.getElementById("responseBox").textContent = "Anfrage wird gesendet..."; // Anfrage senden try { const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json", "X-API-KEY": apiKey // Korrigierter Header }, body: JSON.stringify(body) }); if (response.ok) { const data = await response.json(); // Extrahiere das 'answer'-Feld und entferne mögliche Anführungszeichen let answer = data.answer || ""; if (answer.startsWith('"') && answer.endsWith('"')) { answer = answer.substring(1, answer.length - 1); } // Optional: Entschlüsselung von Unicode-Zeichen try { answer = decodeURIComponent(escape(answer)); } catch (e) { console.warn("Unicode-Entschlüsselung fehlgeschlagen:", e); } // Anzeige der Antwort document.getElementById("responseBox").textContent = answer; } else { // Fehlerbehandlung bei HTTP-Fehlern const errorText = await response.text(); document.getElementById("responseBox").textContent = `Fehler: ${response.status} ${response.statusText}\n${errorText}`; } } catch (error) { // Fehlerbehandlung bei Netzwerk- oder anderen Fehlern document.getElementById("responseBox").textContent = `Fehler bei der Anfrage: ${error.message}`; } }); </script> </body> </html> ``` -------------------------------------------------------------------------------- /clients/Java/3.3 mcp_edit_source/MCPEditSourceClient.java: -------------------------------------------------------------------------------- ```java import org.json.JSONArray; import org.json.JSONObject; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class MCPEditSourceClient { public static void main(String[] args) { // Mindestens 8 Strings im Array erforderlich, z.B.: // --server-ip 127.0.0.1 --server-port 1234 --token X --source-id Y // plus optionale: --title "..." --content "..." --groups ... if (args.length < 8) { printUsage(); return; } // Argumente einlesen String serverIp = getArgument(args, "--server-ip"); String portStr = getArgument(args, "--server-port"); String token = getArgument(args, "--token"); String sourceId = getArgument(args, "--source-id"); String title = getArgument(args, "--title"); String content = getArgument(args, "--content"); List<String> groups = getListArgument(args, "--groups"); // Prüfung auf null if (serverIp == null || portStr == null || token == null || sourceId == null) { System.out.println("Fehler: Mindestens eines der Pflichtargumente fehlt."); return; } // Port in int umwandeln int serverPort; try { serverPort = Integer.parseInt(portStr); } catch (NumberFormatException e) { System.out.println("Fehler: --server-port muss eine ganzzahlige Portangabe sein."); return; } System.out.println("📤 Sende Anfrage zum Editieren einer Quelle..."); // Anfrage an den Server senden String response = sendEditSourceRequest(serverIp, serverPort, token, sourceId, title, content, groups); // Antwort ausgeben System.out.println("Response from server:"); System.out.println(response); } /** * Baut die Payload für die "edit_source"-Anfrage zusammen und sendet sie über TCP. */ private static String sendEditSourceRequest( String serverIp, int serverPort, String token, String sourceId, String title, String content, List<String> groups ) { // Arguments-Objekt erstellen JSONObject arguments = new JSONObject(); arguments.put("sourceId", sourceId); if (title != null && !title.trim().isEmpty()) { arguments.put("title", title); } if (content != null && !content.trim().isEmpty()) { arguments.put("content", content); } // Gruppen (falls keine übergeben, bleibt es einfach eine leere Liste) if (groups == null) { groups = new ArrayList<>(); } JSONArray groupsArray = new JSONArray(groups); arguments.put("groups", groupsArray); // Gesamte Payload JSONObject payload = new JSONObject(); payload.put("command", "edit_source"); payload.put("token", token); payload.put("arguments", arguments); // JSON in String umwandeln String payloadJson = payload.toString(); // TCP-Verbindung aufbauen und senden try (Socket client = new Socket(serverIp, serverPort)) { // Senden OutputStream out = client.getOutputStream(); byte[] data = payloadJson.getBytes(StandardCharsets.UTF_8); out.write(data); out.flush(); // Antwort empfangen InputStream in = client.getInputStream(); byte[] buffer = new byte[4096]; StringBuilder responseBuilder = new StringBuilder(); int bytesRead; do { bytesRead = in.read(buffer); if (bytesRead > 0) { responseBuilder.append(new String(buffer, 0, bytesRead, StandardCharsets.UTF_8)); } } while (bytesRead == buffer.length); return responseBuilder.toString(); } catch (IOException e) { return "Error: " + e.getMessage(); } } /** * Liest den Wert für ein bestimmtes Argument aus (z.B. --server-ip 127.0.0.1). */ private static String getArgument(String[] args, String key) { for (int i = 0; i < args.length - 1; i++) { if (args[i].equals(key)) { return args[i + 1]; } } return null; } /** * Liest eine Liste von Werten aus (z.B. --groups G1 G2 G3 ...), bis zum nächsten -- oder Ende. */ private static List<String> getListArgument(String[] args, String key) { List<String> result = new ArrayList<>(); for (int i = 0; i < args.length; i++) { if (args[i].equals(key)) { // Ab hier Werte einsammeln for (int j = i + 1; j < args.length; j++) { if (args[j].startsWith("--")) { break; } result.add(args[j]); } break; } } return result; } private static void printUsage() { System.out.println("Usage:"); System.out.println(" --server-ip <IP> --server-port <PORT> --token <TOKEN> --source-id <SOURCE_ID>"); System.out.println(" [--title <TITLE>] [--content <CONTENT>] [--groups <LIST_OF_GROUPS>]"); System.out.println(); System.out.println("Example:"); System.out.println(" java -cp .;json-20241224.jar MCPEditSourceClient \\"); System.out.println(" --server-ip 127.0.0.1 --server-port 1234 --token SomeToken --source-id 456 \\"); System.out.println(" --title \"Neuer Titel\" --content \"Neuer Inhalt...\" --groups DevOps Finance"); } } ``` -------------------------------------------------------------------------------- /clients/PHP/9.0 mcp_keygen/MCPKeygenClient.php: -------------------------------------------------------------------------------- ```php <?php /** * MCPKeygenClient.php * * A PHP script that acts as a Keygen Client. It connects to a server via TCP, * sends a keygen request, and receives the server's response. * * Usage: * php MCPKeygenClient.php --server-ip <IP> --server-port <Port> --token <Token> --password <Password> */ /** * Function to parse command line arguments * * @param array $args The command line arguments * @return array An associative array with the parsed arguments */ function parseArguments($args) { $parsedArgs = []; $argc = count($args); for ($i = 1; $i < $argc; $i++) { switch ($args[$i]) { case '--server-ip': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['serverIp'] = $args[++$i]; } else { fwrite(STDERR, "⚠️ Warning: No value provided for --server-ip.\n"); } break; case '--server-port': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['serverPort'] = intval($args[++$i]); } else { fwrite(STDERR, "⚠️ Warning: No value provided for --server-port.\n"); } break; case '--token': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['token'] = $args[++$i]; } else { fwrite(STDERR, "⚠️ Warning: No value provided for --token.\n"); } break; case '--password': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['password'] = $args[++$i]; } else { fwrite(STDERR, "⚠️ Warning: No value provided for --password.\n"); } break; default: fwrite(STDERR, "⚠️ Warning: Unknown argument: {$args[$i]}\n"); } } return $parsedArgs; } /** * Helper function to check if a string starts with a specific prefix * * @param string $string The string to check * @param string $prefix The prefix * @return bool True if the string starts with the prefix, otherwise False */ function startsWith($string, $prefix) { return substr($string, 0, strlen($prefix)) === $prefix; } /** * Function to send a Keygen request over a TCP connection * * @param string $serverIp The server's IP address * @param int $serverPort The server's port * @param string $token The authentication token * @param string $password The password for key generation * @return array The response received from the server as an associative array * @throws Exception On connection errors or JSON parsing errors */ function sendKeygenRequest($serverIp, $serverPort, $token, $password) { $payload = [ "command" => "keygen", "token" => $token, "arguments" => [ "password" => $password ] ]; $jsonPayload = json_encode($payload); if ($jsonPayload === false) { throw new Exception("Error encoding JSON payload: " . json_last_error_msg()); } $errno = 0; $errstr = ''; $timeoutDuration = 10; // Seconds (10 seconds timeout) $client = @fsockopen($serverIp, $serverPort, $errno, $errstr, $timeoutDuration); if (!$client) { throw new Exception("Connection error: $errstr ($errno)"); } echo "🔗 Connected to server ({$serverIp}:{$serverPort}).\n"; echo "📤 Sending Payload: {$jsonPayload}\n"; fwrite($client, $jsonPayload); $responseData = ''; stream_set_timeout($client, $timeoutDuration); while (!feof($client)) { $data = fread($client, 1024); if ($data === false) { throw new Exception("Error reading data from server."); } if ($data === '') { break; // No more data } echo "📥 Received data: {$data}\n"; $responseData .= $data; // Attempt to parse the received data as JSON $parsedData = json_decode($responseData, true); if ($parsedData !== null) { echo "✅ JSON response successfully parsed.\n"; fclose($client); return $parsedData; } // Check if the stream has timed out $info = stream_get_meta_data($client); if ($info['timed_out']) { throw new Exception("Timeout while waiting for data from server."); } } fclose($client); throw new Exception("Connection to server was closed before a complete response was received."); } /** * Main function of the script */ function main($argv) { $parsedArgs = parseArguments($argv); $serverIp = $parsedArgs['serverIp'] ?? null; $serverPort = $parsedArgs['serverPort'] ?? null; $token = $parsedArgs['token'] ?? null; $password = $parsedArgs['password'] ?? null; // Check if all required parameters are present if (!$serverIp || !$serverPort || !$token || !$password) { fwrite(STDERR, "❌ Error: --server-ip, --server-port, --token, and --password are required.\n"); fwrite(STDOUT, "📖 Usage: php MCPKeygenClient.php --server-ip <IP> --server-port <Port> --token <Token> --password <Password>\n"); exit(1); } try { echo "🔑 Sending Keygen request...\n"; $response = sendKeygenRequest( $serverIp, $serverPort, $token, $password ); echo "✔️ Server response:\n"; echo json_encode($response, JSON_PRETTY_PRINT) . "\n"; } catch (Exception $e) { fwrite(STDERR, "❌ Error during Keygen request: " . $e->getMessage() . "\n"); } } // Check if PHP version is at least 7.1 (for better features) if (version_compare(PHP_VERSION, '7.1.0') < 0) { fwrite(STDERR, "❌ ERROR: This script requires PHP version 7.1 or higher.\n"); exit(1); } // Call the main function main($argv); ?> ``` -------------------------------------------------------------------------------- /clients/JavaScript/5.2 mcp_delete_user/MCPDeleteUserClient.js: -------------------------------------------------------------------------------- ```javascript <?php /** * MCPDeleteUserClient.php * * A PHP script that acts as a Delete User Client. It connects to a server via TCP, * sends a request to delete an existing user, and receives the server's response. * * Usage: * php MCPDeleteUserClient.php --server-ip <IP> --server-port <Port> --email <Email> --token <Token> */ /** * Function to parse command line arguments * * @param array $args Array of command line arguments * @return array Associative array with parsed arguments */ function parseArguments($args) { $parsedArgs = []; $argc = count($args); for ($i = 1; $i < $argc; $i++) { switch ($args[$i]) { case '--server-ip': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['serverIp'] = $args[++$i]; } else { fwrite(STDERR, "⚠️ Warning: No value provided for --server-ip.\n"); } break; case '--server-port': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['serverPort'] = intval($args[++$i]); } else { fwrite(STDERR, "⚠️ Warning: No value provided for --server-port.\n"); } break; case '--email': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['email'] = $args[++$i]; } else { fwrite(STDERR, "⚠️ Warning: No value provided for --email.\n"); } break; case '--token': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['token'] = $args[++$i]; } else { fwrite(STDERR, "⚠️ Warning: No value provided for --token.\n"); } break; default: fwrite(STDERR, "⚠️ Warning: Unknown argument: {$args[$i]}\n"); } } return $parsedArgs; } /** * Helper function to check if a string starts with a specific prefix * * @param string $string The string to check * @param string $prefix The prefix * @return bool True if the string starts with the prefix, otherwise False */ function startsWith($string, $prefix) { return substr($string, 0, strlen($prefix)) === $prefix; } /** * Function to send a Delete User request over a TCP connection * * @param string $serverIp The server's IP address * @param int $serverPort The server's port * @param string $email The email of the user to be deleted * @param string $token The authentication token * @return array The response received from the server as an associative array * @throws Exception On connection errors or JSON parsing errors */ function sendDeleteUserRequest($serverIp, $serverPort, $email, $token) { $payload = [ "command" => "delete_user", "token" => $token, "arguments" => [ "email" => $email ] ]; $jsonPayload = json_encode($payload); if ($jsonPayload === false) { throw new Exception("Error while encoding the JSON payload: " . json_last_error_msg()); } $errno = 0; $errstr = ''; $timeoutDuration = 10; // Seconds (10 seconds timeout) $client = @fsockopen($serverIp, $serverPort, $errno, $errstr, $timeoutDuration); if (!$client) { throw new Exception("Connection error: $errstr ($errno)"); } echo "🔗 Connected to server ({$serverIp}:{$serverPort}).\n"; echo "📤 Sending Payload: {$jsonPayload}\n"; fwrite($client, $jsonPayload); $responseData = ''; stream_set_timeout($client, $timeoutDuration); while (!feof($client)) { $data = fread($client, 1024); if ($data === false) { throw new Exception("Error reading data from server."); } if ($data === '') { break; // No more data } echo "📥 Received data: {$data}\n"; $responseData .= $data; // Attempt to parse the received data as JSON $parsedData = json_decode($responseData, true); if ($parsedData !== null) { echo "✅ JSON response successfully parsed.\n"; fclose($client); return $parsedData; } // Check if the stream has timed out $info = stream_get_meta_data($client); if ($info['timed_out']) { throw new Exception("Timeout while waiting for data from server."); } } fclose($client); throw new Exception("Connection to server was closed before a complete response was received."); } /** * Main function of the script */ function main($argv) { $parsedArgs = parseArguments($argv); $serverIp = $parsedArgs['serverIp'] ?? null; $serverPort = $parsedArgs['serverPort'] ?? null; $email = $parsedArgs['email'] ?? null; $token = $parsedArgs['token'] ?? null; // Check if all required parameters are present if (!$serverIp || !$serverPort || !$email || !$token) { fwrite(STDERR, "❌ ERROR: --server-ip, --server-port, --email, and --token are required.\n"); fwrite(STDOUT, "📖 Example: php MCPDeleteUserClient.php --server-ip 192.168.0.1 --server-port 5000 --email [email protected] --token YOUR_AUTH_TOKEN\n"); exit(1); } try { echo "🗑️ Sending Delete-User request...\n"; $response = sendDeleteUserRequest( $serverIp, $serverPort, $email, $token ); echo "✔️ Server response:\n"; echo json_encode($response, JSON_PRETTY_PRINT) . "\n"; } catch (Exception $e) { fwrite(STDERR, "❌ Error deleting user: " . $e->getMessage() . "\n"); } } // Check if PHP version is at least 7.1 (for better features) if (version_compare(PHP_VERSION, '7.1.0') < 0) { fwrite(STDERR, "❌ ERROR: This script requires PHP version 7.1 or higher.\n"); exit(1); } // Call the main function main($argv); ?> ``` -------------------------------------------------------------------------------- /clients/PHP/5.2 mcp_delete_user/MCPDeleteUserClient.php: -------------------------------------------------------------------------------- ```php <?php /** * MCPDeleteUserClient.php * * A PHP script that acts as a Delete User Client. It connects to a server via TCP, * sends a request to delete an existing user, and receives the server's response. * * Usage: * php MCPDeleteUserClient.php --server-ip <IP> --server-port <Port> --email <Email> --token <Token> */ /** * Function to parse command line arguments * * @param array $args Array of command line arguments * @return array Associative array with parsed arguments */ function parseArguments($args) { $parsedArgs = []; $argc = count($args); for ($i = 1; $i < $argc; $i++) { switch ($args[$i]) { case '--server-ip': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['serverIp'] = $args[++$i]; } else { fwrite(STDERR, "⚠️ Warning: No value provided for --server-ip.\n"); } break; case '--server-port': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['serverPort'] = intval($args[++$i]); } else { fwrite(STDERR, "⚠️ Warning: No value provided for --server-port.\n"); } break; case '--email': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['email'] = $args[++$i]; } else { fwrite(STDERR, "⚠️ Warning: No value provided for --email.\n"); } break; case '--token': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['token'] = $args[++$i]; } else { fwrite(STDERR, "⚠️ Warning: No value provided for --token.\n"); } break; default: fwrite(STDERR, "⚠️ Warning: Unknown argument: {$args[$i]}\n"); } } return $parsedArgs; } /** * Helper function to check if a string starts with a specific prefix * * @param string $string The string to check * @param string $prefix The prefix * @return bool True if the string starts with the prefix, otherwise False */ function startsWith($string, $prefix) { return substr($string, 0, strlen($prefix)) === $prefix; } /** * Function to send a Delete User request over a TCP connection * * @param string $serverIp The server's IP address * @param int $serverPort The server's port * @param string $email The email of the user to be deleted * @param string $token The authentication token * @return array The response received from the server as an associative array * @throws Exception On connection errors or JSON parsing errors */ function sendDeleteUserRequest($serverIp, $serverPort, $email, $token) { $payload = [ "command" => "delete_user", "token" => $token, "arguments" => [ "email" => $email ] ]; $jsonPayload = json_encode($payload); if ($jsonPayload === false) { throw new Exception("Error while encoding the JSON payload: " . json_last_error_msg()); } $errno = 0; $errstr = ''; $timeoutDuration = 10; // Seconds (10 seconds timeout) $client = @fsockopen($serverIp, $serverPort, $errno, $errstr, $timeoutDuration); if (!$client) { throw new Exception("Connection error: $errstr ($errno)"); } echo "🔗 Connected to server ({$serverIp}:{$serverPort}).\n"; echo "📤 Sending Payload: {$jsonPayload}\n"; fwrite($client, $jsonPayload); $responseData = ''; stream_set_timeout($client, $timeoutDuration); while (!feof($client)) { $data = fread($client, 1024); if ($data === false) { throw new Exception("Error reading data from server."); } if ($data === '') { break; // No more data } echo "📥 Received data: {$data}\n"; $responseData .= $data; // Attempt to parse the received data as JSON $parsedData = json_decode($responseData, true); if ($parsedData !== null) { echo "✅ JSON response successfully parsed.\n"; fclose($client); return $parsedData; } // Check if the stream has timed out $info = stream_get_meta_data($client); if ($info['timed_out']) { throw new Exception("Timeout while waiting for data from server."); } } fclose($client); throw new Exception("Connection to server was closed before a complete response was received."); } /** * Main function of the script */ function main($argv) { $parsedArgs = parseArguments($argv); $serverIp = $parsedArgs['serverIp'] ?? null; $serverPort = $parsedArgs['serverPort'] ?? null; $email = $parsedArgs['email'] ?? null; $token = $parsedArgs['token'] ?? null; // Check if all required parameters are present if (!$serverIp || !$serverPort || !$email || !$token) { fwrite(STDERR, "❌ ERROR: --server-ip, --server-port, --email, and --token are required.\n"); fwrite(STDOUT, "📖 Example: php MCPDeleteUserClient.php --server-ip 192.168.0.1 --server-port 5000 --email [email protected] --token YOUR_AUTH_TOKEN\n"); exit(1); } try { echo "🗑️ Sending Delete-User request...\n"; $response = sendDeleteUserRequest( $serverIp, $serverPort, $email, $token ); echo "✔️ Server response:\n"; echo json_encode($response, JSON_PRETTY_PRINT) . "\n"; } catch (Exception $e) { fwrite(STDERR, "❌ Error deleting user: " . $e->getMessage() . "\n"); } } // Check if PHP version is at least 7.1 (for better features) if (version_compare(PHP_VERSION, '7.1.0') < 0) { fwrite(STDERR, "❌ ERROR: This script requires PHP version 7.1 or higher.\n"); exit(1); } // Call the main function main($argv); ?> ``` -------------------------------------------------------------------------------- /agents/AgentInterface/Python/network.py: -------------------------------------------------------------------------------- ```python import socket import ssl import json import logging import time from .language import languages class NetworkError(Exception): pass class NetworkClient: def __init__( self, server_ip, server_port, language="en", retries=3, delay=5, use_ssl=True, accept_self_signed=True ): self.server_ip = server_ip self.server_port = server_port self.retries = retries self.delay = delay self.use_ssl = use_ssl self.accept_self_signed = accept_self_signed self.language = language if language in languages else "en" self.lang = languages[self.language] def get_lang_message(self, key, **kwargs): """ Secure method to retrieve messages from the language dictionary. Returns a default message if the key does not exist. """ message = self.lang.get(key, "Message not defined.") utf8_encoded_string = bytes(message, 'utf-8') message = str(utf8_encoded_string, 'utf-8') try: return message.format(**kwargs) except KeyError as e: logging.error(f"Missing placeholder in language file for key '{key}': {e}") return message def send_request(self, payload): payload_json = json.dumps(payload) #logging.info(f"Prepared payload: {payload_json}") for attempt in range(1, self.retries + 1): client_socket = None try: raw_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) raw_socket.settimeout(30) logging.info( self.get_lang_message( "connecting_to_server", ip=self.server_ip, port=self.server_port, attempt=attempt, retries=self.retries ) ) # SSL/TLS initialisieren (falls gewünscht) if self.use_ssl: context = ssl.create_default_context() if self.accept_self_signed: context.check_hostname = False context.verify_mode = ssl.CERT_NONE client_socket = context.wrap_socket(raw_socket, server_hostname=self.server_ip) else: client_socket = raw_socket # Verbinden client_socket.connect((self.server_ip, self.server_port)) logging.info(self.get_lang_message("connection_established")) # Anfrage senden #logging.info( # self.get_lang_message( # "sending_payload", # payload=payload_json # ) #) client_socket.sendall((payload_json + '\n').encode("utf-8")) # Alle Daten empfangen, bis Server von sich aus schließt oder Timeout response = b"" while True: try: part = client_socket.recv(4096) if not part: # Keine Daten mehr -> Server hat Verbindung geschlossen break response += part except socket.timeout: # Wenn wir hier sicher sind, dass keine weiteren Daten mehr kommen, # kann man das Lesen beenden. Oder retry. Je nach Protokoll. logging.warning(self.get_lang_message("connection_timed_out")) break decoded = response.decode("utf-8").strip() #logging.info(f"Received response: {decoded}") if not decoded: raise ValueError("Empty response received") # JSON parsen try: parsed_response = json.loads(decoded) logging.info( self.get_lang_message("formatted_response"), extra={"data": parsed_response} ) if "data" in parsed_response and "personalGroups" in parsed_response["data"]: personal_groups = parsed_response["data"]["personalGroups"] logging.info( self.get_lang_message("personal_groups_received", groups=personal_groups) ) # Erfolgreich -> Socket normal schließen und Ergebnis zurückgeben client_socket.close() return parsed_response except json.JSONDecodeError: logging.error(self.get_lang_message("invalid_json_response")) raise NetworkError(self.get_lang_message("invalid_json_response")) except socket.timeout: logging.warning(self.get_lang_message("connection_timed_out")) except Exception as e: logging.error( self.get_lang_message( "connection_error", error=str(e) ) ) # Bei Misserfolg (und wenn noch Versuche übrig): warten, neu versuchen if attempt < self.retries: logging.info( self.get_lang_message( "retrying_in_seconds", delay=self.delay ) ) time.sleep(self.delay) # Socket schließen (wenn noch offen), kein shutdown(SHUT_RDWR) verwenden if client_socket is not None: try: client_socket.close() except: pass # Nach allen Versuchen fehlgeschlagen logging.error(self.get_lang_message("all_retries_failed")) raise NetworkError(self.get_lang_message("all_retries_failed")) ``` -------------------------------------------------------------------------------- /clients/PHP/4.0 mcp_list_groups/MCPListGroupsClient.php: -------------------------------------------------------------------------------- ```php <?php /** * MCPListGroupsClient.php * * A PHP script acting as a List Groups Client. It connects to a server via TCP, * sends a request to list groups, and receives the server's response. * * Usage: * php MCPListGroupsClient.php --server-ip <IP> --server-port <Port> --token <Token> */ /** * Function to parse command line arguments * * @param array $args Command line arguments * @return array Associative array of parsed arguments */ function parseArguments($args) { $parsedArgs = []; $argc = count($args); for ($i = 1; $i < $argc; $i++) { switch ($args[$i]) { case '--server-ip': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['serverIp'] = $args[++$i]; } else { fwrite(STDERR, "Error: --server-ip expects a value.\n"); exit(1); } break; case '--server-port': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['serverPort'] = intval($args[++$i]); } else { fwrite(STDERR, "Error: --server-port expects a value.\n"); exit(1); } break; case '--token': if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) { $parsedArgs['token'] = $args[++$i]; } else { fwrite(STDERR, "Error: --token expects a value.\n"); exit(1); } break; default: fwrite(STDERR, "⚠️ Warning: Unknown argument: {$args[$i]}\n"); } } return $parsedArgs; } /** * Helper function to check if a string starts with a specific prefix * * @param string $string The string to check * @param string $prefix The prefix * @return bool True if the string starts with the prefix, otherwise False */ function startsWith($string, $prefix) { return substr($string, 0, strlen($prefix)) === $prefix; } /** * Function for interactively prompting a parameter (optional) * * @param string $prompt The prompt message * @return string User input */ function askQuestionPrompt($prompt) { if (preg_match('/^win/i', PHP_OS)) { $vbscript = sys_get_temp_dir() . 'prompt_input.vbs'; file_put_contents($vbscript, 'wscript.echo(InputBox("' . addslashes($prompt) . '", "", ""))'); $response = shell_exec("cscript //nologo " . escapeshellarg($vbscript)); unlink($vbscript); return trim($response); } else { echo $prompt; $handle = fopen("php://stdin", "r"); $response = trim(fgets($handle)); fclose($handle); return $response; } } /** * Function to send a generic request over a TCP connection * * @param string $serverIp The server's IP address * @param int $serverPort The server's port * @param array $payload The payload to send as an associative array * @return array The response received from the server as an associative array * @throws Exception On connection errors or JSON parsing errors */ function sendRequest($serverIp, $serverPort, $payload) { $jsonPayload = json_encode($payload); if ($jsonPayload === false) { throw new Exception("Error while coding the JSON payload: " . json_last_error_msg()); } $errno = 0; $errstr = ''; $timeoutDuration = 10; // Seconds $client = @fsockopen($serverIp, $serverPort, $errno, $errstr, $timeoutDuration); if (!$client) { throw new Exception("Connection error: $errstr ($errno)"); } echo "🔗 Connected to the server ({$serverIp}:{$serverPort}).\n"; echo "📤 Sending payload: $jsonPayload\n"; fwrite($client, $jsonPayload); $responseData = ''; stream_set_timeout($client, $timeoutDuration); while (!feof($client)) { $data = fread($client, 1024); if ($data === false) { throw new Exception("Error reading data from the server."); } if ($data === '') { break; // No more data } echo "📥 Received data: $data\n"; $responseData .= $data; $parsedData = json_decode($responseData, true); if ($parsedData !== null) { echo "✅ JSON response successfully parsed.\n"; fclose($client); return $parsedData; } $info = stream_get_meta_data($client); if ($info['timed_out']) { throw new Exception("Timeout waiting for data from the server."); } } fclose($client); throw new Exception("Connection to the server was closed before a complete response was received."); } /** * Main function of the script */ function main($argv) { $parsedArgs = parseArguments($argv); $serverIp = $parsedArgs['serverIp'] ?? null; $serverPort = $parsedArgs['serverPort'] ?? null; $token = $parsedArgs['token'] ?? null; if (!$serverIp) { $serverIp = askQuestionPrompt('🔗 Please enter the server IP: '); } if (!$serverPort) { $portInput = askQuestionPrompt('🔗 Please enter the server port: '); $serverPort = intval($portInput); if ($serverPort <= 0) { fwrite(STDERR, "❌ ERROR: Invalid server port.\n"); exit(1); } } if (!$token) { $token = askQuestionPrompt('🔒 Please enter your authentication token: '); } if (!$serverIp || !$serverPort || !$token) { fwrite(STDERR, "❌ ERROR: Missing required parameters.\n"); fwrite(STDOUT, "Usage: php MCPListGroupsClient.php --server-ip <IP> --server-port <Port> --token <Token>\n"); exit(1); } $payload = [ "command" => "list_groups", "token" => $token ]; try { echo "📄 Retrieving groups...\n"; $response = sendRequest($serverIp, $serverPort, $payload); echo "✔️ Response:\n"; echo json_encode($response, JSON_PRETTY_PRINT) . "\n"; } catch (Exception $e) { fwrite(STDERR, "❌ ERROR: " . $e->getMessage() . "\n"); } } if (version_compare(PHP_VERSION, '7.1.0') < 0) { fwrite(STDERR, "❌ ERROR: This script requires PHP version 7.1 or higher.\n"); exit(1); } main($argv); ?> ```