Skip to main content
Glama
proximity_handlers_test.go6.48 kB
// ABOUTME: This file contains tests for the station proximity handlers for the MCP server. // ABOUTME: It tests the findNearbyStationsHandler functionality. package server import ( "context" "encoding/json" "testing" "github.com/crdant/mbta-mcp-server/internal/config" "github.com/crdant/mbta-mcp-server/pkg/mbta/models" "github.com/mark3labs/mcp-go/mcp" ) func TestFindNearbyStationsHandler(t *testing.T) { // Create a minimal test server for the handler tests cfg := &config.Config{ APIKey: "test-api-key", Debug: false, LogLevel: "info", Timeout: 30, APIBaseURL: "https://api-test.mbta.com", Environment: "test", } server, err := New(cfg) if err != nil { t.Fatalf("Failed to create server: %v", err) } // Test cases t.Run("Validates required parameters", func(t *testing.T) { // Create a request with missing parameters request := mcp.CallToolRequest{ Params: struct { Name string `json:"name"` Arguments map[string]any `json:"arguments,omitempty"` Meta *struct { ProgressToken mcp.ProgressToken `json:"progressToken,omitempty"` } `json:"_meta,omitempty"` }{ Name: "find_nearby_stations", Arguments: map[string]any{ // Missing latitude and longitude "radius": 1.0, }, }, } // Call the handler response, err := server.findNearbyStationsHandler(context.Background(), request) if err != nil { t.Fatalf("Expected no error, got: %v", err) } // Should return an error response due to missing required parameters if response == nil { t.Fatal("Expected error response, got nil") } // Check for error message in the response textContent, ok := response.Content[0].(mcp.TextContent) if !ok { t.Fatalf("Expected TextContent, got %T", response.Content[0]) } // Parse the error message var errorResponse map[string]interface{} if err := json.Unmarshal([]byte(textContent.Text), &errorResponse); err != nil { t.Fatalf("Failed to parse error response: %v", err) } // Verify error message if errorMessage, ok := errorResponse["error"].(string); !ok || errorMessage == "" { t.Errorf("Expected error message, got: %v", errorResponse) } }) t.Run("Validates parameter types", func(t *testing.T) { // Create a request with incorrect parameter types request := mcp.CallToolRequest{ Params: struct { Name string `json:"name"` Arguments map[string]any `json:"arguments,omitempty"` Meta *struct { ProgressToken mcp.ProgressToken `json:"progressToken,omitempty"` } `json:"_meta,omitempty"` }{ Name: "find_nearby_stations", Arguments: map[string]any{ "latitude": "not-a-number", // Should be a number "longitude": -71.06, "radius": 1.0, }, }, } // Call the handler response, err := server.findNearbyStationsHandler(context.Background(), request) if err != nil { t.Fatalf("Expected no error, got: %v", err) } // Should return an error response due to invalid parameter type if response == nil { t.Fatal("Expected error response, got nil") } // Check for error message in the response textContent, ok := response.Content[0].(mcp.TextContent) if !ok { t.Fatalf("Expected TextContent, got %T", response.Content[0]) } // Parse the error message var errorResponse map[string]interface{} if err := json.Unmarshal([]byte(textContent.Text), &errorResponse); err != nil { t.Fatalf("Failed to parse error response: %v", err) } // Verify error message if errorMessage, ok := errorResponse["error"].(string); !ok || errorMessage == "" { t.Errorf("Expected error message, got: %v", errorResponse) } }) } // Mock code removed to fix linting errors func TestFindNearbyStationsResponse(t *testing.T) { // Test formatting of station proximity results testStops := []models.NearbyStation{ { Stop: models.Stop{ ID: "place-pktrm", Type: "stop", Attributes: models.StopAttributes{ Name: "Park Street", Latitude: 42.35639457, Longitude: -71.0624242, WheelchairBoarding: models.WheelchairBoardingAccessible, Municipality: "Boston", LocationType: models.LocationTypeStation, }, }, DistanceKm: 0.25, }, { Stop: models.Stop{ ID: "place-dwnxg", Type: "stop", Attributes: models.StopAttributes{ Name: "Downtown Crossing", Latitude: 42.355518, Longitude: -71.060225, WheelchairBoarding: models.WheelchairBoardingAccessible, Municipality: "Boston", LocationType: models.LocationTypeStation, }, }, DistanceKm: 0.5, }, } // Create response with the test data response, err := formatNearbyStationsResponse(testStops) if err != nil { t.Fatalf("Failed to format response: %v", err) } // Verify response structure if response == nil { t.Fatal("Expected response, got nil") } // Check for content in the response if len(response.Content) != 1 { t.Fatalf("Expected 1 content item, got %d", len(response.Content)) } // Check that the content is text textContent, ok := response.Content[0].(mcp.TextContent) if !ok { t.Fatalf("Expected TextContent, got %T", response.Content[0]) } // Parse the JSON response var responseData []map[string]interface{} if err := json.Unmarshal([]byte(textContent.Text), &responseData); err != nil { t.Fatalf("Failed to parse response: %v", err) } // Verify the response contains the expected number of stations if len(responseData) != len(testStops) { t.Errorf("Expected %d stations in response, got %d", len(testStops), len(responseData)) } // Verify each station has the required fields for i, station := range responseData { // Check required fields requiredFields := []string{"id", "name", "distance_km", "latitude", "longitude", "municipality", "wheelchair_accessible"} for _, field := range requiredFields { if _, ok := station[field]; !ok { t.Errorf("Station %d missing required field: %s", i, field) } } // Check ID matches original if station["id"] != testStops[i].Stop.ID { t.Errorf("Expected station %d ID to be %s, got %s", i, testStops[i].Stop.ID, station["id"]) } // Check distance matches original if station["distance_km"] != testStops[i].DistanceKm { t.Errorf("Expected station %d distance to be %f, got %v", i, testStops[i].DistanceKm, station["distance_km"]) } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/crdant/mbta-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server