Skip to content

feat: LTA connector#115

Open
mstrivens wants to merge 2 commits intoStackOneHQ:mainfrom
mstrivens:lta-tennis-court-finder
Open

feat: LTA connector#115
mstrivens wants to merge 2 commits intoStackOneHQ:mainfrom
mstrivens:lta-tennis-court-finder

Conversation

@mstrivens
Copy link

@mstrivens mstrivens commented Aug 28, 2025

Summary by cubic

Adds an LTA tennis court finder MCP connector to search UK courts and return availability, with tools for coordinate-based and city-based queries. Registers the connector and adds a local MCP endpoint for testing.

  • New Features
    • New LTAConnectorConfig with tools: find_courts (lat/long, location, date, timeRange) and search_by_city (auto-geocodes via Nominatim).
    • Scrapes LTA results with a desktop User-Agent, parses availability and member-only slots, and returns a clean text summary.
    • Connector registered and exported in mcp-connectors index.
    • .mcp.json: added local "stackone" MCP server at http://localhost:3000/mcp.

Copilot AI review requested due to automatic review settings August 28, 2025 20:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds a new LTA (Lawn Tennis Association) connector that enables finding tennis courts in the UK with availability information based on location and time preferences.

  • Adds a new LTA connector for finding tennis courts with availability data
  • Implements two search methods: by coordinates and by city name with geocoding
  • Integrates the new connector into the main connector registry

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
packages/mcp-connectors/src/index.ts Imports and exports the new LTAConnectorConfig in the connector registry
packages/mcp-connectors/src/connectors/lta.ts Implements the complete LTA tennis court finder with web scraping and geocoding
.mcp.json Adds local development server configuration for testing

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +32 to +49
try {
const response = await fetch(url, {
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
},
});

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

const html = await response.text();
const courts = parseCourtResults(html);
return courts;
} catch (error) {
throw error;
}
Copy link

Copilot AI Aug 28, 2025

Choose a reason for hiding this comment

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

Unnecessary try-catch block that re-throws the error without adding value. Either handle the error appropriately or remove the try-catch block entirely.

Suggested change
try {
const response = await fetch(url, {
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
},
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const html = await response.text();
const courts = parseCourtResults(html);
return courts;
} catch (error) {
throw error;
}
const response = await fetch(url, {
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
},
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const html = await response.text();
const courts = parseCourtResults(html);
return courts;

Copilot uses AI. Check for mistakes.
const name = nameElem?.text.trim() || '';

// Extract address from the court details span
const detailsElem = listing.querySelector('.lta-cart-court-details span');
Copy link

Copilot AI Aug 28, 2025

Choose a reason for hiding this comment

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

There's a typo in the CSS selector. 'lta-cart-court-details' should be 'lta-card-court-details' to match the intended element structure.

Suggested change
const detailsElem = listing.querySelector('.lta-cart-court-details span');
const detailsElem = listing.querySelector('.lta-card-court-details span');

Copilot uses AI. Check for mistakes.
Comment on lines +133 to +139
const parseTimeRange = (timeRange: string): { startHour: number; endHour: number } => {
const [start, end] = timeRange.split('-');
const startHour = parseInt(start.split(':')[0], 10);
const endHour = parseInt(end.split(':')[0], 10);
return { startHour, endHour };
};

Copy link

Copilot AI Aug 28, 2025

Choose a reason for hiding this comment

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

The parseTimeRange function is defined but never used anywhere in the code. This could indicate incomplete implementation or dead code that should be removed.

Suggested change
const parseTimeRange = (timeRange: string): { startHour: number; endHour: number } => {
const [start, end] = timeRange.split('-');
const startHour = parseInt(start.split(':')[0], 10);
const endHour = parseInt(end.split(':')[0], 10);
return { startHour, endHour };
};

Copilot uses AI. Check for mistakes.
timeRange,
});

const url = `${BASE_URL}?${params.toString()}`;
Copy link

Copilot AI Aug 28, 2025

Choose a reason for hiding this comment

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

The function uses BASE_URL for constructing the search URL, but based on the constants defined, it should use SEARCH_URL instead for the actual search functionality.

Suggested change
const url = `${BASE_URL}?${params.toString()}`;
const url = `${SEARCH_URL}?${params.toString()}`;

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files

React with 👍 or 👎 to teach cubic. You can also tag @cubic-dev-ai to give feedback, ask questions, or re-run the review.

const name = nameElem?.text.trim() || '';

// Extract address from the court details span
const detailsElem = listing.querySelector('.lta-cart-court-details span');
Copy link
Contributor

Choose a reason for hiding this comment

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

Functional correctness: Typo in CSS selector ('lta-cart-court-details') breaks address extraction for venues.

Prompt for AI agents
Address the following comment on packages/mcp-connectors/src/connectors/lta.ts at line 67:

<comment>Functional correctness: Typo in CSS selector (&#39;lta-cart-court-details&#39;) breaks address extraction for venues.</comment>

<file context>
@@ -0,0 +1,239 @@
+    const name = nameElem?.text.trim() || &#39;&#39;;
+
+    // Extract address from the court details span
+    const detailsElem = listing.querySelector(&#39;.lta-cart-court-details span&#39;);
+    let address = &#39;&#39;;
+    if (detailsElem) {
</file context>

@mattzcarey mattzcarey changed the title [Max] - Tennis court finder feat: LTA connector Sep 2, 2025
@glebedel
Copy link
Contributor

@claude resolve the conflicts and fix linting

@claude
Copy link
Contributor

claude bot commented Oct 16, 2025

Claude encountered an error —— View job

Failed with exit code 128

I'll analyze this and get back to you.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants