← back to Goodquestion
src/lib/mcp-client.ts
146 lines
import { MCPSearchResult, MCPDocument } from '@/types/swot'
// MCP Server Configuration
interface MCPConfig {
serverUrl: string
apiKey?: string
}
// Default configuration - should be overridden via environment variables
const defaultConfig: MCPConfig = {
serverUrl: process.env.MCP_SERVER_URL || 'http://localhost:8000',
apiKey: process.env.MCP_API_KEY,
}
/**
* MCP Client for interacting with the Model Context Protocol server
* Implements search and fetch tools for accessing local business data
*/
export class MCPClient {
private config: MCPConfig
constructor(config?: Partial<MCPConfig>) {
this.config = { ...defaultConfig, ...config }
}
/**
* Search the MCP vector store for relevant documents
* @param query - Search query string
* @param filters - Optional filters for search (e.g., document type, date range)
* @param limit - Maximum number of results to return
*/
async search(
query: string,
filters?: {
documentType?: string[]
dateFrom?: string
dateTo?: string
location?: string
},
limit: number = 10
): Promise<MCPSearchResult[]> {
try {
const response = await fetch(`${this.config.serverUrl}/search`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(this.config.apiKey && { Authorization: `Bearer ${this.config.apiKey}` }),
},
body: JSON.stringify({ query, filters, limit }),
})
if (!response.ok) {
throw new Error(`MCP search failed: ${response.statusText}`)
}
const data = await response.json()
return data.results as MCPSearchResult[]
} catch (error) {
console.error('MCP search error:', error)
throw error
}
}
/**
* Fetch the full content of a document by ID
* @param documentId - The unique identifier of the document
*/
async fetch(documentId: string): Promise<MCPDocument> {
try {
const response = await fetch(`${this.config.serverUrl}/fetch/${documentId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
...(this.config.apiKey && { Authorization: `Bearer ${this.config.apiKey}` }),
},
})
if (!response.ok) {
throw new Error(`MCP fetch failed: ${response.statusText}`)
}
const data = await response.json()
return data as MCPDocument
} catch (error) {
console.error('MCP fetch error:', error)
throw error
}
}
/**
* Search for competitors in a specific location and business category
*/
async searchCompetitors(
businessType: string,
location: string,
radius: number = 10
): Promise<MCPSearchResult[]> {
const query = `competitors ${businessType} near ${location} within ${radius} miles`
return this.search(query, {
documentType: ['business-directory', 'competitor-analysis'],
location,
})
}
/**
* Search for historical economic data about a location
*/
async searchHistoricalData(location: string): Promise<MCPSearchResult[]> {
const query = `historical economic data ${location} population growth business development`
return this.search(query, {
documentType: ['historical-document', 'economic-report', 'census-data'],
location,
})
}
/**
* Search for market trends and opportunities
*/
async searchMarketTrends(
businessType: string,
location: string
): Promise<MCPSearchResult[]> {
const query = `market trends opportunities ${businessType} ${location}`
return this.search(query, {
documentType: ['market-report', 'trend-analysis', 'industry-report'],
})
}
/**
* Search for regulatory and zoning information
*/
async searchRegulatory(
businessType: string,
location: string
): Promise<MCPSearchResult[]> {
const query = `zoning regulations permits requirements ${businessType} ${location}`
return this.search(query, {
documentType: ['zoning-map', 'regulatory-document', 'permit-guide'],
location,
})
}
}
// Export singleton instance
export const mcpClient = new MCPClient()