2be10ce42c
Code (code/): - TypeScript MCP server with 5 tools (business info, hours, services, booking, related) - PostgreSQL schema with pilot business seed data - /.well-known/mcp-server manifest generator - Railway deployment config (Dockerfile, railway.json) - Multi-tenant gateway placeholder GTM (docs/gtm/): - Partner One-Pager: agency sales asset with economics, onboarding, competitive comparison Legal (docs/legal/): - Data Flow & Privacy: data collection, storage, sharing, GDPR/CCPA commitments - Partnership Agreement Skeleton: template for agency/CoC partnerships - IP Notes: well-known convention positioning, telemetry ownership, open-source strategy
72 lines
2.0 KiB
TypeScript
72 lines
2.0 KiB
TypeScript
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<string, any> {
|
|
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<Record<string, any>> {
|
|
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=<business-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);
|
|
}
|