Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 59 additions & 43 deletions lib/agents/tools/geospatial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@ async function getConnectedMcpClient(): Promise<McpClient | null> {
const mapboxAccessToken = process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN;
const profileId = process.env.NEXT_PUBLIC_SMITHERY_PROFILE_ID;

// Log environment variables (masked for security)
console.log('[GeospatialTool] Environment check:', {
apiKey: apiKey ? `${apiKey.substring(0, 8)}...` : 'MISSING',
mapboxAccessToken: mapboxAccessToken ? `${mapboxAccessToken.substring(0, 8)}...` : 'MISSING',
profileId: profileId ? `${profileId.substring(0, 8)}...` : 'MISSING',
});

// Validate environment variables
if (!apiKey || !mapboxAccessToken || !profileId) {
console.error('[GeospatialTool] Missing required environment variables');
console.error('[GeospatialTool] Missing required environment variables:', {
apiKey: !!apiKey,
mapboxAccessToken: !!mapboxAccessToken,
profileId: !!profileId,
});
return null;
}

Expand All @@ -31,105 +37,115 @@ async function getConnectedMcpClient(): Promise<McpClient | null> {
return null;
}

// Load configuration
let config;
try {
const mapboxMcpConfig = await import('QCX/mapbox_mcp_config.json');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Fix the invalid import path.

The import path QCX/mapbox_mcp_config.json is incorrect. It should be a relative path from the current file location.

-    const mapboxMcpConfig = await import('QCX/mapbox_mcp_config.json');
+    const mapboxMcpConfig = await import('../../../mapbox_mcp_config.json');

🏁 Script executed:

#!/bin/bash
# Description: Verify the existence and location of mapbox_mcp_config.json file

# Search for the config file
fd -t f "mapbox_mcp_config.json"

# Check if the file exists at the repository root
if [ -f "mapbox_mcp_config.json" ]; then
  echo "Config file found at repository root"
  cat mapbox_mcp_config.json | head -20
fi

Length of output: 539


Fix invalid import path — use repo-root relative path

Verified: mapbox_mcp_config.json is at the repository root. Update the import to a relative path from lib/agents/tools/geospatial.tsx.

  • File: lib/agents/tools/geospatial.tsx — line 50
  • Found: mapbox_mcp_config.json at repo root

Suggested change:

-    const mapboxMcpConfig = await import('QCX/mapbox_mcp_config.json');
+    const mapboxMcpConfig = await import('../../../mapbox_mcp_config.json');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const mapboxMcpConfig = await import('QCX/mapbox_mcp_config.json');
const mapboxMcpConfig = await import('../../../mapbox_mcp_config.json');
🤖 Prompt for AI Agents
In lib/agents/tools/geospatial.tsx around line 50, the import uses a
non-repo-relative specifier; change the import to the repository-root relative
path to the JSON file (e.g., ../../../mapbox_mcp_config.json from
lib/agents/tools/geospatial.tsx). Update the import statement to reference that
relative path and ensure the JSON import syntax your build tool requires
(dynamic import or import with assertion) is used so the file resolves correctly
at runtime.

config = {
...mapboxMcpConfig.default || mapboxMcpConfig,
mapboxAccessToken
config = {
...mapboxMcpConfig.default || mapboxMcpConfig,
mapboxAccessToken,
};
console.log('[GeospatialTool] Config loaded successfully');
} catch (configError: any) {
console.error('[GeospatialTool] Failed to load mapbox config:', configError.message);
config = {
mapboxAccessToken,
version: '1.0.0',
name: 'mapbox-mcp-server'
name: 'mapbox-mcp-server',
};
console.log('[GeospatialTool] Using fallback config');
}

// Create Smithery URL with API key and profile ID
const mcpServerBaseUrl = `https://server.smithery.ai/@ngoiyaeric/mapbox-mcp-server?api_key=${apiKey}&profile=${profileId}`;
const smitheryUrlOptions = { config, apiKey, profileId };
const mcpServerBaseUrl = `https://server.smithery.ai/mapbox-mcp-server/mcp?api_key=${smitheryUrlOptions.apiKey}&profile=${smitheryUrlOptions.profileId}`;
let serverUrlToUse: URL;

let serverUrlToUse;
try {
serverUrlToUse = createSmitheryUrl(mcpServerBaseUrl, smitheryUrlOptions);
const urlDisplay = serverUrlToUse.toString().split('?')[0];
console.log('[GeospatialTool] MCP Server URL created:', urlDisplay);


// Validate URL
if (!serverUrlToUse.href || !serverUrlToUse.href.startsWith('https://')) {
throw new Error('Invalid server URL generated');
throw new Error('Invalid server URL: Must use HTTPS protocol');
}
} catch (urlError: any) {
console.error('[GeospatialTool] Error creating Smithery URL:', urlError.message);
console.error('[GeospatialTool] URL options:', {
console.error('[GeospatialTool] URL options:', {
baseUrl: mcpServerBaseUrl,
hasConfig: !!config,
hasApiKey: !!apiKey,
hasProfileId: !!profileId
hasProfileId: !!profileId,
});
return null;
}

// Initialize transport
let transport;
let client;

try {
console.log('[GeospatialTool] Initializing transport for:', serverUrlToUse.toString());
transport = new StreamableHTTPClientTransport(serverUrlToUse);
console.log('[GeospatialTool] Transport created successfully');
} catch (transportError: any) {
console.error('[GeospatialTool] Failed to create transport:', transportError.message);
return null;
}

// Initialize MCP client
try {
client = new MCPClientClass({
name: 'GeospatialToolClient',
version: '1.0.0'
client = new MCPClientClass({
name: 'GeospatialToolClient',
version: '1.0.0',
});
console.log('[GeospatialTool] MCP Client instance created');
} catch (clientError: any) {
console.error('[GeospatialTool] Failed to create MCP client:', clientError.message);
return null;
}

// Connect to MCP server with timeout
try {
console.log('[GeospatialTool] Attempting to connect to MCP server...');

await Promise.race([
client.connect(transport),
new Promise((_, reject) => {
setTimeout(() => reject(new Error('Connection timeout after 15 seconds')), 15000);
setTimeout(() => reject(new Error('Connection timeout after 30 seconds')), 30000);
}),
]);

console.log('[GeospatialTool] Successfully connected to MCP server');


// List available tools for debugging
try {
const tools = await client.listTools();
console.log('[GeospatialTool] Available tools:', tools.tools?.map(t => t.name) || []);
} catch (listError: any) {
console.warn('[GeospatialTool] Could not list tools:', listError.message);
}

return client;
} catch (connectionError: any) {
console.error('[GeospatialTool] MCP connection failed:', connectionError.message);
console.error('[GeospatialTool] Connection error details:', {
name: connectionError.name,
stack: connectionError.stack?.split('\n')[0],
serverUrl: serverUrlToUse?.toString().split('?')[0],
httpStatus: connectionError.response?.status,
httpResponse: connectionError.response?.data,
});


// Ensure client is closed on failure
await closeClient(client);
return null;
}
}

async function closeClient(client: MCPClientClass | null) {
if (!client) return;

try {
await Promise.race([
client.close(),
Expand All @@ -156,21 +172,21 @@ export const geospatialTool = ({
- Map-related requests
- Geographic information lookup`,
parameters: geospatialQuerySchema,
execute: async ({ query, queryType, includeMap }: {
query: string;
queryType?: string;
includeMap?: boolean;
execute: async ({ query, queryType, includeMap }: {
query: string;
queryType?: string;
includeMap?: boolean;
}) => {
console.log('[GeospatialTool] Execute called with:', { query, queryType, includeMap });

const uiFeedbackStream = createStreamableValue<string>();
uiStream.append(<BotMessage content={uiFeedbackStream.value} />);

let feedbackMessage = `Processing geospatial query: "${query}". Connecting to mapping service...`;
uiFeedbackStream.update(feedbackMessage);

const mcpClient = await getConnectedMcpClient();

if (!mcpClient) {
feedbackMessage = 'Geospatial functionality is currently unavailable. Please check your configuration and try again.';
uiFeedbackStream.update(feedbackMessage);
Expand All @@ -185,14 +201,14 @@ export const geospatialTool = ({
};
}

let mcpData: {
location: {
latitude?: number;
longitude?: number;
place_name?: string;
address?: string;
};
mapUrl?: string;
let mcpData: {
location: {
latitude?: number;
longitude?: number;
place_name?: string;
address?: string;
};
mapUrl?: string;
} | null = null;
let toolError: string | null = null;

Expand All @@ -202,9 +218,9 @@ export const geospatialTool = ({
uiStream.update(<BotMessage content={uiFeedbackStream.value} />);

const toolName = queryType === 'directions' ? 'mapbox_directions' : 'mapbox_geocoding';
const toolArgs = {
query,
includeMapPreview: includeMap !== false
const toolArgs = {
searchText: query,
includeMapPreview: includeMap !== false,
};

console.log('[GeospatialTool] Calling tool:', toolName, 'with args:', toolArgs);
Expand Down Expand Up @@ -236,20 +252,20 @@ export const geospatialTool = ({

const geocodeResult = geocodeResultUnknown as { tool_results?: Array<{ content?: unknown }> };
const toolResults = Array.isArray(geocodeResult.tool_results) ? geocodeResult.tool_results : [];

if (toolResults.length === 0 || !toolResults[0]?.content) {
throw new Error('No content returned from mapping service');
}

let content = toolResults[0].content;

if (typeof content === 'string') {
const jsonRegex = /```(?:json)?\n?([\s\S]*?)\n?```/;
const match = content.match(jsonRegex);
if (match) {
content = match[1].trim();
}

try {
if (typeof content === 'string') {
content = JSON.parse(content);
Expand All @@ -261,7 +277,7 @@ export const geospatialTool = ({

if (typeof content === 'object' && content !== null) {
const parsedData = content as any;

if (parsedData.location) {
mcpData = {
location: {
Expand Down