diff --git a/app/api/mcp/route.ts b/app/api/mcp/route.ts index 15c0c9ec..2b763356 100644 --- a/app/api/mcp/route.ts +++ b/app/api/mcp/route.ts @@ -43,6 +43,7 @@ import { listApplicationDeployments, listApplicationEnvs, listApplicationsInProject, + getProject, projectUuidOf, TenantError, upsertApplicationEnv, @@ -418,18 +419,28 @@ async function toolAppsList(principal: Principal) { // Fetch Applications and Services in parallel. // Services are compose stacks created via the composeRaw pathway; // they live at /services not /applications. - const [apps, allServices] = await Promise.allSettled([ + // Coolify's /services response does NOT include a `project` field — services + // belong to environments, and environments belong to projects. So we resolve + // the project's environment IDs first, then filter services by environment_id. + const [apps, allServices, project] = await Promise.allSettled([ listApplicationsInProject(projectUuid), listAllServices(), + getProject(projectUuid), ]); const appList = apps.status === 'fulfilled' ? apps.value : []; + const projectEnvIds = new Set( + project.status === 'fulfilled' + ? (project.value.environments ?? []).map((e) => e.id) + : [], + ); + const serviceList = (allServices.status === 'fulfilled' && Array.isArray(allServices.value) ? (allServices.value as Array>) : [] - ).filter(s => { - const proj = s.project as Record | undefined; - return proj?.uuid === projectUuid; + ).filter((s) => { + const envId = typeof s.environment_id === 'number' ? s.environment_id : Number(s.environment_id); + return projectEnvIds.has(envId); }); return NextResponse.json({ @@ -443,15 +454,21 @@ async function toolAppsList(principal: Principal) { gitBranch: a.git_branch ?? null, resourceType: 'application', })), - ...serviceList.map(s => ({ - uuid: String(s.uuid), - name: String(s.name ?? ''), - status: String(s.status ?? 'unknown'), - fqdn: null, - gitRepository: null, - gitBranch: null, - resourceType: 'service', - })), + ...serviceList.map((s) => { + // Try to extract a usable URL from the service's applications array + // (compose stacks expose their public service's fqdn there). + const apps = (s.applications as Array>) || []; + const publicApp = apps.find((a) => a.fqdn); + return { + uuid: String(s.uuid), + name: String(s.name ?? ''), + status: String(s.status ?? 'unknown'), + fqdn: publicApp?.fqdn ? String(publicApp.fqdn) : null, + gitRepository: null, + gitBranch: null, + resourceType: 'service', + }; + }), ], }); }