enrich_uk_business
Generate comprehensive UK business profiles by combining Companies House data, Google Places ratings, website SSL status, and social media links from a single lookup.
Instructions
Get a comprehensive profile of any UK business. Returns Companies House data (company status, directors, SIC codes), Google Places ratings and reviews, website/SSL status, and social media links — all from a single lookup. Provide a business name and location (city or town). Optionally include a Companies House number or website domain for more precise results.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| business_name | Yes | The business name to look up (e.g. "Greggs", "Nando's") | |
| location | Yes | City, town, or area in the UK (e.g. "Manchester", "Bristol") | |
| company_number | No | Companies House number — 8 digits or 2 letters + 6 digits. Optional. | |
| domain | No | Business website domain without protocol (e.g. "greggs.co.uk"). Optional. |
Implementation Reference
- src/lib/services/enrichment.ts:51-164 (handler)The primary handler function for the `enrich_uk_business` tool, orchestrating multiple data adapters (Companies House, Google Places, DNS, Scraper) and caching.
export async function enrichBusiness( request: EnrichRequest, plan?: string ): Promise<EnrichedBusinessProfile> { const startTime = Date.now(); const profile = createEmptyProfile(request); const input: AdapterInput = { business_name: request.business_name, location: request.location, company_number: request.company_number, domain: request.domain, }; // Round 1: Companies House + Google Places in parallel const [chResult, gpResult] = await Promise.allSettled([ cachedFetch(companiesHouseAdapter, input), cachedFetch(googlePlacesAdapter, input), ]); // Merge Companies House data if (chResult.status === 'fulfilled' && chResult.value.success && chResult.value.data) { const ch = chResult.value.data; profile.companies_house = { company_number: ch.company_number, company_name: ch.company_name, company_status: ch.company_status, incorporation_date: ch.incorporation_date, company_type: ch.company_type, sic_codes: ch.sic_codes, registered_address: ch.registered_address, directors: ch.directors, }; profile.meta.sources_successful.push('companies_house'); if (chResult.value.cached) profile.meta.cached_sources.push('companies_house'); // Update cache key now that we have a company number if (ch.company_number && !input.company_number) { input.company_number = ch.company_number; } } else { profile.meta.sources_failed.push('companies_house'); } // Merge Google Places data if (gpResult.status === 'fulfilled' && gpResult.value.success && gpResult.value.data) { const gp = gpResult.value.data; profile.google_places = { place_id: gp.place_id, display_name: gp.display_name, formatted_address: gp.formatted_address, rating: gp.rating, review_count: gp.review_count, phone: gp.phone, website: gp.website, google_maps_url: gp.google_maps_url, }; profile.meta.sources_successful.push('google_places'); if (gpResult.value.cached) profile.meta.cached_sources.push('google_places'); // Discover domain from Google Places website if not already known if (!input.domain && gp.website) { const discovered = extractDomain(gp.website); if (discovered) { input.domain = discovered; profile.query.domain = discovered; } } } else { profile.meta.sources_failed.push('google_places'); } // Round 2: DNS + Web Scraper (only if domain is available) if (input.domain) { profile.website.domain = input.domain; const [dnsResult, scrapeResult] = await Promise.allSettled([ cachedFetch(dnsCheckAdapter, input), cachedFetch(webScraperAdapter, input), ]); // Merge DNS data if (dnsResult.status === 'fulfilled' && dnsResult.value.success && dnsResult.value.data) { const d = dnsResult.value.data; profile.website.is_live = d.is_live; profile.website.http_status = d.http_status; profile.website.ssl_valid = d.ssl_valid; profile.website.ssl_expiry = d.ssl_expiry; profile.meta.sources_successful.push('dns'); if (dnsResult.value.cached) profile.meta.cached_sources.push('dns'); } else { profile.meta.sources_failed.push('dns'); } // Merge scrape data if (scrapeResult.status === 'fulfilled' && scrapeResult.value.success && scrapeResult.value.data) { profile.social = scrapeResult.value.data; profile.meta.sources_successful.push('scrape'); if (scrapeResult.value.cached) profile.meta.cached_sources.push('scrape'); } else { profile.meta.sources_failed.push('scrape'); } } else { // No domain available — these adapters were not attempted profile.meta.sources_skipped.push('dns'); profile.meta.sources_skipped.push('scrape'); } // Finalize metadata profile.meta.enriched_at = new Date().toISOString(); profile.meta.duration_ms = Date.now() - startTime; return applyPlanGating(profile, plan); } - src/mcp/server.ts:26-58 (registration)The registration block for the `enrich_uk_business` tool in the MCP server.
server.registerTool( 'enrich_uk_business', { title: 'Enrich UK Business', description: 'Get a comprehensive profile of any UK business. Returns Companies House data ' + '(company status, directors, SIC codes), Google Places ratings and reviews, ' + 'website/SSL status, and social media links — all from a single lookup. ' + 'Provide a business name and location (city or town). Optionally include a ' + 'Companies House number or website domain for more precise results.', inputSchema, }, async (args) => { try { const profile = await enrichBusiness({ business_name: args.business_name, location: args.location, company_number: args.company_number, domain: args.domain, }); return { content: [{ type: 'text' as const, text: JSON.stringify(profile, null, 2) }], }; } catch (err) { const message = err instanceof Error ? err.message : 'Unknown error during enrichment'; return { content: [{ type: 'text' as const, text: `Enrichment failed: ${message}` }], isError: true, }; } } ); - src/mcp/server.ts:11-24 (schema)The Zod input schema for the `enrich_uk_business` tool.
const inputSchema = { business_name: z.string().min(1).max(200) .describe('The business name to look up (e.g. "Greggs", "Nando\'s")'), location: z.string().min(1).max(200) .describe('City, town, or area in the UK (e.g. "Manchester", "Bristol")'), company_number: z.string() .regex(/^([0-9]{8}|[A-Za-z]{2}[0-9]{6})$/) .describe('Companies House number — 8 digits or 2 letters + 6 digits. Optional.') .optional(), domain: z.string().max(253) .regex(/^(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,}$/i) .describe('Business website domain without protocol (e.g. "greggs.co.uk"). Optional.') .optional(), };