feat: MVP implementation — MCP server, partner one-pager, legal docs

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
This commit is contained in:
Ty
2026-07-16 14:10:21 -07:00
parent 4def4d0726
commit 2be10ce42c
22 changed files with 3419 additions and 0 deletions
+71
View File
@@ -0,0 +1,71 @@
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);
}