From b2fde60eeea5ac1e980309d909412463d4465b8d Mon Sep 17 00:00:00 2001 From: defiQUG Date: Tue, 21 Apr 2026 22:00:54 -0700 Subject: [PATCH] chore: mcp-proxmox README and index updates Made-with: Cursor --- README.md | 7 +++++-- index.js | 15 +++++++++++++-- src/proxmox_mcp/utils/auth.py | 23 ++++++++++++++++++++++- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a3d1f40..5899ff8 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ Before starting, ensure you have: 3. Add your Proxmox configuration to `.env`: ```bash # Proxmox Configuration (REQUIRED) - PROXMOX_HOST=your-proxmox-ip-or-hostname + PROXMOX_HOST=proxmox-api.d-bis.org PROXMOX_USER=root@pam PROXMOX_TOKEN_NAME=your-token-name PROXMOX_TOKEN_VALUE=your-token-secret-here @@ -101,6 +101,7 @@ Before starting, ensure you have: - `PROXMOX_TOKEN_VALUE` is REQUIRED - there is no default value - `PROXMOX_HOST` defaults to `192.168.6.247` if not specified (change this!) - `PROXMOX_TOKEN_NAME` defaults to `mcpserver` if not specified + - `PROXMOX_TOKEN_NAME` may be either the bare token name or the full token id (`user@realm!token-name`); the server handles both **⚠️ Security Warning**: - `PROXMOX_ALLOW_ELEVATED=false` is the SAFE default - only read operations allowed @@ -164,9 +165,11 @@ Before starting, ensure you have: - **Privilege Separation**: Uncheck for full access or leave checked for limited permissions - Click **Add** 4. **Important**: Copy both the **Token ID** and **Secret** immediately (secret is only shown once) - - Use Token ID as `PROXMOX_TOKEN_NAME` + - Use the bare Token ID as `PROXMOX_TOKEN_NAME` - Use Secret as `PROXMOX_TOKEN_VALUE` +If your secret store already holds the full token id (for example `root@pam!mcp-server`) in `PROXMOX_TOKEN_NAME`, the server will normalize it automatically. + **Permission Requirements:** - **Basic Mode**: Minimal permissions (usually default user permissions work) - **Elevated Mode**: Add permissions for `Sys.Audit`, `VM.Monitor`, `VM.Console` to the user/token diff --git a/index.js b/index.js index 84723e8..84f2cbd 100644 --- a/index.js +++ b/index.js @@ -48,6 +48,13 @@ if (!loadEnvFile(envPath)) { } } +function formatProxmoxAuthHeader(user, tokenName, tokenValue) { + if (tokenName.includes('!')) { + return `PVEAPIToken=${tokenName}=${tokenValue}`; + } + return `PVEAPIToken=${user}!${tokenName}=${tokenValue}`; +} + class ProxmoxServer { constructor() { this.server = new Server( @@ -139,7 +146,11 @@ class ProxmoxServer { const url = `${baseUrl}${endpoint}`; const headers = { - 'Authorization': `PVEAPIToken=${this.proxmoxUser}!${this.proxmoxTokenName}=${this.proxmoxTokenValue}`, + 'Authorization': formatProxmoxAuthHeader( + this.proxmoxUser, + this.proxmoxTokenName, + this.proxmoxTokenValue + ), 'Content-Type': 'application/json' }; @@ -3159,4 +3170,4 @@ class ProxmoxServer { } const server = new ProxmoxServer(); -server.run().catch(console.error); \ No newline at end of file +server.run().catch(console.error); diff --git a/src/proxmox_mcp/utils/auth.py b/src/proxmox_mcp/utils/auth.py index 23572a1..97debff 100644 --- a/src/proxmox_mcp/utils/auth.py +++ b/src/proxmox_mcp/utils/auth.py @@ -13,6 +13,27 @@ class ProxmoxAuth(BaseModel): token_name: str token_value: str + +def normalize_token_name(user: str, token_name: str) -> str: + """ + Normalize a Proxmox token identifier to the bare token name. + + Accepts either: + - bare token name: ``devin-codex`` + - full token id: ``user@realm!devin-codex`` + """ + if "!" not in token_name: + return token_name + + token_user, bare_token_name = token_name.split("!", 1) + if not bare_token_name: + raise ValueError("Invalid PROXMOX_TOKEN_NAME: token id is missing the token name after '!'") + if token_user != user: + raise ValueError( + "PROXMOX_TOKEN_NAME contains a full token id for a different user than PROXMOX_USER" + ) + return bare_token_name + def load_auth_from_env() -> ProxmoxAuth: """ Load Proxmox authentication details from environment variables. @@ -44,7 +65,7 @@ def load_auth_from_env() -> ProxmoxAuth: return ProxmoxAuth( user=user, - token_name=token_name, + token_name=normalize_token_name(user, token_name), token_value=token_value, )