Skip to content

Conversation

@ngoiyaeric
Copy link
Collaborator

@ngoiyaeric ngoiyaeric commented Aug 14, 2025

User description

…n your GeospatialTool.

The GeospatialTool was failing with a "No content returned from mapping service" error. I traced this back to two problems:

  1. The logic for selecting a service was only handling the 'directions' query type. I've updated it to use a switch statement, which correctly maps other query types like 'distance' to the appropriate service, such as 'mapbox_matrix'.

  2. The code was trying to parse a tool_results property from the mapping service's response, but the service actually returns a content property. I've adjusted the parsing logic to use the correct property.

These fixes ensure the right service is called for each query and that the response is parsed correctly, which should resolve the execution failure.


PR Type

Bug fix


Description

  • Fixed service selection logic to handle all query types

  • Corrected response parsing to use content property

  • Added proper switch statement for query type mapping

  • Renamed variables for better clarity and consistency


Diagram Walkthrough

flowchart LR
  A["Query Type"] --> B["Switch Statement"]
  B --> C["mapbox_directions"]
  B --> D["mapbox_matrix"]
  B --> E["mapbox_geocoding"]
  F["Service Response"] --> G["Parse content property"]
  G --> H["Extract text content"]
Loading

File Walkthrough

Relevant files
Bug fix
geospatial.tsx
Fix service selection and response parsing logic                 

lib/agents/tools/geospatial.tsx

  • Replaced simple conditional with comprehensive switch statement for
    service selection
  • Updated response parsing to use content property instead of
    tool_results
  • Renamed variables from geocodeResultUnknown to toolCallResult for
    clarity
  • Added proper handling for 'distance' query type mapping to
    'mapbox_matrix'
+25/-9   

Summary by CodeRabbit

  • New Features

    • Richer geospatial queries with explicit query types, optional destination for directions/distance, and clearer queryType shown in results; built-in query classification and stricter input validation.
  • Bug Fixes

    • Clearer user-facing errors and messages for missing, malformed, or failed mapping service responses.
  • Refactor

    • More resilient calls with retries/timeouts and improved response parsing to reliably surface locations and maps.
  • Chores

    • Added a new mapping backend dependency to support the enhanced flows.

…n your `GeospatialTool`.

The `GeospatialTool` was failing with a "No content returned from mapping service" error. I traced this back to two problems:

1.  The logic for selecting a service was only handling the 'directions' query type. I've updated it to use a switch statement, which correctly maps other query types like 'distance' to the appropriate service, such as 'mapbox_matrix'.

2.  The code was trying to parse a `tool_results` property from the mapping service's response, but the service actually returns a `content` property. I've adjusted the parsing logic to use the correct property.

These fixes ensure the right service is called for each query and that the response is parsed correctly, which should resolve the execution failure.
@vercel
Copy link
Contributor

vercel bot commented Aug 14, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
qcx Ready Preview Comment Aug 15, 2025 8:20am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 14, 2025

Walkthrough

Replaces the old geospatial schema and runtime wiring with a discriminated Zod schema and an MCP-driven geospatial tool: geospatial.execute now accepts the new schema type, dynamically resolves and invokes MCP tools (with retries/timeouts), parses MCP responses into normalized location output, and adds smithery dependency.

Changes

Cohort / File(s) Change Summary
Geospatial tool (MCP integration & execution)
lib/agents/tools/geospatial.tsx
Added robust MCP connection helper, runtime tool discovery, dynamic tool-name resolution by queryType, per-query argument builders, 3-retry loop with 30s timeout, response extraction/parsing (JSON blocks and fallback strings), normalized mcp_response shape, enhanced error/logging, ensured client.close() in finally, and updated execute signature to accept z.infer<typeof geospatialQuerySchema>. Also exports McpClient alias.
Schema: removed (old) and added (new discriminated union)
lib/schema/geospatial.ts (deleted), lib/schema/geospatial.tsx (added)
Removed old single Zod object schema and classifier; added a discriminated-union geospatialQuerySchema covering `search
Dependency manifest
package.json
Added dependency "smithery": "^0.5.2" to dependencies.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant GeospatialTool
  participant MCP_Helper
  participant MCP_Service

  Caller->>GeospatialTool: execute(GeospatialQuery params)
  GeospatialTool->>MCP_Helper: getConnectedMcpClient(env/config)
  MCP_Helper-->>GeospatialTool: MCPClient (connected)
  GeospatialTool->>MCPClient: listTools()
  GeospatialTool->>GeospatialTool: resolve toolName for queryType
  GeospatialTool->>MCPClient: callTool(toolName, toolArgs) with retry & 30s timeout
  MCPClient->>MCP_Service: invoke external tool
  MCP_Service-->>MCPClient: raw serviceResponse
  MCPClient-->>GeospatialTool: toolCallResult
  GeospatialTool->>GeospatialTool: extract JSON / parse locations -> mcp_response
  alt success
    GeospatialTool-->>Caller: MAP_QUERY_TRIGGER { mcp_response, queryType, ... }
  else failure
    GeospatialTool-->>Caller: MAP_QUERY_TRIGGER { error, ... }
  end
  GeospatialTool->>MCPClient: close() (finally)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

Review effort 3/5

Poem

I hop through code and map the way,
I call the MCP, then parse the clay.
With retries stout and timeout tight,
I fetch each place and set it right.
A rabbit trails your route by night. 🐇🗺️

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-geospatial-tool-error

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@CLAassistant
Copy link

CLAassistant commented Aug 14, 2025

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ ngoiyaeric
❌ google-labs-jules[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@qodo-code-review
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Type Safety

The new parsing casts toolCallResult to an object with content?: Array<{ text?: string }> and assumes responseContent[0].text holds the payload. Validate that all mapped services (directions, matrix, geocoding) return this unified shape; otherwise add discriminated parsing or runtime guards.

const serviceResponse = toolCallResult as { content?: Array<{ text?: string }> };
const responseContent = serviceResponse?.content;

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

let content: any = responseContent[0].text;
Retry Logic

Retries on any error including timeouts, but the same 30s timeout is applied for each attempt leading to up to 90s wait. Confirm this is acceptable or reduce timeout/attempts or make them configurable per service.

const MAX_RETRIES = 3;
let retryCount = 0;
let toolCallResult;
while (retryCount < MAX_RETRIES) {
  try {
    toolCallResult = 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));
  }
Switch Default

The switch defaults many query types to geocoding. Ensure this is intentional; consider explicit handling for 'reverse', 'search', and 'map' if they require different services, and log/guard unknown query types.

switch (queryType) {
  case 'directions':
    toolName = 'mapbox_directions';
    break;
  case 'distance':
    toolName = 'mapbox_matrix';
    break;
  case 'geocode':
  case 'reverse':
  case 'search':
  case 'map':
  default:
    toolName = 'mapbox_geocoding';
    break;
}

@codiumai-pr-agent-free
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Error Handling

The error handling for missing content has been moved before checking the content format, but the error message remains generic. Consider adding more specific error messages that indicate whether the service response was missing entirely or had an invalid structure.

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

The response parsing uses 'any' type for content which could be improved with more specific typing. Consider defining proper interfaces for the expected response structure.

const serviceResponse = toolCallResult as { content?: Array<{ text?: string }> };
const responseContent = serviceResponse?.content;

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

let content: any = responseContent[0].text;

@codiumai-pr-agent-free
Copy link
Contributor

codiumai-pr-agent-free bot commented Aug 14, 2025

PR Code Suggestions ✨

No code suggestions found for the PR.

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Aug 14, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Verify MCP response schema

The new parsing assumes the MCP tool returns content[0].text, but MCP tool
responses often vary (messages with role/type, or embedded tool_results) and may
not guarantee this shape. Add a schema-aware parser that handles both legacy
tool_results and the MCP content envelope (text, json, or blobs), and gate on
type fields to avoid runtime failures across different tools or SDK versions.

Examples:

lib/agents/tools/geospatial.tsx [253-260]
const serviceResponse = toolCallResult as { content?: Array<{ text?: string }> };
const responseContent = serviceResponse?.content;

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

let content: any = responseContent[0].text;

Solution Walkthrough:

Before:

// Assume a single, specific response structure
const serviceResponse = toolCallResult as { content?: Array<{ text?: string }> };
const responseContent = serviceResponse?.content;

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

After:

// Handle multiple possible response structures
function extractContent(response: any): string {
  // Check for new content structure
  if (response?.content?.[0]?.text) {
    return response.content[0].text;
  }
  // Check for legacy tool_results structure
  if (response?.tool_results?.[0]?.content) {
    return response.tool_results[0].content;
  }
  throw new Error('Unrecognized response schema from mapping service');
}
let content = extractContent(toolCallResult);
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies that replacing one rigid parsing assumption with another is a brittle fix, proposing a more robust, schema-aware approach that significantly improves resilience against future API changes.

High
Possible issue
Normalize input before routing
Suggestion Impact:The commit implements a similar normalization approach but in a different way. Instead of directly normalizing queryType, the code was refactored to use a more sophisticated tool selection mechanism that handles different query types through a function that returns the appropriate tool name based on available tools.

code diff:

+      const toolName = await (async () => {
+        const { tools } = await mcpClient.listTools().catch(() => ({ tools: [] }));
+        const names = new Set(tools?.map((t: any) => t.name) || []);
+        const prefer = (...cands: string[]) => cands.find(n => names.has(n));
+        switch (queryType) {
+          case 'directions':
+          case 'distance': return prefer('calculate_distance', 'mapbox_matrix', 'mapbox_directions') || 'mapbox_matrix';
+          case 'search': return prefer('search_nearby_places', 'mapbox_geocoding') || 'mapbox_geocoding';
+          case 'map': return prefer('generate_map_link', 'mapbox_geocoding') || 'mapbox_geocoding';
+          case 'reverse':
+          case 'geocode': return prefer('geocode_location', 'mapbox_geocoding') || 'mapbox_geocoding';
+        }
+      })();

Ensure queryType is normalized (trimmed, lowercased) before the switch to avoid
misrouting due to casing or whitespace. Also guard against non-string values to
prevent unexpected fallthrough to default.

lib/agents/tools/geospatial.tsx [204-219]

+let normalizedType = typeof queryType === 'string' ? queryType.trim().toLowerCase() : '';
 let toolName;
-switch (queryType) {
+switch (normalizedType) {
   case 'directions':
     toolName = 'mapbox_directions';
     break;
   case 'distance':
     toolName = 'mapbox_matrix';
     break;
   case 'geocode':
   case 'reverse':
   case 'search':
   case 'map':
+    toolName = 'mapbox_geocoding';
+    break;
   default:
     toolName = 'mapbox_geocoding';
     break;
 }

[Suggestion processed]

Suggestion importance[1-10]: 5

__

Why: The suggestion improves robustness by normalizing the queryType input, which prevents potential misrouting due to casing or whitespace variations.

Low
  • More

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
lib/agents/tools/geospatial.tsx (4)

231-231: Type the tool call result for clarity and safer parsing

Add a minimal structural type to document expectations from MCP and help catch mistakes.

-      let toolCallResult;
+      let toolCallResult: { content?: Array<{ text?: string | null }> } | undefined;

234-239: Timeout + retries are solid; consider an AbortController if supported

The Promise.race-based 30s timeout with retries is good. If MCP's client supports abort signals, switching to an AbortController would avoid work continuing in the background after timeouts.


251-251: Avoid logging the full raw tool result in production

The raw payload can be large and may contain sensitive data. Gate the log and trim to a preview.

-      console.log('[GeospatialTool] Raw tool result:', toolCallResult);
+      if (process.env.NODE_ENV !== 'production') {
+        const preview = (() => {
+          try { return JSON.stringify(toolCallResult).slice(0, 2000); } catch { return String(toolCallResult).slice(0, 2000); }
+        })();
+        console.log('[GeospatialTool] Raw tool result preview:', preview);
+      }

313-320: Public API shape changed: add queryType and error to GeospatialToolOutput

The returned payload now includes queryType and error, but the consumer interface (components/map/map-query-handler.tsx:17-22) doesn’t declare them. This is safe at runtime but can cause TypeScript excess-property warnings where object literals are typed. Update the interface to reflect the new fields (optional).

Proposed interface update (outside this file):

// components/map/map-query-handler.tsx
interface GeospatialToolOutput {
  type: string; // e.g., "MAP_QUERY_TRIGGER"
  originalUserInput: string;
  timestamp: string;
  mcp_response: McpResponseData | null;
  // New (optional) fields returned by geospatialTool:
  queryType?: string;
  error?: string | null;
}

Would you like me to open a follow-up PR to align the types and add a quick unit test for the content parsing fallback?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 475b38c and 2e1164d.

📒 Files selected for processing (1)
  • lib/agents/tools/geospatial.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
lib/agents/tools/geospatial.tsx (3)
components/map/map-query-handler.tsx (3)
  • GeospatialToolOutput (18-23)
  • toolOutput (33-74)
  • MapQueryHandlerProps (25-28)
mapbox_mcp/hooks.ts (3)
  • query (91-156)
  • address (158-174)
  • location (195-212)
mapbox_mcp/index.ts (1)
  • testMCPConnection (14-89)

I've just corrected a couple of issues that were causing problems with my location-based abilities.

First, I was misinterpreting some of the data I received from geospatial services. I've fixed that now.

Second, I realized some of my functions for calculating directions and distances were incorrectly expecting geographic coordinates instead of place names. I've updated my approach to properly handle place names for these requests.

I've also improved my error handling. Now, if a location query fails, I can give you a more specific reason why, instead of just a generic error message.

These changes make my geospatial skills more robust, so I can better handle your requests for directions, distances, and geocoding.
I performed an extensive debugging process to fix multiple issues in the GeospatialTool, and as a result, it is now significantly more robust.

The key changes I made are:

1.  **Corrected Tool Selection:** I updated the tool to use the `_by_places` variants of the Mapbox tools (`mapbox_directions_by_places`, `mapbox_matrix_by_places`) for direction and distance queries, as these are designed to work with place names.

2.  **Structured Argument Passing:** I updated the tool's `execute` function signature to accept a `destination` parameter, in line with the tool's Zod schema. This allows structured data (`query` as origin, `destination` as destination) to be passed as a `places` array to the underlying service, which replaces a brittle string-splitting logic.

3.  **Improved Error Handling:** I improved the tool to inspect the `isError` flag in the response from the mapping service and propagate the specific error message. This will provide much better feedback on failures.

4.  **Build Fixes:** I resolved a transient TypeScript build error (`Cannot find name 'GeospatialQuery'`) by using an inline type definition for the `execute` function parameters, ensuring a stable build.

These changes collectively address a series of related bugs, starting from a generic "No content returned" error to more specific argument validation errors, ultimately leading to a correctly implemented and robust geospatial tool.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🔭 Outside diff range comments (1)
lib/agents/tools/geospatial.tsx (1)

246-251: Fix MCP call signature — pass (name, args) instead of an object

The MCP JS client in this repo is used with positional arguments (see mapbox_mcp/hooks.ts). Passing an object here will likely fail at runtime.

Apply this diff:

-          toolCallResult = await Promise.race([
-            mcpClient.callTool({ name: toolName, arguments: toolArgs }),
+          toolCallResult = await Promise.race([
+            mcpClient.callTool(toolName, toolArgs),
             new Promise((_, reject) => {
               setTimeout(() => reject(new Error('Tool call timeout after 30 seconds')), 30000);
             }),
           ]);
♻️ Duplicate comments (3)
lib/agents/tools/geospatial.tsx (3)

210-225: Map to actual tool names exposed by your MCP server (or resolve dynamically)

The hardcoded names 'mapbox_directions_by_places'/'mapbox_matrix_by_places'/'mapbox_geocoding' may not exist. In this repo, MCP tools referenced are typically: geocode_location, calculate_distance, search_nearby_places, generate_map_link. Mismatched names will produce “tool not found.”

Replace the switch with a dynamic resolver that prefers available tools (falling back to static names):

-      let toolName;
-      switch (queryType) {
-        case 'directions':
-          toolName = 'mapbox_directions_by_places';
-          break;
-        case 'distance':
-          toolName = 'mapbox_matrix_by_places';
-          break;
-        case 'geocode':
-        case 'reverse':
-        case 'search':
-        case 'map':
-        default:
-          toolName = 'mapbox_geocoding';
-          break;
-      }
+      let toolName: string | undefined;
+      try {
+        const { tools } = await mcpClient.listTools();
+        const names = new Set((tools ?? []).map((t: any) => t.name));
+        const prefer = (...cands: string[]) => cands.find(n => names.has(n));
+        switch (queryType) {
+          case 'directions':
+            toolName = prefer('mapbox_directions_by_places', 'mapbox_directions', 'get_directions');
+            break;
+          case 'distance':
+            toolName = prefer('calculate_distance', 'mapbox_matrix_by_places', 'mapbox_matrix');
+            break;
+          case 'search':
+            toolName = prefer('search_nearby_places', 'mapbox_geocoding', 'geocode_location');
+            break;
+          case 'map':
+            toolName = prefer('generate_map_link', 'mapbox_geocoding', 'geocode_location');
+            break;
+          case 'reverse':
+          case 'geocode':
+          default:
+            toolName = prefer('geocode_location', 'mapbox_geocoding');
+        }
+      } catch {
+        // Fallback if listTools fails
+        switch (queryType) {
+          case 'directions': toolName = 'mapbox_directions'; break;
+          case 'distance': toolName = 'mapbox_matrix'; break;
+          default: toolName = 'mapbox_geocoding';
+        }
+      }

272-279: Don’t assume payload is in content[0]; scan all content blocks and prefer fenced JSON

Limiting to content[0].text is brittle and will reintroduce “No content returned” for valid multi-block responses.

Apply this diff:

-      const responseContent = serviceResponse?.content;
-
-      if (!responseContent || responseContent.length === 0 || !responseContent[0].text) {
-        throw new Error('No content returned from mapping service');
-      }
-
-      let content: any = responseContent[0].text;
+      type McpContentBlock = { text?: string | null } | { [k: string]: any };
+      const blocks: McpContentBlock[] = Array.isArray(serviceResponse?.content) ? (serviceResponse!.content as McpContentBlock[]) : [];
+      const textBlocks = blocks
+        .map(b => (typeof (b as any)?.text === 'string' ? ((b as any).text as string) : null))
+        .filter((t): t is string => !!t && t.trim().length > 0);
+      if (textBlocks.length === 0) {
+        throw new Error('No content returned from mapping service');
+      }
+      const preferredText = textBlocks.find(t => /```(?:json)?\s*[\s\S]*?```/i.test(t)) ?? textBlocks[0];
+      let content: any = preferredText;

227-236: Fix geospatial tool: use server tool names and correct argument keys

The geospatial tool is calling MCP tools with mismatched names/args (e.g. using searchText and mapbox_* names) while the MCP client code exposes tools like geocode_location, calculate_distance, and search_nearby_places. This will produce bad requests or no-ops.

Files to fix:

  • lib/agents/tools/geospatial.tsx — replace the tool-name mapping and the toolArgs construction (currently around the switch + the block using searchText / places).
  • Reference: mapbox_mcp/hooks.ts shows the expected tool schemas (geocode_location expects { query, includeMapPreview? }; calculate_distance expects { from, to, profile, includeRouteMap? }; search_nearby_places expects { location, query, radius, limit }).

Apply this diff to align args with the MCP server:

-      switch (queryType) {
-        case 'directions':
-          toolName = 'mapbox_directions_by_places';
-          break;
-        case 'distance':
-          toolName = 'mapbox_matrix_by_places';
-          break;
-        case 'geocode':
-        case 'reverse':
-        case 'search':
-        case 'map':
-        default:
-          toolName = 'mapbox_geocoding';
-          break;
-      }
-
-      let toolArgs;
-      if (toolName === 'mapbox_directions_by_places' || toolName === 'mapbox_matrix_by_places') {
-        const places = [query];
-        if (destination) {
-          places.push(destination);
-        }
-        toolArgs = { places, includeMapPreview: includeMap !== false };
-      } else {
-        toolArgs = { searchText: query, includeMapPreview: includeMap !== false };
-      }
+      // Align tool names and arguments with the MCP server (see mapbox_mcp/hooks.ts)
+      switch (queryType) {
+        case 'directions':
+        case 'distance':
+          // The MCP exposes a `calculate_distance` tool for routes/distances
+          toolName = 'calculate_distance';
+          break;
+        case 'search':
+          toolName = 'search_nearby_places';
+          break;
+        case 'geocode':
+        case 'reverse':
+        case 'map':
+        default:
+          toolName = 'geocode_location';
+          break;
+      }
+
+      let toolArgs: any;
+      if (toolName === 'calculate_distance') {
+        if (destination) {
+          toolArgs = {
+            from: query,
+            to: destination,
+            profile: 'driving',
+            includeRouteMap: includeMap !== false,
+          };
+        } else {
+          // No destination — fall back to geocoding the query instead of sending an invalid distance request.
+          toolName = 'geocode_location';
+          toolArgs = { query, includeMapPreview: includeMap !== false };
+        }
+      } else if (toolName === 'search_nearby_places') {
+        toolArgs = {
+          location: query,
+          query,
+          radius: 1000,
+          limit: 5,
+        };
+      } else {
+        // geocode_location and safe default
+        toolArgs = { query, includeMapPreview: includeMap !== false };
+      }

Reasoning/evidence: mapbox_mcp/index.ts and mapbox_mcp/hooks.ts call geocode_location with { query, includeMapPreview } and calculate_distance with { from, to, profile, includeRouteMap }, so geospatial.tsx must use the same names/keys to avoid 4xx/invalid-tool-arg errors.

🧹 Nitpick comments (6)
lib/agents/tools/geospatial.tsx (6)

296-314: Broaden response mapping to handle common location shapes (lat/lng, center array, geometry.coordinates)

Requiring parsedData.location only handles one shape. MCP tools often return { lat, lng }, { center: [lng, lat] }, or { geometry: { coordinates: [lng, lat] } }.

Apply this diff:

-      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");
-      }
+      if (typeof content === 'object' && content !== null) {
+        const parsedData = content as any;
+        const loc = parsedData.location ?? parsedData.result?.location ?? null;
+        let latitude: number | undefined;
+        let longitude: number | undefined;
+        let place_name: string | undefined;
+        let address: string | undefined;
+
+        if (loc) {
+          latitude = loc.latitude ?? loc.lat;
+          longitude = loc.longitude ?? loc.lng ?? loc.lon ?? loc.long;
+          place_name = loc.place_name ?? loc.name;
+          address = loc.address ?? loc.formatted_address;
+        }
+
+        // Common alt shapes
+        const center = parsedData.center ?? parsedData.coordinates ?? parsedData.geometry?.coordinates;
+        if ((latitude == null || longitude == null) && Array.isArray(center) && center.length >= 2) {
+          // center/coordinates convention: [lng, lat]
+          longitude = Number(center[0]);
+          latitude = Number(center[1]);
+        }
+
+        if (latitude != null && longitude != null) {
+          mcpData = {
+            location: { latitude, longitude, place_name, address },
+            mapUrl: parsedData.mapUrl || parsedData.map_url,
+          };
+        } else {
+          throw new Error("Response missing required coordinates");
+        }
+      } else {
+        throw new Error("Unexpected response format from mapping service");
+      }

170-170: Reduce PII/log noise — truncate logged query/destination

Logging full user queries can leak PII and flood logs. Truncate to a safe preview.

-    console.log('[GeospatialTool] Execute called with:', { query, queryType, includeMap, destination });
+    console.log('[GeospatialTool] Execute called with:', { 
+      query: query?.slice(0, 80), 
+      queryType, 
+      includeMap, 
+      destination: destination?.slice(0, 80) 
+    });

265-271: Don’t rely on isError unless documented by your MCP client

In this repo, callTool throws on tool errors and the result is a content array. The isError flag may not exist and could produce false paths.

If isError isn’t part of your client’s ToolResult, drop this check and rely on try/catch around callTool. Otherwise guard with a strict boolean check:

-      if (serviceResponse.isError) {
+      if (serviceResponse && (serviceResponse as any).isError === true) {
         const errorMessage = serviceResponse.content?.[0]?.text || 'Unknown error from mapping service';
         throw new Error(errorMessage);
       }

263-263: Avoid dumping full tool results to logs

toolCallResult may contain large payloads. Consider logging a compact summary instead.

-      console.log('[GeospatialTool] Raw tool result:', toolCallResult);
+      console.log('[GeospatialTool] Raw tool result:', {
+        hasContent: !!(toolCallResult as any)?.content,
+        contentBlocks: Array.isArray((toolCallResult as any)?.content) ? (toolCallResult as any).content.length : 0
+      });

240-261: Optional: add backoff to retries and avoid orphaned in-flight calls

Nice use of retries and timeout. Consider exponential backoff (e.g., 500ms, 1s, 2s) and, if the SDK supports it, an abort signal to cancel in-flight calls after timeout to prevent server-side work from accumulating.


331-338: Expose queryType to consumers (type hint)

You return queryType in the payload, but components/map/map-query-handler.tsx’s GeospatialToolOutput doesn’t include it. It’s fine at runtime, but adding it to the type improves clarity.

Outside this file, update the interface:

// components/map/map-query-handler.tsx
interface GeospatialToolOutput {
  type: string;
  originalUserInput: string;
  timestamp: string;
  mcp_response: McpResponseData | null;
  queryType?: string; // add
}

I can open a follow-up PR if you want.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2e1164d and 22d862c.

📒 Files selected for processing (1)
  • lib/agents/tools/geospatial.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
lib/agents/tools/geospatial.tsx (2)
components/map/map-query-handler.tsx (4)
  • toolOutput (33-74)
  • GeospatialToolOutput (18-23)
  • MapQueryHandlerProps (25-28)
  • prevData (39-49)
mapbox_mcp/hooks.ts (3)
  • query (91-156)
  • address (158-174)
  • location (195-212)
🔇 Additional comments (1)
lib/agents/tools/geospatial.tsx (1)

159-169: Confirmed: schema includes optional destination field

  • lib/schema/geospatial.ts — destination: z.string().optional() (lines ~32–34)
  • lib/agents/tools/geospatial.tsx — execute accepts destination?: string (lines 158–169)

No changes required.

I've completed an extensive, iterative debugging process to resolve a cascade of issues within the `GeospatialTool`. I have significantly refactored it, and it is now robust and correct.

The key changes are:

1.  **Correct Tool Selection:** The tool now uses the `_by_places` variants of the Mapbox tools (`mapbox_directions_by_places`, `mapbox_matrix_by_places`) for direction and distance queries, which are designed to work with place names.

2.  **Structured Argument Passing:** The tool's `execute` function signature has been updated to correctly accept all parameters from its Zod schema (e.g., `destination`). This allows structured data to be provided and passed as a `places` array to the underlying service, eliminating brittle string parsing.

3.  **Robust Response & Error Handling:**
    - The tool now inspects the `isError` flag in the service response and propagates specific error messages, providing much better feedback on failures.
    - The logic for parsing successful responses has been fixed to correctly handle the `results` array returned by the Mapbox API, resolving the "missing 'location' field" error.

4.  **Build Stability:** I resolved transient TypeScript build errors by using a stable inline type definition for the `execute` function parameters, ensuring a successful build.

These changes collectively address a series of related bugs, from generic errors to specific validation and parsing failures, resulting in a correctly implemented and reliable geospatial tool.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🔭 Outside diff range comments (1)
lib/agents/tools/geospatial.tsx (1)

347-353: Add optional queryType to GeospatialToolOutput

lib/agents/tools/geospatial.tsx now returns queryType; update the consumer type to match.

  • File to update: components/map/map-query-handler.tsx — modify interface GeospatialToolOutput to include queryType?: string; (insert after originalUserInput).

Suggested diff:

@@
 interface GeospatialToolOutput {
   type: string; // e.g., "MAP_QUERY_TRIGGER"
   originalUserInput: string;
+  queryType?: string;
   timestamp: string;
   mcp_response: McpResponseData | null;
 }
♻️ Duplicate comments (2)
lib/agents/tools/geospatial.tsx (2)

210-225: Wrong MCP tool-name mapping; resolve dynamically to actual server tools

The switch maps to non-existent names (mapbox_directions_by_places, mapbox_matrix_by_places, mapbox_geocoding). In this repo, the MCP server exposes tools like geocode_location, calculate_distance, search_nearby_places, generate_map_link (see mapbox_mcp/hooks.ts). Current mappings will 404 or return errors at runtime.

Replace the static switch with a dynamic resolver that prefers available tools and falls back to known names:

-      let toolName;
-      switch (queryType) {
-        case 'directions':
-          toolName = 'mapbox_directions_by_places';
-          break;
-        case 'distance':
-          toolName = 'mapbox_matrix_by_places';
-          break;
-        case 'geocode':
-        case 'reverse':
-        case 'search':
-        case 'map':
-        default:
-          toolName = 'mapbox_geocoding';
-          break;
-      }
+      const toolName = await (async () => {
+        try {
+          const { tools } = await mcpClient.listTools();
+          const names = new Set((tools ?? []).map((t: any) => t.name));
+          const prefer = (...cands: string[]) => cands.find(n => names.has(n));
+          switch (queryType) {
+            case 'directions':
+            case 'distance':
+              return prefer('calculate_distance', 'mapbox_matrix', 'mapbox_directions')!;
+            case 'search':
+              return prefer('search_nearby_places', 'mapbox_geocoding')!;
+            case 'map':
+              return prefer('generate_map_link', 'mapbox_geocoding')!;
+            case 'reverse':
+            case 'geocode':
+            default:
+              return prefer('geocode_location', 'mapbox_geocoding')!;
+          }
+        } catch {
+          switch (queryType) {
+            case 'directions': return 'mapbox_directions';
+            case 'distance': return 'mapbox_matrix';
+            case 'search': return 'mapbox_geocoding';
+            case 'map': return 'mapbox_geocoding';
+            case 'reverse':
+            case 'geocode':
+            default: return 'mapbox_geocoding';
+          }
+        }
+      })();

265-279: Parse all content blocks and prefer JSON; don’t assume content[0].text

MCP responses often include multiple content blocks; JSON might be in a later block or in a json-typed block. Restricting to content[0].text is brittle and can re-trigger “No content returned”.

Apply this parsing refactor:

-      const serviceResponse = toolCallResult as { content?: Array<{ text?: string }>, isError?: boolean };
-
-      if (serviceResponse.isError) {
-        const errorMessage = serviceResponse.content?.[0]?.text || 'Unknown error from mapping service';
-        throw new Error(errorMessage);
-      }
-
-      const responseContent = serviceResponse?.content;
-
-      if (!responseContent || responseContent.length === 0 || !responseContent[0].text) {
-        throw new Error('No content returned from mapping service');
-      }
-
-      let content: any = responseContent[0].text;
+      type McpContent = { type?: string; text?: string | null; json?: any; [k: string]: any };
+      const serviceResponse = toolCallResult as { content?: McpContent[]; isError?: boolean };
+      const blocks = Array.isArray(serviceResponse?.content) ? serviceResponse!.content! : [];
+
+      if (serviceResponse.isError) {
+        const firstText = blocks.find(b => typeof b?.text === 'string')?.text;
+        throw new Error(firstText || 'Unknown error from mapping service');
+      }
+
+      if (blocks.length === 0) {
+        throw new Error('No content returned from mapping service');
+      }
+
+      // Prefer a json-typed block; otherwise parse a text block (fenced JSON if present)
+      const jsonBlock = blocks.find(b => b && 'json' in b && (b as any).json != null) as (McpContent | undefined);
+      let content: any;
+      if (jsonBlock && jsonBlock.json != null) {
+        content = jsonBlock.json;
+      } else {
+        const textBlocks = blocks
+          .map(b => (typeof b?.text === 'string' ? (b!.text as string) : null))
+          .filter((t): t is string => !!t && t.trim().length > 0);
+
+        if (textBlocks.length === 0) {
+          throw new Error('No content returned from mapping service');
+        }
+
+        const preferredText =
+          textBlocks.find(t => /```(?:json)?\s*[\s\S]*?```/i.test(t)) ?? textBlocks[0];
+
+        let maybeJson: string = preferredText;
+        const fenced = preferredText.match(/```(?:json)?\n?([\s\S]*?)\n?```/i);
+        if (fenced) {
+          maybeJson = fenced[1].trim();
+        }
+        content = maybeJson;
+      }
🧹 Nitpick comments (3)
lib/agents/tools/geospatial.tsx (3)

227-236: Require destination for distance/directions and shape args appropriately

If the selected tool is a distance/directions tool, a missing destination will likely fail. Also, arg shapes differ across tools. At minimum, validate destination. Optionally, send both common arg shapes so the server can pick what it needs.

-      let toolArgs;
-      if (toolName === 'mapbox_directions_by_places' || toolName === 'mapbox_matrix_by_places') {
-        const places = [query];
-        if (destination) {
-          places.push(destination);
-        }
-        toolArgs = { places, includeMapPreview: includeMap !== false };
-      } else {
-        toolArgs = { searchText: query, includeMapPreview: includeMap !== false };
-      }
+      let toolArgs: Record<string, any>;
+      const isRoute = ['calculate_distance', 'mapbox_matrix', 'mapbox_directions'].includes(toolName);
+      if (isRoute) {
+        if (!destination) {
+          throw new Error('“destination” is required for directions/distance queries');
+        }
+        // Provide multiple common shapes; MCP server can ignore extras.
+        toolArgs = {
+          origin: query,
+          destination,
+          from: query,
+          to: destination,
+          places: [query, destination],
+          includeMapPreview: includeMap !== false,
+        };
+      } else {
+        toolArgs = { searchText: query, query, includeMapPreview: includeMap !== false };
+      }

Please verify expected arg names against your MCP server’s handlers (calculate_distance/geocode_location).


263-263: Avoid logging raw tool results to reduce noise/PII risk

The entire MCP response can be large and may include user-derived strings. Log a concise summary instead.

-      console.log('[GeospatialTool] Raw tool result:', toolCallResult);
+      console.log('[GeospatialTool] Tool call completed');

Optionally, log only block counts/types after you construct blocks in the parsing section.


299-312: Improve result-shape tolerance and coordinate extraction

Different handlers may emit coordinates as center: [lng,lat], lat/lng, or nested coordinates. Add fallbacks and validate numbers. Also consider map_url on either the root or first result.

-        if (parsedData.results && Array.isArray(parsedData.results) && parsedData.results.length > 0) {
-          // For now, just take the first result.
-          const firstResult = parsedData.results[0];
-          mcpData = {
-            location: {
-              latitude: firstResult.coordinates?.latitude,
-              longitude: firstResult.coordinates?.longitude,
-              place_name: firstResult.name || firstResult.place_name,
-              address: firstResult.full_address || firstResult.address,
-            },
-            mapUrl: parsedData.mapUrl,
-          };
-        }
+        if (parsedData.results && Array.isArray(parsedData.results) && parsedData.results.length > 0) {
+          const firstResult = parsedData.results[0];
+          const lat =
+            firstResult?.coordinates?.latitude ??
+            firstResult?.lat ??
+            (Array.isArray(firstResult?.center) ? firstResult.center[1] : undefined);
+          const lng =
+            firstResult?.coordinates?.longitude ??
+            firstResult?.lng ??
+            (Array.isArray(firstResult?.center) ? firstResult.center[0] : undefined);
+          if (typeof lat !== 'number' || typeof lng !== 'number') {
+            throw new Error('Invalid coordinates in mapping service result');
+          }
+          mcpData = {
+            location: {
+              latitude: lat,
+              longitude: lng,
+              place_name: firstResult.name || firstResult.place_name,
+              address: firstResult.full_address || firstResult.address || firstResult.formatted_address,
+            },
+            mapUrl: parsedData.mapUrl || parsedData.map_url || firstResult.mapUrl || firstResult.map_url,
+          };
+        }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 22d862c and 162fbd4.

📒 Files selected for processing (1)
  • lib/agents/tools/geospatial.tsx (5 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
lib/agents/tools/geospatial.tsx (2)
components/map/map-query-handler.tsx (4)
  • toolOutput (33-74)
  • GeospatialToolOutput (18-23)
  • MapQueryHandlerProps (25-28)
  • prevData (39-49)
mapbox_mcp/hooks.ts (3)
  • query (91-156)
  • address (158-174)
  • location (195-212)
🔇 Additional comments (3)
lib/agents/tools/geospatial.tsx (3)

170-170: LGTM: helpful input logging

Including destination in the execute log will aid debugging.


246-251: LGTM: robust timeout around tool call with retries

Wrapping the tool invocation in a 30s Promise.race with retry is solid.


159-169: Confirmed: destination is present in schema — no change required

Verified that geospatialQuerySchema includes the optional field.

  • lib/schema/geospatial.ts — lines ~32–34: destination: z.string().optional().describe("Destination for directions queries (when different from main query)")
  • lib/agents/tools/geospatial.tsx — execute signature includes destination?: string (lines ~163–169)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
lib/agents/tools/geospatial.tsx (2)

180-193: Tool name resolution correctly handles available tools.

The dynamic resolver implementation addresses the previous issue by checking available tools and using prefer to select the appropriate tool. The fallback values ensure the code won't break if tools are unavailable.


228-240: Content parsing implementation handles multiple blocks correctly.

The code properly addresses the previous concern about parsing only content[0] by scanning all content blocks and preferring JSON-fenced blocks. The fallback logic ensures robustness.

🧹 Nitpick comments (2)
lib/schema/geospatial.tsx (1)

13-121: Consider adding coordinate validation for string-based location inputs.

While the schema validates coordinate objects, the string-based location fields (origin, destination, location) could benefit from additional validation to catch common issues early.

Consider adding a custom refinement to validate coordinate strings when they're provided in "lat,lng" format:

+const coordinateStringRegex = /^-?\d+\.?\d*\s*,\s*-?\d+\.?\d*$/;
+const validateLocationString = z.string()
+  .min(1, "Location cannot be empty")
+  .refine((val) => {
+    // If it looks like coordinates, validate the ranges
+    if (coordinateStringRegex.test(val)) {
+      const [lat, lng] = val.split(',').map(s => parseFloat(s.trim()));
+      return lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180;
+    }
+    return true; // Non-coordinate strings are valid
+  }, "Invalid coordinate values");

 export const geospatialQuerySchema = z.discriminatedUnion('queryType', [
   // ... in the geocode object:
-    location: z.string()
-      .min(1, "Location cannot be empty")
+    location: validateLocationString
       .describe("The location to geocode - address, place name, or landmark"),
lib/agents/tools/geospatial.tsx (1)

195-205: Consider validating required parameters before tool invocation.

While the schema enforces required fields, adding runtime validation before the tool call would provide better error messages if the schema validation is bypassed.

Add parameter validation before building toolArgs:

 // Build arguments
 const toolArgs = (() => {
   switch (queryType) {
     case 'directions':
-    case 'distance': return { places: [params.origin, params.destination], includeMapPreview: includeMap, mode: params.mode || 'driving' };
+    case 'distance': 
+      if (!params.origin || !params.destination) {
+        throw new Error(`Missing required parameters for ${queryType}: origin and destination`);
+      }
+      return { places: [params.origin, params.destination], includeMapPreview: includeMap, mode: params.mode || 'driving' };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 162fbd4 and 1310b26.

⛔ Files ignored due to path filters (1)
  • bun.lockb is excluded by !**/bun.lockb
📒 Files selected for processing (4)
  • lib/agents/tools/geospatial.tsx (4 hunks)
  • lib/schema/geospatial.ts (0 hunks)
  • lib/schema/geospatial.tsx (1 hunks)
  • package.json (1 hunks)
💤 Files with no reviewable changes (1)
  • lib/schema/geospatial.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
lib/schema/geospatial.tsx (2)
components/map/map-data-context.tsx (1)
  • MapData (7-17)
mapbox_mcp/hooks.ts (1)
  • DistanceResult (24-31)
lib/agents/tools/geospatial.tsx (5)
lib/schema/geospatial.tsx (1)
  • geospatialQuerySchema (13-121)
components/message.tsx (1)
  • BotMessage (11-29)
mapbox_mcp/index.ts (1)
  • testMCPConnection (14-89)
components/map/map-query-handler.tsx (1)
  • GeospatialToolOutput (18-23)
mapbox_mcp/hooks.ts (4)
  • mcp (65-81)
  • query (91-156)
  • mcp (83-89)
  • address (158-174)
🔇 Additional comments (7)
package.json (1)

79-79: LGTM! The smithery dependency addition aligns with the MCP-driven geospatial tool implementation.

The addition of the smithery package (version ^0.5.2) properly supports the new MCP-based workflow in lib/agents/tools/geospatial.tsx, which uses createSmitheryUrl from @smithery/sdk.

lib/schema/geospatial.tsx (2)

3-11: Well-structured schema design with good use of discriminated unions.

The implementation correctly uses Zod's discriminated union pattern for type safety and conditional requirements. The schema design thoughtfully separates concerns by query type and provides clear documentation for each field.


127-152: The classifier function provides reasonable heuristics.

The implementation uses simple keyword matching which works well for basic classification. The regex pattern for coordinate detection is appropriate.

Note: For future enhancements, you might consider adding support for more complex patterns like "what's near [location]" for search queries or "show route from A to B" for directions.

lib/agents/tools/geospatial.tsx (4)

36-123: Robust MCP connection setup with comprehensive error handling.

The getConnectedMcpClient function implements excellent defensive programming with proper environment validation, config fallback, timeout protection, and detailed logging at each step.


242-253: Response normalization handles multiple formats well.

The code correctly handles both results array and location object formats, with proper field mapping for different response structures.


257-265: Ensure MCP client cleanup happens in all error paths.

The finally block correctly ensures client cleanup, and the error handling provides clear user feedback.


267-267: Return value structure is well-designed for downstream processing.

The MAP_QUERY_TRIGGER payload includes all necessary information for UI components to render the results appropriately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants