-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
Summary
HTTP MCP servers defined in marketplace plugins silently fail to authenticate. The OAuth authorization flow (RFC 9728 discovery → browser prompt) never triggers. The same server added manually to ~/.copilot/mcp-config.json works correctly and prompts for authorization.
Reproduction
-
Create a marketplace plugin with an HTTP MCP server requiring OAuth:
.github/plugin/marketplace.json:{ "plugins": [{ "name": "my-plugin", "source": "plugins/my-plugin", "mcpServers": { "my-server": { "type": "http", "url": "https://my-oauth-protected-mcp-server.example.com", "tools": ["*"] } } }] }The MCP server implements RFC 9728 (
/.well-known/oauth-protected-resource) and RFC 8414 (/.well-known/oauth-authorization-server), returning 401 for unauthenticated requests. -
Install the plugin via the CLI marketplace.
-
Start a new session — the plugin's skill loads, but no OAuth prompt appears and no MCP tools are available.
-
Add the identical server config to
~/.copilot/mcp-config.json— the CLI correctly discovers OAuth metadata and prompts for authorization.
Note: Using an incorrect server URL does produce an error, confirming the plugin MCP config is being read.
Root Cause
In the bundled CLI code (app.js v1.0.4-0), the oj class (MCP host) accepts an onOAuthRequired callback as its 5th constructor parameter. This callback is what triggers the browser-based OAuth flow when a server returns 401.
Workspace MCP host (manual config) — receives all parameters:
new oj(ee, {mcpServers: this.mcpServers ?? {}}, this.excludedTools, this.envValueMode, void 0, this.runtimeSettings)Plugin MCP host (getOrCreateHost in Qot class) — only passes 2 parameters:
// In Qot.getOrCreateHost():
let o = {mcpServers: n};
let s = new oj(this.logger, o); // onOAuthRequired is never passed!Because onOAuthRequired is undefined, the getAuthProvider method returns early:
async getAuthProvider(e, n) {
if (!this.onOAuthRequired) return; // ← always exits here for plugin servers
// ... OAuth flow never reached
}The 401 is silently swallowed and the server fails to connect without any user-visible error.
Expected Behavior
Plugin-sourced HTTP MCP servers should trigger the same OAuth authorization flow as manually-configured ones. The Qot.getOrCreateHost() method should forward the onOAuthRequired callback to the oj constructor.
Workaround
Add the MCP server manually to ~/.copilot/mcp-config.json alongside the plugin installation:
{
"mcpServers": {
"my-server": {
"type": "http",
"url": "https://my-oauth-protected-mcp-server.example.com"
}
}
}Authorize it there; the plugin's skills can then use the MCP tools.
Environment
- CLI Version: 1.0.4-0
- OS: Windows 11 (ARM64)
- Plugin format: Marketplace plugin with
mcpServersinmarketplace.json - MCP server transport: HTTP with RFC 9728 OAuth
- Not affected:
stdioMCP servers in plugins (e.g., workiq), manually configured HTTP MCP servers