/** * sh-mcp-ops application assembly. * * Wires the registry, auth provider, audit logger, and rate limiter into the * shared Express host (build-plan §2.2). Exported separately from `index.ts` so * tests can build the app without binding a port. */ import { ConsoleAuditLogger, InMemoryRateLimiter, createApp, type DispatchDeps, } from '@sh-mcp/shared'; import type { Express } from 'express'; import { buildOpsRegistry } from './registry.js'; import { buildOpsAuthProvider } from './auth.js'; import { loadOpsConfig, type OpsConfig } from './config.js'; export interface BuildAppResult { app: Express; config: OpsConfig; } /** Build the ops server app. Pass a config to override env loading (tests). */ export async function buildOpsApp(configOverride?: OpsConfig): Promise { const config = configOverride ?? loadOpsConfig(); const registry = await buildOpsRegistry(config); const authProvider = buildOpsAuthProvider(config); const deps: DispatchDeps = { auditLogger: new ConsoleAuditLogger(), // Generous local limits; tightened per-tier in production (design.md §7.3). rateLimiter: new InMemoryRateLimiter({ sessionCap: 200, perToolLimit: 60, windowMs: 60_000, }), }; const app = createApp({ registry, authProvider, deps, mcpInfo: { name: 'sh-mcp-ops', version: '0.1.0' }, openApi: { info: { title: 'Sea Haven MCP — Ops', version: '0.1.0', description: 'Operations-tier tools (read-mostly). design.md §3.', }, servers: [{ url: `http://localhost:${config.port}`, description: 'local' }], }, }); return { app, config }; }