merge: server architecture modularization
This commit is contained in:
+73
-11
@@ -2,11 +2,25 @@ import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { resolveAgentGooseMode } from './policies.mjs';
|
||||
|
||||
/** Spawned as a separate Node process by goosed; must sit beside bundled portal runtime. */
|
||||
export function resolveSandboxMcpServerPath(overridePath) {
|
||||
function resolveBundledMcpServerPath(filename, overridePath, runtimeRoot) {
|
||||
const normalized = String(overridePath ?? '').trim();
|
||||
if (normalized) return normalized;
|
||||
return path.join(path.dirname(fileURLToPath(import.meta.url)), 'mindspace-sandbox-mcp.mjs');
|
||||
const normalizedRuntimeRoot = String(
|
||||
runtimeRoot ?? process.env.MEMIND_PORTAL_H5_ROOT ?? '',
|
||||
).trim();
|
||||
return path.join(
|
||||
normalizedRuntimeRoot || path.dirname(fileURLToPath(import.meta.url)),
|
||||
filename,
|
||||
);
|
||||
}
|
||||
|
||||
/** Spawned as a separate Node process by goosed; must sit beside bundled portal runtime. */
|
||||
export function resolveSandboxMcpServerPath(overridePath, runtimeRoot) {
|
||||
return resolveBundledMcpServerPath(
|
||||
'mindspace-sandbox-mcp.mjs',
|
||||
overridePath,
|
||||
runtimeRoot,
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveSandboxMcpNodeExecPath(overridePath) {
|
||||
@@ -17,6 +31,25 @@ export function resolveSandboxMcpNodeExecPath(overridePath) {
|
||||
|
||||
const LOOPBACK_PG_HOSTS = new Set(['127.0.0.1', 'localhost', '::1']);
|
||||
|
||||
function rewritePgUnixSocketUrlForContainer(sourceUrl, hostGateway) {
|
||||
const raw = String(sourceUrl ?? '').trim();
|
||||
const authorityMatch = raw.match(/^(postgres(?:ql)?:\/\/[^@/]+@)\/(.*)$/i);
|
||||
if (!authorityMatch) return null;
|
||||
try {
|
||||
const parsed = new URL(`${authorityMatch[1]}localhost/${authorityMatch[2]}`);
|
||||
const socketHost = String(parsed.searchParams.get('host') ?? '').trim();
|
||||
if (!socketHost.startsWith('/')) return null;
|
||||
const port = String(parsed.searchParams.get('port') ?? '5432').trim() || '5432';
|
||||
parsed.hostname = String(hostGateway || 'host.docker.internal').trim();
|
||||
parsed.port = port;
|
||||
parsed.searchParams.delete('host');
|
||||
parsed.searchParams.delete('port');
|
||||
return parsed.toString();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveSandboxMcpUserDataPgUrl({
|
||||
portalUrl,
|
||||
mcpUrl,
|
||||
@@ -36,16 +69,30 @@ export function resolveSandboxMcpUserDataPgUrl({
|
||||
}
|
||||
return parsed.toString();
|
||||
} catch {
|
||||
const rewrittenSocketUrl = rewritePgUnixSocketUrlForContainer(sourceUrl, hostGateway);
|
||||
if (rewrittenSocketUrl) {
|
||||
const parsed = new URL(rewrittenSocketUrl);
|
||||
if (!parsed.password) {
|
||||
const error = new Error(
|
||||
'Containerized private-data MCP cannot convert a passwordless PostgreSQL Unix-socket DSN to TCP. Configure MINDSPACE_USERDATA_MCP_PG_URL with a container-reachable authenticated DSN.',
|
||||
);
|
||||
error.code = 'MINDSPACE_USERDATA_MCP_PG_URL_REQUIRED';
|
||||
throw error;
|
||||
}
|
||||
return rewrittenSocketUrl;
|
||||
}
|
||||
// Preserve the configured value so the MCP reports the real configuration
|
||||
// error instead of silently falling back to its local Unix socket default.
|
||||
return sourceUrl;
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveMindSearchMcpServerPath(overridePath) {
|
||||
const normalized = String(overridePath ?? '').trim();
|
||||
if (normalized) return normalized;
|
||||
return path.join(path.dirname(fileURLToPath(import.meta.url)), 'tkmind-search-mcp.mjs');
|
||||
export function resolveMindSearchMcpServerPath(overridePath, runtimeRoot) {
|
||||
return resolveBundledMcpServerPath(
|
||||
'tkmind-search-mcp.mjs',
|
||||
overridePath,
|
||||
runtimeRoot,
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveMindSearchMcpEndpoint(
|
||||
@@ -65,10 +112,12 @@ export function resolveMindSearchMcpEndpoint(
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveExcelMcpServerPath(overridePath) {
|
||||
const normalized = String(overridePath ?? '').trim();
|
||||
if (normalized) return normalized;
|
||||
return path.join(path.dirname(fileURLToPath(import.meta.url)), 'tkmind-excel-mcp.mjs');
|
||||
export function resolveExcelMcpServerPath(overridePath, runtimeRoot) {
|
||||
return resolveBundledMcpServerPath(
|
||||
'tkmind-excel-mcp.mjs',
|
||||
overridePath,
|
||||
runtimeRoot,
|
||||
);
|
||||
}
|
||||
|
||||
export const CAPABILITY_CATALOG = [
|
||||
@@ -369,6 +418,19 @@ function sandboxMcpEnvs(sandboxMcp, mcpTools) {
|
||||
if (sandboxMcp.workspaceRoot || localRoot) envs.MINDSPACE_WORKSPACE_ROOT = sandboxMcp.workspaceRoot || localRoot;
|
||||
if (sandboxMcp.workspaceRef) envs.MINDSPACE_WORKSPACE_REF = sandboxMcp.workspaceRef;
|
||||
if (sandboxMcp.userId) envs.PRIVATE_DATA_USER_ID = sandboxMcp.userId;
|
||||
for (const [key, value] of [
|
||||
['H5_PUBLIC_BASE_URL', sandboxMcp.publicBaseUrl],
|
||||
['H5_PORTAL_BASE_URL', sandboxMcp.portalBaseUrl],
|
||||
['H5_PORT', sandboxMcp.portalPort],
|
||||
[
|
||||
'MEMIND_PAGE_DATA_DELIVERY_BASE_URL',
|
||||
sandboxMcp.pageDataDeliveryBaseUrl,
|
||||
],
|
||||
]) {
|
||||
if (value != null && String(value).trim()) {
|
||||
envs[key] = String(value).trim();
|
||||
}
|
||||
}
|
||||
if (mcpTools.includes('generate_image')) {
|
||||
if (sandboxMcp.agentApiBaseUrl) {
|
||||
envs.MINDSPACE_AGENT_API_BASE_URL = sandboxMcp.agentApiBaseUrl;
|
||||
|
||||
Reference in New Issue
Block a user