import { pool } from './db/schema.js'; interface ManifestConfig { businessSlug: string; serverBaseUrl: string; } /** * Generate the /.well-known/mcp-server JSON manifest. * * Businesses (or their agencies) upload this file to their website root * at `/.well-known/mcp-server`. AI agents discover it automatically. */ export function generateManifest(config: ManifestConfig): Record { const { businessSlug, serverBaseUrl } = config; return { mcp_server: `${serverBaseUrl}/mcp/${businessSlug}`, protocol: 'streamable-http', version: '0.1.0', business: businessSlug, provider: 'geolocal.io', discovery: { transport: 'stdio', tools: [ 'get_business_info', 'get_hours', 'get_services', 'get_booking_link', 'get_related_businesses', ], }, }; } export async function getManifestForBusiness( businessSlug: string, serverBaseUrl: string = 'https://mcp.geolocal.io' ): Promise> { const result = await pool.query( `SELECT slug, name, mcp_endpoint FROM businesses WHERE slug = $1`, [businessSlug] ); if (result.rows.length === 0) { throw new Error(`Business '${businessSlug}' not found`); } const b = result.rows[0]; const baseUrl = b.mcp_endpoint || serverBaseUrl; return generateManifest({ businessSlug, serverBaseUrl: baseUrl }); } /** * CLI: Generate a manifest file for a given business slug. * Usage: npx tsx src/manifest-generator.ts --slug=frisco-german-auto */ async function cli() { const args = process.argv.slice(2); const slugArg = args.find((a) => a.startsWith('--slug=')); if (!slugArg) { console.error('Usage: npx tsx src/manifest-generator.ts --slug='); process.exit(1); } const slug = slugArg.split('=')[1]; const manifest = await getManifestForBusiness(slug); console.log(JSON.stringify(manifest, null, 2)); } if (process.argv[1]?.includes('manifest-generator')) { cli().catch(console.error); }