Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/lib/agent-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,14 @@ export async function runAgentWizard(
const spinner = clack.spinner();

// Determine MCP URL: CLI flag > env var > production default
// Use EU subdomain for EU users to work around Claude Code's OAuth bug
// See: https://github.com/anthropics/claude-code/issues/2267
const mcpUrl = options.localMcp
? 'http://localhost:8787/mcp'
: process.env.MCP_URL || 'https://mcp.posthog.com/mcp';
: process.env.MCP_URL ||
(cloudRegion === 'eu'
? 'https://mcp-eu.posthog.com/mcp'
: 'https://mcp.posthog.com/mcp');

const agent = initializeAgent(
{
Expand Down
18 changes: 8 additions & 10 deletions src/steps/add-mcp-server-to-clients/__tests__/defaults.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ describe('defaults', () => {
);
});

it('should add region param for EU region', () => {
it('should use EU subdomain for EU region', () => {
const url = buildMCPUrl('streamable-http', undefined, false, 'eu');
expect(url).toBe('https://mcp.posthog.com/mcp?region=eu');
expect(url).toBe('https://mcp-eu.posthog.com/mcp');
});

it('should not add region param for US region (default)', () => {
Expand All @@ -43,11 +43,9 @@ describe('defaults', () => {
expect(url).toBe('http://localhost:8787/mcp');
});

it('should combine features and region params', () => {
it('should combine EU subdomain with features param', () => {
const url = buildMCPUrl('streamable-http', ['dashboards'], false, 'eu');
expect(url).toBe(
'https://mcp.posthog.com/mcp?features=dashboards&region=eu',
);
expect(url).toBe('https://mcp-eu.posthog.com/mcp?features=dashboards');
});
});

Expand Down Expand Up @@ -78,15 +76,15 @@ describe('defaults', () => {
expect(config).not.toHaveProperty('env');
});

it('should include region in URL for EU users in OAuth mode', () => {
it('should use EU subdomain for EU users in OAuth mode', () => {
const config = getDefaultServerConfig(
undefined,
'streamable-http',
undefined,
false,
'eu',
);
expect(config.args).toContain('https://mcp.posthog.com/mcp?region=eu');
expect(config.args).toContain('https://mcp-eu.posthog.com/mcp');
});
});

Expand All @@ -112,15 +110,15 @@ describe('defaults', () => {
expect(config).not.toHaveProperty('headers');
});

it('should include region in URL for EU users', () => {
it('should use EU subdomain for EU users', () => {
const config = getNativeHTTPServerConfig(
undefined,
'streamable-http',
undefined,
false,
'eu',
);
expect(config.url).toBe('https://mcp.posthog.com/mcp?region=eu');
expect(config.url).toBe('https://mcp-eu.posthog.com/mcp');
});
});
});
16 changes: 8 additions & 8 deletions src/steps/add-mcp-server-to-clients/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,14 @@ export const buildMCPUrl = (
local?: boolean,
region?: CloudRegion,
) => {
const host = local ? 'http://localhost:8787' : 'https://mcp.posthog.com';
// Use subdomain for EU to work around Claude Code's OAuth bug where it ignores
// the authorization_servers field and fetches /.well-known/oauth-authorization-server
// directly from the MCP server hostname. See: https://github.com/anthropics/claude-code/issues/2267
const host = local
? 'http://localhost:8787'
: region === 'eu'
? 'https://mcp-eu.posthog.com'
: 'https://mcp.posthog.com';
const baseUrl = `${host}/${type === 'sse' ? 'sse' : 'mcp'}`;

const isAllFeaturesSelected =
Expand All @@ -96,13 +103,6 @@ export const buildMCPUrl = (
params.push(`features=${selectedFeatures.join(',')}`);
}

// Add region param for non-US regions to route OAuth to the correct authorization server.
// US is the default, so we only need to specify region for EU users.
// Not needed in local mode since local dev always uses the same auth server.
if (region && region !== 'us' && !local) {
params.push(`region=${region}`);
}

return params.length > 0 ? `${baseUrl}?${params.join('&')}` : baseUrl;
};

Expand Down
Loading