This is page 11 of 20. Use http://codebase.md/fujitsu-ai/mcp-server-for-mas-developments?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .gitattributes
├── .gitignore
├── agents
│ ├── __init__.py
│ ├── AgentInterface
│ │ ├── __init__.py
│ │ ├── Python
│ │ │ ├── __init__.py
│ │ │ ├── agent.py
│ │ │ ├── color.py
│ │ │ ├── config.py
│ │ │ ├── language.py
│ │ │ ├── local_file_handler.py
│ │ │ └── network.py
│ │ └── requirements.txt
│ ├── AgentMonitoring
│ │ ├── ChatBot-Agent Dashboard Example - Grafana.json
│ │ ├── images
│ │ │ ├── Grafana.png
│ │ │ └── Prometheus.png
│ │ ├── IoT-Agent Dashboard Example - Grafana.json
│ │ ├── OpenAI compatible API - Agent Dashboard Example - Grafana.json
│ │ ├── prometheus Example.yml
│ │ └── README.md
│ ├── ChatBotAgent
│ │ ├── __init__.py
│ │ ├── config.json.example
│ │ ├── html
│ │ │ ├── favicon.ico
│ │ │ ├── index_de.html
│ │ │ ├── index.html
│ │ │ ├── Logo_light.svg
│ │ │ ├── start_http_server.ps1
│ │ │ └── start_http_server.sh
│ │ ├── Python
│ │ │ ├── __init__.py
│ │ │ └── chatbot_agent.py
│ │ ├── README.md
│ │ └── requirements.txt
│ ├── IoTAgent
│ │ ├── config_example.json
│ │ ├── Python
│ │ │ ├── iot_mqtt_agent.py
│ │ │ └── language.py
│ │ ├── README.md
│ │ └── requirements.txt
│ ├── ISMAgent
│ │ ├── config_example.json
│ │ ├── PGPT Scenario Prompts
│ │ │ ├── ISM System Prompt - Detecting Error State.txt
│ │ │ ├── ISM User Post-Prompt - Detecting Error State.txt
│ │ │ ├── ISM User Pre-Prompt - Detecting Error State.txt
│ │ │ └── README.md
│ │ ├── Python
│ │ │ ├── ism_agent.py
│ │ │ └── language.py
│ │ ├── README.md
│ │ ├── requirements.txt
│ │ └── start_ism_agent.ps1
│ ├── MCP-Client
│ │ ├── __init__.py
│ │ ├── .env.example
│ │ ├── Python
│ │ │ ├── __init__.py
│ │ │ ├── chat_handler.py
│ │ │ ├── config.py
│ │ │ ├── environment.py
│ │ │ ├── llm_client.py
│ │ │ ├── mcp_client_sse.py
│ │ │ ├── mcp_client.py
│ │ │ ├── messages
│ │ │ │ ├── __init__.py
│ │ │ │ ├── message_types
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── incrementing_id_message.py
│ │ │ │ │ ├── initialize_message.py
│ │ │ │ │ ├── json_rpc_message.py
│ │ │ │ │ ├── ping_message.py
│ │ │ │ │ ├── prompts_messages.py
│ │ │ │ │ ├── prompts_models.py
│ │ │ │ │ ├── resources_messages.py
│ │ │ │ │ └── tools_messages.py
│ │ │ │ ├── send_call_tool.py
│ │ │ │ ├── send_initialize_message.py
│ │ │ │ ├── send_message.py
│ │ │ │ ├── send_ping.py
│ │ │ │ ├── send_prompts.py
│ │ │ │ ├── send_resources.py
│ │ │ │ └── send_tools_list.py
│ │ │ ├── system_prompt_generator.py
│ │ │ ├── tools_handler.py
│ │ │ └── transport
│ │ │ ├── __init__.py
│ │ │ └── stdio
│ │ │ ├── __init__.py
│ │ │ ├── stdio_client.py
│ │ │ ├── stdio_server_parameters.py
│ │ │ └── stdio_server_shutdown.py
│ │ ├── README.md
│ │ ├── requirements.txt
│ │ └── server_config.json
│ ├── OpenAI_Compatible_API_Agent
│ │ ├── __init__.py
│ │ ├── docker-compose.yml
│ │ ├── Dockerfile
│ │ ├── pgpt_openai_api_mcp.json.example
│ │ ├── pgpt_openai_api_proxy.json.example
│ │ ├── Python
│ │ │ ├── __init__.py
│ │ │ ├── client_tests
│ │ │ │ ├── __init__.py
│ │ │ │ ├── openai_test_client_structured.py
│ │ │ │ ├── openai_test_client_tools.py
│ │ │ │ ├── openai_test_client.py
│ │ │ │ ├── vllm_client_multimodal.py
│ │ │ │ ├── vllm_client.py
│ │ │ │ ├── vllm_structured.py
│ │ │ │ └── vllm_structured2.py
│ │ │ ├── generate_api_key.py
│ │ │ ├── open_ai_helper.py
│ │ │ ├── openai_compatible_api.py
│ │ │ ├── openai_mcp_api.py
│ │ │ ├── pgpt_api.py
│ │ │ ├── privategpt_api.py
│ │ │ └── vllmproxy.py
│ │ ├── README.md
│ │ └── requirements.txt
│ └── SourceManagerAgent
│ ├── __init__.py
│ ├── config.json.example
│ └── Python
│ ├── __init__.py
│ ├── file_tools
│ │ └── loader_factory.py
│ ├── file_upload_agent.py
│ └── local_db.py
├── clients
│ ├── __init__.py
│ ├── C# .Net
│ │ ├── 1.0 mcp_login
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_login.deps.json
│ │ │ │ ├── mcp_login.dll
│ │ │ │ ├── mcp_login.exe
│ │ │ │ ├── mcp_login.pdb
│ │ │ │ ├── mcp_login.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_login.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_login.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_login.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_login.assets.cache
│ │ │ │ │ ├── mcp_login.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_login.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_login.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_login.csproj.Up2Date
│ │ │ │ │ ├── mcp_login.dll
│ │ │ │ │ ├── mcp_login.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_login.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_login.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_login.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_login.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_login.dll
│ │ │ │ ├── mcp_login.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_login.csproj.nuget.g.props
│ │ │ │ ├── mcp_login.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 1.1 mcp_logout
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_logout.deps.json
│ │ │ │ ├── mcp_logout.dll
│ │ │ │ ├── mcp_logout.exe
│ │ │ │ ├── mcp_logout.pdb
│ │ │ │ ├── mcp_logout.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_logout.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_logout.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_logout.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_logout.assets.cache
│ │ │ │ │ ├── mcp_logout.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_logout.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_logout.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_logout.csproj.Up2Date
│ │ │ │ │ ├── mcp_logout.dll
│ │ │ │ │ ├── mcp_logout.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_logout.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_logout.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_logout.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_logout.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_logout.dll
│ │ │ │ ├── mcp_logout.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_logout.csproj.nuget.g.props
│ │ │ │ ├── mcp_logout.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 2.0 mcp_chat
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_chat.deps.json
│ │ │ │ ├── mcp_chat.dll
│ │ │ │ ├── mcp_chat.exe
│ │ │ │ ├── mcp_chat.pdb
│ │ │ │ ├── mcp_chat.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_chat.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_chat.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_chat.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_chat.assets.cache
│ │ │ │ │ ├── mcp_chat.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_chat.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_chat.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_chat.csproj.Up2Date
│ │ │ │ │ ├── mcp_chat.dll
│ │ │ │ │ ├── mcp_chat.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_chat.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_chat.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_chat.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_chat.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_chat.dll
│ │ │ │ ├── mcp_chat.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_chat.csproj.nuget.g.props
│ │ │ │ ├── mcp_chat.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 2.1 mcp_continue_chat
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_continue_chat.deps.json
│ │ │ │ ├── mcp_continue_chat.dll
│ │ │ │ ├── mcp_continue_chat.exe
│ │ │ │ ├── mcp_continue_chat.pdb
│ │ │ │ ├── mcp_continue_chat.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_continue_chat.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_cont.EF178231.Up2Date
│ │ │ │ │ ├── mcp_continue_chat.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_continue_chat.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_continue_chat.assets.cache
│ │ │ │ │ ├── mcp_continue_chat.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_continue_chat.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_continue_chat.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_continue_chat.dll
│ │ │ │ │ ├── mcp_continue_chat.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_continue_chat.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_continue_chat.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_continue_chat.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_continue_chat.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_continue_chat.dll
│ │ │ │ ├── mcp_continue_chat.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_continue_chat.csproj.nuget.g.props
│ │ │ │ ├── mcp_continue_chat.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_get_chat_info.deps.json
│ │ │ │ ├── mcp_get_chat_info.dll
│ │ │ │ ├── mcp_get_chat_info.exe
│ │ │ │ ├── mcp_get_chat_info.pdb
│ │ │ │ ├── mcp_get_chat_info.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── Dokumente - Verknüpfung.lnk
│ │ │ ├── mcp_get_chat_info.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_get_.DFF47B4E.Up2Date
│ │ │ │ │ ├── mcp_get_chat_info.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_get_chat_info.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_get_chat_info.assets.cache
│ │ │ │ │ ├── mcp_get_chat_info.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_get_chat_info.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_get_chat_info.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_get_chat_info.dll
│ │ │ │ │ ├── mcp_get_chat_info.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_get_chat_info.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_get_chat_info.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_get_chat_info.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_get_chat_info.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_get_chat_info.dll
│ │ │ │ ├── mcp_get_chat_info.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_get_chat_info.csproj.nuget.g.props
│ │ │ │ ├── mcp_get_chat_info.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 3.0 mcp_create_source
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_create_source.deps.json
│ │ │ │ ├── mcp_create_source.dll
│ │ │ │ ├── mcp_create_source.exe
│ │ │ │ ├── mcp_create_source.pdb
│ │ │ │ ├── mcp_create_source.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_create_source.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_crea.CB4ED912.Up2Date
│ │ │ │ │ ├── mcp_create_source.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_create_source.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_create_source.assets.cache
│ │ │ │ │ ├── mcp_create_source.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_create_source.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_create_source.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_create_source.dll
│ │ │ │ │ ├── mcp_create_source.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_create_source.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_create_source.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_create_source.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_create_source.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_create_source.dll
│ │ │ │ ├── mcp_create_source.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_create_source.csproj.nuget.g.props
│ │ │ │ ├── mcp_create_source.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 3.1 mcp_get_source
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_get_source.deps.json
│ │ │ │ ├── mcp_get_source.dll
│ │ │ │ ├── mcp_get_source.exe
│ │ │ │ ├── mcp_get_source.pdb
│ │ │ │ ├── mcp_get_source.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_get_source.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_get_.4E61956F.Up2Date
│ │ │ │ │ ├── mcp_get_source.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_get_source.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_get_source.assets.cache
│ │ │ │ │ ├── mcp_get_source.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_get_source.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_get_source.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_get_source.dll
│ │ │ │ │ ├── mcp_get_source.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_get_source.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_get_source.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_get_source.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_get_source.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_get_source.dll
│ │ │ │ ├── mcp_get_source.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_get_source.csproj.nuget.g.props
│ │ │ │ ├── mcp_get_source.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 3.2 mcp_list_sources
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_list_sources.deps.json
│ │ │ │ ├── mcp_list_sources.dll
│ │ │ │ ├── mcp_list_sources.exe
│ │ │ │ ├── mcp_list_sources.pdb
│ │ │ │ ├── mcp_list_sources.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_list_sources.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_list_sources.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_list_sources.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_list_sources.assets.cache
│ │ │ │ │ ├── mcp_list_sources.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_list_sources.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_list_sources.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_list_sources.dll
│ │ │ │ │ ├── mcp_list_sources.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_list_sources.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_list_sources.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_list_sources.pdb
│ │ │ │ │ ├── mcp_list.A720E197.Up2Date
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_list_sources.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_list_sources.dll
│ │ │ │ ├── mcp_list_sources.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_list_sources.csproj.nuget.g.props
│ │ │ │ ├── mcp_list_sources.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 3.3 mcp_edit_source
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_edit_source.deps.json
│ │ │ │ ├── mcp_edit_source.dll
│ │ │ │ ├── mcp_edit_source.exe
│ │ │ │ ├── mcp_edit_source.pdb
│ │ │ │ ├── mcp_edit_source.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_edit_source.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_edit_source.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_edit_source.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_edit_source.assets.cache
│ │ │ │ │ ├── mcp_edit_source.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_edit_source.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_edit_source.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_edit_source.dll
│ │ │ │ │ ├── mcp_edit_source.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_edit_source.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_edit_source.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_edit_source.pdb
│ │ │ │ │ ├── mcp_edit.7303BE3B.Up2Date
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_edit_source.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_edit_source.dll
│ │ │ │ ├── mcp_edit_source.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_edit_source.csproj.nuget.g.props
│ │ │ │ ├── mcp_edit_source.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 3.4 mcp_delete_source
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_delete_source.deps.json
│ │ │ │ ├── mcp_delete_source.dll
│ │ │ │ ├── mcp_delete_source.exe
│ │ │ │ ├── mcp_delete_source.pdb
│ │ │ │ ├── mcp_delete_source.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_delete_source.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_dele.67DD13F9.Up2Date
│ │ │ │ │ ├── mcp_delete_source.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_delete_source.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_delete_source.assets.cache
│ │ │ │ │ ├── mcp_delete_source.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_delete_source.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_delete_source.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_delete_source.dll
│ │ │ │ │ ├── mcp_delete_source.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_delete_source.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_delete_source.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_delete_source.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_delete_source.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_delete_source.dll
│ │ │ │ ├── mcp_delete_source.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_delete_source.csproj.nuget.g.props
│ │ │ │ ├── mcp_delete_source.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 4.0 mcp_list_groups
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_list_groups.deps.json
│ │ │ │ ├── mcp_list_groups.dll
│ │ │ │ ├── mcp_list_groups.exe
│ │ │ │ ├── mcp_list_groups.pdb
│ │ │ │ ├── mcp_list_groups.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_list_groups.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_list_groups.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_list_groups.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_list_groups.assets.cache
│ │ │ │ │ ├── mcp_list_groups.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_list_groups.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_list_groups.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_list_groups.dll
│ │ │ │ │ ├── mcp_list_groups.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_list_groups.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_list_groups.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_list_groups.pdb
│ │ │ │ │ ├── mcp_list.EBD5E0D2.Up2Date
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_list_groups.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_list_groups.dll
│ │ │ │ ├── mcp_list_groups.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_list_groups.csproj.nuget.g.props
│ │ │ │ ├── mcp_list_groups.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 4.1 mcp_store_group
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_store_group.deps.json
│ │ │ │ ├── mcp_store_group.dll
│ │ │ │ ├── mcp_store_group.exe
│ │ │ │ ├── mcp_store_group.pdb
│ │ │ │ ├── mcp_store_group.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_store_group.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_stor.AFB4AA35.Up2Date
│ │ │ │ │ ├── mcp_store_group.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_store_group.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_store_group.assets.cache
│ │ │ │ │ ├── mcp_store_group.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_store_group.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_store_group.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_store_group.dll
│ │ │ │ │ ├── mcp_store_group.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_store_group.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_store_group.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_store_group.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_store_group.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_store_group.dll
│ │ │ │ ├── mcp_store_group.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_store_group.csproj.nuget.g.props
│ │ │ │ ├── mcp_store_group.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 4.2 mcp_delete_group
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_delete_group.deps.json
│ │ │ │ ├── mcp_delete_group.dll
│ │ │ │ ├── mcp_delete_group.exe
│ │ │ │ ├── mcp_delete_group.pdb
│ │ │ │ ├── mcp_delete_group.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_delete_group.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_dele.FE1C6298.Up2Date
│ │ │ │ │ ├── mcp_delete_group.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_delete_group.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_delete_group.assets.cache
│ │ │ │ │ ├── mcp_delete_group.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_delete_group.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_delete_group.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_delete_group.dll
│ │ │ │ │ ├── mcp_delete_group.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_delete_group.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_delete_group.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_delete_group.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_delete_group.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_delete_group.dll
│ │ │ │ ├── mcp_delete_group.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_delete_group.csproj.nuget.g.props
│ │ │ │ ├── mcp_delete_group.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 5.0 mcp_store_user
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_store_user.deps.json
│ │ │ │ ├── mcp_store_user.dll
│ │ │ │ ├── mcp_store_user.exe
│ │ │ │ ├── mcp_store_user.pdb
│ │ │ │ ├── mcp_store_user.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_store_user.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_stor.6C0F0C8A.Up2Date
│ │ │ │ │ ├── mcp_store_user.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_store_user.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_store_user.assets.cache
│ │ │ │ │ ├── mcp_store_user.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_store_user.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_store_user.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_store_user.dll
│ │ │ │ │ ├── mcp_store_user.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_store_user.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_store_user.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_store_user.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_store_user.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_store_user.dll
│ │ │ │ ├── mcp_store_user.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_store_user.csproj.nuget.g.props
│ │ │ │ ├── mcp_store_user.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 5.1 mcp_edit_user
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_edit_user.deps.json
│ │ │ │ ├── mcp_edit_user.dll
│ │ │ │ ├── mcp_edit_user.exe
│ │ │ │ ├── mcp_edit_user.pdb
│ │ │ │ ├── mcp_edit_user.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_edit_user.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_edit_user.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_edit_user.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_edit_user.assets.cache
│ │ │ │ │ ├── mcp_edit_user.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_edit_user.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_edit_user.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_edit_user.dll
│ │ │ │ │ ├── mcp_edit_user.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_edit_user.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_edit_user.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_edit_user.pdb
│ │ │ │ │ ├── mcp_edit.94A30270.Up2Date
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_edit_user.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_edit_user.dll
│ │ │ │ ├── mcp_edit_user.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_edit_user.csproj.nuget.g.props
│ │ │ │ ├── mcp_edit_user.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── 5.2 mcp_delete_user
│ │ │ ├── bin
│ │ │ │ └── Debug
│ │ │ │ └── net9.0
│ │ │ │ ├── mcp_delete_user.deps.json
│ │ │ │ ├── mcp_delete_user.dll
│ │ │ │ ├── mcp_delete_user.exe
│ │ │ │ ├── mcp_delete_user.pdb
│ │ │ │ ├── mcp_delete_user.runtimeconfig.json
│ │ │ │ └── Newtonsoft.Json.dll
│ │ │ ├── mcp_delete_user.csproj
│ │ │ ├── obj
│ │ │ │ ├── Debug
│ │ │ │ │ └── net9.0
│ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs
│ │ │ │ │ ├── apphost.exe
│ │ │ │ │ ├── mcp_dele.CEB7E33D.Up2Date
│ │ │ │ │ ├── mcp_delete_user.AssemblyInfo.cs
│ │ │ │ │ ├── mcp_delete_user.AssemblyInfoInputs.cache
│ │ │ │ │ ├── mcp_delete_user.assets.cache
│ │ │ │ │ ├── mcp_delete_user.csproj.AssemblyReference.cache
│ │ │ │ │ ├── mcp_delete_user.csproj.CoreCompileInputs.cache
│ │ │ │ │ ├── mcp_delete_user.csproj.FileListAbsolute.txt
│ │ │ │ │ ├── mcp_delete_user.dll
│ │ │ │ │ ├── mcp_delete_user.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ │ │ ├── mcp_delete_user.genruntimeconfig.cache
│ │ │ │ │ ├── mcp_delete_user.GlobalUsings.g.cs
│ │ │ │ │ ├── mcp_delete_user.pdb
│ │ │ │ │ ├── ref
│ │ │ │ │ │ └── mcp_delete_user.dll
│ │ │ │ │ └── refint
│ │ │ │ │ └── mcp_delete_user.dll
│ │ │ │ ├── mcp_delete_user.csproj.nuget.dgspec.json
│ │ │ │ ├── mcp_delete_user.csproj.nuget.g.props
│ │ │ │ ├── mcp_delete_user.csproj.nuget.g.targets
│ │ │ │ ├── project.assets.json
│ │ │ │ └── project.nuget.cache
│ │ │ └── Program.cs
│ │ ├── Code Archiv
│ │ │ ├── mcp_chat.cs
│ │ │ ├── mcp_continue_chat.cs
│ │ │ ├── mcp_create_source.cs
│ │ │ ├── mcp_delete_group.cs
│ │ │ ├── mcp_delete_source.cs
│ │ │ ├── mcp_delete_user.cs
│ │ │ ├── mcp_edit_source.cs
│ │ │ ├── mcp_edit_user.cs
│ │ │ ├── mcp_get_chat_info.cs
│ │ │ ├── mcp_get_source.cs
│ │ │ ├── mcp_list_groups.cs
│ │ │ ├── mcp_list_sources.cs
│ │ │ ├── mcp_login.cs
│ │ │ ├── mcp_logout.cs
│ │ │ ├── mcp_store_group.cs
│ │ │ └── mcp_store_user.cs
│ │ └── README.md
│ ├── C++
│ │ ├── .vscode
│ │ │ └── launch.json
│ │ ├── 1.0 mcp_login
│ │ │ ├── MCPLoginClient.cpp
│ │ │ └── Non-TLS version
│ │ │ ├── MCPLoginClient.cpp
│ │ │ └── MCPLoginClient.exe
│ │ ├── 1.1 mcp_logout
│ │ │ ├── MCPLogoutClient.cpp
│ │ │ └── MCPLogoutClient.exe
│ │ ├── 2.0 mcp_chat
│ │ │ ├── MCPChatClient.cpp
│ │ │ └── MCPChatClient.exe
│ │ ├── 2.1 mcp_continue_chat
│ │ │ ├── MCPChatContinuationClient.cpp
│ │ │ └── MCPChatContinuationClient.exe
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ ├── MCPGetChatInfoClient.cpp
│ │ │ └── MCPGetChatInfoClient.exe
│ │ ├── 3.0 mcp_create_source
│ │ │ ├── MCPCreateSourceClient.cpp
│ │ │ └── MCPCreateSourceClient.exe
│ │ ├── 3.1 mcp_get_source
│ │ │ ├── MCPGetSourceClient.cpp
│ │ │ └── MCPGetSourceClient.exe
│ │ ├── 3.2 mcp_list_sources
│ │ │ ├── MCPListSourcesClient.cpp
│ │ │ └── MCPListSourcesClient.exe
│ │ ├── 3.3 mcp_edit_source
│ │ │ ├── MCPEditSourceClient.cpp
│ │ │ └── MCPEditSourceClient.exe
│ │ ├── 3.4 mcp_delete_source
│ │ │ ├── MCPDeleteSourceClient.cpp
│ │ │ └── MCPDeleteSourceClient.exe
│ │ ├── 4.0 mcp_list_groups
│ │ │ ├── MCPListGroupsClient.cpp
│ │ │ └── MCPListGroupsClient.exe
│ │ ├── 4.1 mcp_store_group
│ │ │ ├── MCPStoreGroupClient.cpp
│ │ │ └── MCPStoreGroupClient.exe
│ │ ├── 4.2 mcp_delete_group
│ │ │ ├── MPCDeleteGroupClient.cpp
│ │ │ └── MPCDeleteGroupClient.exe
│ │ ├── 5.0 mcp_store_user
│ │ │ ├── MCPStoreUserClient.cpp
│ │ │ └── MCPStoreUserClient.exe
│ │ ├── 5.1 mcp_edit_user
│ │ │ ├── MCPEditUserClient.cpp
│ │ │ └── MCPEditUserClient.exe
│ │ ├── 5.2 mcp_delete_user
│ │ │ ├── MCPDeleteUserClient.cpp
│ │ │ └── MCPDeleteUserClient.exe
│ │ ├── 9.0 mcp_keygen
│ │ │ ├── MCPKeygenClient.cpp
│ │ │ └── MCPKeygenClient.exe
│ │ └── README.md
│ ├── Go
│ │ ├── 1.0 mcp_login
│ │ │ ├── go.mod
│ │ │ ├── MCPLoginClient.exe
│ │ │ └── MCPLoginClient.go
│ │ ├── 1.1 mcp_logout
│ │ │ ├── MCPLogoutClient.exe
│ │ │ └── MCPLogoutClient.go
│ │ ├── 2.0 mcp_chat
│ │ │ ├── MCPChatClient.exe
│ │ │ └── MCPChatClient.go
│ │ ├── 2.1 mcp_continue_chat
│ │ │ ├── MCPChatContinuationClient.exe
│ │ │ └── MCPChatContinuationClient.go
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ ├── MCPGetChatInfoClient.exe
│ │ │ └── MCPGetChatInfoClient.go
│ │ ├── 3.0 mcp_create_source
│ │ │ ├── MCPCreateSourceClient.exe
│ │ │ └── MCPCreateSourceClient.go
│ │ ├── 3.1 mcp_get_source
│ │ │ ├── MCPGetSourceClient.exe
│ │ │ └── MCPGetSourceClient.go
│ │ ├── 3.2 mcp_list_sources
│ │ │ ├── MCPListSourcesClient.exe
│ │ │ └── MCPListSourcesClient.go
│ │ ├── 3.3 mcp_edit_source
│ │ │ ├── MCPEditSourceClient.exe
│ │ │ └── MCPEditSourceClient.go
│ │ ├── 3.4 mcp_delete_source
│ │ │ ├── MCPDeleteSourceClient.exe
│ │ │ └── MCPDeleteSourceClient.go
│ │ ├── 4.0 mcp_list_groups
│ │ │ ├── MCPListGroupsClient.exe
│ │ │ └── MCPListGroupsClient.go
│ │ ├── 4.1 mcp_store_group
│ │ │ ├── MCPStoreGroupClient.exe
│ │ │ └── MCPStoreGroupClient.go
│ │ ├── 4.2 mcp_delete_group
│ │ │ ├── MCPDeleteGroupClient.exe
│ │ │ └── MCPDeleteGroupClient.go
│ │ ├── 5.0 mcp_store_user
│ │ │ ├── MCPStoreUserClient.exe
│ │ │ └── MCPStoreUserClient.go
│ │ ├── 5.1 mcp_edit_user
│ │ │ ├── MCPEditUserClient.exe
│ │ │ └── MCPEditUserClient.go
│ │ ├── 5.2 mcp_delete_user
│ │ │ ├── MCPDeleteUserClient.exe
│ │ │ └── MCPDeleteUserClient.go
│ │ ├── 9.0 mcp_keygen
│ │ │ ├── MCPKeygenClient.exe
│ │ │ └── MCPKeygenClient.go
│ │ └── README.md
│ ├── Gradio
│ │ ├── Api.py
│ │ ├── config.json.example
│ │ ├── config.py
│ │ ├── favicon.ico
│ │ ├── file_tools
│ │ │ └── loader_factory.py
│ │ ├── language.py
│ │ ├── logos
│ │ │ ├── fsas.png
│ │ │ └── Logo_dark.svg
│ │ ├── main.py
│ │ ├── mcp_client.py
│ │ ├── mcp_servers
│ │ │ ├── arxiv
│ │ │ │ ├── arxiv-stdio.js
│ │ │ │ ├── package.json
│ │ │ │ ├── README.md
│ │ │ │ ├── requirements.txt
│ │ │ │ └── server_config.example.json
│ │ │ ├── demo-mcp-server
│ │ │ │ ├── demo-tools-sse.js
│ │ │ │ ├── demo-tools-stdio.js
│ │ │ │ └── tools
│ │ │ │ ├── assets.js
│ │ │ │ ├── calculator.js
│ │ │ │ └── weather.js
│ │ │ ├── filesystem
│ │ │ │ ├── Dockerfile
│ │ │ │ ├── index.ts
│ │ │ │ ├── package.json
│ │ │ │ ├── README.md
│ │ │ │ ├── test
│ │ │ │ │ └── new.txt
│ │ │ │ └── tsconfig.json
│ │ │ ├── moondream
│ │ │ │ └── server.py
│ │ │ ├── pgpt
│ │ │ │ ├── __init__.py
│ │ │ │ ├── Api.py
│ │ │ │ ├── config.json.example
│ │ │ │ ├── config.py
│ │ │ │ ├── language.py
│ │ │ │ ├── pyproject.toml
│ │ │ │ ├── README.md
│ │ │ │ └── server.py
│ │ │ ├── replicate_flux
│ │ │ │ └── server.py
│ │ │ └── sqlite
│ │ │ ├── .python-version
│ │ │ ├── Dockerfile
│ │ │ ├── pyproject.toml
│ │ │ ├── README.md
│ │ │ └── src
│ │ │ └── mcp_server_sqlite
│ │ │ ├── __init__.py
│ │ │ └── server.py
│ │ ├── messages
│ │ │ ├── __init__.py
│ │ │ ├── message_types
│ │ │ │ ├── __init__.py
│ │ │ │ ├── incrementing_id_message.py
│ │ │ │ ├── initialize_message.py
│ │ │ │ ├── json_rpc_message.py
│ │ │ │ ├── ping_message.py
│ │ │ │ ├── prompts_messages.py
│ │ │ │ ├── prompts_models.py
│ │ │ │ ├── resources_messages.py
│ │ │ │ └── tools_messages.py
│ │ │ ├── send_call_tool.py
│ │ │ ├── send_initialize_message.py
│ │ │ ├── send_message.py
│ │ │ ├── send_ping.py
│ │ │ ├── send_prompts.py
│ │ │ ├── send_resources.py
│ │ │ └── send_tools_list.py
│ │ ├── README.md
│ │ ├── requirements.txt
│ │ ├── server_config.json
│ │ ├── SourceManagement.py
│ │ ├── transport
│ │ │ ├── __init__.py
│ │ │ └── stdio
│ │ │ ├── __init__.py
│ │ │ ├── stdio_client.py
│ │ │ ├── stdio_server_parameters.py
│ │ │ └── stdio_server_shutdown.py
│ │ ├── tsconfig.json
│ │ └── UserManagement.py
│ ├── Java
│ │ ├── 1.0 mcp_login
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPLoginClient.class
│ │ │ └── MCPLoginClient.java
│ │ ├── 1.1 mcp_logout
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPLogoutClient.class
│ │ │ └── MCPLogoutClient.java
│ │ ├── 2.0 mcp_chat
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPChatClient.class
│ │ │ └── MCPChatClient.java
│ │ ├── 2.1 mcp_continue_chat
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPContinueChatClient.class
│ │ │ └── MCPContinueChatClient.java
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPGetChatInfoClient.class
│ │ │ └── MCPGetChatInfoClient.java
│ │ ├── 3.0 mcp_create_source
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPCreateSourceClient.class
│ │ │ └── MCPCreateSourceClient.java
│ │ ├── 3.1 mcp_get_source
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPGetSourceClient.class
│ │ │ └── MCPGetSourceClient.java
│ │ ├── 3.2 mcp_list_sources
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPListSourcesClient.class
│ │ │ └── MCPListSourcesClient.java
│ │ ├── 3.3 mcp_edit_source
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPEditSourceClient.class
│ │ │ └── MCPEditSourceClient.java
│ │ ├── 3.4 mcp_delete_source
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPDeleteSourceClient.class
│ │ │ └── MCPDeleteSourceClient.java
│ │ ├── 4.0 mcp_list_groups
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPListGroupsClient.class
│ │ │ └── MCPListGroupsClient.java
│ │ ├── 4.1 mcp_store_group
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPStoreGroupClient.class
│ │ │ └── MCPStoreGroupClient.java
│ │ ├── 4.2 mcp_delete_group
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPDeleteGroupClient.class
│ │ │ └── MCPDeleteGroupClient.java
│ │ ├── 5.0 mcp_store_user
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPStoreUserClient.class
│ │ │ └── MCPStoreUserClient.java
│ │ ├── 5.1 mcp_edit_user
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPEditUserClient.class
│ │ │ └── MCPEditUserClient.java
│ │ ├── 5.2 mcp_delete_user
│ │ │ ├── json-20241224.jar
│ │ │ ├── MCPDeleteUserClient.class
│ │ │ └── MCPDeleteUserClient.java
│ │ └── README.md
│ ├── JavaScript
│ │ ├── 1.0 mcp_login
│ │ │ └── MCPLoginClient.js
│ │ ├── 1.1 mcp_logout
│ │ │ └── MCPLogoutClient.js
│ │ ├── 2.0 mcp_chat
│ │ │ └── MCPChatClient.js
│ │ ├── 2.1 mcp_continue_chat
│ │ │ └── MCPContinueChatClient.js
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ └── MCPGetChatInfoClient.js
│ │ ├── 3.0 mcp_create_source
│ │ │ └── MCPCreateSourceClient.js
│ │ ├── 3.1 mcp_get_source
│ │ │ └── MCPGetSourceClient.js
│ │ ├── 3.2 mcp_list_sources
│ │ │ └── MCPListSourcesClient.js
│ │ ├── 3.3 mcp_edit_source
│ │ │ └── MCPEditSourceClient.js
│ │ ├── 3.4 mcp_delete_source
│ │ │ └── MCPDeleteSourceClient.js
│ │ ├── 4.0 mcp_list_groups
│ │ │ └── MCPListGroupsClient.js
│ │ ├── 4.1 mcp_store_group
│ │ │ └── MCPStoreGroupClient.js
│ │ ├── 4.2 mcp_delete_group
│ │ │ └── MCPDeleteGroupClient.js
│ │ ├── 5.0 mcp_store_user
│ │ │ └── MCPStoreUserClient.js
│ │ ├── 5.1 mcp_edit_user
│ │ │ └── MCPEditUserClient.js
│ │ ├── 5.2 mcp_delete_user
│ │ │ └── MCPDeleteUserClient.js
│ │ ├── 9.0 mcp_keygen
│ │ │ └── MCPKeygenClient.js
│ │ └── README.md
│ ├── PHP
│ │ ├── 1.0 mcp_login
│ │ │ └── MCPLoginClient.php
│ │ ├── 1.1 mcp_logout
│ │ │ └── MCPLogoutClient.php
│ │ ├── 2.0 mcp_chat
│ │ │ └── MCPChatClient.php
│ │ ├── 2.1 mcp_continue_chat
│ │ │ └── MCPContinueChatClient.php
│ │ ├── 2.2 mcp_get_chat_info
│ │ │ └── MCPGetChatInfoClient.php
│ │ ├── 3.0 mcp_create_source
│ │ │ └── MCPCreateSourceClient.php
│ │ ├── 3.1 mcp_get_source
│ │ │ └── MCPGetSourceClient.php
│ │ ├── 3.2 mcp_list_sources
│ │ │ └── MCPListSourcesClient.php
│ │ ├── 3.3 mcp_edit_source
│ │ │ └── MCPEditSourceClient.php
│ │ ├── 3.4 mcp_delete_source
│ │ │ └── MCPDeleteSourceClient.php
│ │ ├── 4.0 mcp_list_groups
│ │ │ └── MCPListGroupsClient.php
│ │ ├── 4.1 mcp_store_group
│ │ │ └── MCPStoreGroupClient.php
│ │ ├── 4.2 mcp_delete_group
│ │ │ └── MCPDeleteGroupClient.php
│ │ ├── 5.0 mcp_store_user
│ │ │ └── MCPStoreUserClient.php
│ │ ├── 5.1 mcp_edit_user
│ │ │ └── MCPEditUserClient.php
│ │ ├── 5.2 mcp_delete_user
│ │ │ └── MCPDeleteUserClient.php
│ │ ├── 9.0 mcp_keygen
│ │ │ └── MCPKeygenClient.php
│ │ └── README.md
│ └── Python
│ ├── __init__.py
│ ├── 1.0 mcp_login
│ │ └── MCPLoginClient.py
│ ├── 1.1 mcp_logout
│ │ └── MCPLogoutClient.py
│ ├── 2.0 mcp_chat
│ │ └── MCPChatClient.py
│ ├── 2.1 mcp_continue_chat
│ │ └── MCPContinueChatClient.py
│ ├── 2.2 mcp_get_chat_info
│ │ └── MCPGetChatInfoClient.py
│ ├── 2.3 mcp_delete_all_chats
│ │ └── MCPDeleteAllChatsClient.py
│ ├── 2.4 mcp_delete_chat
│ │ └── MCPDeleteChatClient.py
│ ├── 3.0 mcp_create_source
│ │ └── MCPCreateSourceClient.py
│ ├── 3.1 mcp_get_source
│ │ └── MCPGetSourceClient.py
│ ├── 3.2 mcp_list_sources
│ │ └── MCPListSourcesClient.py
│ ├── 3.3 mcp_edit_source
│ │ └── MCPEditSourceClient.py
│ ├── 3.4 mcp_delete_source
│ │ └── MCPDeleteSourceClient.py
│ ├── 4.0 mcp_list_groups
│ │ └── MCPListGroupsClient.py
│ ├── 4.1 mcp_store_group
│ │ └── MCPStoreGroupClient.py
│ ├── 4.2 mcp_delete_group
│ │ └── MCPDeleteGroupClient.py
│ ├── 5.0 mcp_store_user
│ │ └── MCPStoreUserClient.py
│ ├── 5.1 mcp_edit_user
│ │ └── MCPEditUserClient.py
│ ├── 5.2 mcp_delete_user
│ │ └── MCPDeleteUserClient.py
│ ├── 9.0 mcp_keygen
│ │ └── MCPKeygenClient.py
│ ├── Gradio
│ │ ├── __init__.py
│ │ └── server_config.json
│ └── README.md
├── examples
│ ├── create_users_from_csv
│ │ ├── config.json.example
│ │ ├── config.py
│ │ ├── create_users_from_csv.py
│ │ └── language.py
│ ├── dynamic_sources
│ │ └── rss_reader
│ │ ├── Api.py
│ │ ├── config.json.example
│ │ ├── config.py
│ │ ├── demo_dynamic_sources.py
│ │ └── rss_parser.py
│ ├── example_users_to_add_no_tz.csv
│ └── sftp_upload_with_id
│ ├── Api.py
│ ├── config_ftp.json.example
│ ├── config.py
│ ├── demo_upload.py
│ ├── language.py
│ └── requirements.txt
├── images
│ ├── alternative mcp client.png
│ ├── favicon
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ └── site.webmanifest
│ ├── mcp-general-architecture.png
│ ├── privateGPT-MCP.png
│ └── privateGPT.png
├── InstallMPCServer.sh
├── jest.config.js
├── LICENSE
├── package.json
├── pgpt.env.json.example
├── README.md
├── security
│ ├── generate_decrypted_password.js
│ └── generate_encrypted_password.js
├── src
│ ├── helper.js
│ ├── index.js
│ ├── logger.js
│ ├── pgpt-messages.js
│ ├── public
│ │ ├── index.html
│ │ └── pgpt-mcp-logo.png
│ ├── services
│ │ └── pgpt-service.ts
│ └── types
│ └── api.ts
├── start_chatbot_agent.ps1
├── start_chatbot_agent.sh
├── start_iot_agent.ps1
├── start_iot_agent.sh
├── start_openai_compatible_api_agent.ps1
├── start_openai_compatible_api_agent.sh
├── tsconfig.json
├── ver
│ ├── index_np.js
│ └── index_proxy_np.js
└── WORKLOG.md
```
# Files
--------------------------------------------------------------------------------
/WORKLOG.md:
--------------------------------------------------------------------------------
```markdown
1 | # PrivateGPT MCP Server Development Log
2 |
3 | ## ⚠️ Warning: User Management Implementation
4 |
5 | **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.
6 |
7 | The following user management endpoints require careful implementation:
8 |
9 | ### Create User (POST /api/v1/users)
10 | Required functionality:
11 | - Create new user with name, email, and password
12 | - Set optional language and timezone
13 | - Configure public access and group assignments
14 | - Assign user roles
15 | - Set up FTP access if needed
16 | - Handle all required fields:
17 | ```json
18 | {
19 | "name": "User Name",
20 | "email": "[email protected]",
21 | "password": "UserPassword123",
22 | "language": "en",
23 | "timezone": "UTC",
24 | "usePublic": true,
25 | "groups": ["Group A"],
26 | "roles": ["Sources"],
27 | "activateFtp": true,
28 | "ftpPassword": "FTPPassword!"
29 | }
30 | ```
31 |
32 | ### Edit User (PATCH /api/v1/users)
33 | Required functionality:
34 | - Update user details by email
35 | - Modify name, language, and group assignments
36 | - Handle partial updates
37 | - Fields that can be updated:
38 | ```json
39 | {
40 | "email": "[email protected]",
41 | "name": "Updated Name",
42 | "language": "en",
43 | "groups": ["Updated Group"]
44 | }
45 | ```
46 |
47 | ### Delete User (DELETE /api/v1/users)
48 | ⚠️ **Critical Operation**
49 | Required functionality:
50 | - Remove user by email
51 | - Clean up associated data
52 | - Handle dependencies:
53 | ```json
54 | {
55 | "email": "[email protected]"
56 | }
57 | ```
58 |
59 | ## Implementation Status
60 |
61 | ### Core Server Structure
62 | - ✅ Basic MCP server setup with stdio transport
63 | - ✅ Error handling and graceful shutdown
64 | - ✅ Type-safe request handling
65 | - ✅ Input validation for all tools
66 |
67 | ### API Integration
68 | - ✅ Authentication with Bearer tokens
69 | - ✅ Automatic token refresh
70 | - ✅ Error mapping to MCP error codes
71 | - ✅ JSON response formatting
72 |
73 | ### Tools Implementation
74 | 1. Chat Tool
75 | - ✅ Chat creation with knowledge base selection
76 | - ✅ Support for public and document knowledge bases
77 | - ✅ Group-based access control
78 | - ✅ Language support
79 | - ✅ Chat continuation support
80 |
81 | 2. Source Management
82 | - ✅ Source creation with markdown formatting
83 | - ✅ Group assignment for private sources
84 | - ✅ Source listing by group
85 | - ✅ Source details retrieval
86 | - ✅ Source deletion
87 | - ✅ Source editing
88 |
89 | 3. Group Management
90 | - ✅ List personal and assignable groups
91 | - ✅ Group-based visibility control
92 | - ✅ Personal group handling
93 | - ✅ Group creation
94 | - ✅ Group deletion
95 |
96 | ## API Behavior Notes
97 |
98 | ### Authentication
99 | - Uses Bearer token authentication via `/api/v1/login`
100 | - Token required for all authenticated endpoints
101 | - Token invalidation via `/api/v1/logout`
102 |
103 | ### Group Management
104 | - GET `/api/v1/groups` returns personalGroups and assignableGroups arrays
105 | - Personal group appears in both arrays
106 | - Groups control access to sources and knowledge base
107 | - Full CRUD operations implemented and tested
108 |
109 | ### Source Management
110 | - Sources can be public or private
111 | - Private sources require group assignment
112 | - Sources are vectorized asynchronously
113 | - Source states: creation → vectorized
114 | - Source operations:
115 | - POST `/api/v1/sources` for creation
116 | - DELETE `/api/v1/sources/{sourceId}` for removal
117 | - PATCH `/api/v1/sources/{sourceId}` for editing
118 | - Can list sources by group
119 | - Can verify source state and visibility
120 | - All operations tested and verified
121 |
122 | ### Chat System
123 | - Two knowledge base types:
124 | - Public (usePublic: true)
125 | - Document (specific groups)
126 | - Chat operations:
127 | - Initial creation: POST `/api/v1/chats`
128 | - Continuation: PATCH `/api/v1/chats/{chatId}`
129 | - Details: GET `/api/v1/chats/{chatId}`
130 | - Chat features:
131 | - Preserves complete message history
132 | - Context-aware responses
133 | - Group-based access control
134 | - Language support
135 |
136 | ## Implementation Details
137 |
138 | ### Type Safety
139 | - Comprehensive TypeScript interfaces for all API interactions
140 | - Runtime validation for all tool inputs
141 | - Error type mapping between API and MCP
142 |
143 | ### Error Handling
144 | - API errors mapped to appropriate MCP error codes
145 | - Detailed error messages preserved
146 | - Authentication errors handled gracefully
147 |
148 | ### Resource Management
149 | - No direct resource exposure currently
150 | - All data access through tools
151 | - Future potential for direct resource access
152 |
153 | ## Future Improvements
154 | 1. Performance Optimizations:
155 | - Add caching layer
156 | - Optimize API requests
157 | - Improve response times
158 |
159 | 2. Monitoring and Observability:
160 | - Add comprehensive logging
161 | - Add metrics collection
162 | - Add performance tracking
163 |
164 | 3. Documentation:
165 | - Add API reference documentation
166 | - Add deployment guides
167 | - Add troubleshooting guides
168 |
169 | 4. Security Enhancements:
170 | - Add rate limiting
171 | - Implement request validation
172 | - Add security headers
173 | - Enhance token management
174 | - Add user session management
175 |
176 | ## Testing Notes
177 | - ✅ All major API endpoints tested
178 | - ✅ Group-based access control verified
179 | - ✅ Chat system behavior documented
180 | - ✅ Source visibility rules confirmed
181 | - ✅ Error handling validated
182 | - ✅ Source CRUD operations verified
183 | - ✅ Group CRUD operations verified
184 | - ✅ User management API functionality tested
185 |
```
--------------------------------------------------------------------------------
/clients/C++/1.0 mcp_login/MCPLoginClient.cpp:
--------------------------------------------------------------------------------
```cpp
1 | #include <iostream>
2 | #include <string>
3 | #include <map>
4 | #include <cstring>
5 | #include <cstdlib>
6 | #include <sstream>
7 | #include <stdexcept>
8 | #include <json/json.h>
9 | #include <openssl/ssl.h>
10 | #include <openssl/err.h>
11 |
12 | #ifdef _WIN32
13 | #include <winsock2.h>
14 | #include <ws2tcpip.h>
15 | #pragma comment(lib, "ws2_32.lib")
16 | #pragma comment(lib, "libssl.lib")
17 | #pragma comment(lib, "libcrypto.lib")
18 | #else
19 | #include <sys/socket.h>
20 | #include <arpa/inet.h>
21 | #include <unistd.h>
22 | #endif
23 |
24 | // Function to parse command-line arguments
25 | std::map<std::string, std::string> parseArguments(int argc, char* argv[]) {
26 | std::map<std::string, std::string> args;
27 | for (int i = 1; i < argc; i++) {
28 | std::string key = argv[i];
29 | if (i + 1 < argc) {
30 | args[key] = argv[++i];
31 | }
32 | }
33 | return args;
34 | }
35 |
36 | void init_openssl() {
37 | SSL_load_error_strings();
38 | OpenSSL_add_ssl_algorithms();
39 | }
40 |
41 | void cleanup_openssl() {
42 | EVP_cleanup();
43 | }
44 |
45 | SSL_CTX* create_context() {
46 | const SSL_METHOD* method;
47 | SSL_CTX* ctx;
48 |
49 | method = TLS_client_method();
50 | ctx = SSL_CTX_new(method);
51 | if (!ctx) {
52 | perror("Unable to create SSL context");
53 | ERR_print_errors_fp(stderr);
54 | exit(EXIT_FAILURE);
55 | }
56 |
57 | return ctx;
58 | }
59 |
60 | std::string sendRequest(const std::string& serverIp, int serverPort, const Json::Value& payload) {
61 | init_openssl();
62 | SSL_CTX* ctx = create_context();
63 |
64 | #ifdef _WIN32
65 | WSADATA wsaData;
66 | WSAStartup(MAKEWORD(2,2), &wsaData);
67 | #endif
68 |
69 | int sock = socket(AF_INET, SOCK_STREAM, 0);
70 | if (sock < 0) {
71 | SSL_CTX_free(ctx);
72 | #ifdef _WIN32
73 | WSACleanup();
74 | #endif
75 | throw std::runtime_error("Failed to create socket");
76 | }
77 |
78 | struct sockaddr_in serverAddr;
79 | serverAddr.sin_family = AF_INET;
80 | serverAddr.sin_port = htons(serverPort);
81 | if (inet_pton(AF_INET, serverIp.c_str(), &serverAddr.sin_addr) <= 0) {
82 | #ifdef _WIN32
83 | closesocket(sock);
84 | WSACleanup();
85 | #else
86 | close(sock);
87 | #endif
88 | SSL_CTX_free(ctx);
89 | throw std::runtime_error("Invalid server IP address");
90 | }
91 |
92 | if (connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
93 | #ifdef _WIN32
94 | closesocket(sock);
95 | WSACleanup();
96 | #else
97 | close(sock);
98 | #endif
99 | SSL_CTX_free(ctx);
100 | throw std::runtime_error("Connection failed");
101 | }
102 |
103 | SSL* ssl = SSL_new(ctx);
104 | SSL_set_fd(ssl, sock);
105 | if (SSL_connect(ssl) <= 0) {
106 | ERR_print_errors_fp(stderr);
107 | #ifdef _WIN32
108 | closesocket(sock);
109 | WSACleanup();
110 | #else
111 | close(sock);
112 | #endif
113 | SSL_free(ssl);
114 | SSL_CTX_free(ctx);
115 | throw std::runtime_error("Failed to create SSL connection");
116 | }
117 |
118 | // Serialize the JSON payload to a string
119 | Json::StreamWriterBuilder writer;
120 | std::string payloadJson = Json::writeString(writer, payload);
121 |
122 | // Send the payload
123 | if (SSL_write(ssl, payloadJson.c_str(), payloadJson.size()) <= 0) {
124 | #ifdef _WIN32
125 | closesocket(sock);
126 | WSACleanup();
127 | #else
128 | close(sock);
129 | #endif
130 | SSL_free(ssl);
131 | SSL_CTX_free(ctx);
132 | throw std::runtime_error("Failed to send data");
133 | }
134 |
135 | // Receive the response
136 | char buffer[4096];
137 | int bytesRead = SSL_read(ssl, buffer, sizeof(buffer) - 1);
138 | if (bytesRead < 0) {
139 | #ifdef _WIN32
140 | closesocket(sock);
141 | WSACleanup();
142 | #else
143 | close(sock);
144 | #endif
145 | SSL_free(ssl);
146 | SSL_CTX_free(ctx);
147 | throw std::runtime_error("Failed to receive data");
148 | }
149 |
150 | buffer[bytesRead] = '\0'; // Null-terminate the received data
151 |
152 | SSL_free(ssl);
153 | #ifdef _WIN32
154 | closesocket(sock);
155 | WSACleanup();
156 | #else
157 | close(sock);
158 | #endif
159 | SSL_CTX_free(ctx);
160 | cleanup_openssl();
161 |
162 | return std::string(buffer);
163 | }
164 |
165 | int main(int argc, char* argv[]) {
166 | try {
167 | auto args = parseArguments(argc, argv);
168 |
169 | // Extract required parameters
170 | std::string serverIp = args["--server-ip"];
171 | int serverPort = std::stoi(args["--server-port"]);
172 | std::string email = args["--email"];
173 | std::string password = args["--password"];
174 |
175 | if (serverIp.empty() || serverPort == 0 || email.empty() || password.empty()) {
176 | std::cerr << "❌ ERROR: Missing required parameters.\n";
177 | return 1;
178 | }
179 |
180 | std::cout << "🔐 Logging in...\n";
181 |
182 | // Build the payload
183 | Json::Value payload;
184 | payload["command"] = "login";
185 | payload["arguments"]["email"] = email;
186 | payload["arguments"]["password"] = password;
187 |
188 | // Send request and get response
189 | std::string responseJson = sendRequest(serverIp, serverPort, payload);
190 |
191 | // Parse and print the server response
192 | Json::CharReaderBuilder reader;
193 | Json::Value response;
194 | std::istringstream responseStream(responseJson);
195 | std::string errs;
196 |
197 | if (!Json::parseFromStream(reader, responseStream, &response, &errs)) {
198 | throw std::runtime_error("Failed to parse server response: " + errs);
199 | }
200 |
201 | std::cout << "✅ Server Response:\n" << response.toStyledString();
202 | } catch (const std::exception& e) {
203 | std::cerr << "❌ ERROR: " << e.what() << '\n';
204 | return 1;
205 | }
206 |
207 | return 0;
208 | }
209 |
```
--------------------------------------------------------------------------------
/src/logger.js:
--------------------------------------------------------------------------------
```javascript
1 | // logger.js
2 | import winston from 'winston';
3 | import chalk from 'chalk';
4 | import stripAnsi from 'strip-ansi';
5 | import fs from 'fs';
6 | import path from 'path';
7 | import { fileURLToPath } from 'url';
8 |
9 | // ESM-Äquivalent von __dirname
10 | const __filename = fileURLToPath(import.meta.url);
11 | const __dirname = path.dirname(__filename);
12 |
13 | // Bestimmen Sie den Pfad zur Log-Datei relativ zu `logger.js`
14 | const LOG_FILE_PATH = path.join(__dirname, '../logs/server.log'); // Passen Sie den Pfad nach Bedarf an
15 |
16 | // Hilfsfunktionen für Symbole und Farben
17 | function getLevelSymbol(level) {
18 | const symbols = {
19 | info: 'ℹ️',
20 | warn: '⚠️',
21 | error: '❌',
22 | debug: '🐞',
23 | };
24 | return symbols[level] || '';
25 | }
26 |
27 | function chalkForLevel(level) {
28 | const levels = {
29 | info: chalk.blue,
30 | warn: chalk.yellow,
31 | error: chalk.red,
32 | debug: chalk.green,
33 | };
34 | return levels[level] || chalk.white;
35 | }
36 |
37 | // Variable zur Steuerung der Dateiausgabe
38 | let allowWrittenLogfile = false;
39 |
40 | // Initialisieren der Transports mit nur der Konsolenausgabe
41 | const transports = [
42 | new winston.transports.Console({
43 | format: winston.format.combine(
44 | winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
45 | winston.format.printf(({ timestamp, level, message }) => {
46 | const symbol = getLevelSymbol(level);
47 | const coloredMessage = `${chalkForLevel(level)(symbol)} ${message}`;
48 | return `${timestamp} | ${coloredMessage}`;
49 | })
50 | ),
51 | }),
52 | ];
53 |
54 | // Erstellen des Winston-Loggers
55 | const logger = winston.createLogger({
56 | level: 'info',
57 | transports: transports,
58 | });
59 |
60 | /**
61 | * Funktion zum Hinzufügen des File-Transports
62 | */
63 | function addFileTransport() {
64 | const logDir = path.dirname(LOG_FILE_PATH);
65 | if (!fs.existsSync(logDir)) {
66 | fs.mkdirSync(logDir, { recursive: true });
67 | }
68 |
69 | const fileTransport = new winston.transports.File({
70 | filename: LOG_FILE_PATH,
71 | level: 'info', // Stellen Sie sicher, dass der Level ausreichend niedrig ist
72 | maxsize: 10485760, // 10 MB pro Datei
73 | maxFiles: 5, // Maximal 5 Dateien
74 | format: winston.format.combine(
75 | winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
76 | winston.format.printf(({ timestamp, level, message }) => {
77 | const symbol = getLevelSymbol(level);
78 | const plainMessage = stripAnsi(`${symbol} ${message}`); // ANSI-Codes entfernen
79 | return `${timestamp} | ${plainMessage}`;
80 | })
81 | ),
82 | });
83 |
84 | // Fehler-Handler hinzufügen
85 | fileTransport.on('error', (error) => {
86 | console.error(chalk.red('File-Transport Fehler:'), error);
87 | });
88 |
89 | // Prüfen, ob der Transport bereits hinzugefügt wurde, um Duplikate zu vermeiden
90 | if (!logger.transports.some(t => t instanceof winston.transports.File)) {
91 | logger.add(fileTransport);
92 | }
93 | }
94 |
95 | /**
96 | * Funktion zum Entfernen des File-Transports
97 | */
98 | function removeFileTransport() {
99 | const fileTransport = logger.transports.find(
100 | (t) => t instanceof winston.transports.File
101 | );
102 | if (fileTransport) {
103 | logger.remove(fileTransport);
104 | }
105 | }
106 |
107 | /**
108 | * Funktion zum Setzen von allowWrittenLogfile
109 | * @param {boolean} value - true, um Dateilogs zu erlauben; false, um sie zu deaktivieren
110 | */
111 | function setAllowWrittenLogfile(value) {
112 | allowWrittenLogfile = value;
113 | if (allowWrittenLogfile) {
114 | addFileTransport();
115 | logEvent('system', 'wrlog', 'File logs activated.', 'File logs are now activated.', 'info');
116 |
117 | // Überprüfen, ob der File-Transport hinzugefügt wurde
118 | const fileTransport = logger.transports.find(t => t instanceof winston.transports.File);
119 | if (fileTransport) {
120 | // console.log(chalk.green('File-Transport erfolgreich hinzugefügt.'));
121 | } else {
122 | console.log(chalk.red('Error: File transport could not be added.'));
123 | }
124 | } else {
125 | removeFileTransport();
126 | logEvent('system', 'wrlog', 'File logs deactivated.', 'File logs are now deactivated.', 'info');
127 | }
128 | }
129 |
130 | /**
131 | * Zentrale Logging-Funktion
132 | * @param {string} clientIP - IP-Adresse des Clients
133 | * @param {number|string} clientPort - Port des Clients
134 | * @param {string} functionName - Name der aufgerufenen Funktion
135 | * @param {string|object} status - Status der Rückmeldung
136 | * @param {string} level - Log-Level ('info', 'warn', 'error', 'debug')
137 | */
138 | function logEvent(clientIP, clientPort, functionName, status, level = 'info') {
139 | // Kürzen und formatieren der Felder
140 | const ip = String(clientIP || 'N/A').padEnd(23).substring(0, 23); // Mindestens 8 Zeichen für die IP
141 | const port = String(clientPort || 'N/A').padEnd(5).substring(0, 5); // 5 Zeichen für den Port
142 | const func = String(functionName || 'N/A').padEnd(26).substring(0, 26); // 20 Zeichen für den Funktionsnamen
143 | const stat = String(status || '').padEnd(120).substring(0, 120); // 100 Zeichen für den Status
144 |
145 | // Formatierte Logzeile
146 | const logLine = `${ip}:${port} | ${func} | ${stat}`;
147 | // Log-Ausgabe basierend auf dem Level
148 | logger.log({ level, message: logLine });
149 | }
150 |
151 |
152 | export { logger, logEvent, setAllowWrittenLogfile, LOG_FILE_PATH };
153 |
```
--------------------------------------------------------------------------------
/clients/C++/5.1 mcp_edit_user/MCPEditUserClient.cpp:
--------------------------------------------------------------------------------
```cpp
1 | #include <iostream>
2 | #include <string>
3 | #include <map>
4 | #include <vector>
5 | #include <sstream>
6 | #include <stdexcept>
7 | #include <json/json.h>
8 | #include <winsock2.h>
9 | #include <ws2tcpip.h>
10 |
11 | #pragma comment(lib, "ws2_32.lib") // Verlinkung mit der Winsock-Bibliothek
12 |
13 | // Funktion zum Parsen von Argumenten
14 | std::map<std::string, std::string> parseArguments(int argc, char* argv[]) {
15 | std::map<std::string, std::string> args;
16 | for (int i = 1; i < argc; ++i) {
17 | std::string key = argv[i];
18 | if (i + 1 < argc && key.rfind("--", 0) == 0) {
19 | args[key] = argv[++i];
20 | }
21 | }
22 | return args;
23 | }
24 |
25 | // Funktion zum Parsen von Listen-Argumenten
26 | std::vector<std::string> parseListArgument(int argc, char* argv[], const std::string& key) {
27 | std::vector<std::string> values;
28 | for (int i = 1; i < argc; ++i) {
29 | if (argv[i] == key && i + 1 < argc) {
30 | for (int j = i + 1; j < argc && std::string(argv[j]).rfind("--", 0) != 0; ++j) {
31 | values.push_back(argv[j]);
32 | }
33 | }
34 | }
35 | return values;
36 | }
37 |
38 | // Funktion zum Senden der Anfrage
39 | std::string sendRequest(const std::string& serverIp, int serverPort, const Json::Value& payload) {
40 | Json::StreamWriterBuilder writer;
41 | std::string payloadJson = Json::writeString(writer, payload);
42 |
43 | // Winsock initialisieren
44 | WSADATA wsaData;
45 | if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
46 | throw std::runtime_error("Failed to initialize Winsock.");
47 | }
48 |
49 | // Socket erstellen
50 | SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
51 | if (sock == INVALID_SOCKET) {
52 | WSACleanup();
53 | throw std::runtime_error("Failed to create socket.");
54 | }
55 |
56 | // Server-Adresse konfigurieren
57 | sockaddr_in serverAddr;
58 | serverAddr.sin_family = AF_INET;
59 | serverAddr.sin_port = htons(serverPort);
60 | if (inet_pton(AF_INET, serverIp.c_str(), &serverAddr.sin_addr) <= 0) {
61 | closesocket(sock);
62 | WSACleanup();
63 | throw std::runtime_error("Invalid server IP address.");
64 | }
65 |
66 | // Verbindung herstellen
67 | if (connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
68 | closesocket(sock);
69 | WSACleanup();
70 | throw std::runtime_error("Connection failed.");
71 | }
72 |
73 | // Daten senden
74 | if (send(sock, payloadJson.c_str(), payloadJson.size(), 0) < 0) {
75 | closesocket(sock);
76 | WSACleanup();
77 | throw std::runtime_error("Failed to send data.");
78 | }
79 |
80 | // Antwort empfangen
81 | char buffer[4096];
82 | int bytesRead;
83 | std::ostringstream response;
84 |
85 | do {
86 | bytesRead = recv(sock, buffer, sizeof(buffer) - 1, 0);
87 | if (bytesRead > 0) {
88 | buffer[bytesRead] = '\0'; // Null-terminieren
89 | response << buffer;
90 | }
91 | } while (bytesRead == sizeof(buffer) - 1);
92 |
93 | // Socket schließen
94 | closesocket(sock);
95 | WSACleanup();
96 |
97 | return response.str();
98 | }
99 |
100 | int main(int argc, char* argv[]) {
101 | try {
102 | auto args = parseArguments(argc, argv);
103 |
104 | // Pflichtargumente überprüfen
105 | if (args["--server-ip"].empty() || args["--server-port"].empty() || args["--token"].empty() || args["--email"].empty() || args["--name"].empty()) {
106 | std::cerr << "Usage: --server-ip <IP> --server-port <PORT> --token <TOKEN> --email <EMAIL> --name <NAME> [optional parameters]\n";
107 | return 1;
108 | }
109 |
110 | // Argumente auslesen
111 | std::string serverIp = args["--server-ip"];
112 | int serverPort = std::stoi(args["--server-port"]);
113 | std::string token = args["--token"];
114 | std::string email = args["--email"];
115 | std::string name = args["--name"];
116 | std::string language = args.count("--language") ? args["--language"] : "en";
117 | std::string timezone = args.count("--timezone") ? args["--timezone"] : "UTC";
118 | std::string password = args["--password"];
119 | bool publicUpload = args.count("--publicUpload") > 0;
120 | auto groups = parseListArgument(argc, argv, "--groups");
121 | auto roles = parseListArgument(argc, argv, "--roles");
122 | bool activateFtp = args.count("--activateFtp") > 0;
123 | std::string ftpPassword = args["--ftpPassword"];
124 |
125 | // JSON-Payload erstellen
126 | Json::Value payload;
127 | payload["command"] = "edit_user";
128 | payload["token"] = token;
129 | payload["arguments"]["email"] = email;
130 | payload["arguments"]["name"] = name;
131 | payload["arguments"]["language"] = language;
132 | payload["arguments"]["timezone"] = timezone;
133 | if (!password.empty()) payload["arguments"]["password"] = password;
134 | payload["arguments"]["publicUpload"] = publicUpload;
135 | for (const auto& group : groups) {
136 | payload["arguments"]["groups"].append(group);
137 | }
138 | for (const auto& role : roles) {
139 | payload["arguments"]["roles"].append(role);
140 | }
141 | payload["arguments"]["activateFtp"] = activateFtp;
142 | if (!ftpPassword.empty()) payload["arguments"]["ftpPassword"] = ftpPassword;
143 |
144 | std::cout << "📤 Sending edit user request...\n";
145 |
146 | // Anfrage senden und Antwort erhalten
147 | std::string response = sendRequest(serverIp, serverPort, payload);
148 |
149 | std::cout << "✔️ Response from server:\n" << response << "\n";
150 | } catch (const std::exception& e) {
151 | std::cerr << "❌ ERROR: " << e.what() << "\n";
152 | return 1;
153 | }
154 |
155 | return 0;
156 | }
157 |
```
--------------------------------------------------------------------------------
/clients/JavaScript/3.3 mcp_edit_source/MCPEditSourceClient.js:
--------------------------------------------------------------------------------
```javascript
1 | const net = require('net');
2 | const readline = require('readline');
3 | const { argv, exit } = require('process');
4 |
5 | // Funktion zum Parsen der Kommandozeilenargumente
6 | function parseArguments(args) {
7 | const parsedArgs = {};
8 | for (let i = 2; i < args.length; i++) {
9 | switch (args[i]) {
10 | case '--server-ip':
11 | parsedArgs.serverIp = args[++i];
12 | break;
13 | case '--server-port':
14 | parsedArgs.serverPort = parseInt(args[++i], 10);
15 | break;
16 | case '--token':
17 | parsedArgs.token = args[++i];
18 | break;
19 | case '--source-id':
20 | parsedArgs.sourceId = args[++i];
21 | break;
22 | case '--title':
23 | parsedArgs.title = args[++i];
24 | break;
25 | case '--content':
26 | parsedArgs.content = args[++i];
27 | break;
28 | case '--groups':
29 | // Sammle alle Gruppenargumente bis zum nächsten Flag oder Ende
30 | parsedArgs.groups = [];
31 | while (i + 1 < args.length && !args[i + 1].startsWith('--')) {
32 | parsedArgs.groups.push(args[++i]);
33 | }
34 | break;
35 | default:
36 | console.warn(`⚠️ Unbekanntes Argument: ${args[i]}`);
37 | }
38 | }
39 | return parsedArgs;
40 | }
41 |
42 | // Funktion zum interaktiven Abfragen eines Parameters (optional)
43 | function askQuestion(query) {
44 | const rl = readline.createInterface({
45 | input: process.stdin,
46 | output: process.stdout,
47 | terminal: true
48 | });
49 |
50 | return new Promise((resolve) => {
51 | rl.question(query, (answer) => {
52 | rl.close();
53 | resolve(answer);
54 | });
55 | });
56 | }
57 |
58 | // Funktion zum Senden einer Edit-Source-Anfrage über eine TCP-Verbindung
59 | function sendEditSourceRequest(serverIp, serverPort, payload) {
60 | return new Promise((resolve, reject) => {
61 | const client = new net.Socket();
62 | let responseData = '';
63 |
64 | client.connect(serverPort, serverIp, () => {
65 | console.log(`🔗 Verbindung zum Server (${serverIp}:${serverPort}) hergestellt.`);
66 | const payloadString = JSON.stringify(payload);
67 | console.log(`📤 Sende Payload: ${payloadString}`);
68 | client.write(payloadString);
69 | });
70 |
71 | client.on('data', (data) => {
72 | console.log(`📥 Empfangene Daten: ${data}`);
73 | responseData += data.toString();
74 | try {
75 | const parsedData = JSON.parse(responseData);
76 | console.log('✅ JSON-Antwort erfolgreich geparst.');
77 | resolve(parsedData);
78 | client.destroy(); // Verbindung schließen
79 | } catch (err) {
80 | console.warn('⚠️ Antwort noch nicht vollständig oder ungültiges JSON. Weitere Daten werden erwartet.');
81 | // Antwort noch nicht vollständig, weiter empfangen
82 | }
83 | });
84 |
85 | client.on('close', () => {
86 | console.log('🔒 Verbindung zum Server geschlossen.');
87 | });
88 |
89 | client.on('error', (err) => {
90 | console.error('❌ Verbindungsfehler:', err.message);
91 | reject(err);
92 | });
93 | });
94 | }
95 |
96 | // Hauptfunktion
97 | async function main() {
98 | const args = argv;
99 | const parsedArgs = parseArguments(args);
100 | let { serverIp, serverPort, token, sourceId, title, content, groups } = parsedArgs;
101 |
102 | // Überprüfen, ob alle erforderlichen Parameter vorhanden sind, sonst interaktiv abfragen
103 | if (!serverIp) {
104 | serverIp = await askQuestion('🔗 Bitte gib die Server-IP ein: ');
105 | }
106 | if (!serverPort) {
107 | const portInput = await askQuestion('🔗 Bitte gib den Server-Port ein: ');
108 | serverPort = parseInt(portInput, 10);
109 | }
110 | if (!token) {
111 | token = await askQuestion('🔒 Bitte gib dein Authentifizierungstoken ein: ');
112 | }
113 | if (!sourceId) {
114 | sourceId = await askQuestion('📁 Bitte gib die Source-ID ein: ');
115 | }
116 |
117 | // Überprüfen, ob mindestens eines der optionalen Parameter vorhanden ist
118 | if (title === undefined && content === undefined && (groups === undefined || groups.length === 0)) {
119 | console.warn('⚠️ Keine Änderungsparameter angegeben. Es werden mindestens eines der folgenden benötigt: --title, --content, --groups.');
120 | exit(1);
121 | }
122 |
123 | // Optional: Abfrage fehlender optionaler Parameter, wenn entsprechende Flags gesetzt sind
124 | // Hier gehen wir davon aus, dass --title, --content und --groups bereits korrekt geparst wurden
125 | // und entweder definiert sind oder nicht angegeben wurden.
126 |
127 | // Entferne unerwünschte Schlüssel mit undefined oder null Werten
128 | const filteredArguments = {};
129 | if (sourceId) filteredArguments.sourceId = sourceId;
130 | if (title) filteredArguments.title = title;
131 | if (content) filteredArguments.content = content;
132 | if (groups && groups.length > 0) filteredArguments.groups = groups;
133 |
134 | const payload = {
135 | command: "edit_source",
136 | token: token,
137 | arguments: filteredArguments
138 | };
139 |
140 | try {
141 | console.log('🛠️ Sende Edit-Source-Anfrage...');
142 | const response = await sendEditSourceRequest(serverIp, serverPort, payload);
143 | console.log('✅ Server Response:');
144 | console.log(JSON.stringify(response, null, 2));
145 | } catch (err) {
146 | console.error('❌ ERROR:', err.message);
147 | }
148 | }
149 |
150 | main();
151 |
```
--------------------------------------------------------------------------------
/clients/JavaScript/4.1 mcp_store_group/MCPStoreGroupClient.js:
--------------------------------------------------------------------------------
```javascript
1 | const net = require('net');
2 | const readline = require('readline');
3 | const { argv, exit } = require('process');
4 |
5 | /**
6 | * Funktion zum Parsen der Kommandozeilenargumente
7 | * @param {string[]} args - Array von Kommandozeilenargumenten
8 | * @returns {Object} - Objekt mit geparsten Argumenten
9 | */
10 | function parseArguments(args) {
11 | const parsedArgs = {};
12 | for (let i = 2; i < args.length; i++) {
13 | switch (args[i]) {
14 | case '--server-ip':
15 | parsedArgs.serverIp = args[++i];
16 | break;
17 | case '--server-port':
18 | parsedArgs.serverPort = parseInt(args[++i], 10);
19 | break;
20 | case '--group-name':
21 | parsedArgs.groupName = args[++i];
22 | break;
23 | case '--token':
24 | parsedArgs.token = args[++i];
25 | break;
26 | case '--description':
27 | parsedArgs.description = args[++i];
28 | break;
29 | default:
30 | console.warn(`⚠️ Unbekanntes Argument: ${args[i]}`);
31 | }
32 | }
33 | return parsedArgs;
34 | }
35 |
36 | /**
37 | * Funktion zum interaktiven Abfragen eines Parameters (optional)
38 | * @param {string} query - Frage an den Benutzer
39 | * @returns {Promise<string>} - Antwort des Benutzers
40 | */
41 | function askQuestion(query) {
42 | const rl = readline.createInterface({
43 | input: process.stdin,
44 | output: process.stdout,
45 | terminal: true
46 | });
47 |
48 | return new Promise((resolve) => {
49 | rl.question(query, (answer) => {
50 | rl.close();
51 | resolve(answer);
52 | });
53 | });
54 | }
55 |
56 | /**
57 | * Sendet eine Anfrage an den MCP-Server, um eine neue Gruppe zu speichern.
58 | *
59 | * @param {string} serverIp - IP-Adresse des MCP-Servers
60 | * @param {number} serverPort - Portnummer des MCP-Servers
61 | * @param {string} groupName - Name der zu speichernden Gruppe
62 | * @param {string} token - Authentifizierungstoken
63 | * @param {string} description - Beschreibung der Gruppe (optional)
64 | * @returns {Promise<Object>} - Antwort vom Server
65 | */
66 | function sendStoreGroupRequest(serverIp, serverPort, groupName, token, description) {
67 | return new Promise((resolve, reject) => {
68 | const client = new net.Socket();
69 | const payload = {
70 | command: "store_group",
71 | token: token,
72 | arguments: {
73 | groupName: groupName,
74 | description: description
75 | }
76 | };
77 | const payloadString = JSON.stringify(payload);
78 |
79 | // Timeout setzen (optional)
80 | const TIMEOUT_DURATION = 10000; // 10 Sekunden
81 | const timeout = setTimeout(() => {
82 | client.destroy(); // Verbindung zerstören
83 | reject(new Error('Verbindungs-Timeout: Der Server hat nicht rechtzeitig geantwortet.'));
84 | }, TIMEOUT_DURATION);
85 |
86 | client.connect(serverPort, serverIp, () => {
87 | console.log(`🔗 Verbindung zum Server (${serverIp}:${serverPort}) hergestellt.`);
88 | console.log(`📤 Sende Payload: ${payloadString}`);
89 | client.write(payloadString);
90 | });
91 |
92 | let responseData = '';
93 |
94 | client.on('data', (data) => {
95 | console.log(`📥 Empfangene Daten: ${data}`);
96 | responseData += data.toString();
97 | try {
98 | const parsedData = JSON.parse(responseData);
99 | console.log('✅ JSON-Antwort erfolgreich geparst.');
100 | clearTimeout(timeout);
101 | resolve(parsedData);
102 | client.destroy(); // Verbindung schließen
103 | } catch (err) {
104 | console.warn('⚠️ Antwort noch nicht vollständig oder ungültiges JSON. Weitere Daten werden erwartet.');
105 | // Weiter empfangen
106 | }
107 | });
108 |
109 | client.on('close', () => {
110 | console.log('🔒 Verbindung zum Server geschlossen.');
111 | clearTimeout(timeout);
112 | });
113 |
114 | client.on('error', (err) => {
115 | console.error('❌ Verbindungsfehler:', err.message);
116 | clearTimeout(timeout);
117 | reject(err);
118 | });
119 | });
120 | }
121 |
122 | // Hauptfunktion
123 | async function main() {
124 | const args = argv;
125 | const parsedArgs = parseArguments(args);
126 | let { serverIp, serverPort, groupName, token, description } = parsedArgs;
127 |
128 | // Überprüfen, ob alle erforderlichen Parameter vorhanden sind, sonst interaktiv abfragen
129 | if (!serverIp) {
130 | serverIp = await askQuestion('🔗 Bitte gib die Server-IP ein: ');
131 | }
132 | if (!serverPort) {
133 | const portInput = await askQuestion('🔗 Bitte gib den Server-Port ein: ');
134 | serverPort = parseInt(portInput, 10);
135 | }
136 | if (!groupName) {
137 | groupName = await askQuestion('📛 Bitte gib den Gruppennamen ein: ');
138 | }
139 | if (!token) {
140 | token = await askQuestion('🔒 Bitte gib dein Authentifizierungstoken ein: ');
141 | }
142 | // Beschreibung ist optional, kein Abfrage notwendig
143 |
144 | const payload = {
145 | command: "store_group",
146 | token: token,
147 | arguments: {
148 | groupName: groupName,
149 | description: description || ""
150 | }
151 | };
152 |
153 | try {
154 | console.log('🗃️ Sende Store-Group-Anfrage...');
155 | const response = await sendStoreGroupRequest(serverIp, serverPort, groupName, token, description);
156 | console.log('✔️ Antwort vom Server:', JSON.stringify(response, null, 2));
157 | } catch (err) {
158 | console.error('❌ Fehler:', err.message);
159 | }
160 | }
161 |
162 | main();
163 |
```
--------------------------------------------------------------------------------
/clients/JavaScript/5.1 mcp_edit_user/MCPEditUserClient.js:
--------------------------------------------------------------------------------
```javascript
1 | const net = require('net');
2 | const readline = require('readline');
3 | const { argv } = require('process');
4 |
5 | /**
6 | * Funktion zum Parsen der Kommandozeilenargumente
7 | * @param {string[]} args - Array von Kommandozeilenargumenten
8 | * @returns {Object} - Objekt mit geparsten Argumenten
9 | */
10 | function parseArguments(args) {
11 | const parsedArgs = {};
12 | for (let i = 2; i < args.length; i++) {
13 | switch (args[i]) {
14 | case '--server-ip':
15 | parsedArgs.serverIp = args[++i];
16 | break;
17 | case '--server-port':
18 | parsedArgs.serverPort = parseInt(args[++i], 10);
19 | break;
20 | case '--token':
21 | parsedArgs.token = args[++i];
22 | break;
23 | case '--name':
24 | parsedArgs.name = args[++i];
25 | break;
26 | case '--email':
27 | parsedArgs.email = args[++i];
28 | break;
29 | case '--password':
30 | parsedArgs.password = args[++i];
31 | break;
32 | case '--language':
33 | parsedArgs.language = args[++i];
34 | break;
35 | case '--timezone':
36 | parsedArgs.timezone = args[++i];
37 | break;
38 | case '--roles':
39 | parsedArgs.roles = [];
40 | while (i + 1 < args.length && !args[i + 1].startsWith('--')) {
41 | parsedArgs.roles.push(args[++i]);
42 | }
43 | break;
44 | case '--groups':
45 | parsedArgs.groups = [];
46 | while (i + 1 < args.length && !args[i + 1].startsWith('--')) {
47 | parsedArgs.groups.push(args[++i]);
48 | }
49 | break;
50 | case '--usePublic':
51 | parsedArgs.usePublic = true;
52 | break;
53 | case '--activateFtp':
54 | parsedArgs.activateFtp = true;
55 | break;
56 | case '--ftpPassword':
57 | parsedArgs.ftpPassword = args[++i];
58 | break;
59 | default:
60 | console.warn(`⚠️ Unbekanntes Argument: ${args[i]}`);
61 | }
62 | }
63 | return parsedArgs;
64 | }
65 |
66 | /**
67 | * Sendet eine Anfrage an den MCP-Server, um einen Benutzer zu bearbeiten.
68 | *
69 | * @param {string} serverIp - IP-Adresse des MCP-Servers
70 | * @param {number} serverPort - Portnummer des MCP-Servers
71 | * @param {string} token - Authentifizierungstoken
72 | * @param {Object} args - Argumente für den zu bearbeitenden Benutzer
73 | * @returns {Promise<string>} - Antwort vom Server
74 | */
75 | function sendEditUserRequest(serverIp, serverPort, token, args) {
76 | return new Promise((resolve, reject) => {
77 | const client = new net.Socket();
78 | const payload = {
79 | command: "edit_user",
80 | token: token,
81 | arguments: {
82 | name: args.name,
83 | email: args.email,
84 | password: args.password,
85 | language: args.language,
86 | timezone: args.timezone,
87 | roles: args.roles || [],
88 | groups: args.groups || [],
89 | usePublic: args.usePublic || false,
90 | activateFtp: args.activateFtp || false,
91 | ftpPassword: args.ftpPassword
92 | }
93 | };
94 |
95 | // Entferne Null- oder undefined-Werte
96 | payload.arguments = Object.fromEntries(Object.entries(payload.arguments).filter(([_, v]) => v != null));
97 |
98 | const payloadString = JSON.stringify(payload);
99 |
100 | // Timeout setzen
101 | const TIMEOUT_DURATION = 10000; // 10 Sekunden
102 | const timeout = setTimeout(() => {
103 | client.destroy();
104 | reject(new Error('Verbindungs-Timeout: Der Server hat nicht rechtzeitig geantwortet.'));
105 | }, TIMEOUT_DURATION);
106 |
107 | client.connect(serverPort, serverIp, () => {
108 | console.log(`🔗 Verbindung zum Server (${serverIp}:${serverPort}) hergestellt.`);
109 | console.log(`📤 Sende Payload: ${payloadString}`);
110 | client.write(payloadString);
111 | });
112 |
113 | let responseData = '';
114 |
115 | client.on('data', (data) => {
116 | responseData += data.toString();
117 | try {
118 | const parsedData = JSON.parse(responseData);
119 | clearTimeout(timeout);
120 | resolve(parsedData);
121 | client.destroy();
122 | } catch (e) {
123 | // Weiter empfangen, falls JSON unvollständig ist
124 | }
125 | });
126 |
127 | client.on('close', () => {
128 | console.log('🔒 Verbindung zum Server geschlossen.');
129 | });
130 |
131 | client.on('error', (err) => {
132 | clearTimeout(timeout);
133 | reject(err);
134 | });
135 | });
136 | }
137 |
138 | // Hauptfunktion
139 | async function main() {
140 | const args = parseArguments(argv);
141 |
142 | if (!args.serverIp || !args.serverPort || !args.token) {
143 | console.error('❌ Fehler: --server-ip, --server-port und --token sind erforderlich.');
144 | console.log('📖 Beispiel: node MCPEditUserClient.js --server-ip 192.168.0.1 --server-port 5000 --token YOUR_AUTH_TOKEN');
145 | process.exit(1);
146 | }
147 |
148 | try {
149 | console.log('🧑💻 Sende Edit-User-Anfrage...');
150 | const response = await sendEditUserRequest(
151 | args.serverIp,
152 | args.serverPort,
153 | args.token,
154 | args
155 | );
156 | console.log('✔️ Antwort vom Server:', JSON.stringify(response, null, 2));
157 | } catch (err) {
158 | console.error('❌ Fehler beim Bearbeiten des Benutzers:', err.message);
159 | }
160 | }
161 |
162 | main();
163 |
```
--------------------------------------------------------------------------------
/clients/Java/2.0 mcp_chat/MCPChatClient.java:
--------------------------------------------------------------------------------
```java
1 | import org.json.JSONArray;
2 | import org.json.JSONObject;
3 |
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 | import java.net.Socket;
8 | import java.nio.charset.StandardCharsets;
9 | import java.util.ArrayList;
10 | import java.util.Arrays;
11 | import java.util.List;
12 |
13 | public class MCPChatClient {
14 |
15 | public static void main(String[] args) {
16 | // Minimalprüfung, ob genug Argumente für --server-ip, --server-port, --token, --question vorliegen.
17 | // (Die eigentliche Prüfung machen wir etwas weiter unten ausführlicher.)
18 | if (args.length < 5) {
19 | printUsage();
20 | return;
21 | }
22 |
23 | // Argumente auslesen
24 | String serverIp = getArgument(args, "--server-ip");
25 | String serverPortStr = getArgument(args, "--server-port");
26 | String token = getArgument(args, "--token");
27 | String question = getArgument(args, "--question");
28 | boolean usePublic = Arrays.asList(args).contains("--use-public");
29 | String language = getArgument(args, "--language");
30 | if (language == null) {
31 | language = "de"; // Defaultwert wie im Original
32 | }
33 |
34 | // Groups (kommagetrennt)
35 | List<String> groups = new ArrayList<>();
36 | String groupsArgument = getArgument(args, "--groups");
37 | if (groupsArgument != null) {
38 | // Zerlege den String an Kommas
39 | String[] groupArray = groupsArgument.split(",");
40 | groups.addAll(Arrays.asList(groupArray));
41 | }
42 |
43 | // Vollständige Prüfung
44 | if (serverIp == null || serverPortStr == null || token == null || question == null) {
45 | printUsage();
46 | return;
47 | }
48 |
49 | int serverPort = Integer.parseInt(serverPortStr);
50 |
51 | // Anfrage an den Server stellen
52 | String response = sendMCPRequest(serverIp, serverPort, token, question, usePublic, groups, language);
53 | System.out.println("Response from server:");
54 | System.out.println(response);
55 | }
56 |
57 | /**
58 | * Liest den Wert eines Arguments aus (z.B. --server-ip 127.0.0.1).
59 | * Gibt null zurück, wenn der Schlüssel nicht gefunden wurde.
60 | */
61 | private static String getArgument(String[] args, String key) {
62 | for (int i = 0; i < args.length - 1; i++) {
63 | if (args[i].equals(key)) {
64 | // Gib das nächste Element zurück, sofern vorhanden
65 | return args[i + 1];
66 | }
67 | }
68 | return null;
69 | }
70 |
71 | /**
72 | * Stellt eine Socket-Verbindung her, sendet das JSON-Payload und empfängt die Antwort.
73 | */
74 | private static String sendMCPRequest(String serverIp,
75 | int serverPort,
76 | String token,
77 | String question,
78 | boolean usePublic,
79 | List<String> groups,
80 | String language) {
81 |
82 | // Payload aufbauen
83 | JSONObject payload = new JSONObject();
84 | payload.put("command", "chat");
85 | payload.put("token", token);
86 |
87 | // arguments
88 | JSONObject arguments = new JSONObject();
89 | arguments.put("question", question);
90 | arguments.put("usePublic", usePublic);
91 | arguments.put("language", language);
92 |
93 | // Falls du lieber ein reines Array statt List speichern möchtest,
94 | // kannst du direkt new JSONArray(groups) verwenden.
95 | // Hier konvertieren wir die Java-Liste in ein JSONArray:
96 | JSONArray groupsArray = new JSONArray(groups);
97 | arguments.put("groups", groupsArray);
98 |
99 | payload.put("arguments", arguments);
100 |
101 | // Konvertiere das JSON-Objekt in einen String
102 | String payloadJson = payload.toString();
103 |
104 | try (Socket client = new Socket(serverIp, serverPort)) {
105 | // Sende das JSON-Payload
106 | OutputStream outputStream = client.getOutputStream();
107 | byte[] data = payloadJson.getBytes(StandardCharsets.UTF_8);
108 | outputStream.write(data);
109 | outputStream.flush();
110 |
111 | // Antwort empfangen
112 | InputStream inputStream = client.getInputStream();
113 | byte[] buffer = new byte[4096];
114 | StringBuilder responseBuilder = new StringBuilder();
115 |
116 | int bytesRead;
117 | do {
118 | bytesRead = inputStream.read(buffer);
119 | if (bytesRead > 0) {
120 | responseBuilder.append(new String(buffer, 0, bytesRead, StandardCharsets.UTF_8));
121 | }
122 | } while (bytesRead == buffer.length);
123 |
124 | return responseBuilder.toString();
125 |
126 | } catch (IOException e) {
127 | // Fehler in ein JSON-Objekt packen, wie im Original
128 | JSONObject errorResponse = new JSONObject();
129 | errorResponse.put("status", "error");
130 | errorResponse.put("message", e.getMessage());
131 | return errorResponse.toString();
132 | }
133 | }
134 |
135 | private static void printUsage() {
136 | System.out.println("Usage: ");
137 | System.out.println(" --server-ip <IP> --server-port <PORT> --token <TOKEN> --question <QUESTION>");
138 | System.out.println(" [--use-public] [--groups <GROUPS>] [--language <LANGUAGE>]");
139 | System.out.println();
140 | System.out.println("Example:");
141 | System.out.println(" java -cp .;json-20241224.jar MCPChatClient --server-ip 127.0.0.1 --server-port 1234 \\");
142 | System.out.println(" --token 12345 --question \"Hallo Welt?\" --use-public --groups \"devops,hr\"");
143 | }
144 | }
145 |
```
--------------------------------------------------------------------------------
/clients/Gradio/transport/stdio/stdio_client.py:
--------------------------------------------------------------------------------
```python
1 | # transport/stdio/stdio_client.py
2 | import json
3 | import logging
4 | import sys
5 | import traceback
6 | from contextlib import asynccontextmanager
7 |
8 | import anyio
9 | from anyio.streams.text import TextReceiveStream
10 |
11 | from ...mcp_client import get_default_environment
12 | from ...messages.message_types.json_rpc_message import JSONRPCMessage
13 | from ...transport.stdio.stdio_server_parameters import StdioServerParameters
14 |
15 |
16 | @asynccontextmanager
17 | async def stdio_client(server: StdioServerParameters):
18 | # ensure we have a server command
19 | if not server.command:
20 | raise ValueError("Server command must not be empty.")
21 |
22 | # ensure we have server arguments as a list or tuple
23 | if not isinstance(server.args, (list, tuple)):
24 | raise ValueError("Server arguments must be a list or tuple.")
25 |
26 | # create the the read and write streams
27 | read_stream_writer, read_stream = anyio.create_memory_object_stream(0)
28 | write_stream, write_stream_reader = anyio.create_memory_object_stream(0)
29 |
30 | # start the subprocess
31 | process = await anyio.open_process(
32 | [server.command, *server.args],
33 | env={**get_default_environment(), **(server.env or {})},
34 | stderr=sys.stderr,
35 | )
36 |
37 | # started server
38 | logging.debug(
39 | f"Subprocess started with PID {process.pid}, command: {server.command}"
40 | )
41 |
42 | # create a task to read from the subprocess' stdout
43 | async def process_json_line(line: str, writer):
44 | try:
45 | logging.debug(f"Processing line: {line.strip()}")
46 | data = json.loads(line)
47 |
48 | # parse the json
49 | logging.debug(f"Parsed JSON data: {data}")
50 |
51 | # validate the jsonrpc message
52 | message = JSONRPCMessage.model_validate(data)
53 | logging.debug(f"Validated JSONRPCMessage: {message}")
54 |
55 | # send the message
56 | await writer.send(message)
57 | except json.JSONDecodeError as exc:
58 | # not valid json
59 | logging.error(f"JSON decode error: {exc}. Line: {line.strip()}")
60 | except Exception as exc:
61 | # other exception
62 | logging.error(f"Error processing message: {exc}. Line: {line.strip()}")
63 | logging.debug(f"Traceback:\n{traceback.format_exc()}")
64 |
65 | async def stdout_reader():
66 | """Read JSON-RPC messages from the server's stdout."""
67 | assert process.stdout, "Opened process is missing stdout"
68 | buffer = ""
69 | logging.debug("Starting stdout_reader")
70 | try:
71 | async with read_stream_writer:
72 | async for chunk in TextReceiveStream(process.stdout):
73 | lines = (buffer + chunk).split("\n")
74 | buffer = lines.pop()
75 | for line in lines:
76 | if line.strip():
77 | await process_json_line(line, read_stream_writer)
78 | if buffer.strip():
79 | await process_json_line(buffer, read_stream_writer)
80 | except anyio.ClosedResourceError:
81 | logging.debug("Read stream closed.")
82 | except Exception as exc:
83 | logging.error(f"Unexpected error in stdout_reader: {exc}")
84 | logging.debug(f"Traceback:\n{traceback.format_exc()}")
85 | raise
86 | finally:
87 | logging.debug("Exiting stdout_reader")
88 |
89 | async def stdin_writer():
90 | """Send JSON-RPC messages from the write stream to the server's stdin."""
91 | assert process.stdin, "Opened process is missing stdin"
92 | logging.debug("Starting stdin_writer")
93 | try:
94 | async with write_stream_reader:
95 | async for message in write_stream_reader:
96 | json_str = message.model_dump_json(exclude_none=True)
97 | logging.debug(f"Sending: {json_str}")
98 | await process.stdin.send((json_str + "\n").encode())
99 | except anyio.ClosedResourceError:
100 | logging.debug("Write stream closed.")
101 | except Exception as exc:
102 | logging.error(f"Unexpected error in stdin_writer: {exc}")
103 | logging.debug(f"Traceback:\n{traceback.format_exc()}")
104 | raise
105 | finally:
106 | logging.debug("Exiting stdin_writer")
107 |
108 | async def terminate_process():
109 | """Gracefully terminate the subprocess."""
110 | try:
111 | if process.returncode is None: # Process is still running
112 | logging.debug("Terminating subprocess...")
113 | process.terminate()
114 | with anyio.fail_after(5):
115 | await process.wait()
116 | else:
117 | logging.info("Process already terminated.")
118 | except TimeoutError:
119 | logging.warning(
120 | "Process did not terminate gracefully. Forcefully killing it."
121 | )
122 | try:
123 | process.kill()
124 | except Exception as kill_exc:
125 | logging.error(f"Error killing process: {kill_exc}")
126 | except Exception as exc:
127 | logging.error(f"Error during process termination: {exc}")
128 |
129 | try:
130 | async with anyio.create_task_group() as tg, process:
131 | tg.start_soon(stdout_reader)
132 | tg.start_soon(stdin_writer)
133 | yield read_stream, write_stream
134 |
135 | # exit the task group
136 | exit_code = await process.wait()
137 | logging.info(f"Process exited with code {exit_code}")
138 | except Exception as exc:
139 | # other exception
140 | logging.error(f"Unhandled error in TaskGroup: {exc}")
141 | logging.debug(f"Traceback:\n{traceback.format_exc()}")
142 | if hasattr(exc, "__cause__") and exc.__cause__:
143 | logging.debug(f"TaskGroup exception cause: {exc.__cause__}")
144 | raise
145 | finally:
146 | await terminate_process()
147 |
```
--------------------------------------------------------------------------------
/agents/MCP-Client/Python/transport/stdio/stdio_client.py:
--------------------------------------------------------------------------------
```python
1 | # transport/stdio/stdio_client.py
2 | import json
3 | import logging
4 | import sys
5 | import traceback
6 | from contextlib import asynccontextmanager
7 |
8 | import anyio
9 | from anyio.streams.text import TextReceiveStream
10 |
11 | from ...environment import get_default_environment
12 | from ...messages.message_types.json_rpc_message import JSONRPCMessage
13 | from ...transport.stdio.stdio_server_parameters import StdioServerParameters
14 |
15 |
16 | @asynccontextmanager
17 | async def stdio_client(server: StdioServerParameters):
18 | # ensure we have a server command
19 | if not server.command:
20 | raise ValueError("Server command must not be empty.")
21 |
22 | # ensure we have server arguments as a list or tuple
23 | if not isinstance(server.args, (list, tuple)):
24 | raise ValueError("Server arguments must be a list or tuple.")
25 |
26 | # create the the read and write streams
27 | read_stream_writer, read_stream = anyio.create_memory_object_stream(0)
28 | write_stream, write_stream_reader = anyio.create_memory_object_stream(0)
29 |
30 | # start the subprocess
31 | process = await anyio.open_process(
32 | [server.command, *server.args],
33 | env={**get_default_environment(), **(server.env or {})},
34 | stderr=sys.stderr,
35 | )
36 |
37 | # started server
38 | logging.debug(
39 | f"Subprocess started with PID {process.pid}, command: {server.command}"
40 | )
41 |
42 | # create a task to read from the subprocess' stdout
43 | async def process_json_line(line: str, writer):
44 | try:
45 | logging.debug(f"Processing line: {line.strip()}")
46 | data = json.loads(line)
47 |
48 | # parse the json
49 | logging.debug(f"Parsed JSON data: {data}")
50 |
51 | # validate the jsonrpc message
52 | message = JSONRPCMessage.model_validate(data)
53 | logging.debug(f"Validated JSONRPCMessage: {message}")
54 |
55 | # send the message
56 | await writer.send(message)
57 | except json.JSONDecodeError as exc:
58 | # not valid json
59 | logging.error(f"JSON decode error: {exc}. Line: {line.strip()}")
60 | except Exception as exc:
61 | # other exception
62 | logging.error(f"Error processing message: {exc}. Line: {line.strip()}")
63 | logging.debug(f"Traceback:\n{traceback.format_exc()}")
64 |
65 | async def stdout_reader():
66 | """Read JSON-RPC messages from the server's stdout."""
67 | assert process.stdout, "Opened process is missing stdout"
68 | buffer = ""
69 | logging.debug("Starting stdout_reader")
70 | try:
71 | async with read_stream_writer:
72 | async for chunk in TextReceiveStream(process.stdout):
73 | lines = (buffer + chunk).split("\n")
74 | buffer = lines.pop()
75 | for line in lines:
76 | if line.strip():
77 | await process_json_line(line, read_stream_writer)
78 | if buffer.strip():
79 | await process_json_line(buffer, read_stream_writer)
80 | except anyio.ClosedResourceError:
81 | logging.debug("Read stream closed.")
82 | except Exception as exc:
83 | logging.error(f"Unexpected error in stdout_reader: {exc}")
84 | logging.debug(f"Traceback:\n{traceback.format_exc()}")
85 | raise
86 | finally:
87 | logging.debug("Exiting stdout_reader")
88 |
89 | async def stdin_writer():
90 | """Send JSON-RPC messages from the write stream to the server's stdin."""
91 | assert process.stdin, "Opened process is missing stdin"
92 | logging.debug("Starting stdin_writer")
93 | try:
94 | async with write_stream_reader:
95 | async for message in write_stream_reader:
96 | json_str = message.model_dump_json(exclude_none=True)
97 | logging.debug(f"Sending: {json_str}")
98 | await process.stdin.send((json_str + "\n").encode())
99 | except anyio.ClosedResourceError:
100 | logging.debug("Write stream closed.")
101 | except Exception as exc:
102 | logging.error(f"Unexpected error in stdin_writer: {exc}")
103 | logging.debug(f"Traceback:\n{traceback.format_exc()}")
104 | raise
105 | finally:
106 | logging.debug("Exiting stdin_writer")
107 |
108 | async def terminate_process():
109 | """Gracefully terminate the subprocess."""
110 | try:
111 | if process.returncode is None: # Process is still running
112 | logging.debug("Terminating subprocess...")
113 | process.terminate()
114 | with anyio.fail_after(5):
115 | await process.wait()
116 | else:
117 | logging.info("Process already terminated.")
118 | except TimeoutError:
119 | logging.warning(
120 | "Process did not terminate gracefully. Forcefully killing it."
121 | )
122 | try:
123 | process.kill()
124 | except Exception as kill_exc:
125 | logging.error(f"Error killing process: {kill_exc}")
126 | except Exception as exc:
127 | logging.error(f"Error during process termination: {exc}")
128 |
129 | try:
130 | async with anyio.create_task_group() as tg, process:
131 | tg.start_soon(stdout_reader)
132 | tg.start_soon(stdin_writer)
133 | yield read_stream, write_stream
134 |
135 | # exit the task group
136 | exit_code = await process.wait()
137 | logging.info(f"Process exited with code {exit_code}")
138 | except Exception as exc:
139 | # other exception
140 | logging.error(f"Unhandled error in TaskGroup: {exc}")
141 | logging.debug(f"Traceback:\n{traceback.format_exc()}")
142 | if hasattr(exc, "__cause__") and exc.__cause__:
143 | logging.debug(f"TaskGroup exception cause: {exc.__cause__}")
144 | raise
145 | finally:
146 | await terminate_process()
147 |
```
--------------------------------------------------------------------------------
/clients/JavaScript/4.2 mcp_delete_group/MCPDeleteGroupClient.js:
--------------------------------------------------------------------------------
```javascript
1 | const net = require('net');
2 | const readline = require('readline');
3 | const { argv, exit } = require('process');
4 |
5 | /**
6 | * Funktion zum Parsen der Kommandozeilenargumente
7 | * @param {string[]} args - Array von Kommandozeilenargumenten
8 | * @returns {Object} - Objekt mit geparsten Argumenten
9 | */
10 | function parseArguments(args) {
11 | const parsedArgs = {};
12 | for (let i = 2; i < args.length; i++) {
13 | switch (args[i]) {
14 | case '--server-ip':
15 | if (i + 1 < args.length) {
16 | parsedArgs.serverIp = args[++i];
17 | } else {
18 | console.warn('⚠️ Kein Wert für --server-ip angegeben.');
19 | }
20 | break;
21 | case '--server-port':
22 | if (i + 1 < args.length) {
23 | parsedArgs.serverPort = parseInt(args[++i], 10);
24 | } else {
25 | console.warn('⚠️ Kein Wert für --server-port angegeben.');
26 | }
27 | break;
28 | case '--token':
29 | if (i + 1 < args.length) {
30 | parsedArgs.token = args[++i];
31 | } else {
32 | console.warn('⚠️ Kein Wert für --token angegeben.');
33 | }
34 | break;
35 | case '--group-name':
36 | if (i + 1 < args.length) {
37 | parsedArgs.groupName = args[++i];
38 | } else {
39 | console.warn('⚠️ Kein Wert für --group-name angegeben.');
40 | }
41 | break;
42 | default:
43 | console.warn(`⚠️ Unbekanntes Argument: ${args[i]}`);
44 | }
45 | }
46 | return parsedArgs;
47 | }
48 |
49 | /**
50 | * Funktion zum interaktiven Abfragen eines Parameters (optional)
51 | * @param {string} query - Frage an den Benutzer
52 | * @returns {Promise<string>} - Antwort des Benutzers
53 | */
54 | function askQuestion(query) {
55 | const rl = readline.createInterface({
56 | input: process.stdin,
57 | output: process.stdout,
58 | terminal: true
59 | });
60 |
61 | return new Promise((resolve) => {
62 | rl.question(query, (answer) => {
63 | rl.close();
64 | resolve(answer);
65 | });
66 | });
67 | }
68 |
69 | /**
70 | * Sendet eine Anfrage an den MCP-Server, um eine bestehende Gruppe zu löschen.
71 | *
72 | * @param {string} serverIp - IP-Adresse des MCP-Servers
73 | * @param {number} serverPort - Portnummer des MCP-Servers
74 | * @param {string} token - Authentifizierungstoken
75 | * @param {string} groupName - Name der zu löschenden Gruppe
76 | * @returns {Promise<Object>} - Antwort vom Server
77 | */
78 | function sendDeleteGroupRequest(serverIp, serverPort, token, groupName) {
79 | return new Promise((resolve, reject) => {
80 | const client = new net.Socket();
81 | const payload = {
82 | command: "delete_group",
83 | token: token,
84 | arguments: {
85 | groupName: groupName
86 | }
87 | };
88 | const payloadString = JSON.stringify(payload);
89 |
90 | // Timeout setzen (optional)
91 | const TIMEOUT_DURATION = 10000; // 10 Sekunden
92 | const timeout = setTimeout(() => {
93 | client.destroy(); // Verbindung zerstören
94 | reject(new Error('Verbindungs-Timeout: Der Server hat nicht rechtzeitig geantwortet.'));
95 | }, TIMEOUT_DURATION);
96 |
97 | client.connect(serverPort, serverIp, () => {
98 | console.log(`🔗 Verbindung zum Server (${serverIp}:${serverPort}) hergestellt.`);
99 | console.log(`📤 Sende Payload: ${payloadString}`);
100 | client.write(payloadString);
101 | });
102 |
103 | let responseData = '';
104 |
105 | client.on('data', (data) => {
106 | console.log(`📥 Empfangene Daten: ${data}`);
107 | responseData += data.toString();
108 | try {
109 | const parsedData = JSON.parse(responseData);
110 | console.log('✅ JSON-Antwort erfolgreich geparst.');
111 | clearTimeout(timeout);
112 | resolve(parsedData);
113 | client.destroy(); // Verbindung schließen
114 | } catch (err) {
115 | console.warn('⚠️ Antwort noch nicht vollständig oder ungültiges JSON. Weitere Daten werden erwartet.');
116 | // Weiter empfangen
117 | }
118 | });
119 |
120 | client.on('close', () => {
121 | console.log('🔒 Verbindung zum Server geschlossen.');
122 | clearTimeout(timeout);
123 | });
124 |
125 | client.on('error', (err) => {
126 | console.error('❌ Verbindungsfehler:', err.message);
127 | clearTimeout(timeout);
128 | reject(err);
129 | });
130 | });
131 | }
132 |
133 | // Hauptfunktion
134 | async function main() {
135 | const args = argv;
136 | const parsedArgs = parseArguments(args);
137 | let { serverIp, serverPort, token, groupName } = parsedArgs;
138 |
139 | // Überprüfen, ob alle erforderlichen Parameter vorhanden sind, sonst interaktiv abfragen
140 | if (!serverIp) {
141 | serverIp = await askQuestion('🔗 Bitte gib die Server-IP ein: ');
142 | }
143 | if (!serverPort) {
144 | const portInput = await askQuestion('🔗 Bitte gib den Server-Port ein: ');
145 | serverPort = parseInt(portInput, 10);
146 | }
147 | if (!token) {
148 | token = await askQuestion('🔒 Bitte gib dein Authentifizierungstoken ein: ');
149 | }
150 | if (!groupName) {
151 | groupName = await askQuestion('👥 Bitte gib den Namen der Gruppe ein: ');
152 | }
153 |
154 | const payload = {
155 | command: "delete_group",
156 | token: token,
157 | arguments: {
158 | groupName: groupName
159 | }
160 | };
161 |
162 | try {
163 | console.log('🗑️ Sende Delete-Group-Anfrage...');
164 | const response = await sendDeleteGroupRequest(serverIp, serverPort, token, groupName);
165 | console.log('✔️ Antwort vom Server:', JSON.stringify(response, null, 2));
166 | } catch (err) {
167 | console.error('❌ Fehler:', err.message);
168 | }
169 | }
170 |
171 | main();
172 |
```
--------------------------------------------------------------------------------
/agents/OpenAI_Compatible_API_Agent/Python/openai_compatible_api.py:
--------------------------------------------------------------------------------
```python
1 | import json
2 | from pathlib import Path
3 |
4 | from starlette.responses import StreamingResponse
5 |
6 | from fastapi import FastAPI, Request, HTTPException
7 | from threading import local
8 |
9 | from agents.OpenAI_Compatible_API_Agent.Python.open_ai_helper import ChatInstance, \
10 | ChatCompletionRequest, CompletionRequest, _resp_sync, _resp_async_generator, models, Message, _resp_async_generator_completions, _resp_sync_completions
11 | from .privategpt_api import PrivateGPTAPI
12 |
13 | from ...AgentInterface.Python.config import Config, ConfigError
14 | import uvicorn
15 |
16 | app = FastAPI(title="OpenAI-compatible API for PrivateGPT")
17 | request_context = local()
18 | instances = []
19 |
20 | # Konfiguration laden
21 | try:
22 | config_file = Path.absolute(Path(__file__).parent.parent / "pgpt_openai_api_proxy.json")
23 | config = Config(config_file=config_file, required_fields=["base_url"])
24 | default_groups = config.get("groups", [])
25 | except ConfigError as e:
26 | print(f"Configuration Error: {e}")
27 | exit(1)
28 |
29 |
30 |
31 | @app.middleware("http")
32 | async def store_request_headers(request: Request, call_next):
33 | request_context.headers = dict(request.headers)
34 | response = await call_next(request)
35 | return response
36 |
37 |
38 | @app.post("/chat/completions")
39 | async def chat_completions(request: ChatCompletionRequest):
40 | headers = getattr(request_context, "headers", {})
41 | client_api_key = str(headers['authorization']).split(" ")[1]
42 | groups = default_groups
43 | force_new_session = False
44 |
45 | if request.groups:
46 | groups = request.groups
47 | if request.newSession:
48 | force_new_session = True
49 |
50 | print("Groups: " + str(groups))
51 |
52 | if request.messages:
53 | #Check if this api-key already has a running instance
54 | indices = [i for i, x in enumerate(instances) if
55 | x.api_key == client_api_key]
56 | index = -1
57 | if len(indices) > 0:
58 | index = indices[0]
59 | if index > -1:
60 | # if we already have an instance, just reuse it. No need to open new connection
61 | if instances[index].agent.chosen_groups != groups:
62 | print("⚠️ New Groups requested, switching to new Chat..")
63 | config.set_value("groups", groups)
64 | instances[index].agent.chat_id = None
65 | elif force_new_session:
66 | print("⚠️ New Session Requested, switching to new Chat..")
67 | config.set_value("groups", groups)
68 | instances[index].agent.chat_id = None
69 |
70 | pgpt = instances[index].agent
71 |
72 | else:
73 | #otherwise connect via api-key
74 | config.set_value("groups", groups)
75 | pgpt = PrivateGPTAPI(config, client_api_key=client_api_key)
76 | # remember that we already have an instance for the api key
77 | instance = ChatInstance(client_api_key, pgpt)
78 | instances.append(instance)
79 |
80 | if pgpt.logged_in:
81 | response = pgpt.respond_with_context(request.messages, request.response_format, request.tools)
82 | if response is not None:
83 | if "answer" not in response:
84 | response["answer"] = "No Response received"
85 | if response is None or ("answer" in response and response["answer"] == "error"):
86 | pgpt.login()
87 | else:
88 | response = {
89 | "chatId": "0",
90 | "answer": "API Key not valid",
91 | }
92 | else:
93 | response = {
94 | "chatId": "0",
95 | "answer": "No Input given",
96 | }
97 |
98 | if request.stream:
99 | return StreamingResponse(
100 | _resp_async_generator(response, request), media_type="application/x-ndjson"
101 | )
102 | else:
103 | return _resp_sync(response, request)
104 |
105 |
106 | # legacy completions API
107 | @app.post("/completions")
108 | async def completions(request: CompletionRequest):
109 | headers = getattr(request_context, "headers", {})
110 | client_api_key = str(headers['authorization']).split(" ")[1]
111 | groups = default_groups
112 | if request.groups:
113 | groups = request.groups
114 | print("Groups: " + str(groups))
115 | if request.prompt:
116 |
117 | #otherwise connect via api-key
118 | config.set_value("groups", groups)
119 | pgpt = PrivateGPTAPI(config, client_api_key=client_api_key)
120 | # remember that we already have an instance for the api key
121 |
122 | if pgpt.logged_in:
123 | response = pgpt.respond_with_context([Message(role="user", content=request.prompt)], request.response_format, request.tools)
124 |
125 | if "answer" not in response:
126 | response["answer"] = "No Response received"
127 | if "answer" in response and response["answer"] == "error":
128 | if pgpt.login():
129 | pgpt.create_chat()
130 | else:
131 | response = {
132 | "chatId": "0",
133 | "answer": "API Key not valid",
134 | }
135 | else:
136 | response = {
137 | "chatId": "0",
138 | "answer": "No Input given",
139 | }
140 |
141 | if request.stream :
142 | return StreamingResponse(
143 | _resp_async_generator_completions(response, request), media_type="application/x-ndjson"
144 | )
145 | else:
146 | return _resp_sync_completions(response, request)
147 |
148 |
149 |
150 | @app.get("/models")
151 | def return_models():
152 | return {
153 | "object": "list",
154 | "data": models
155 | }
156 |
157 |
158 | @app.get('/models/{model_id}')
159 | async def get_model(model_id: str):
160 | filtered_entries = list(filter(lambda item: item["id"] == model_id, models))
161 | entry = filtered_entries[0] if filtered_entries else None
162 | print(entry)
163 | if entry is None:
164 | raise HTTPException(status_code=404, detail="Model not found")
165 | return entry
166 |
167 |
168 | if __name__ == "__main__":
169 | api_ip = config.get("api_ip", "0.0.0.0")
170 | api_port = config.get("api_port", 8001)
171 | uvicorn.run(app, host=api_ip, port=int(api_port))
172 |
173 |
174 |
175 |
```
--------------------------------------------------------------------------------
/agents/ChatBotAgent/html/index.html:
--------------------------------------------------------------------------------
```html
1 | <!DOCTYPE html>
2 | <html lang="de">
3 | <head>
4 | <meta charset="UTF-8">
5 | <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 | <title>ChatBot Agent Interface</title>
7 | <style>
8 | body {
9 | font-family: Arial, sans-serif;
10 | margin: 20px;
11 | padding: 0;
12 | background-color: #f4f4f9;
13 | }
14 | .container {
15 | max-width: 600px;
16 | margin: 0 auto;
17 | background: white;
18 | padding: 20px;
19 | border-radius: 8px;
20 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
21 | text-align: center; /* Zentriert den Inhalt */
22 | }
23 | .logo {
24 | display: block;
25 | margin: 0 auto 20px; /* Zentriert das Logo und fügt Abstand ein */
26 | width: 150px;
27 | height: auto;
28 | }
29 | h1 {
30 | text-align: center;
31 | color: #333;
32 | }
33 | textarea, select, input, button {
34 | width: 100%;
35 | margin: 10px 0;
36 | padding: 10px;
37 | font-size: 16px;
38 | border: 1px solid #ccc;
39 | border-radius: 5px;
40 | box-sizing: border-box;
41 | }
42 | button {
43 | background-color: #007BFF;
44 | color: white;
45 | border: none;
46 | cursor: pointer;
47 | font-size: 16px;
48 | }
49 | button:hover {
50 | background-color: #0056b3;
51 | }
52 | .response-box {
53 | margin-top: 20px;
54 | padding: 15px;
55 | border: 1px solid #ccc;
56 | border-radius: 5px;
57 | background-color: #f9f9f9;
58 | white-space: pre-wrap;
59 | font-family: monospace;
60 | }
61 | </style>
62 | </head>
63 | <body>
64 | <div class="container">
65 | <!-- Logo einfügen -->
66 | <img src="Logo_light.svg" alt="Logo" class="logo">
67 |
68 | <h1>ChatBot Agent</h1>
69 |
70 | <form id="queryForm">
71 | <label for="question">Question:</label>
72 | <textarea id="question" rows="3" placeholder="Enter your question here..." required></textarea>
73 |
74 | <label for="language">Language:</label>
75 | <select id="language">
76 | <option value="en" selected>English</option>
77 | <option value="de">German</option>
78 | </select>
79 |
80 | <label for="groups">Groups (optional, separated by commas):</label>
81 | <input type="text" id="groups" placeholder="Example: Group1, Group2">
82 |
83 | <label>
84 | <input type="checkbox" id="usePublic" checked>
85 | Use general knowledge
86 | </label>
87 |
88 | <button type="submit">Send Request</button>
89 | </form>
90 |
91 | <div class="response-box" id="responseBox">
92 | The response will be displayed here...
93 | </div>
94 | </div>
95 |
96 | <script>
97 | const apiUrl = "http://127.0.0.1:5001/ask"; // URL der API
98 | const apiKey = "IhrSichererAPIKey123"; // API-Key
99 |
100 | document.getElementById("queryForm").addEventListener("submit", async function(event) {
101 | event.preventDefault();
102 |
103 | // Eingaben aus dem Formular abrufen
104 | const question = document.getElementById("question").value.trim();
105 | const language = document.getElementById("language").value;
106 | const groupsInput = document.getElementById("groups").value;
107 | const groups = groupsInput
108 | .split(",")
109 | .map(group => group.trim())
110 | .filter(group => group); // Leere Gruppen entfernen
111 | const usePublic = document.getElementById("usePublic").checked;
112 |
113 | if (!question) {
114 | alert("Please enter a question.");
115 | return;
116 | }
117 |
118 | // JSON-Body für die Anfrage erstellen
119 | const body = {
120 | question: question,
121 | usePublic: usePublic,
122 | groups: groups,
123 | language: language
124 | };
125 |
126 | // Anzeige der Anfrage im Response-Box (optional)
127 | document.getElementById("responseBox").textContent = "Sending request...";
128 |
129 | // Anfrage senden
130 | try {
131 | const response = await fetch(apiUrl, {
132 | method: "POST",
133 | headers: {
134 | "Content-Type": "application/json",
135 | "X-API-KEY": apiKey // Korrigierter Header
136 | },
137 | body: JSON.stringify(body)
138 | });
139 |
140 | if (response.ok) {
141 | const data = await response.json();
142 |
143 | // Extrahiere das 'answer'-Feld und entferne mögliche Anführungszeichen
144 | let answer = data.answer || "";
145 | if (answer.startsWith('"') && answer.endsWith('"')) {
146 | answer = answer.substring(1, answer.length - 1);
147 | }
148 |
149 | // Optional: Entschlüsselung von Unicode-Zeichen
150 | try {
151 | answer = decodeURIComponent(escape(answer));
152 | } catch (e) {
153 | console.warn("Unicode decoding failed:", e);
154 | }
155 |
156 | // Anzeige der Antwort
157 | document.getElementById("responseBox").textContent = answer;
158 | } else {
159 | // Fehlerbehandlung bei HTTP-Fehlern
160 | const errorText = await response.text();
161 | document.getElementById("responseBox").textContent = `Error: ${response.status} ${response.statusText}\n${errorText}`;
162 | }
163 | } catch (error) {
164 | // Fehlerbehandlung bei Netzwerk- oder anderen Fehlern
165 | document.getElementById("responseBox").textContent = `Request failed: ${error.message}`;
166 | }
167 | });
168 | </script>
169 | </body>
170 | </html>
```
--------------------------------------------------------------------------------
/agents/ChatBotAgent/html/index_de.html:
--------------------------------------------------------------------------------
```html
1 | <!DOCTYPE html>
2 | <html lang="de">
3 | <head>
4 | <meta charset="UTF-8">
5 | <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 | <title>ChatBot Agent Interface</title>
7 | <style>
8 | body {
9 | font-family: Arial, sans-serif;
10 | margin: 20px;
11 | padding: 0;
12 | background-color: #f4f4f9;
13 | }
14 | .container {
15 | max-width: 600px;
16 | margin: 0 auto;
17 | background: white;
18 | padding: 20px;
19 | border-radius: 8px;
20 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
21 | text-align: center; /* Zentriert den Inhalt */
22 | }
23 | .logo {
24 | display: block;
25 | margin: 0 auto 20px; /* Zentriert das Logo und fügt Abstand ein */
26 | width: 150px;
27 | height: auto;
28 | }
29 | h1 {
30 | text-align: center;
31 | color: #333;
32 | }
33 | textarea, select, input, button {
34 | width: 100%;
35 | margin: 10px 0;
36 | padding: 10px;
37 | font-size: 16px;
38 | border: 1px solid #ccc;
39 | border-radius: 5px;
40 | box-sizing: border-box;
41 | }
42 | button {
43 | background-color: #007BFF;
44 | color: white;
45 | border: none;
46 | cursor: pointer;
47 | font-size: 16px;
48 | }
49 | button:hover {
50 | background-color: #0056b3;
51 | }
52 | .response-box {
53 | margin-top: 20px;
54 | padding: 15px;
55 | border: 1px solid #ccc;
56 | border-radius: 5px;
57 | background-color: #f9f9f9;
58 | white-space: pre-wrap;
59 | font-family: monospace;
60 | }
61 | </style>
62 | </head>
63 | <body>
64 | <div class="container">
65 | <!-- Logo einfügen -->
66 | <img src="Logo_light.svg" alt="Logo" class="logo">
67 |
68 | <h1>ChatBot Agent</h1>
69 |
70 | <form id="queryForm">
71 | <label for="question">Frage:</label>
72 | <textarea id="question" rows="3" placeholder="Geben Sie Ihre Frage ein..." required></textarea>
73 |
74 | <label for="language">Sprache:</label>
75 | <select id="language">
76 | <option value="de" selected>Deutsch</option>
77 | <option value="en">Englisch</option>
78 | </select>
79 |
80 | <label for="groups">Gruppen (optional, getrennt durch Kommas):</label>
81 | <input type="text" id="groups" placeholder="Beispiel: Gruppe1, Gruppe2">
82 |
83 | <label>
84 | <input type="checkbox" id="usePublic" checked>
85 | Öffentliche Daten verwenden
86 | </label>
87 |
88 | <button type="submit">Anfrage senden</button>
89 | </form>
90 |
91 | <div class="response-box" id="responseBox">
92 | Antwort wird hier angezeigt...
93 | </div>
94 | </div>
95 |
96 | <script>
97 | const apiUrl = "http://192.168.100.185:5001/ask"; // URL der API
98 | const apiKey = "IhrSichererAPIKey123"; // API-Key
99 |
100 | document.getElementById("queryForm").addEventListener("submit", async function(event) {
101 | event.preventDefault();
102 |
103 | // Eingaben aus dem Formular abrufen
104 | const question = document.getElementById("question").value.trim();
105 | const language = document.getElementById("language").value;
106 | const groupsInput = document.getElementById("groups").value;
107 | const groups = groupsInput
108 | .split(",")
109 | .map(group => group.trim())
110 | .filter(group => group); // Leere Gruppen entfernen
111 | const usePublic = document.getElementById("usePublic").checked;
112 |
113 | if (!question) {
114 | alert("Bitte geben Sie eine Frage ein.");
115 | return;
116 | }
117 |
118 | // JSON-Body für die Anfrage erstellen
119 | const body = {
120 | question: question,
121 | usePublic: usePublic,
122 | groups: groups,
123 | language: language
124 | };
125 |
126 | // Anzeige der Anfrage im Response-Box (optional)
127 | document.getElementById("responseBox").textContent = "Anfrage wird gesendet...";
128 |
129 | // Anfrage senden
130 | try {
131 | const response = await fetch(apiUrl, {
132 | method: "POST",
133 | headers: {
134 | "Content-Type": "application/json",
135 | "X-API-KEY": apiKey // Korrigierter Header
136 | },
137 | body: JSON.stringify(body)
138 | });
139 |
140 | if (response.ok) {
141 | const data = await response.json();
142 |
143 | // Extrahiere das 'answer'-Feld und entferne mögliche Anführungszeichen
144 | let answer = data.answer || "";
145 | if (answer.startsWith('"') && answer.endsWith('"')) {
146 | answer = answer.substring(1, answer.length - 1);
147 | }
148 |
149 | // Optional: Entschlüsselung von Unicode-Zeichen
150 | try {
151 | answer = decodeURIComponent(escape(answer));
152 | } catch (e) {
153 | console.warn("Unicode-Entschlüsselung fehlgeschlagen:", e);
154 | }
155 |
156 | // Anzeige der Antwort
157 | document.getElementById("responseBox").textContent = answer;
158 | } else {
159 | // Fehlerbehandlung bei HTTP-Fehlern
160 | const errorText = await response.text();
161 | document.getElementById("responseBox").textContent = `Fehler: ${response.status} ${response.statusText}\n${errorText}`;
162 | }
163 | } catch (error) {
164 | // Fehlerbehandlung bei Netzwerk- oder anderen Fehlern
165 | document.getElementById("responseBox").textContent = `Fehler bei der Anfrage: ${error.message}`;
166 | }
167 | });
168 | </script>
169 | </body>
170 | </html>
171 |
```
--------------------------------------------------------------------------------
/clients/Java/3.3 mcp_edit_source/MCPEditSourceClient.java:
--------------------------------------------------------------------------------
```java
1 | import org.json.JSONArray;
2 | import org.json.JSONObject;
3 |
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 | import java.net.Socket;
8 | import java.nio.charset.StandardCharsets;
9 | import java.util.ArrayList;
10 | import java.util.Arrays;
11 | import java.util.List;
12 |
13 | public class MCPEditSourceClient {
14 |
15 | public static void main(String[] args) {
16 | // Mindestens 8 Strings im Array erforderlich, z.B.:
17 | // --server-ip 127.0.0.1 --server-port 1234 --token X --source-id Y
18 | // plus optionale: --title "..." --content "..." --groups ...
19 | if (args.length < 8) {
20 | printUsage();
21 | return;
22 | }
23 |
24 | // Argumente einlesen
25 | String serverIp = getArgument(args, "--server-ip");
26 | String portStr = getArgument(args, "--server-port");
27 | String token = getArgument(args, "--token");
28 | String sourceId = getArgument(args, "--source-id");
29 | String title = getArgument(args, "--title");
30 | String content = getArgument(args, "--content");
31 | List<String> groups = getListArgument(args, "--groups");
32 |
33 | // Prüfung auf null
34 | if (serverIp == null || portStr == null || token == null || sourceId == null) {
35 | System.out.println("Fehler: Mindestens eines der Pflichtargumente fehlt.");
36 | return;
37 | }
38 |
39 | // Port in int umwandeln
40 | int serverPort;
41 | try {
42 | serverPort = Integer.parseInt(portStr);
43 | } catch (NumberFormatException e) {
44 | System.out.println("Fehler: --server-port muss eine ganzzahlige Portangabe sein.");
45 | return;
46 | }
47 |
48 | System.out.println("📤 Sende Anfrage zum Editieren einer Quelle...");
49 |
50 | // Anfrage an den Server senden
51 | String response = sendEditSourceRequest(serverIp, serverPort, token, sourceId, title, content, groups);
52 |
53 | // Antwort ausgeben
54 | System.out.println("Response from server:");
55 | System.out.println(response);
56 | }
57 |
58 | /**
59 | * Baut die Payload für die "edit_source"-Anfrage zusammen und sendet sie über TCP.
60 | */
61 | private static String sendEditSourceRequest(
62 | String serverIp,
63 | int serverPort,
64 | String token,
65 | String sourceId,
66 | String title,
67 | String content,
68 | List<String> groups
69 | ) {
70 | // Arguments-Objekt erstellen
71 | JSONObject arguments = new JSONObject();
72 | arguments.put("sourceId", sourceId);
73 |
74 | if (title != null && !title.trim().isEmpty()) {
75 | arguments.put("title", title);
76 | }
77 |
78 | if (content != null && !content.trim().isEmpty()) {
79 | arguments.put("content", content);
80 | }
81 |
82 | // Gruppen (falls keine übergeben, bleibt es einfach eine leere Liste)
83 | if (groups == null) {
84 | groups = new ArrayList<>();
85 | }
86 | JSONArray groupsArray = new JSONArray(groups);
87 | arguments.put("groups", groupsArray);
88 |
89 | // Gesamte Payload
90 | JSONObject payload = new JSONObject();
91 | payload.put("command", "edit_source");
92 | payload.put("token", token);
93 | payload.put("arguments", arguments);
94 |
95 | // JSON in String umwandeln
96 | String payloadJson = payload.toString();
97 |
98 | // TCP-Verbindung aufbauen und senden
99 | try (Socket client = new Socket(serverIp, serverPort)) {
100 | // Senden
101 | OutputStream out = client.getOutputStream();
102 | byte[] data = payloadJson.getBytes(StandardCharsets.UTF_8);
103 | out.write(data);
104 | out.flush();
105 |
106 | // Antwort empfangen
107 | InputStream in = client.getInputStream();
108 | byte[] buffer = new byte[4096];
109 | StringBuilder responseBuilder = new StringBuilder();
110 |
111 | int bytesRead;
112 | do {
113 | bytesRead = in.read(buffer);
114 | if (bytesRead > 0) {
115 | responseBuilder.append(new String(buffer, 0, bytesRead, StandardCharsets.UTF_8));
116 | }
117 | } while (bytesRead == buffer.length);
118 |
119 | return responseBuilder.toString();
120 |
121 | } catch (IOException e) {
122 | return "Error: " + e.getMessage();
123 | }
124 | }
125 |
126 | /**
127 | * Liest den Wert für ein bestimmtes Argument aus (z.B. --server-ip 127.0.0.1).
128 | */
129 | private static String getArgument(String[] args, String key) {
130 | for (int i = 0; i < args.length - 1; i++) {
131 | if (args[i].equals(key)) {
132 | return args[i + 1];
133 | }
134 | }
135 | return null;
136 | }
137 |
138 | /**
139 | * Liest eine Liste von Werten aus (z.B. --groups G1 G2 G3 ...), bis zum nächsten -- oder Ende.
140 | */
141 | private static List<String> getListArgument(String[] args, String key) {
142 | List<String> result = new ArrayList<>();
143 | for (int i = 0; i < args.length; i++) {
144 | if (args[i].equals(key)) {
145 | // Ab hier Werte einsammeln
146 | for (int j = i + 1; j < args.length; j++) {
147 | if (args[j].startsWith("--")) {
148 | break;
149 | }
150 | result.add(args[j]);
151 | }
152 | break;
153 | }
154 | }
155 | return result;
156 | }
157 |
158 | private static void printUsage() {
159 | System.out.println("Usage:");
160 | System.out.println(" --server-ip <IP> --server-port <PORT> --token <TOKEN> --source-id <SOURCE_ID>");
161 | System.out.println(" [--title <TITLE>] [--content <CONTENT>] [--groups <LIST_OF_GROUPS>]");
162 | System.out.println();
163 | System.out.println("Example:");
164 | System.out.println(" java -cp .;json-20241224.jar MCPEditSourceClient \\");
165 | System.out.println(" --server-ip 127.0.0.1 --server-port 1234 --token SomeToken --source-id 456 \\");
166 | System.out.println(" --title \"Neuer Titel\" --content \"Neuer Inhalt...\" --groups DevOps Finance");
167 | }
168 | }
169 |
```
--------------------------------------------------------------------------------
/clients/PHP/9.0 mcp_keygen/MCPKeygenClient.php:
--------------------------------------------------------------------------------
```php
1 | <?php
2 | /**
3 | * MCPKeygenClient.php
4 | *
5 | * A PHP script that acts as a Keygen Client. It connects to a server via TCP,
6 | * sends a keygen request, and receives the server's response.
7 | *
8 | * Usage:
9 | * php MCPKeygenClient.php --server-ip <IP> --server-port <Port> --token <Token> --password <Password>
10 | */
11 |
12 | /**
13 | * Function to parse command line arguments
14 | *
15 | * @param array $args The command line arguments
16 | * @return array An associative array with the parsed arguments
17 | */
18 | function parseArguments($args) {
19 | $parsedArgs = [];
20 | $argc = count($args);
21 | for ($i = 1; $i < $argc; $i++) {
22 | switch ($args[$i]) {
23 | case '--server-ip':
24 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
25 | $parsedArgs['serverIp'] = $args[++$i];
26 | } else {
27 | fwrite(STDERR, "⚠️ Warning: No value provided for --server-ip.\n");
28 | }
29 | break;
30 | case '--server-port':
31 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
32 | $parsedArgs['serverPort'] = intval($args[++$i]);
33 | } else {
34 | fwrite(STDERR, "⚠️ Warning: No value provided for --server-port.\n");
35 | }
36 | break;
37 | case '--token':
38 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
39 | $parsedArgs['token'] = $args[++$i];
40 | } else {
41 | fwrite(STDERR, "⚠️ Warning: No value provided for --token.\n");
42 | }
43 | break;
44 | case '--password':
45 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
46 | $parsedArgs['password'] = $args[++$i];
47 | } else {
48 | fwrite(STDERR, "⚠️ Warning: No value provided for --password.\n");
49 | }
50 | break;
51 | default:
52 | fwrite(STDERR, "⚠️ Warning: Unknown argument: {$args[$i]}\n");
53 | }
54 | }
55 | return $parsedArgs;
56 | }
57 |
58 | /**
59 | * Helper function to check if a string starts with a specific prefix
60 | *
61 | * @param string $string The string to check
62 | * @param string $prefix The prefix
63 | * @return bool True if the string starts with the prefix, otherwise False
64 | */
65 | function startsWith($string, $prefix) {
66 | return substr($string, 0, strlen($prefix)) === $prefix;
67 | }
68 |
69 | /**
70 | * Function to send a Keygen request over a TCP connection
71 | *
72 | * @param string $serverIp The server's IP address
73 | * @param int $serverPort The server's port
74 | * @param string $token The authentication token
75 | * @param string $password The password for key generation
76 | * @return array The response received from the server as an associative array
77 | * @throws Exception On connection errors or JSON parsing errors
78 | */
79 | function sendKeygenRequest($serverIp, $serverPort, $token, $password) {
80 | $payload = [
81 | "command" => "keygen",
82 | "token" => $token,
83 | "arguments" => [
84 | "password" => $password
85 | ]
86 | ];
87 |
88 | $jsonPayload = json_encode($payload);
89 | if ($jsonPayload === false) {
90 | throw new Exception("Error encoding JSON payload: " . json_last_error_msg());
91 | }
92 |
93 | $errno = 0;
94 | $errstr = '';
95 | $timeoutDuration = 10; // Seconds (10 seconds timeout)
96 | $client = @fsockopen($serverIp, $serverPort, $errno, $errstr, $timeoutDuration);
97 |
98 | if (!$client) {
99 | throw new Exception("Connection error: $errstr ($errno)");
100 | }
101 |
102 | echo "🔗 Connected to server ({$serverIp}:{$serverPort}).\n";
103 | echo "📤 Sending Payload: {$jsonPayload}\n";
104 |
105 | fwrite($client, $jsonPayload);
106 |
107 | $responseData = '';
108 | stream_set_timeout($client, $timeoutDuration);
109 |
110 | while (!feof($client)) {
111 | $data = fread($client, 1024);
112 | if ($data === false) {
113 | throw new Exception("Error reading data from server.");
114 | }
115 | if ($data === '') {
116 | break; // No more data
117 | }
118 | echo "📥 Received data: {$data}\n";
119 | $responseData .= $data;
120 |
121 | // Attempt to parse the received data as JSON
122 | $parsedData = json_decode($responseData, true);
123 | if ($parsedData !== null) {
124 | echo "✅ JSON response successfully parsed.\n";
125 | fclose($client);
126 | return $parsedData;
127 | }
128 |
129 | // Check if the stream has timed out
130 | $info = stream_get_meta_data($client);
131 | if ($info['timed_out']) {
132 | throw new Exception("Timeout while waiting for data from server.");
133 | }
134 | }
135 |
136 | fclose($client);
137 | throw new Exception("Connection to server was closed before a complete response was received.");
138 | }
139 |
140 | /**
141 | * Main function of the script
142 | */
143 | function main($argv) {
144 | $parsedArgs = parseArguments($argv);
145 | $serverIp = $parsedArgs['serverIp'] ?? null;
146 | $serverPort = $parsedArgs['serverPort'] ?? null;
147 | $token = $parsedArgs['token'] ?? null;
148 | $password = $parsedArgs['password'] ?? null;
149 |
150 | // Check if all required parameters are present
151 | if (!$serverIp || !$serverPort || !$token || !$password) {
152 | fwrite(STDERR, "❌ Error: --server-ip, --server-port, --token, and --password are required.\n");
153 | fwrite(STDOUT, "📖 Usage: php MCPKeygenClient.php --server-ip <IP> --server-port <Port> --token <Token> --password <Password>\n");
154 | exit(1);
155 | }
156 |
157 | try {
158 | echo "🔑 Sending Keygen request...\n";
159 | $response = sendKeygenRequest(
160 | $serverIp,
161 | $serverPort,
162 | $token,
163 | $password
164 | );
165 | echo "✔️ Server response:\n";
166 | echo json_encode($response, JSON_PRETTY_PRINT) . "\n";
167 | } catch (Exception $e) {
168 | fwrite(STDERR, "❌ Error during Keygen request: " . $e->getMessage() . "\n");
169 | }
170 | }
171 |
172 | // Check if PHP version is at least 7.1 (for better features)
173 | if (version_compare(PHP_VERSION, '7.1.0') < 0) {
174 | fwrite(STDERR, "❌ ERROR: This script requires PHP version 7.1 or higher.\n");
175 | exit(1);
176 | }
177 |
178 | // Call the main function
179 | main($argv);
180 | ?>
181 |
```
--------------------------------------------------------------------------------
/clients/JavaScript/5.2 mcp_delete_user/MCPDeleteUserClient.js:
--------------------------------------------------------------------------------
```javascript
1 | <?php
2 | /**
3 | * MCPDeleteUserClient.php
4 | *
5 | * A PHP script that acts as a Delete User Client. It connects to a server via TCP,
6 | * sends a request to delete an existing user, and receives the server's response.
7 | *
8 | * Usage:
9 | * php MCPDeleteUserClient.php --server-ip <IP> --server-port <Port> --email <Email> --token <Token>
10 | */
11 |
12 | /**
13 | * Function to parse command line arguments
14 | *
15 | * @param array $args Array of command line arguments
16 | * @return array Associative array with parsed arguments
17 | */
18 | function parseArguments($args) {
19 | $parsedArgs = [];
20 | $argc = count($args);
21 | for ($i = 1; $i < $argc; $i++) {
22 | switch ($args[$i]) {
23 | case '--server-ip':
24 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
25 | $parsedArgs['serverIp'] = $args[++$i];
26 | } else {
27 | fwrite(STDERR, "⚠️ Warning: No value provided for --server-ip.\n");
28 | }
29 | break;
30 | case '--server-port':
31 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
32 | $parsedArgs['serverPort'] = intval($args[++$i]);
33 | } else {
34 | fwrite(STDERR, "⚠️ Warning: No value provided for --server-port.\n");
35 | }
36 | break;
37 | case '--email':
38 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
39 | $parsedArgs['email'] = $args[++$i];
40 | } else {
41 | fwrite(STDERR, "⚠️ Warning: No value provided for --email.\n");
42 | }
43 | break;
44 | case '--token':
45 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
46 | $parsedArgs['token'] = $args[++$i];
47 | } else {
48 | fwrite(STDERR, "⚠️ Warning: No value provided for --token.\n");
49 | }
50 | break;
51 | default:
52 | fwrite(STDERR, "⚠️ Warning: Unknown argument: {$args[$i]}\n");
53 | }
54 | }
55 | return $parsedArgs;
56 | }
57 |
58 | /**
59 | * Helper function to check if a string starts with a specific prefix
60 | *
61 | * @param string $string The string to check
62 | * @param string $prefix The prefix
63 | * @return bool True if the string starts with the prefix, otherwise False
64 | */
65 | function startsWith($string, $prefix) {
66 | return substr($string, 0, strlen($prefix)) === $prefix;
67 | }
68 |
69 | /**
70 | * Function to send a Delete User request over a TCP connection
71 | *
72 | * @param string $serverIp The server's IP address
73 | * @param int $serverPort The server's port
74 | * @param string $email The email of the user to be deleted
75 | * @param string $token The authentication token
76 | * @return array The response received from the server as an associative array
77 | * @throws Exception On connection errors or JSON parsing errors
78 | */
79 | function sendDeleteUserRequest($serverIp, $serverPort, $email, $token) {
80 | $payload = [
81 | "command" => "delete_user",
82 | "token" => $token,
83 | "arguments" => [
84 | "email" => $email
85 | ]
86 | ];
87 |
88 | $jsonPayload = json_encode($payload);
89 | if ($jsonPayload === false) {
90 | throw new Exception("Error while encoding the JSON payload: " . json_last_error_msg());
91 | }
92 |
93 | $errno = 0;
94 | $errstr = '';
95 | $timeoutDuration = 10; // Seconds (10 seconds timeout)
96 | $client = @fsockopen($serverIp, $serverPort, $errno, $errstr, $timeoutDuration);
97 |
98 | if (!$client) {
99 | throw new Exception("Connection error: $errstr ($errno)");
100 | }
101 |
102 | echo "🔗 Connected to server ({$serverIp}:{$serverPort}).\n";
103 | echo "📤 Sending Payload: {$jsonPayload}\n";
104 |
105 | fwrite($client, $jsonPayload);
106 |
107 | $responseData = '';
108 | stream_set_timeout($client, $timeoutDuration);
109 |
110 | while (!feof($client)) {
111 | $data = fread($client, 1024);
112 | if ($data === false) {
113 | throw new Exception("Error reading data from server.");
114 | }
115 | if ($data === '') {
116 | break; // No more data
117 | }
118 | echo "📥 Received data: {$data}\n";
119 | $responseData .= $data;
120 |
121 | // Attempt to parse the received data as JSON
122 | $parsedData = json_decode($responseData, true);
123 | if ($parsedData !== null) {
124 | echo "✅ JSON response successfully parsed.\n";
125 | fclose($client);
126 | return $parsedData;
127 | }
128 |
129 | // Check if the stream has timed out
130 | $info = stream_get_meta_data($client);
131 | if ($info['timed_out']) {
132 | throw new Exception("Timeout while waiting for data from server.");
133 | }
134 | }
135 |
136 | fclose($client);
137 | throw new Exception("Connection to server was closed before a complete response was received.");
138 | }
139 |
140 | /**
141 | * Main function of the script
142 | */
143 | function main($argv) {
144 | $parsedArgs = parseArguments($argv);
145 | $serverIp = $parsedArgs['serverIp'] ?? null;
146 | $serverPort = $parsedArgs['serverPort'] ?? null;
147 | $email = $parsedArgs['email'] ?? null;
148 | $token = $parsedArgs['token'] ?? null;
149 |
150 | // Check if all required parameters are present
151 | if (!$serverIp || !$serverPort || !$email || !$token) {
152 | fwrite(STDERR, "❌ ERROR: --server-ip, --server-port, --email, and --token are required.\n");
153 | fwrite(STDOUT, "📖 Example: php MCPDeleteUserClient.php --server-ip 192.168.0.1 --server-port 5000 --email [email protected] --token YOUR_AUTH_TOKEN\n");
154 | exit(1);
155 | }
156 |
157 | try {
158 | echo "🗑️ Sending Delete-User request...\n";
159 | $response = sendDeleteUserRequest(
160 | $serverIp,
161 | $serverPort,
162 | $email,
163 | $token
164 | );
165 | echo "✔️ Server response:\n";
166 | echo json_encode($response, JSON_PRETTY_PRINT) . "\n";
167 | } catch (Exception $e) {
168 | fwrite(STDERR, "❌ Error deleting user: " . $e->getMessage() . "\n");
169 | }
170 | }
171 |
172 | // Check if PHP version is at least 7.1 (for better features)
173 | if (version_compare(PHP_VERSION, '7.1.0') < 0) {
174 | fwrite(STDERR, "❌ ERROR: This script requires PHP version 7.1 or higher.\n");
175 | exit(1);
176 | }
177 |
178 | // Call the main function
179 | main($argv);
180 | ?>
181 |
```
--------------------------------------------------------------------------------
/clients/PHP/5.2 mcp_delete_user/MCPDeleteUserClient.php:
--------------------------------------------------------------------------------
```php
1 | <?php
2 | /**
3 | * MCPDeleteUserClient.php
4 | *
5 | * A PHP script that acts as a Delete User Client. It connects to a server via TCP,
6 | * sends a request to delete an existing user, and receives the server's response.
7 | *
8 | * Usage:
9 | * php MCPDeleteUserClient.php --server-ip <IP> --server-port <Port> --email <Email> --token <Token>
10 | */
11 |
12 | /**
13 | * Function to parse command line arguments
14 | *
15 | * @param array $args Array of command line arguments
16 | * @return array Associative array with parsed arguments
17 | */
18 | function parseArguments($args) {
19 | $parsedArgs = [];
20 | $argc = count($args);
21 | for ($i = 1; $i < $argc; $i++) {
22 | switch ($args[$i]) {
23 | case '--server-ip':
24 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
25 | $parsedArgs['serverIp'] = $args[++$i];
26 | } else {
27 | fwrite(STDERR, "⚠️ Warning: No value provided for --server-ip.\n");
28 | }
29 | break;
30 | case '--server-port':
31 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
32 | $parsedArgs['serverPort'] = intval($args[++$i]);
33 | } else {
34 | fwrite(STDERR, "⚠️ Warning: No value provided for --server-port.\n");
35 | }
36 | break;
37 | case '--email':
38 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
39 | $parsedArgs['email'] = $args[++$i];
40 | } else {
41 | fwrite(STDERR, "⚠️ Warning: No value provided for --email.\n");
42 | }
43 | break;
44 | case '--token':
45 | if (isset($args[$i + 1]) && !startsWith($args[$i + 1], '--')) {
46 | $parsedArgs['token'] = $args[++$i];
47 | } else {
48 | fwrite(STDERR, "⚠️ Warning: No value provided for --token.\n");
49 | }
50 | break;
51 | default:
52 | fwrite(STDERR, "⚠️ Warning: Unknown argument: {$args[$i]}\n");
53 | }
54 | }
55 | return $parsedArgs;
56 | }
57 |
58 | /**
59 | * Helper function to check if a string starts with a specific prefix
60 | *
61 | * @param string $string The string to check
62 | * @param string $prefix The prefix
63 | * @return bool True if the string starts with the prefix, otherwise False
64 | */
65 | function startsWith($string, $prefix) {
66 | return substr($string, 0, strlen($prefix)) === $prefix;
67 | }
68 |
69 | /**
70 | * Function to send a Delete User request over a TCP connection
71 | *
72 | * @param string $serverIp The server's IP address
73 | * @param int $serverPort The server's port
74 | * @param string $email The email of the user to be deleted
75 | * @param string $token The authentication token
76 | * @return array The response received from the server as an associative array
77 | * @throws Exception On connection errors or JSON parsing errors
78 | */
79 | function sendDeleteUserRequest($serverIp, $serverPort, $email, $token) {
80 | $payload = [
81 | "command" => "delete_user",
82 | "token" => $token,
83 | "arguments" => [
84 | "email" => $email
85 | ]
86 | ];
87 |
88 | $jsonPayload = json_encode($payload);
89 | if ($jsonPayload === false) {
90 | throw new Exception("Error while encoding the JSON payload: " . json_last_error_msg());
91 | }
92 |
93 | $errno = 0;
94 | $errstr = '';
95 | $timeoutDuration = 10; // Seconds (10 seconds timeout)
96 | $client = @fsockopen($serverIp, $serverPort, $errno, $errstr, $timeoutDuration);
97 |
98 | if (!$client) {
99 | throw new Exception("Connection error: $errstr ($errno)");
100 | }
101 |
102 | echo "🔗 Connected to server ({$serverIp}:{$serverPort}).\n";
103 | echo "📤 Sending Payload: {$jsonPayload}\n";
104 |
105 | fwrite($client, $jsonPayload);
106 |
107 | $responseData = '';
108 | stream_set_timeout($client, $timeoutDuration);
109 |
110 | while (!feof($client)) {
111 | $data = fread($client, 1024);
112 | if ($data === false) {
113 | throw new Exception("Error reading data from server.");
114 | }
115 | if ($data === '') {
116 | break; // No more data
117 | }
118 | echo "📥 Received data: {$data}\n";
119 | $responseData .= $data;
120 |
121 | // Attempt to parse the received data as JSON
122 | $parsedData = json_decode($responseData, true);
123 | if ($parsedData !== null) {
124 | echo "✅ JSON response successfully parsed.\n";
125 | fclose($client);
126 | return $parsedData;
127 | }
128 |
129 | // Check if the stream has timed out
130 | $info = stream_get_meta_data($client);
131 | if ($info['timed_out']) {
132 | throw new Exception("Timeout while waiting for data from server.");
133 | }
134 | }
135 |
136 | fclose($client);
137 | throw new Exception("Connection to server was closed before a complete response was received.");
138 | }
139 |
140 | /**
141 | * Main function of the script
142 | */
143 | function main($argv) {
144 | $parsedArgs = parseArguments($argv);
145 | $serverIp = $parsedArgs['serverIp'] ?? null;
146 | $serverPort = $parsedArgs['serverPort'] ?? null;
147 | $email = $parsedArgs['email'] ?? null;
148 | $token = $parsedArgs['token'] ?? null;
149 |
150 | // Check if all required parameters are present
151 | if (!$serverIp || !$serverPort || !$email || !$token) {
152 | fwrite(STDERR, "❌ ERROR: --server-ip, --server-port, --email, and --token are required.\n");
153 | fwrite(STDOUT, "📖 Example: php MCPDeleteUserClient.php --server-ip 192.168.0.1 --server-port 5000 --email [email protected] --token YOUR_AUTH_TOKEN\n");
154 | exit(1);
155 | }
156 |
157 | try {
158 | echo "🗑️ Sending Delete-User request...\n";
159 | $response = sendDeleteUserRequest(
160 | $serverIp,
161 | $serverPort,
162 | $email,
163 | $token
164 | );
165 | echo "✔️ Server response:\n";
166 | echo json_encode($response, JSON_PRETTY_PRINT) . "\n";
167 | } catch (Exception $e) {
168 | fwrite(STDERR, "❌ Error deleting user: " . $e->getMessage() . "\n");
169 | }
170 | }
171 |
172 | // Check if PHP version is at least 7.1 (for better features)
173 | if (version_compare(PHP_VERSION, '7.1.0') < 0) {
174 | fwrite(STDERR, "❌ ERROR: This script requires PHP version 7.1 or higher.\n");
175 | exit(1);
176 | }
177 |
178 | // Call the main function
179 | main($argv);
180 | ?>
181 |
```