Skip to content

Conversation

@ngoiyaeric
Copy link
Collaborator

@ngoiyaeric ngoiyaeric commented Aug 14, 2025

User description

…ange of new capabilities to help you with your project, including:

  • Geocoding addresses and locations.
  • Getting directions between two points.
  • Calculating travel times between multiple origins and destinations.
  • Generating isochrone polygons.
  • Creating static map images.

To support this, I created a new reusable client helper at lib/agents/tools/mapbox/mcp-client.ts to handle the connection to the Mapbox server and reduce code duplication. I've also added Zod schemas for these new capabilities in lib/schema/mapbox.ts.

As you requested, I've left the existing geospatial.tsx component in place, only correcting a minor import path.

Additionally, I fixed an issue with a non-standard QCX path alias. I removed it from package.json and replaced the imports with relative paths to ensure the project builds correctly.


PR Type

Enhancement


Description

  • Add comprehensive Mapbox integration with five new tools

  • Create reusable MCP client for Mapbox server connections

  • Define Zod schemas for Mapbox API validation

  • Fix import paths by removing non-standard alias


Diagram Walkthrough

flowchart LR
  A["MCP Client"] --> B["Mapbox Tools"]
  B --> C["Geocoding"]
  B --> D["Directions"]
  B --> E["Matrix"]
  B --> F["Isochrone"]
  B --> G["Static Images"]
  H["Zod Schemas"] --> B
  I["Tool Registry"] --> B
Loading

File Walkthrough

Relevant files
Enhancement
8 files
mcp-client.ts
Create reusable Mapbox MCP client helper                                 
+97/-0   
mapbox.ts
Add Zod validation schemas for Mapbox APIs                             
+57/-0   
geocoding.tsx
Implement Mapbox geocoding tool with UI feedback                 
+73/-0   
directions.tsx
Add directions tool for route planning                                     
+77/-0   
matrix.tsx
Create travel time matrix calculation tool                             
+77/-0   
isochrone.tsx
Implement isochrone polygon generation tool                           
+77/-0   
static-image.tsx
Add static map image generation tool                                         
+87/-0   
index.tsx
Register five new Mapbox tools in registry                             
+26/-5   
Bug fix
2 files
geospatial.tsx
Fix import path from QCX alias                                                     
+1/-1     
hooks.ts
Replace QCX alias with relative import                                     
+1/-1     
Configuration changes
1 files
package.json
Remove non-standard QCX path alias                                             
+0/-1     

…ange of new capabilities to help you with your project, including:

*   Geocoding addresses and locations.
*   Getting directions between two points.
*   Calculating travel times between multiple origins and destinations.
*   Generating isochrone polygons.
*   Creating static map images.

To support this, I created a new reusable client helper at `lib/agents/tools/mapbox/mcp-client.ts` to handle the connection to the Mapbox server and reduce code duplication. I've also added Zod schemas for these new capabilities in `lib/schema/mapbox.ts`.

As you requested, I've left the existing `geospatial.tsx` component in place, only correcting a minor import path.

Additionally, I fixed an issue with a non-standard `QCX` path alias. I removed it from `package.json` and replaced the imports with relative paths to ensure the project builds correctly.
@vercel
Copy link

vercel bot commented Aug 14, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Project Deployment Preview Comments Updated (UTC)
qcx Ready Preview Comment Aug 14, 2025 6:03am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 14, 2025

Warning

Rate limit exceeded

@ngoiyaeric has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 20 minutes and 20 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 20bb0e5 and fec93c7.

⛔ Files ignored due to path filters (1)
  • bun.lockb is excluded by !**/bun.lockb
📒 Files selected for processing (11)
  • lib/agents/tools/geospatial.tsx (1 hunks)
  • lib/agents/tools/index.tsx (2 hunks)
  • lib/agents/tools/mapbox/directions.tsx (1 hunks)
  • lib/agents/tools/mapbox/geocoding.tsx (1 hunks)
  • lib/agents/tools/mapbox/isochrone.tsx (1 hunks)
  • lib/agents/tools/mapbox/matrix.tsx (1 hunks)
  • lib/agents/tools/mapbox/mcp-client.ts (1 hunks)
  • lib/agents/tools/mapbox/static-image.tsx (1 hunks)
  • lib/schema/mapbox.ts (1 hunks)
  • mapbox_mcp/hooks.ts (1 hunks)
  • package.json (0 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/mapbox-tools

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

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@codiumai-pr-agent-free
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 Security concerns

Sensitive information exposure:
The code in mcp-client.ts (lines 37-38) constructs a URL with API key and profile ID directly in the string. While these values come from environment variables, embedding them directly in URLs can lead to accidental exposure in logs, browser history, or referrer headers. Consider using proper authentication headers or a more secure method for passing these credentials.

⚡ Recommended focus areas for review

Error Handling

The client uses hardcoded fallback configuration when config import fails, which might not work in production. Consider more robust error handling or configuration validation.

} catch (configError: any) {
  console.error(
    '[MCP-Client] Failed to load mapbox config:',
    configError.message
  )
  config = {
    mapboxAccessToken,
    version: '1.0.0',
    name: 'mapbox-mcp-server'
  }
}
Code Duplication

The JSON parsing logic is duplicated across all Mapbox tool files. Consider extracting this common functionality into a shared utility function.

  let content = toolResults[0].content
  if (typeof content === 'string') {
    const jsonRegex = /```(?:json)?\n?([\s\S]*?)\n?```/
    const match = content.match(jsonRegex)
    if (match) {
      content = JSON.parse(match[1].trim())
    } else {
      content = JSON.parse(content)
    }
  }
  result = content
} catch (error: any) {
  console.error('Mapbox geocoding tool error:', error)
  const errorMessage = `Error searching for "${query}": ${error.message}`
Conditional Rendering

The static image tool has different rendering logic than other tools, with conditional UI based on imageUrl presence. This inconsistency might cause maintenance issues.

if (result.imageUrl) {
  uiStream.update(
    <Card className="p-4 mt-2 text-sm">
      <img src={result.imageUrl} alt="Static Map" />
    </Card>
  )
} else {
  uiStream.update(
    <Card className="p-4 mt-2 text-sm">
      <pre>{JSON.stringify(result, null, 2)}</pre>
    </Card>
  )
}

@qodo-merge-pro
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 Security concerns

Sensitive information exposure:
Environment variables are read on the client side via NEXT_PUBLIC_* keys and some error messages may log configuration issues. Ensure that only non-sensitive public tokens are exposed with NEXT_PUBLIC_ and avoid logging full URLs containing api_key or profile in production logs.

⚡ Recommended focus areas for review

Error Handling

The client helper swallows configuration/URL/transport errors by returning null, which propagates generic "tool not available" messages. Consider surfacing more specific errors or metrics and ensure sensitive details aren't logged. Also evaluate whether returning null vs throwing leads to silent failures upstream.

export async function getConnectedMcpClient(): Promise<McpClient | null> {
  const apiKey = process.env.NEXT_PUBLIC_SMITHERY_API_KEY
  const mapboxAccessToken = process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN
  const profileId = process.env.NEXT_PUBLIC_SMITHERY_PROFILE_ID

  if (!apiKey || !mapboxAccessToken || !profileId) {
    console.error('[MCP-Client] Missing required environment variables')
    return null
  }

  let config
  try {
    const mapboxMcpConfig = await import('../../../../mapbox_mcp_config.json')
    config = {
      ...(mapboxMcpConfig.default || mapboxMcpConfig),
      mapboxAccessToken
    }
  } catch (configError: any) {
    console.error(
      '[MCP-Client] Failed to load mapbox config:',
      configError.message
    )
    config = {
      mapboxAccessToken,
      version: '1.0.0',
      name: 'mapbox-mcp-server'
    }
  }

  const smitheryUrlOptions = { config, apiKey, profileId }
  const mcpServerBaseUrl = `https://server.smithery.ai/mapbox-mcp-server/mcp?api_key=${smitheryUrlOptions.apiKey}&profile=${smitheryUrlOptions.profileId}`

  let serverUrlToUse
  try {
    serverUrlToUse = createSmitheryUrl(mcpServerBaseUrl, smitheryUrlOptions)
  } catch (urlError: any) {
    console.error('[MCP-Client] Error creating Smithery URL:', urlError.message)
    return null
  }

  let transport
  try {
    transport = new StreamableHTTPClientTransport(serverUrlToUse)
  } catch (transportError: any) {
    console.error(
      '[MCP-Client] Failed to create transport:',
      transportError.message
    )
    return null
  }

JSON Parsing Robustness
Each tool attempts to parse content with a regex for fenced JSON or raw JSON; if the server returns arrays, objects, or non-JSON strings, this will throw. Consider guarding JSON.parse with try/catch per branch and handling already-parsed objects or other content types.

UI Rendering Assumption

The code checks result.imageUrl before rendering an , but upstream result shaping isn't guaranteed. Validate the presence and type of URL and consider alt text/width/height handling to avoid broken images or layout shifts.

uiFeedbackStream.done()
if (result.imageUrl) {
  uiStream.update(
    <Card className="p-4 mt-2 text-sm">
      <img src={result.imageUrl} alt="Static Map" />
    </Card>
  )
} else {
  uiStream.update(
    <Card className="p-4 mt-2 text-sm">
      <pre>{JSON.stringify(result, null, 2)}</pre>
    </Card>
  )
}

@codiumai-pr-agent-free
Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Duplicate JSON parsing logic

Each Mapbox tool file contains identical JSON parsing logic that extracts
content from API responses. Consider refactoring this repeated pattern into a
shared utility function in the mcp-client.ts file to improve maintainability and
reduce duplication across all five Mapbox tool implementations.

Examples:

lib/agents/tools/mapbox/geocoding.tsx [44-53]
let content = toolResults[0].content
if (typeof content === 'string') {
  const jsonRegex = /```(?:json)?\n?([\s\S]*?)\n?```/
  const match = content.match(jsonRegex)
  if (match) {
    content = JSON.parse(match[1].trim())
  } else {
    content = JSON.parse(content)
  }
}
lib/agents/tools/mapbox/directions.tsx [48-57]
let content = toolResults[0].content
if (typeof content === 'string') {
  const jsonRegex = /```(?:json)?\n?([\s\S]*?)\n?```/
  const match = content.match(jsonRegex)
  if (match) {
    content = JSON.parse(match[1].trim())
  } else {
    content = JSON.parse(content)
  }
}

Solution Walkthrough:

Before:

// In each of the 5 tool files (e.g., geocoding.tsx)
try {
  const geocodeResult = await mcpClient.callTool(...)
  const toolResults = (geocodeResult as any)?.tool_results || []
  // ... check for empty toolResults ...
  let content = toolResults[0].content
  if (typeof content === 'string') {
    const jsonRegex = /```(?:json)?\n?([\s\S]*?)\n?```/
    const match = content.match(jsonRegex)
    if (match) {
      content = JSON.parse(match[1].trim())
    } else {
      content = JSON.parse(content)
    }
  }
  result = content
} catch (error: any) { ... }

After:

// In mcp-client.ts
export function parseToolResult(toolResult: any) {
  if (!toolResult?.tool_results?.[0]?.content) {
    throw new Error('No content returned from mapping service');
  }
  let content = toolResult.tool_results[0].content;
  if (typeof content === 'string') {
    const match = content.match(/```(?:json)?\n?([\s\S]*?)\n?```/);
    content = JSON.parse(match ? match[1].trim() : content);
  }
  return content;
}

// In each tool file (e.g., geocoding.tsx)
try {
  const geocodeResult = await mcpClient.callTool(...)
  result = parseToolResult(geocodeResult)
} catch (error: any) { ... }
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies significant code duplication across all five new Mapbox tool files and proposes a valid refactoring to improve maintainability.

Low
General
Enhance image element attributes

The image URL might contain sensitive information like API keys. Add width and
height attributes to the image element to ensure proper rendering and prevent
layout shifts, and consider validating the URL to ensure it's from a trusted
source.

lib/agents/tools/mapbox/static-image.tsx [71-76]

 if (result.imageUrl) {
   uiStream.update(
     <Card className="p-4 mt-2 text-sm">
-      <img src={result.imageUrl} alt="Static Map" />
+      <img 
+        src={result.imageUrl} 
+        alt="Static Map" 
+        width={width} 
+        height={height}
+        loading="lazy"
+      />
     </Card>
   )
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly proposes adding width and height attributes to the <img> tag, which is a best practice to prevent layout shift and improves user experience.

Low
Possible issue
Improve import path robustness

The relative import path for the mapbox_mcp_config.json file may cause issues in
different environments. Consider using a more robust approach like dynamic
import with error handling or an absolute path to ensure consistent loading
across environments.

lib/agents/tools/mapbox/mcp-client.ts [19]

-const mapboxMcpConfig = await import('../../../../mapbox_mcp_config.json')
+let mapboxMcpConfig;
+try {
+  mapboxMcpConfig = await import('../../../../mapbox_mcp_config.json');
+} catch (e) {
+  // Try alternative path if the first one fails
+  mapboxMcpConfig = await import('@/mapbox_mcp_config.json');
+}
  • Apply / Chat
Suggestion importance[1-10]: 4

__

Why: The suggestion correctly identifies that relative paths can be brittle, but the existing code already handles import failures in a try-catch block with a fallback, mitigating the issue's severity.

Low
  • More

@qodo-merge-pro
Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Unify MCP client reuse

Each Mapbox tool creates, uses, and closes a new MCP client per call, which will
add significant latency and connection overhead under concurrent or chained tool
usage. Introduce a shared connection lifecycle (pooling/singleton with heartbeat
and retry) in the mcp-client helper and have tools acquire and release from it,
rather than repeatedly connecting/tearing down, to improve performance and
reliability.

Examples:

lib/agents/tools/mapbox/directions.tsx [27-66]
const mcpClient = await getConnectedMcpClient()
if (!mcpClient) {
  // ...
  return { error }
}

let result
try {
  // ... call tool using mcpClient
} catch (error: any) {

 ... (clipped 4 lines)
lib/agents/tools/mapbox/geocoding.tsx [23-62]
const mcpClient = await getConnectedMcpClient()
if (!mcpClient) {
  // ...
  return { error }
}

let result
try {
  // ... call tool using mcpClient
} catch (error: any) {

 ... (clipped 4 lines)

Solution Walkthrough:

Before:

// In each Mapbox tool's execute function:
async execute({ ...args }) {
  const mcpClient = await getConnectedMcpClient(); // Creates a new connection
  try {
    // ... use client to call tool
  } catch (error) {
    // ... handle error
  } finally {
    await closeClient(mcpClient); // Tears down the connection
  }
  return result;
}

After:

// In mcp-client.ts:
let sharedClient = null;
async function getSharedMcpClient() {
  if (sharedClient && sharedClient.isConnected) { // Or some health check
    return sharedClient;
  }
  sharedClient = await /* ... new connection logic ... */;
  return sharedClient;
}

// In each Mapbox tool's execute function:
async execute({ ...args }) {
  const mcpClient = await getSharedMcpClient(); // Reuses a single connection
  // ... use client, no finally block to close it
  return result;
}
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a major performance bottleneck and design flaw affecting all new Mapbox tools, proposing a robust solution that significantly improves efficiency and reliability.

High
General
Guard against missing image URL

result can be an error object or undefined on failures. Add a null/shape check
before accessing imageUrl to prevent runtime errors and render a helpful message
when the image URL is missing. This improves robustness and UI feedback.

lib/agents/tools/mapbox/static-image.tsx [70-83]

 uiFeedbackStream.done()
-if (result.imageUrl) {
+const imageUrl = (result && typeof result === 'object') ? (result as any).imageUrl : undefined
+if (typeof imageUrl === 'string' && imageUrl.length > 0) {
   uiStream.update(
     <Card className="p-4 mt-2 text-sm">
-      <img src={result.imageUrl} alt="Static Map" />
+      <img src={imageUrl} alt="Static Map" />
     </Card>
   )
 } else {
   uiStream.update(
     <Card className="p-4 mt-2 text-sm">
-      <pre>{JSON.stringify(result, null, 2)}</pre>
+      <pre>{JSON.stringify(result ?? { error: 'No image URL returned' }, null, 2)}</pre>
     </Card>
   )
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that result could be an error object or null, and adds a necessary check for result.imageUrl to prevent runtime errors.

Medium
Possible issue
Prevent duplicated query parameters

Avoid duplicating query parameters: you embed api_key and profile in
mcpServerBaseUrl and also pass them in smitheryUrlOptions, which
createSmitheryUrl will likely append again. Build the base URL without sensitive
params and let createSmitheryUrl add them. This prevents malformed URLs and
leaking credentials in logs.

lib/agents/tools/mapbox/mcp-client.ts [36-45]

 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/mapbox-mcp-server/mcp'
 
 let serverUrlToUse
 try {
   serverUrlToUse = createSmitheryUrl(mcpServerBaseUrl, smitheryUrlOptions)
 } catch (urlError: any) {
   console.error('[MCP-Client] Error creating Smithery URL:', urlError.message)
   return null
 }
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies that query parameters are likely being duplicated, which could lead to malformed URLs, and proposes a clean fix.

Low
  • More

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.

3 participants