fix: HTTP health probes use container IP for internal network communication
mcpd and MCP containers share the mcp-servers Docker network. HTTP probes must use the container's internal IP + containerPort instead of localhost + host-mapped port. Also extracts container IP from Docker inspect. Updated home-assistant template to use ghcr.io/homeassistant-ai/ha-mcp Docker image (SSE transport) instead of broken npm package. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -138,6 +138,19 @@ export class DockerContainerManager implements McpOrchestrator {
|
||||
if (port !== undefined) {
|
||||
result.port = port;
|
||||
}
|
||||
|
||||
// Extract container IP from first non-default network
|
||||
const networks = info.NetworkSettings?.Networks;
|
||||
if (networks) {
|
||||
for (const [, net] of Object.entries(networks)) {
|
||||
const netInfo = net as { IPAddress?: string };
|
||||
if (netInfo.IPAddress) {
|
||||
result.ip = netInfo.IPAddress;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ export class HealthProbeRunner {
|
||||
|
||||
try {
|
||||
if (server.transport === 'SSE' || server.transport === 'STREAMABLE_HTTP') {
|
||||
result = await this.probeHttp(instance, healthCheck, timeoutMs);
|
||||
result = await this.probeHttp(instance, server, healthCheck, timeoutMs);
|
||||
} else {
|
||||
result = await this.probeStdio(instance, server, healthCheck, timeoutMs);
|
||||
}
|
||||
@@ -172,11 +172,26 @@ export class HealthProbeRunner {
|
||||
/** Probe an HTTP/SSE MCP server by sending a JSON-RPC tool call. */
|
||||
private async probeHttp(
|
||||
instance: McpInstance,
|
||||
server: McpServer,
|
||||
healthCheck: HealthCheckSpec,
|
||||
timeoutMs: number,
|
||||
): Promise<ProbeResult> {
|
||||
if (!instance.port) {
|
||||
return { healthy: false, latencyMs: 0, message: 'No port assigned' };
|
||||
if (!instance.containerId) {
|
||||
return { healthy: false, latencyMs: 0, message: 'No container ID' };
|
||||
}
|
||||
|
||||
// Get container IP for internal network communication
|
||||
// (mcpd and MCP containers share the mcp-servers network)
|
||||
const containerInfo = await this.orchestrator.inspectContainer(instance.containerId);
|
||||
const containerPort = (server.containerPort as number | null) ?? 3000;
|
||||
|
||||
let url: string;
|
||||
if (containerInfo.ip) {
|
||||
url = `http://${containerInfo.ip}:${containerPort}`;
|
||||
} else if (instance.port) {
|
||||
url = `http://localhost:${instance.port}`;
|
||||
} else {
|
||||
return { healthy: false, latencyMs: 0, message: 'No container IP or port' };
|
||||
}
|
||||
|
||||
const start = Date.now();
|
||||
@@ -187,7 +202,7 @@ export class HealthProbeRunner {
|
||||
|
||||
try {
|
||||
// Initialize
|
||||
const initResp = await fetch(`http://localhost:${instance.port}`, {
|
||||
const initResp = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json, text/event-stream' },
|
||||
body: JSON.stringify({
|
||||
@@ -206,14 +221,14 @@ export class HealthProbeRunner {
|
||||
if (sessionId) headers['Mcp-Session-Id'] = sessionId;
|
||||
|
||||
// Send initialized notification
|
||||
await fetch(`http://localhost:${instance.port}`, {
|
||||
await fetch(url, {
|
||||
method: 'POST', headers,
|
||||
body: JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized' }),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
// Call health check tool
|
||||
const toolResp = await fetch(`http://localhost:${instance.port}`, {
|
||||
const toolResp = await fetch(url, {
|
||||
method: 'POST', headers,
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0', id: 2, method: 'tools/call',
|
||||
|
||||
@@ -30,6 +30,8 @@ export interface ContainerInfo {
|
||||
name: string;
|
||||
state: 'running' | 'stopped' | 'starting' | 'error' | 'unknown';
|
||||
port?: number;
|
||||
/** Container IP on the first non-default network (for internal communication) */
|
||||
ip?: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user