From 96a99e97c9468f7594fd2de4324b006d75b07948 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Thu, 14 Aug 2025 10:20:55 +0000
Subject: [PATCH 1/8] fix(geospatial): Align parameter with server expectation
A geospatial request was sending a `query` parameter, but the server expected `searchText`. This caused a validation error.
This commit renames the parameter to `searchText` to match the server's API, resolving the error.
---
lib/agents/tools/geospatial.tsx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/agents/tools/geospatial.tsx b/lib/agents/tools/geospatial.tsx
index 80a05738..826ba48f 100644
--- a/lib/agents/tools/geospatial.tsx
+++ b/lib/agents/tools/geospatial.tsx
@@ -202,9 +202,9 @@ export const geospatialTool = ({
uiStream.update();
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);
From 26bf23e4518592977b72a69ee76bfede131cd233 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Thu, 14 Aug 2025 10:36:28 +0000
Subject: [PATCH 2/8] fix(geospatial): Correct server URL and align tool
parameter
This commit addresses two issues:
1. **Parameter Mismatch:** The geospatial tool was sending a `query` parameter, but the server expected `searchText`. This has been corrected.
2. **Incorrect Server URL:** The tool was constructing an incorrect URL, leading to a 404 error. The `mcpServerBaseUrl` has been updated to the correct endpoint you provided, which includes the necessary user scope.
---
lib/agents/tools/geospatial.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/agents/tools/geospatial.tsx b/lib/agents/tools/geospatial.tsx
index 826ba48f..0ece89f7 100644
--- a/lib/agents/tools/geospatial.tsx
+++ b/lib/agents/tools/geospatial.tsx
@@ -50,7 +50,7 @@ async function getConnectedMcpClient(): Promise {
}
const smitheryUrlOptions = { config, apiKey, profileId };
- const mcpServerBaseUrl = `https://server.smithery.ai/mapbox-mcp-server/mcp?api_key=${smitheryUrlOptions.apiKey}&profile=${smitheryUrlOptions.profileId}`;
+ const mcpServerBaseUrl = `https://server.smithery.ai/@ngoiyaeric/mapbox-mcp-server`;
let serverUrlToUse;
try {
From 7755b0bcb46b255349943b97287a7db7807227d5 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Thu, 14 Aug 2025 10:45:16 +0000
Subject: [PATCH 3/8] I've made a commit to fix the geospatial tool. Here's a
summary of the changes:
1. **Authentication:** I've updated the HTTP transport to send the API key as a Bearer token in the `Authorization` header, which resolves the 401 Unauthorized error.
2. **Server URL:** I've corrected the base URL for the Smithery server to point to your user-specific endpoint, fixing the 404 Not Found error.
3. **Tool Parameter:** I've changed the `mapbox_geocoding` tool call to use the `searchText` parameter instead of `query`. This aligns with the server's API and fixes the initial tool execution failure.
---
lib/agents/tools/geospatial.tsx | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/lib/agents/tools/geospatial.tsx b/lib/agents/tools/geospatial.tsx
index 0ece89f7..ae940dfc 100644
--- a/lib/agents/tools/geospatial.tsx
+++ b/lib/agents/tools/geospatial.tsx
@@ -76,7 +76,11 @@ async function getConnectedMcpClient(): Promise {
let client;
try {
- transport = new StreamableHTTPClientTransport(serverUrlToUse);
+ transport = new StreamableHTTPClientTransport(serverUrlToUse, {
+ headers: {
+ Authorization: `Bearer ${apiKey}`,
+ },
+ });
console.log('[GeospatialTool] Transport created successfully');
} catch (transportError: any) {
console.error('[GeospatialTool] Failed to create transport:', transportError.message);
From 091e0041c1b5823b6efbe5d03860589476e3e52a Mon Sep 17 00:00:00 2001
From: EreQ
Date: Thu, 14 Aug 2025 13:50:52 +0300
Subject: [PATCH 4/8] Update geospatial.tsx
---
lib/agents/tools/geospatial.tsx | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/lib/agents/tools/geospatial.tsx b/lib/agents/tools/geospatial.tsx
index ae940dfc..1544884e 100644
--- a/lib/agents/tools/geospatial.tsx
+++ b/lib/agents/tools/geospatial.tsx
@@ -50,7 +50,7 @@ async function getConnectedMcpClient(): Promise {
}
const smitheryUrlOptions = { config, apiKey, profileId };
- const mcpServerBaseUrl = `https://server.smithery.ai/@ngoiyaeric/mapbox-mcp-server`;
+ const mcpServerBaseUrl = `https://server.smithery.ai/@ngoiyaeric/mapbox-mcp-server?api_key=${smitheryUrlOptions.apiKey}&profile=${smitheryUrlOptions.profileId}`;
let serverUrlToUse;
try {
@@ -75,12 +75,9 @@ async function getConnectedMcpClient(): Promise {
let transport;
let client;
- try {
- transport = new StreamableHTTPClientTransport(serverUrlToUse, {
- headers: {
- Authorization: `Bearer ${apiKey}`,
- },
- });
+
+ transport = new StreamableHTTPClientTransport(serverUrlToUse);
+
console.log('[GeospatialTool] Transport created successfully');
} catch (transportError: any) {
console.error('[GeospatialTool] Failed to create transport:', transportError.message);
From d9d12b10a44125e87e6ec4a0803eaad3684cd1cd Mon Sep 17 00:00:00 2001
From: EreQ
Date: Thu, 14 Aug 2025 14:34:42 +0300
Subject: [PATCH 5/8] Update geospatial.tsx
---
lib/agents/tools/geospatial.tsx | 118 ++++++++++++++++++++------------
1 file changed, 74 insertions(+), 44 deletions(-)
diff --git a/lib/agents/tools/geospatial.tsx b/lib/agents/tools/geospatial.tsx
index 1544884e..6f338022 100644
--- a/lib/agents/tools/geospatial.tsx
+++ b/lib/agents/tools/geospatial.tsx
@@ -15,14 +15,20 @@ async function getConnectedMcpClient(): Promise {
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;
}
@@ -31,12 +37,20 @@ async function getConnectedMcpClient(): Promise {
return null;
}
+ // Validate profile ID format (UUID)
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
+ if (!uuidRegex.test(profileId)) {
+ console.error('[GeospatialTool] Invalid profile ID format:', profileId);
+ return null;
+ }
+
+ // Load configuration
let config;
try {
const mapboxMcpConfig = await import('QCX/mapbox_mcp_config.json');
- config = {
- ...mapboxMcpConfig.default || mapboxMcpConfig,
- mapboxAccessToken
+ config = {
+ ...mapboxMcpConfig.default || mapboxMcpConfig,
+ mapboxAccessToken,
};
console.log('[GeospatialTool] Config loaded successfully');
} catch (configError: any) {
@@ -44,50 +58,61 @@ async function getConnectedMcpClient(): Promise {
config = {
mapboxAccessToken,
version: '1.0.0',
- name: 'mapbox-mcp-server'
+ name: 'mapbox-mcp-server',
};
console.log('[GeospatialTool] Using fallback config');
}
- const smitheryUrlOptions = { config, apiKey, profileId };
- const mcpServerBaseUrl = `https://server.smithery.ai/@ngoiyaeric/mapbox-mcp-server?api_key=${smitheryUrlOptions.apiKey}&profile=${smitheryUrlOptions.profileId}`;
+ // Create Smithery URL without API key in query parameters
+ const mcpServerBaseUrl = `https://server.smithery.ai/@ngoiyaeric/mapbox-mcp-server?profile=${profileId}`;
+ const smitheryUrlOptions = { config, 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 with authentication headers
let transport;
let client;
-
-
- transport = new StreamableHTTPClientTransport(serverUrlToUse);
+ const headers = {
+ Authorization: `Bearer ${apiKey}`,
+ 'X-Profile-ID': profileId,
+ 'Content-Type': 'application/json',
+ };
+ try {
+ console.log('[GeospatialTool] Initializing transport with headers:', {
+ Authorization: `Bearer ${apiKey.substring(0, 8)}...`,
+ 'X-Profile-ID': profileId.substring(0, 8) + '...',
+ });
+ transport = new StreamableHTTPClientTransport(serverUrlToUse, { headers });
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) {
@@ -95,25 +120,27 @@ async function getConnectedMcpClient(): Promise {
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);
@@ -121,8 +148,11 @@ async function getConnectedMcpClient(): Promise {
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;
}
@@ -130,7 +160,7 @@ async function getConnectedMcpClient(): Promise {
async function closeClient(client: MCPClientClass | null) {
if (!client) return;
-
+
try {
await Promise.race([
client.close(),
@@ -157,13 +187,13 @@ 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();
uiStream.append();
@@ -171,7 +201,7 @@ export const geospatialTool = ({
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);
@@ -186,14 +216,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;
@@ -237,20 +267,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);
@@ -262,7 +292,7 @@ export const geospatialTool = ({
if (typeof content === 'object' && content !== null) {
const parsedData = content as any;
-
+
if (parsedData.location) {
mcpData = {
location: {
From d5455317806790e1a85619cd4b466feac8465107 Mon Sep 17 00:00:00 2001
From: EreQ
Date: Thu, 14 Aug 2025 14:42:26 +0300
Subject: [PATCH 6/8] Update geospatial.tsx
---
lib/agents/tools/geospatial.tsx | 22 +++++++---------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/lib/agents/tools/geospatial.tsx b/lib/agents/tools/geospatial.tsx
index 6f338022..fbbb4bee 100644
--- a/lib/agents/tools/geospatial.tsx
+++ b/lib/agents/tools/geospatial.tsx
@@ -63,9 +63,9 @@ async function getConnectedMcpClient(): Promise {
console.log('[GeospatialTool] Using fallback config');
}
- // Create Smithery URL without API key in query parameters
- const mcpServerBaseUrl = `https://server.smithery.ai/@ngoiyaeric/mapbox-mcp-server?profile=${profileId}`;
- const smitheryUrlOptions = { config, profileId };
+ // 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 };
let serverUrlToUse: URL;
try {
@@ -82,26 +82,18 @@ async function getConnectedMcpClient(): Promise {
console.error('[GeospatialTool] URL options:', {
baseUrl: mcpServerBaseUrl,
hasConfig: !!config,
+ hasApiKey: !!apiKey,
hasProfileId: !!profileId,
});
return null;
}
- // Initialize transport with authentication headers
+ // Initialize transport
let transport;
let client;
- const headers = {
- Authorization: `Bearer ${apiKey}`,
- 'X-Profile-ID': profileId,
- 'Content-Type': 'application/json',
- };
-
try {
- console.log('[GeospatialTool] Initializing transport with headers:', {
- Authorization: `Bearer ${apiKey.substring(0, 8)}...`,
- 'X-Profile-ID': profileId.substring(0, 8) + '...',
- });
- transport = new StreamableHTTPClientTransport(serverUrlToUse, { headers });
+ 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);
From 36bebf76b1eebada2c6b6840953fa57f71c1a9b6 Mon Sep 17 00:00:00 2001
From: EreQ
Date: Thu, 14 Aug 2025 14:47:49 +0300
Subject: [PATCH 7/8] Update geospatial.tsx
---
lib/agents/tools/geospatial.tsx | 156 +-------------------------------
1 file changed, 5 insertions(+), 151 deletions(-)
diff --git a/lib/agents/tools/geospatial.tsx b/lib/agents/tools/geospatial.tsx
index fbbb4bee..92dc9f98 100644
--- a/lib/agents/tools/geospatial.tsx
+++ b/lib/agents/tools/geospatial.tsx
@@ -37,10 +37,10 @@ async function getConnectedMcpClient(): Promise {
return null;
}
- // Validate profile ID format (UUID)
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
- if (!uuidRegex.test(profileId)) {
- console.error('[GeospatialTool] Invalid profile ID format:', profileId);
+ // Validate profile ID format (basic check for non-empty string with allowed characters)
+ const profileIdRegex = /^[a-zA-Z0-9-_]+$/;
+ if (!profileIdRegex.test(profileId)) {
+ console.error('[GeospatialTool] Invalid profile ID format (must contain only letters, numbers, hyphens, or underscores):', profileId);
return null;
}
@@ -180,150 +180,4 @@ export const geospatialTool = ({
- Geographic information lookup`,
parameters: geospatialQuerySchema,
execute: async ({ query, queryType, includeMap }: {
- query: string;
- queryType?: string;
- includeMap?: boolean;
- }) => {
- console.log('[GeospatialTool] Execute called with:', { query, queryType, includeMap });
-
- const uiFeedbackStream = createStreamableValue();
- uiStream.append();
-
- 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);
- uiFeedbackStream.done();
- uiStream.update();
- return {
- type: 'MAP_QUERY_TRIGGER',
- originalUserInput: query,
- timestamp: new Date().toISOString(),
- mcp_response: null,
- error: 'MCP client initialization failed - check environment variables and network connectivity',
- };
- }
-
- let mcpData: {
- location: {
- latitude?: number;
- longitude?: number;
- place_name?: string;
- address?: string;
- };
- mapUrl?: string;
- } | null = null;
- let toolError: string | null = null;
-
- try {
- feedbackMessage = `Connected to mapping service. Processing "${query}"...`;
- uiFeedbackStream.update(feedbackMessage);
- uiStream.update();
-
- const toolName = queryType === 'directions' ? 'mapbox_directions' : 'mapbox_geocoding';
- const toolArgs = {
- searchText: query,
- includeMapPreview: includeMap !== false,
- };
-
- console.log('[GeospatialTool] Calling tool:', toolName, 'with args:', toolArgs);
-
- // Retry logic for tool call
- const MAX_RETRIES = 3;
- let retryCount = 0;
- let geocodeResultUnknown;
- while (retryCount < MAX_RETRIES) {
- try {
- geocodeResultUnknown = await Promise.race([
- mcpClient.callTool({ name: toolName, arguments: toolArgs }),
- new Promise((_, reject) => {
- setTimeout(() => reject(new Error('Tool call timeout after 30 seconds')), 30000);
- }),
- ]);
- break;
- } catch (error: any) {
- retryCount++;
- if (retryCount === MAX_RETRIES) {
- throw error;
- }
- console.warn(`[GeospatialTool] Retry ${retryCount}/${MAX_RETRIES} after error: ${error.message}`);
- await new Promise(resolve => setTimeout(resolve, 1000));
- }
- }
-
- console.log('[GeospatialTool] Raw tool result:', geocodeResultUnknown);
-
- 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);
- }
- } catch (parseError) {
- console.warn('[GeospatialTool] Content is not JSON, using as string:', content);
- }
- }
-
- if (typeof content === 'object' && content !== null) {
- const parsedData = content as any;
-
- if (parsedData.location) {
- mcpData = {
- location: {
- latitude: parsedData.location.latitude,
- longitude: parsedData.location.longitude,
- place_name: parsedData.location.place_name || parsedData.location.name,
- address: parsedData.location.address || parsedData.location.formatted_address,
- },
- mapUrl: parsedData.mapUrl || parsedData.map_url,
- };
- } else {
- throw new Error("Response missing required 'location' field");
- }
- } else {
- throw new Error("Unexpected response format from mapping service");
- }
-
- feedbackMessage = `Successfully processed location query for: ${mcpData.location.place_name || query}`;
- uiFeedbackStream.update(feedbackMessage);
-
- } catch (error: any) {
- console.error('[GeospatialTool] Tool execution failed:', error.message);
- console.error('[GeospatialTool] Error stack:', error.stack);
- toolError = `Mapping service error: ${error.message}`;
- feedbackMessage = toolError;
- uiFeedbackStream.update(feedbackMessage);
- } finally {
- await closeClient(mcpClient);
- uiFeedbackStream.done();
- uiStream.update();
- }
-
- return {
- type: 'MAP_QUERY_TRIGGER',
- originalUserInput: query,
- queryType: queryType || 'geocode',
- timestamp: new Date().toISOString(),
- mcp_response: mcpData,
- error: toolError,
- };
- },
-});
+ query:
From 95c2b4c4279fefe02e068dff5da433e56353a734 Mon Sep 17 00:00:00 2001
From: EreQ
Date: Thu, 14 Aug 2025 14:50:17 +0300
Subject: [PATCH 8/8] Update geospatial.tsx
---
lib/agents/tools/geospatial.tsx | 155 ++++++++++++++++++++++++++++++--
1 file changed, 147 insertions(+), 8 deletions(-)
diff --git a/lib/agents/tools/geospatial.tsx b/lib/agents/tools/geospatial.tsx
index 92dc9f98..5e247f7e 100644
--- a/lib/agents/tools/geospatial.tsx
+++ b/lib/agents/tools/geospatial.tsx
@@ -37,13 +37,6 @@ async function getConnectedMcpClient(): Promise {
return null;
}
- // Validate profile ID format (basic check for non-empty string with allowed characters)
- const profileIdRegex = /^[a-zA-Z0-9-_]+$/;
- if (!profileIdRegex.test(profileId)) {
- console.error('[GeospatialTool] Invalid profile ID format (must contain only letters, numbers, hyphens, or underscores):', profileId);
- return null;
- }
-
// Load configuration
let config;
try {
@@ -180,4 +173,150 @@ export const geospatialTool = ({
- Geographic information lookup`,
parameters: geospatialQuerySchema,
execute: async ({ query, queryType, includeMap }: {
- query:
+ query: string;
+ queryType?: string;
+ includeMap?: boolean;
+ }) => {
+ console.log('[GeospatialTool] Execute called with:', { query, queryType, includeMap });
+
+ const uiFeedbackStream = createStreamableValue();
+ uiStream.append();
+
+ 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);
+ uiFeedbackStream.done();
+ uiStream.update();
+ return {
+ type: 'MAP_QUERY_TRIGGER',
+ originalUserInput: query,
+ timestamp: new Date().toISOString(),
+ mcp_response: null,
+ error: 'MCP client initialization failed - check environment variables and network connectivity',
+ };
+ }
+
+ let mcpData: {
+ location: {
+ latitude?: number;
+ longitude?: number;
+ place_name?: string;
+ address?: string;
+ };
+ mapUrl?: string;
+ } | null = null;
+ let toolError: string | null = null;
+
+ try {
+ feedbackMessage = `Connected to mapping service. Processing "${query}"...`;
+ uiFeedbackStream.update(feedbackMessage);
+ uiStream.update();
+
+ const toolName = queryType === 'directions' ? 'mapbox_directions' : 'mapbox_geocoding';
+ const toolArgs = {
+ searchText: query,
+ includeMapPreview: includeMap !== false,
+ };
+
+ console.log('[GeospatialTool] Calling tool:', toolName, 'with args:', toolArgs);
+
+ // Retry logic for tool call
+ const MAX_RETRIES = 3;
+ let retryCount = 0;
+ let geocodeResultUnknown;
+ while (retryCount < MAX_RETRIES) {
+ try {
+ geocodeResultUnknown = await Promise.race([
+ mcpClient.callTool({ name: toolName, arguments: toolArgs }),
+ new Promise((_, reject) => {
+ setTimeout(() => reject(new Error('Tool call timeout after 30 seconds')), 30000);
+ }),
+ ]);
+ break;
+ } catch (error: any) {
+ retryCount++;
+ if (retryCount === MAX_RETRIES) {
+ throw error;
+ }
+ console.warn(`[GeospatialTool] Retry ${retryCount}/${MAX_RETRIES} after error: ${error.message}`);
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ }
+ }
+
+ console.log('[GeospatialTool] Raw tool result:', geocodeResultUnknown);
+
+ 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);
+ }
+ } catch (parseError) {
+ console.warn('[GeospatialTool] Content is not JSON, using as string:', content);
+ }
+ }
+
+ if (typeof content === 'object' && content !== null) {
+ const parsedData = content as any;
+
+ if (parsedData.location) {
+ mcpData = {
+ location: {
+ latitude: parsedData.location.latitude,
+ longitude: parsedData.location.longitude,
+ place_name: parsedData.location.place_name || parsedData.location.name,
+ address: parsedData.location.address || parsedData.location.formatted_address,
+ },
+ mapUrl: parsedData.mapUrl || parsedData.map_url,
+ };
+ } else {
+ throw new Error("Response missing required 'location' field");
+ }
+ } else {
+ throw new Error("Unexpected response format from mapping service");
+ }
+
+ feedbackMessage = `Successfully processed location query for: ${mcpData.location.place_name || query}`;
+ uiFeedbackStream.update(feedbackMessage);
+
+ } catch (error: any) {
+ console.error('[GeospatialTool] Tool execution failed:', error.message);
+ console.error('[GeospatialTool] Error stack:', error.stack);
+ toolError = `Mapping service error: ${error.message}`;
+ feedbackMessage = toolError;
+ uiFeedbackStream.update(feedbackMessage);
+ } finally {
+ await closeClient(mcpClient);
+ uiFeedbackStream.done();
+ uiStream.update();
+ }
+
+ return {
+ type: 'MAP_QUERY_TRIGGER',
+ originalUserInput: query,
+ queryType: queryType || 'geocode',
+ timestamp: new Date().toISOString(),
+ mcp_response: mcpData,
+ error: toolError,
+ };
+ },
+});