find_site_by_domain
Search across all servers for a site by domain name using partial match. Quickly locate any site linked to a domain in your Ploi infrastructure.
Instructions
Search for a site by domain name across all servers
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | The domain name to search for (partial match supported) |
Implementation Reference
- src/tools/sites.ts:26-390 (registration)The `registerSiteTools` function is exported and called from `src/tools/index.ts` (via `registerAllTools`), which registers all tools including 'find_site_by_domain' on the MCP server.
export function registerSiteTools(server: McpServer, client: PloiClient) { server.tool( "list_sites", "List all sites on a server", { server_id: z.coerce.number().describe("The ID of the server"), }, async ({ server_id }) => { const sites = await client.listSites(server_id); return { content: [ { type: "text" as const, text: JSON.stringify(sites, null, 2), }, ], }; } ); server.tool( "get_site", "Get details of a specific site", { server_id: z.coerce.number().describe("The ID of the server"), site_id: z.coerce.number().describe("The ID of the site"), }, async ({ server_id, site_id }) => { const site = await client.getSite(server_id, site_id); return { content: [ { type: "text" as const, text: JSON.stringify(site, null, 2), }, ], }; } ); server.tool( "deploy_site", "Trigger deployment for a site and wait for it to complete. Returns status when done.", { server_id: z.coerce.number().describe("The ID of the server"), site_id: z.coerce.number().describe("The ID of the site to deploy"), }, async ({ server_id, site_id }) => { await client.deploySite(server_id, site_id); // Poll until deployment completes (max 5 minutes) const maxAttempts = 60; const pollInterval = 5000; // 5 seconds for (let attempt = 0; attempt < maxAttempts; attempt++) { await new Promise(resolve => setTimeout(resolve, pollInterval)); const site = await client.getSite(server_id, site_id); if (site.status === "active") { return { content: [ { type: "text" as const, text: `✅ Deployment successful!\n\nSite: ${site.domain}\nStatus: ${site.status}`, }, ], }; } if (site.status !== "deploying") { // Some other status (error, etc) return { content: [ { type: "text" as const, text: `⚠️ Deployment ended with status: ${site.status}\n\nSite: ${site.domain}`, }, ], }; } } return { content: [ { type: "text" as const, text: `⏱️ Deployment still in progress after 5 minutes. Check status manually.`, }, ], }; } ); server.tool( "get_site_logs", "Get deployment/site logs", { server_id: z.coerce.number().describe("The ID of the server"), site_id: z.coerce.number().describe("The ID of the site"), }, async ({ server_id, site_id }) => { try { const logs = await client.getSiteLogs(server_id, site_id); return { content: [ { type: "text" as const, text: String(logs || "No logs available"), }, ], }; } catch (error) { return { content: [ { type: "text" as const, text: `Error fetching site logs: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); server.tool( "suspend_site", "Suspend a site", { server_id: z.coerce.number().describe("The ID of the server"), site_id: z.coerce.number().describe("The ID of the site to suspend"), }, async ({ server_id, site_id }) => { await client.suspendSite(server_id, site_id); return { content: [ { type: "text" as const, text: `Site ${site_id} on server ${server_id} has been suspended`, }, ], }; } ); server.tool( "resume_site", "Resume a suspended site", { server_id: z.coerce.number().describe("The ID of the server"), site_id: z.coerce.number().describe("The ID of the site to resume"), }, async ({ server_id, site_id }) => { await client.resumeSite(server_id, site_id); return { content: [ { type: "text" as const, text: `Site ${site_id} on server ${server_id} has been resumed`, }, ], }; } ); server.tool( "deploy_project", "Deploy the current project using .ploi.json config file and wait for completion. Use this when the user says 'deploy' without specifying a site.", { project_path: z.string().describe("The path to the project directory containing .ploi.json"), }, async ({ project_path }) => { const config = await readPloiConfig(project_path); if (!config) { return { content: [ { type: "text" as const, text: `No .ploi.json config found in ${project_path}. Create one with:\n{\n "server_id": YOUR_SERVER_ID,\n "site_id": YOUR_SITE_ID\n}\n\nOr use: "link this project to yourdomain.com"`, }, ], }; } const initialSite = await client.getSite(config.server_id, config.site_id); await client.deploySite(config.server_id, config.site_id); // Poll until deployment completes (max 5 minutes) const maxAttempts = 60; const pollInterval = 5000; // 5 seconds for (let attempt = 0; attempt < maxAttempts; attempt++) { await new Promise(resolve => setTimeout(resolve, pollInterval)); const site = await client.getSite(config.server_id, config.site_id); if (site.status === "active") { return { content: [ { type: "text" as const, text: `✅ Deployment successful!\n\nSite: ${site.domain}\nStatus: ${site.status}`, }, ], }; } if (site.status !== "deploying") { return { content: [ { type: "text" as const, text: `⚠️ Deployment ended with status: ${site.status}\n\nSite: ${site.domain}`, }, ], }; } } return { content: [ { type: "text" as const, text: `⏱️ Deployment still in progress after 5 minutes for ${initialSite.domain}. Check status manually.`, }, ], }; } ); server.tool( "get_project_deploy_status", "Check deployment status for the current project using .ploi.json config", { project_path: z.string().describe("The path to the project directory containing .ploi.json"), }, async ({ project_path }) => { const config = await readPloiConfig(project_path); if (!config) { return { content: [ { type: "text" as const, text: `No .ploi.json config found in ${project_path}`, }, ], }; } const site = await client.getSite(config.server_id, config.site_id); return { content: [ { type: "text" as const, text: JSON.stringify({ domain: site.domain, status: site.status, server_id: config.server_id, site_id: config.site_id, }, null, 2), }, ], }; } ); server.tool( "find_site_by_domain", "Search for a site by domain name across all servers", { domain: z.string().describe("The domain name to search for (partial match supported)"), }, async ({ domain }) => { const servers = await client.listServers(); const results: Array<{ server_id: number; server_name: string; site: Site }> = []; for (const server of servers) { const sites = await client.listSites(server.id); for (const site of sites) { if (site.domain.toLowerCase().includes(domain.toLowerCase())) { results.push({ server_id: server.id, server_name: server.name, site, }); } } } if (results.length === 0) { return { content: [ { type: "text" as const, text: `No sites found matching "${domain}"`, }, ], }; } return { content: [ { type: "text" as const, text: JSON.stringify(results, null, 2), }, ], }; } ); server.tool( "init_project", "Initialize .ploi.json config for a project by searching for a domain. Use when user wants to link a project to a Ploi site.", { project_path: z.string().describe("The path to the project directory"), domain: z.string().describe("The domain name of the Ploi site to link"), }, async ({ project_path, domain }) => { const servers = await client.listServers(); let foundServer: { id: number; name: string } | null = null; let foundSite: Site | null = null; for (const server of servers) { const sites = await client.listSites(server.id); for (const site of sites) { if (site.domain.toLowerCase().includes(domain.toLowerCase())) { foundServer = { id: server.id, name: server.name }; foundSite = site; break; } } if (foundSite) break; } if (!foundSite || !foundServer) { return { content: [ { type: "text" as const, text: `No site found matching "${domain}". Use list_servers and list_sites to find your site.`, }, ], }; } const config = { server_id: foundServer.id, site_id: foundSite.id, }; const configPath = join(project_path, ".ploi.json"); await writeFile(configPath, JSON.stringify(config, null, 2) + "\n"); return { content: [ { type: "text" as const, text: `Created .ploi.json for ${foundSite.domain}\n\nServer: ${foundServer.name} (${foundServer.id})\nSite: ${foundSite.domain} (${foundSite.id})\n\nYou can now use "deploy" to deploy this project.`, }, ], }; } ); } - src/tools/sites.ts:292-335 (handler)The handler for the 'find_site_by_domain' tool. It iterates over all servers, lists sites on each, does a case-insensitive partial match on the domain, and returns matching results.
server.tool( "find_site_by_domain", "Search for a site by domain name across all servers", { domain: z.string().describe("The domain name to search for (partial match supported)"), }, async ({ domain }) => { const servers = await client.listServers(); const results: Array<{ server_id: number; server_name: string; site: Site }> = []; for (const server of servers) { const sites = await client.listSites(server.id); for (const site of sites) { if (site.domain.toLowerCase().includes(domain.toLowerCase())) { results.push({ server_id: server.id, server_name: server.name, site, }); } } } if (results.length === 0) { return { content: [ { type: "text" as const, text: `No sites found matching "${domain}"`, }, ], }; } return { content: [ { type: "text" as const, text: JSON.stringify(results, null, 2), }, ], }; } ); - src/tools/sites.ts:295-297 (schema)The input schema: requires a `domain` string parameter (supports partial match) defined using Zod.
{ domain: z.string().describe("The domain name to search for (partial match supported)"), }, - src/tools/index.ts:7-11 (helper)The `registerAllTools` function that dispatches to `registerSiteTools`, which registers the 'find_site_by_domain' tool.
export function registerAllTools(server: McpServer, client: PloiClient) { registerServerTools(server, client); registerSiteTools(server, client); registerDatabaseTools(server, client); }