From bfcc271f7979e72904f7b2d7a7c0747b6cfc7141 Mon Sep 17 00:00:00 2001 From: Ace Data Cloud Dev Date: Mon, 12 Oct 2026 11:58:05 +0800 Subject: [PATCH 1/2] docs(vscode): guide model selection and first tool results --- face/vscode/README.md | 4 +++- fish/vscode/README.md | 4 +++- flux/vscode/README.md | 4 +++- grok/vscode/README.md | 4 +++- kling/vscode/README.md | 4 +++- midjourney/vscode/README.md | 4 +++- minimax/vscode/README.md | 6 ++++-- nanobanana/vscode/README.md | 4 +++- scripts/build_vscode_extensions.py | 4 +++- seedance/vscode/README.md | 4 +++- seedream/vscode/README.md | 4 +++- serp/vscode/README.md | 4 +++- suno/vscode/README.md | 4 +++- veo/vscode/README.md | 4 +++- wan/vscode/README.md | 4 +++- 15 files changed, 46 insertions(+), 16 deletions(-) diff --git a/face/vscode/README.md b/face/vscode/README.md index 7b91f572..a9caa83e 100644 --- a/face/vscode/README.md +++ b/face/vscode/README.md @@ -17,7 +17,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `face` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for an image task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Face Transform MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=face_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/fish/vscode/README.md b/fish/vscode/README.md index 7087ef67..8b796210 100644 --- a/fish/vscode/README.md +++ b/fish/vscode/README.md @@ -17,7 +17,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `fish` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for an audio task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Fish Audio MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=fish_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/flux/vscode/README.md b/flux/vscode/README.md index 3d88a76b..ed4400b8 100644 --- a/flux/vscode/README.md +++ b/flux/vscode/README.md @@ -16,7 +16,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `flux` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for a image task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Flux MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=flux_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/grok/vscode/README.md b/grok/vscode/README.md index 7292bcf7..898b5ff3 100644 --- a/grok/vscode/README.md +++ b/grok/vscode/README.md @@ -16,7 +16,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `grok` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for a video task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Grok MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=grok_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/kling/vscode/README.md b/kling/vscode/README.md index e2d99475..ff963c4d 100644 --- a/kling/vscode/README.md +++ b/kling/vscode/README.md @@ -16,7 +16,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `kling` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for a video task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Kling MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=kling_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/midjourney/vscode/README.md b/midjourney/vscode/README.md index 8139a920..f49bf54d 100644 --- a/midjourney/vscode/README.md +++ b/midjourney/vscode/README.md @@ -16,7 +16,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `midjourney` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for a image task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Midjourney MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=midjourney_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/minimax/vscode/README.md b/minimax/vscode/README.md index eeb93d90..c3ea40b1 100644 --- a/minimax/vscode/README.md +++ b/minimax/vscode/README.md @@ -16,9 +16,11 @@ Connect VS Code MCP clients to MiniMax H3 video generation through AceDataCloud. 1. Install the extension. 2. Run **MiniMax MCP: Set Ace Data Cloud API Key**. -3. Open the MCP server picker and enable **MiniMax MCP**. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **MiniMax MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=minimax_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. -The extension connects to `https://minimax.mcp.acedata.cloud/mcp`. Get a token at https://platform.acedata.cloud/console/applications.?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=minimax_mcp_vscode_api_key +The extension connects to `https://minimax.mcp.acedata.cloud/mcp`. Get an application API key using the instructions below. ### Get your API key diff --git a/nanobanana/vscode/README.md b/nanobanana/vscode/README.md index d0a0e953..219d9784 100644 --- a/nanobanana/vscode/README.md +++ b/nanobanana/vscode/README.md @@ -16,7 +16,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `nanobanana` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for a image task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **NanoBanana MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=nanobanana_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/scripts/build_vscode_extensions.py b/scripts/build_vscode_extensions.py index b3ddad1e..52cff865 100644 --- a/scripts/build_vscode_extensions.py +++ b/scripts/build_vscode_extensions.py @@ -387,7 +387,9 @@ def render_readme(svc: Service, tools: list[tuple[str, str]]) -> str: 1. **Install this extension.** VS Code registers the `{svc.alias}` MCP server automatically. 2. {credential_step} -3. **Open Copilot Chat** in agent mode and ask for a {svc.domain} task — the extension prompts for the {credential_label} the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **{svc.display_name}**. If the list is empty, choose **Update Tools**. The extension prompts for the {credential_label} on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/seedance/vscode/README.md b/seedance/vscode/README.md index c61a9d52..450a6f3c 100644 --- a/seedance/vscode/README.md +++ b/seedance/vscode/README.md @@ -16,7 +16,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `seedance` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for a video task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Seedance MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=seedance_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/seedream/vscode/README.md b/seedream/vscode/README.md index 562245b5..19fd71b9 100644 --- a/seedream/vscode/README.md +++ b/seedream/vscode/README.md @@ -16,7 +16,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `seedream` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for a image task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Seedream MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=seedream_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/serp/vscode/README.md b/serp/vscode/README.md index 21d72187..2f407be8 100644 --- a/serp/vscode/README.md +++ b/serp/vscode/README.md @@ -16,7 +16,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `serp` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for a search task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Serp MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=serp_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/suno/vscode/README.md b/suno/vscode/README.md index 62a7eb4e..af1c266f 100644 --- a/suno/vscode/README.md +++ b/suno/vscode/README.md @@ -16,7 +16,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `suno` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for a music task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Suno MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=suno_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/veo/vscode/README.md b/veo/vscode/README.md index 6b07adec..b5d834c8 100644 --- a/veo/vscode/README.md +++ b/veo/vscode/README.md @@ -16,7 +16,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `veo` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for a video task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Veo MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=veo_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: diff --git a/wan/vscode/README.md b/wan/vscode/README.md index 474c2fbf..d37ab3b0 100644 --- a/wan/vscode/README.md +++ b/wan/vscode/README.md @@ -16,7 +16,9 @@ can call it directly from chat. 1. **Install this extension.** VS Code registers the `wan` MCP server automatically. 2. **Get an application API key** using the detailed steps below. Check service access and your current balance before the first request. -3. **Open Copilot Chat** in agent mode and ask for a video task — the extension prompts for the API key the first time and stores it in the OS keychain via VS Code's `SecretStorage`. +3. **Select a model with tool calling in VS Code Chat.** You can use your existing model, or install [Ace Data Cloud Chat Models](https://marketplace.visualstudio.com/items?itemName=acedatacloud.chat-models). For the Ace model, first follow its [setup guide](https://github.com/AceDataCloud/VSCodeModelProvider#4-show-the-model-in-chat), open **Chat: Manage Language Models**, make the model visible, and select it in Chat. BYOK Chat does not require GitHub sign-in or a Copilot plan; organization policies still apply. +4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **Wan MCP**. If the list is empty, choose **Update Tools**. The extension prompts for the API key on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. +5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=wan_mcp_vscode_console_usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. You can rotate or remove the API key any time from the command palette: From ef844e9fdde0385925c8359d2e6822639d094407 Mon Sep 17 00:00:00 2001 From: Ace Data Cloud Dev Date: Mon, 12 Oct 2026 12:56:28 +0800 Subject: [PATCH 2/2] fix(vscode): correct credential prompts and source attribution --- .github/workflows/ci.yaml | 4 ++ acedatacloud/vscode/README.md | 8 +-- acedatacloud/vscode/extension.js | 16 +++--- acedatacloud/vscode/package.json | 4 +- face/vscode/extension.js | 16 +++--- fish/vscode/extension.js | 16 +++--- flux/vscode/extension.js | 14 ++--- grok/vscode/extension.js | 14 ++--- hailuo/vscode/extension.js | 14 ++--- kling/vscode/extension.js | 14 ++--- luma/vscode/extension.js | 14 ++--- midjourney/vscode/extension.js | 14 ++--- nanobanana/vscode/extension.js | 14 ++--- producer/vscode/extension.js | 14 ++--- scripts/build_vscode_extensions.py | 64 ++++++++++++++++----- scripts/test_vscode_credentials.js | 91 ++++++++++++++++++++++++++++++ seedance/vscode/extension.js | 14 ++--- seedream/vscode/extension.js | 14 ++--- serp/vscode/extension.js | 14 ++--- shorturl/vscode/extension.js | 14 ++--- suno/vscode/extension.js | 14 ++--- veo/vscode/extension.js | 14 ++--- wan/vscode/extension.js | 14 ++--- 23 files changed, 280 insertions(+), 149 deletions(-) create mode 100644 scripts/test_vscode_credentials.js diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3b82bbc1..f1d08db9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,6 +27,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version: 22 + - run: node --test scripts/test_vscode_credentials.js - run: python3 scripts/check_readme_inventory.py - run: python3 scripts/sync_oauth.py --check - run: python3 -m unittest diff --git a/acedatacloud/vscode/README.md b/acedatacloud/vscode/README.md index 2c2e94db..5fed0a16 100644 --- a/acedatacloud/vscode/README.md +++ b/acedatacloud/vscode/README.md @@ -19,10 +19,10 @@ can call it directly from chat. 2. **Get an account token** from [Account Tokens](https://platform.acedata.cloud/console/platform-tokens?utm_source=vscode_marketplace&utm_medium=referral&utm_campaign=evergreen&utm_content=acedatacloud_mcp_vscode_platform_token), following the steps below. This account server requires a `platform-...` token. 3. **Open Copilot Chat** in agent mode and ask for a account task — the extension prompts for the account token the first time and stores it in the OS keychain via VS Code's `SecretStorage`. -You can rotate or remove the API key any time from the command palette: +You can rotate or remove the account token any time from the command palette: -- **Ace Data Cloud Account MCP: Set Ace Data Cloud API Key** -- **Ace Data Cloud Account MCP: Clear Ace Data Cloud API Key** +- **Ace Data Cloud Account MCP: Set Ace Data Cloud Platform Token** +- **Ace Data Cloud Account MCP: Clear Ace Data Cloud Platform Token** > The default config talks to the **hosted streamable-HTTP endpoint** at > `https://mcp.acedata.cloud/mcp` — no Python, no `uvx`, no local install needed. @@ -66,7 +66,7 @@ Provider id : acedatacloud.acedatacloud Server label: Ace Data Cloud Account MCP Server URL : https://mcp.acedata.cloud/mcp Transport : Streamable HTTP -Auth : Bearer API key from VS Code SecretStorage (or $ACEDATACLOUD_PLATFORM_TOKEN) +Auth : Bearer account token from VS Code SecretStorage (or $ACEDATACLOUD_PLATFORM_TOKEN) ``` You don't need to edit `mcp.json` — the extension handles registration and diff --git a/acedatacloud/vscode/extension.js b/acedatacloud/vscode/extension.js index 5d150b45..7c65f1c4 100644 --- a/acedatacloud/vscode/extension.js +++ b/acedatacloud/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.acedatacloud.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "acedatacloud.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/platform-tokens?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=acedatacloud_mcp_extension_platform_token"; async function readToken(context) { const env = process.env.ACEDATACLOUD_PLATFORM_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud platform token`, + prompt: `Paste an Ace Data Cloud platform token from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "Platform Token from /console/platform-tokens", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: platform token saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: platform token cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,8 +75,8 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + - `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` + `${SERVER_LABEL} needs an Ace Data Cloud platform token. ` + + `Run "${SERVER_LABEL}: Set Ace Data Cloud Platform Token" from the command palette.` ); } return new vscode.McpHttpServerDefinition(server.label, server.uri, { diff --git a/acedatacloud/vscode/package.json b/acedatacloud/vscode/package.json index 9b337e52..6e6a5b6e 100644 --- a/acedatacloud/vscode/package.json +++ b/acedatacloud/vscode/package.json @@ -50,12 +50,12 @@ "commands": [ { "command": "acedatacloud.acedatacloud.setApiToken", - "title": "Ace Data Cloud Account MCP: Set Ace Data Cloud API Key", + "title": "Ace Data Cloud Account MCP: Set Ace Data Cloud Platform Token", "category": "MCP" }, { "command": "acedatacloud.acedatacloud.clearApiToken", - "title": "Ace Data Cloud Account MCP: Clear Ace Data Cloud API Key", + "title": "Ace Data Cloud Account MCP: Clear Ace Data Cloud Platform Token", "category": "MCP" } ] diff --git a/face/vscode/extension.js b/face/vscode/extension.js index 4736ecab..ec7b1c81 100644 --- a/face/vscode/extension.js +++ b/face/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.face.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "face.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=face_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,8 +75,8 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + - `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } return new vscode.McpHttpServerDefinition(server.label, server.uri, { diff --git a/fish/vscode/extension.js b/fish/vscode/extension.js index 730af286..e418dc84 100644 --- a/fish/vscode/extension.js +++ b/fish/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.fish.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "fish.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=fish_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,8 +75,8 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + - `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } return new vscode.McpHttpServerDefinition(server.label, server.uri, { diff --git a/flux/vscode/extension.js b/flux/vscode/extension.js index 0f12c245..f51246e0 100644 --- a/flux/vscode/extension.js +++ b/flux/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.flux.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "flux.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=flux_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/grok/vscode/extension.js b/grok/vscode/extension.js index f7b75886..0aca262a 100644 --- a/grok/vscode/extension.js +++ b/grok/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.grok.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "grok.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=grok_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/hailuo/vscode/extension.js b/hailuo/vscode/extension.js index a7f747b3..24b53334 100644 --- a/hailuo/vscode/extension.js +++ b/hailuo/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.hailuo.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "hailuo.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=hailuo_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/kling/vscode/extension.js b/kling/vscode/extension.js index 4c7c5467..62a30d78 100644 --- a/kling/vscode/extension.js +++ b/kling/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.kling.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "kling.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=kling_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/luma/vscode/extension.js b/luma/vscode/extension.js index ce22bbc8..62d8d23a 100644 --- a/luma/vscode/extension.js +++ b/luma/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.luma.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "luma.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=luma_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/midjourney/vscode/extension.js b/midjourney/vscode/extension.js index fb48cbc8..ecc9c5a3 100644 --- a/midjourney/vscode/extension.js +++ b/midjourney/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.midjourney.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "midjourney.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=midjourney_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/nanobanana/vscode/extension.js b/nanobanana/vscode/extension.js index dde6be93..ced487f0 100644 --- a/nanobanana/vscode/extension.js +++ b/nanobanana/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.nanobanana.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "nanobanana.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=nanobanana_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/producer/vscode/extension.js b/producer/vscode/extension.js index 8163a41e..9d2e38de 100644 --- a/producer/vscode/extension.js +++ b/producer/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.producer.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "producer.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=producer_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/scripts/build_vscode_extensions.py b/scripts/build_vscode_extensions.py index 52cff865..713020f0 100644 --- a/scripts/build_vscode_extensions.py +++ b/scripts/build_vscode_extensions.py @@ -26,8 +26,10 @@ from collections.abc import Iterable from dataclasses import dataclass from pathlib import Path +from urllib.parse import urlencode, urlsplit, urlunsplit import yaml +from marketing_readmes import contract as attribution_contract from marketing_readmes import render as render_marketing_readme from mcp_catalog import documentation_target, load_catalog from token_onboarding import token_guide @@ -65,6 +67,40 @@ class Service: def hosted_url(self) -> str: return self.hosted_url_override or f"https://{self.alias}.mcp.acedata.cloud/mcp" + @property + def credential_label(self) -> str: + return ( + "Platform Token" + if self.token_env == "ACEDATACLOUD_PLATFORM_TOKEN" + else "API Key" + ) + + @property + def credential_url(self) -> str: + rules = attribution_contract() + account = self.token_env == "ACEDATACLOUD_PLATFORM_TOKEN" + parts = urlsplit(self.signup_url) + path = "/console/platform-tokens" if account else "/console/applications" + placement = "platform_token" if account else "api_key" + content = rules["link_defaults"]["content_template"].format( + entry=self.alias.replace("-", "_") + "_mcp", + surface="extension", + placement=placement, + ) + tags = { + "utm_source": "vscode", + "utm_medium": rules["sources"]["vscode"], + "utm_campaign": rules["link_defaults"]["campaign"], + "utm_content": content, + } + if any( + len(value) > rules["max_tag_length"] + or not re.fullmatch(rules["tag_pattern"], value) + for value in tags.values() + ): + raise ValueError("Invalid VS Code credential attribution") + return urlunsplit((parts.scheme, parts.netloc, path, urlencode(tags), "")) + @property def provider_id(self) -> str: # ID exposed to VS Code's MCP machinery. Keep it stable per service so @@ -203,12 +239,12 @@ def render_package_json(svc: Service) -> str: "commands": [ { "command": svc.set_token_cmd, - "title": f"{svc.display_name}: Set Ace Data Cloud API Key", + "title": f"{svc.display_name}: Set Ace Data Cloud {svc.credential_label}", "category": "MCP", }, { "command": svc.clear_token_cmd, - "title": f"{svc.display_name}: Clear Ace Data Cloud API Key", + "title": f"{svc.display_name}: Clear Ace Data Cloud {svc.credential_label}", "category": "MCP", }, ], @@ -242,7 +278,7 @@ def render_extension_js(svc: Service) -> str: // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "{svc.alias}.apiToken"; -const SIGNUP_URL = "{svc.signup_url}"; +const CREDENTIAL_URL = "{svc.credential_url}"; async function readToken(context) {{ const env = process.env.{svc.token_env}; @@ -253,9 +289,9 @@ def render_extension_js(svc: Service) -> str: async function promptForToken(context) {{ const token = await vscode.window.showInputBox({{ - title: `${{SERVER_LABEL}} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${{SIGNUP_URL}}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${{SERVER_LABEL}} — Ace Data Cloud {svc.credential_label.lower()}`, + prompt: `Paste an Ace Data Cloud {svc.credential_label.lower()} from ${{CREDENTIAL_URL}}. Stored in VS Code SecretStorage.`, + placeHolder: "{svc.credential_label} from {urlsplit(svc.credential_url).path}", password: true, ignoreFocusOut: true, }}); @@ -274,13 +310,13 @@ def render_extension_js(svc: Service) -> str: vscode.commands.registerCommand(SET_TOKEN_CMD, async () => {{ const t = await promptForToken(context); if (t) {{ - vscode.window.showInformationMessage(`${{SERVER_LABEL}}: API key saved.`); + vscode.window.showInformationMessage(`${{SERVER_LABEL}}: {svc.credential_label.lower()} saved.`); onDidChange.fire(); }} }}), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => {{ await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${{SERVER_LABEL}}: API key cleared.`); + vscode.window.showInformationMessage(`${{SERVER_LABEL}}: {svc.credential_label.lower()} cleared.`); onDidChange.fire(); }}), context.secrets.onDidChange((e) => {{ @@ -296,8 +332,8 @@ def render_extension_js(svc: Service) -> str: if (!token) token = await promptForToken(context); if (!token) {{ throw new Error( - `${{SERVER_LABEL}} needs an Ace Data Cloud API key. ` + - `Run "${{SERVER_LABEL}}: Set Ace Data Cloud API Key" from the command palette.` + `${{SERVER_LABEL}} needs an Ace Data Cloud {svc.credential_label.lower()}. ` + + `Run "${{SERVER_LABEL}}: Set Ace Data Cloud {svc.credential_label}" from the command palette.` ); }} return new vscode.McpHttpServerDefinition(server.label, server.uri, {{ @@ -391,10 +427,10 @@ def render_readme(svc: Service, tools: list[tuple[str, str]]) -> str: 4. **Enable this server's tools.** Open **Chat → Agent → Configure Tools** and select only the tools you need under **{svc.display_name}**. If the list is empty, choose **Update Tools**. The extension prompts for the {credential_label} on first use and saves it in VS Code's `SecretStorage`. Disable another copy of the same server from the Ace MCP bundle or manual `mcp.json` to avoid duplicate tools. 5. **Verify one result.** Check the Tool Reference below and current pricing before running a request. If you already have a task ID, enable its task-query tool and query that same ID first. An accepted generation is not a completed result: poll the original task until it reaches a successful terminal state, open the returned media, and match the task ID in [Usage](https://platform.acedata.cloud/console/usage). Do not resubmit generation to poll. Model Chat and background utility calls can add separate charges to the service request. -You can rotate or remove the API key any time from the command palette: +You can rotate or remove the {credential_label} any time from the command palette: -- **{svc.display_name}: Set Ace Data Cloud API Key** -- **{svc.display_name}: Clear Ace Data Cloud API Key** +- **{svc.display_name}: Set Ace Data Cloud {svc.credential_label}** +- **{svc.display_name}: Clear Ace Data Cloud {svc.credential_label}** > The default config talks to the **hosted streamable-HTTP endpoint** at > `{svc.hosted_url}` — no Python, no `uvx`, no local install needed. @@ -432,7 +468,7 @@ def render_readme(svc: Service, tools: list[tuple[str, str]]) -> str: Server label: {svc.display_name} Server URL : {svc.hosted_url} Transport : Streamable HTTP -Auth : Bearer API key from VS Code SecretStorage (or ${svc.token_env}) +Auth : Bearer {credential_label} from VS Code SecretStorage (or ${svc.token_env}) ``` You don't need to edit `mcp.json` — the extension handles registration and diff --git a/scripts/test_vscode_credentials.js b/scripts/test_vscode_credentials.js new file mode 100644 index 00000000..5e98ee8f --- /dev/null +++ b/scripts/test_vscode_credentials.js @@ -0,0 +1,91 @@ +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const test = require('node:test'); +const vm = require('node:vm'); + +const root = path.resolve(__dirname, '..'); +const services = ['acedatacloud', 'face', 'fish', 'flux', 'grok', 'hailuo', 'kling', 'luma', 'midjourney', 'nanobanana', 'producer', 'seedance', 'seedream', 'serp', 'shorturl', 'suno', 'veo', 'wan']; + +function load(alias, { input, env = {}, stored } = {}) { + const state = { prompts: [], commands: new Map(), secrets: new Map(), provider: undefined }; + if (stored) state.secrets.set(`${alias}.apiToken`, stored); + const vscode = { + EventEmitter: class { event() {} fire() {} }, + Uri: { parse: value => new URL(value) }, + McpHttpServerDefinition: class { + constructor(label, uri, headers) { Object.assign(this, { label, uri, headers }); } + }, + commands: { registerCommand: (id, action) => { state.commands.set(id, action); return {}; } }, + window: { + showInputBox: async options => { state.prompts.push(options); return input; }, + showInformationMessage: () => {}, + }, + lm: { registerMcpServerDefinitionProvider: (_, provider) => { state.provider = provider; return {}; } }, + }; + const context = { + subscriptions: [], + secrets: { + get: async key => state.secrets.get(key), + store: async (key, value) => state.secrets.set(key, value), + delete: async key => state.secrets.delete(key), + onDidChange: () => ({}), + }, + }; + const sandbox = { module: { exports: {} }, process: { env }, require: name => { + assert.equal(name, 'vscode'); return vscode; + } }; + vm.runInNewContext(fs.readFileSync(path.join(root, alias, 'vscode/extension.js'), 'utf8'), sandbox); + sandbox.module.exports.activate(context); + state.resolve = () => state.provider.resolveMcpServerDefinition(state.provider.provideMcpServerDefinitions()[0]); + return state; +} + +test('generated credential prompts use the matching credential page and current attribution', async t => { + for (const alias of services) await t.test(alias, async () => { + const account = alias === 'acedatacloud'; + const state = load(alias, { input: account ? ' platform-test-token ' : ' test-api-key ' }); + const definition = await state.resolve(); + const prompt = state.prompts[0]; + const url = new URL(prompt.prompt.match(/https:\/\/\S+/)[0].replace(/\.$/, '')); + assert.equal(url.origin, 'https://platform.acedata.cloud'); + assert.equal(url.pathname, account ? '/console/platform-tokens' : '/console/applications'); + assert.equal(url.searchParams.get('utm_source'), 'vscode'); + assert.equal(url.searchParams.get('utm_medium'), 'referral'); + assert.equal(url.searchParams.get('utm_campaign'), 'evergreen'); + assert.equal(url.searchParams.get('utm_content'), `${alias}_mcp_extension_${account ? 'platform_token' : 'api_key'}`); + assert.equal(prompt.password, true); + assert.equal(definition.headers.Authorization, account ? 'Bearer platform-test-token' : 'Bearer test-api-key'); + assert.equal(state.secrets.get(`${alias}.apiToken`), account ? 'platform-test-token' : 'test-api-key'); + assert.equal(definition.uri.search, ''); + }); +}); + +test('account cancellation explains the platform-token command without persisting a value', async () => { + const state = load('acedatacloud'); + await assert.rejects(state.resolve(), /Set Ace Data Cloud Platform Token/); + assert.equal(state.secrets.size, 0); +}); + +test('configured credentials keep precedence and do not prompt', async () => { + for (const alias of ['acedatacloud', 'suno']) { + const variable = alias === 'acedatacloud' ? 'ACEDATACLOUD_PLATFORM_TOKEN' : 'ACEDATACLOUD_API_TOKEN'; + const state = load(alias, { env: { [variable]: ' env-test-token ' }, stored: 'stored-test-token' }); + const definition = await state.resolve(); + assert.equal(definition.headers.Authorization, 'Bearer env-test-token'); + assert.equal(state.prompts.length, 0); + } +}); + +test('existing clear command still removes the per-service credential', async () => { + const state = load('acedatacloud', { stored: 'platform-test-token' }); + await state.commands.get('acedatacloud.acedatacloud.clearApiToken')(); + assert.equal(state.secrets.size, 0); +}); + +test('account command labels match its prompted credential', () => { + const pkg = JSON.parse(fs.readFileSync(path.join(root, 'acedatacloud/vscode/package.json'), 'utf8')); + assert.equal(pkg.contributes.commands[0].command, 'acedatacloud.acedatacloud.setApiToken'); + assert.match(pkg.contributes.commands[0].title, /Set Ace Data Cloud Platform Token$/); + assert.match(pkg.contributes.commands[1].title, /Clear Ace Data Cloud Platform Token$/); +}); diff --git a/seedance/vscode/extension.js b/seedance/vscode/extension.js index e1f85243..655f28a7 100644 --- a/seedance/vscode/extension.js +++ b/seedance/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.seedance.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "seedance.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=seedance_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/seedream/vscode/extension.js b/seedream/vscode/extension.js index 8adeb9bf..347ede80 100644 --- a/seedream/vscode/extension.js +++ b/seedream/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.seedream.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "seedream.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=seedream_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/serp/vscode/extension.js b/serp/vscode/extension.js index 7e15e7dd..4096387a 100644 --- a/serp/vscode/extension.js +++ b/serp/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.serp.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "serp.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=serp_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/shorturl/vscode/extension.js b/shorturl/vscode/extension.js index 3bc3549f..89c962e0 100644 --- a/shorturl/vscode/extension.js +++ b/shorturl/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.shorturl.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "shorturl.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=shorturl_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/suno/vscode/extension.js b/suno/vscode/extension.js index 09026e2c..dccd7660 100644 --- a/suno/vscode/extension.js +++ b/suno/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.suno.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "suno.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=suno_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/veo/vscode/extension.js b/veo/vscode/extension.js index a4eb90d7..677744d0 100644 --- a/veo/vscode/extension.js +++ b/veo/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.veo.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "veo.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=veo_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); } diff --git a/wan/vscode/extension.js b/wan/vscode/extension.js index e9197161..018adc38 100644 --- a/wan/vscode/extension.js +++ b/wan/vscode/extension.js @@ -21,7 +21,7 @@ const CLEAR_TOKEN_CMD = "acedatacloud.wan.clearApiToken"; // Per-extension SecretStorage namespace; we keep one key per service so // rotating one API key doesn't affect siblings. const SECRET_KEY = "wan.apiToken"; -const SIGNUP_URL = "https://platform.acedata.cloud"; +const CREDENTIAL_URL = "https://platform.acedata.cloud/console/applications?utm_source=vscode&utm_medium=referral&utm_campaign=evergreen&utm_content=wan_mcp_extension_api_key"; async function readToken(context) { const env = process.env.ACEDATACLOUD_API_TOKEN; @@ -32,9 +32,9 @@ async function readToken(context) { async function promptForToken(context) { const token = await vscode.window.showInputBox({ - title: `${SERVER_LABEL} — Ace Data Cloud API key`, - prompt: `Paste an API key from ${SIGNUP_URL}/console/applications (Applications -> API Key). Stored in the OS keychain.`, - placeHolder: "API key from /console/applications", + title: `${SERVER_LABEL} — Ace Data Cloud api key`, + prompt: `Paste an Ace Data Cloud api key from ${CREDENTIAL_URL}. Stored in VS Code SecretStorage.`, + placeHolder: "API Key from /console/applications", password: true, ignoreFocusOut: true, }); @@ -53,13 +53,13 @@ function activate(context) { vscode.commands.registerCommand(SET_TOKEN_CMD, async () => { const t = await promptForToken(context); if (t) { - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key saved.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key saved.`); onDidChange.fire(); } }), vscode.commands.registerCommand(CLEAR_TOKEN_CMD, async () => { await context.secrets.delete(SECRET_KEY); - vscode.window.showInformationMessage(`${SERVER_LABEL}: API key cleared.`); + vscode.window.showInformationMessage(`${SERVER_LABEL}: api key cleared.`); onDidChange.fire(); }), context.secrets.onDidChange((e) => { @@ -75,7 +75,7 @@ function activate(context) { if (!token) token = await promptForToken(context); if (!token) { throw new Error( - `${SERVER_LABEL} needs an Ace Data Cloud API key. ` + + `${SERVER_LABEL} needs an Ace Data Cloud api key. ` + `Run "${SERVER_LABEL}: Set Ace Data Cloud API Key" from the command palette.` ); }