Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | 38x 38x 38x 10x 10x 1x 1x 9x 10x 10x 7x 7x 7x 7x 4x 6x 10x 10x 10x 10x 10x 7x 7x 7x 7x 7x 10x 37x 34x 37x 37x 9x 9x 9x 3x 3x 37x 37x 2x 38x 38x 37x 27x | /**
* @module mcp-client/config/gateway-resolver
* @description Resolve the MCP gateway URL when running inside the AWF
* sandbox (gh-aw v0.69+ uses port 8080 via `host.docker.internal`).
*
* Falls back to the direct onrender HTTPS endpoint for local dev / CI
* outside the sandbox. All resolution is best-effort: missing config
* files never raise — they only steer the URL choice.
*
* @author Hack23 AB
* @license Apache-2.0
*/
import fs from 'fs';
import { hasMcpGatewayApiKey } from './auth.js';
/**
* Default MCP gateway port. The `ghcr.io/github/gh-aw-mcpg` container exports
* `MCP_GATEWAY_PORT` in the compiled `news-*.lock.yml` workflows. Was `80`
* in gh-aw <0.69 and is `8080` in gh-aw >=0.69. Always resolve dynamically
* from `mcp-config.json`/env when possible — see {@link getAwfGatewayPort}.
*/
const DEFAULT_MCP_GATEWAY_PORT = 8080;
const DEFAULT_MCP_GATEWAY_DOMAIN = 'host.docker.internal';
/**
* Direct onrender HTTPS endpoint for the riksdag-regering MCP server.
*
* Exported so the `mcp-client` barrel (`scripts/mcp-client/index.ts`) can
* re-publish it as part of the public surface and the network-diagnostics
* test suite has a single source of truth to assert against.
*/
export const DIRECT_MCP_SERVER_URL = 'https://riksdag-regering-ai.onrender.com/mcp';
/**
* Resolve the MCP gateway port from (in order):
* 1. `MCP_GATEWAY_PORT` env var (set by the gh-aw lock file at gateway start)
* 2. `gateway.port` in mcp-config.json (written by the gh-aw mcp-gateway bootstrap)
* 3. {@link DEFAULT_MCP_GATEWAY_PORT}
*/
export function getAwfGatewayPort(): number {
const envPort = process.env['MCP_GATEWAY_PORT'];
if (envPort) {
const parsed = Number.parseInt(envPort, 10);
Eif (Number.isFinite(parsed) && parsed > 0) return parsed;
}
const configPath = process.env['GH_AW_MCP_CONFIG'] ?? '/home/runner/.copilot/mcp-config.json';
try {
if (fs.existsSync(configPath)) {
const raw = JSON.parse(fs.readFileSync(configPath, 'utf8')) as Record<string, unknown>;
const gateway = raw['gateway'] as Record<string, unknown> | undefined;
const port = gateway?.['port'];
if (typeof port === 'number' && port > 0) return port;
Iif (typeof port === 'string') {
const parsed = Number.parseInt(port, 10);
if (Number.isFinite(parsed) && parsed > 0) return parsed;
}
}
} catch {
// Best-effort — fall through to default port
}
return DEFAULT_MCP_GATEWAY_PORT;
}
/**
* Resolve the MCP gateway domain from (in order):
* 1. `MCP_GATEWAY_DOMAIN` env var
* 2. `gateway.domain` in mcp-config.json
* 3. {@link DEFAULT_MCP_GATEWAY_DOMAIN}
*/
export function getAwfGatewayDomain(): string {
const envDomain = process.env['MCP_GATEWAY_DOMAIN'];
Iif (envDomain) return envDomain;
const configPath = process.env['GH_AW_MCP_CONFIG'] ?? '/home/runner/.copilot/mcp-config.json';
try {
if (fs.existsSync(configPath)) {
const raw = JSON.parse(fs.readFileSync(configPath, 'utf8')) as Record<string, unknown>;
const gateway = raw['gateway'] as Record<string, unknown> | undefined;
const domain = gateway?.['domain'];
if (typeof domain === 'string' && domain.length > 0) return domain;
}
} catch {
// Best-effort — fall through to default domain
}
return DEFAULT_MCP_GATEWAY_DOMAIN;
}
/**
* Build the AWF gateway URL for a given MCP server name. Used as the routing
* target inside the AWF sandbox where direct HTTPS to onrender.com is blocked.
*/
export function buildAwfGatewayUrl(serverName: string): string {
return `http://${getAwfGatewayDomain()}:${getAwfGatewayPort()}/mcp/${serverName}`;
}
/**
* Detect whether the current process runs inside the AWF sandbox with the
* MCP gateway active. Heuristic matches `scripts/mcp-setup.sh`:
* - `MCP_GATEWAY_API_KEY` env var present (checked via `hasMcpGatewayApiKey`
* in `config/auth.ts` — the single auditable sink for token-bearing env
* reads), OR
* - `gateway.apiKey` present in `mcp-config.json`, OR
* - `mcpServers['riksdag-regering'].headers.Authorization` present in
* `mcp-config.json` (populated by the gateway bootstrap).
*
* When true, the client must route through the gateway domain/port resolved
* by {@link buildAwfGatewayUrl} rather than the direct onrender HTTPS URL.
* The AWF api-proxy performs TLS MITM on outbound HTTPS which produces
* `EPROTO SSL wrong version number` when Node.js hits onrender.com directly,
* so gateway routing is mandatory inside the sandbox even when
* `scripts/mcp-setup.sh` was not sourced first.
*/
export function isAwfGatewayActive(): boolean {
if (hasMcpGatewayApiKey()) return true;
const configPath = process.env['GH_AW_MCP_CONFIG'] ?? '/home/runner/.copilot/mcp-config.json';
try {
if (!fs.existsSync(configPath)) return false;
const raw = JSON.parse(fs.readFileSync(configPath, 'utf8')) as Record<string, unknown>;
const gateway = raw['gateway'] as Record<string, unknown> | undefined;
if (gateway?.['apiKey']) return true;
const mcpServers = raw['mcpServers'] as Record<string, unknown> | undefined;
const rrServer = mcpServers?.['riksdag-regering'] as Record<string, unknown> | undefined;
const headers = rrServer?.['headers'] as Record<string, unknown> | undefined;
if (headers?.['Authorization']) return true;
} catch {
// Config read is best-effort — absence of config is not an error.
}
return false;
}
/**
* Resolve the default MCP server URL.
* Priority:
* 1. `MCP_SERVER_URL` env var (explicit override — e.g. from `mcp-setup.sh`).
* 2. AWF sandbox auto-detection → gateway URL on the dynamically-resolved
* `MCP_GATEWAY_DOMAIN:MCP_GATEWAY_PORT` (gh-aw v0.69+ uses port 8080).
* 3. Direct onrender HTTPS endpoint (local dev / CI outside AWF sandbox).
*/
export function getDefaultMcpServerUrl(): string {
const explicit = process.env['MCP_SERVER_URL'];
if (explicit) return explicit;
if (isAwfGatewayActive()) return buildAwfGatewayUrl('riksdag-regering');
return DIRECT_MCP_SERVER_URL;
}
|