@withinfocus/tba-mcp-server 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Matt Bishop
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,614 @@
1
+ # The Blue Alliance MCP Server
2
+
3
+ A Model Context Protocol (MCP) server that provides access to The Blue Alliance API for FIRST Robotics Competition data. This server enables AI assistants and other MCP clients to retrieve comprehensive FRC team, event, and match information.
4
+
5
+ ## Features
6
+
7
+ - **Team Information**: Get detailed team profiles, participation history, awards, and media
8
+ - **Event Data**: Access event details, rankings, matches, and elimination alliances
9
+ - **Match Results**: Retrieve match data with scores, alliances, and breakdowns
10
+ - **Historical Data**: Query data from 1992 to the current year
11
+
12
+ ## Prerequisites
13
+
14
+ - Node.js 22
15
+ - The Blue Alliance API key (register at [thebluealliance.com/account](https://www.thebluealliance.com/account))
16
+
17
+ ## Installation
18
+
19
+ ### From npm
20
+
21
+ ```bash
22
+ npm install -g @withinfocus/tba-mcp-server
23
+ ```
24
+
25
+ ### From source
26
+
27
+ ```bash
28
+ git clone https://github.com/withinfocus/tba-mcp-server.git
29
+ cd tba-mcp-server
30
+ npm install
31
+ npm run build
32
+ ```
33
+
34
+ ## Configuration
35
+
36
+ Set your The Blue Alliance API key as an environment variable:
37
+
38
+ ```bash
39
+ export TBA_API_KEY=your_api_key_here
40
+ ```
41
+
42
+ Or create a `.env` file:
43
+
44
+ ```
45
+ TBA_API_KEY=your_api_key_here
46
+ ```
47
+
48
+ ## Usage
49
+
50
+ Open up your application configuration, e.g. for Claude Desktop:
51
+
52
+ ```json
53
+ {
54
+ "mcpServers": {
55
+ "tba": {
56
+ "command": "npx",
57
+ "args": ["-y", "@withinfocus/tba-mcp-server"],
58
+ "env": {
59
+ "TBA_API_KEY": "your_api_key_here"
60
+ }
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+ ## Available Tools
67
+
68
+ This MCP server provides many tools for accessing The Blue Alliance API. All tools validate input parameters and return structured, type-safe data.
69
+
70
+ ### Team Information Tools
71
+
72
+ #### Core Team Data
73
+
74
+ - **`get_team`** - Get detailed team information
75
+ - Parameters: `team_key` (string, format: frcXXXX)
76
+ - Returns: Complete team profile including location, website, rookie year, motto
77
+ - Example: `get_team(team_key="frc86")`
78
+
79
+ - **`get_team_simple`** - Get simplified team information
80
+ - Parameters: `team_key` (string, format: frcXXXX)
81
+ - Returns: Basic team data (number, name, city, state, country)
82
+
83
+ #### Team Participation & History
84
+
85
+ - **`get_team_years_participated`** - Get years a team has participated in competition
86
+ - Parameters: `team_key` (string)
87
+ - Returns: Array of years (numbers)
88
+
89
+ - **`get_team_districts`** - Get district history for a team
90
+ - Parameters: `team_key` (string)
91
+ - Returns: Array of district objects with abbreviation, display name, key, year
92
+
93
+ - **`get_team_robots`** - Get robot names for a team by year
94
+ - Parameters: `team_key` (string)
95
+ - Returns: Array of robot objects with year, name, key
96
+
97
+ - **`get_team_history`** - Get comprehensive historical data for a team
98
+ - Parameters: `team_key` (string)
99
+ - Returns: Awards, events, matches, and robots across all years
100
+
101
+ #### Team Events & Performance
102
+
103
+ - **`get_team_events`** - Get events a team participated in for a specific year
104
+ - Parameters: `team_key` (string), `year` (number, 1992-current+1)
105
+ - Returns: Array of detailed event objects
106
+
107
+ - **`get_team_events_simple`** - Get simplified events for a team in a year
108
+ - Parameters: `team_key` (string), `year` (number)
109
+ - Returns: Array of basic event data
110
+
111
+ - **`get_team_events_keys`** - Get event keys for a team in a year
112
+ - Parameters: `team_key` (string), `year` (number)
113
+ - Returns: Array of event key strings
114
+
115
+ - **`get_team_events_all`** - Get all events a team has participated in across all years
116
+ - Parameters: `team_key` (string)
117
+ - Returns: Array of detailed event objects
118
+
119
+ - **`get_team_event_status`** - Get team's rank and status at a specific event
120
+ - Parameters: `team_key` (string), `event_key` (string)
121
+ - Returns: Qualification ranking, alliance info, playoff status
122
+
123
+ - **`get_team_event_statuses`** - Get team's status at all events in a year
124
+ - Parameters: `team_key` (string), `year` (number)
125
+ - Returns: Object mapping event keys to status objects
126
+
127
+ #### Team Matches
128
+
129
+ - **`get_team_matches`** - Get detailed matches for a team in a year
130
+ - Parameters: `team_key` (string), `year` (number)
131
+ - Returns: Array of complete match objects with scores, alliances, breakdowns
132
+
133
+ - **`get_team_matches_simple`** - Get simplified matches for a team in a year
134
+ - Parameters: `team_key` (string), `year` (number)
135
+ - Returns: Array of basic match data
136
+
137
+ - **`get_team_matches_keys`** - Get match keys for a team in a year
138
+ - Parameters: `team_key` (string), `year` (number)
139
+ - Returns: Array of match key strings
140
+
141
+ - **`get_team_event_matches`** - Get detailed matches for a team at a specific event
142
+ - Parameters: `team_key` (string), `event_key` (string)
143
+ - Returns: Array of complete match objects
144
+
145
+ - **`get_team_event_matches_simple`** - Get simplified matches for a team at an event
146
+ - Parameters: `team_key` (string), `event_key` (string)
147
+ - Returns: Array of basic match data
148
+
149
+ - **`get_team_event_matches_keys`** - Get match keys for a team at an event
150
+ - Parameters: `team_key` (string), `event_key` (string)
151
+ - Returns: Array of match key strings
152
+
153
+ #### Team Awards
154
+
155
+ - **`get_team_awards`** - Get awards won by a team in a specific year
156
+ - Parameters: `team_key` (string), `year` (number)
157
+ - Returns: Array of award objects with name, type, event, recipients
158
+
159
+ - **`get_team_awards_all`** - Get all awards won by a team across all years
160
+ - Parameters: `team_key` (string)
161
+ - Returns: Array of award objects
162
+
163
+ - **`get_team_event_awards`** - Get awards won by a team at a specific event
164
+ - Parameters: `team_key` (string), `event_key` (string)
165
+ - Returns: Array of award objects
166
+
167
+ #### Team Media & Social
168
+
169
+ - **`get_team_media`** - Get media for a team in a specific year
170
+ - Parameters: `team_key` (string), `year` (number)
171
+ - Returns: Array of media objects (photos, videos, etc.)
172
+
173
+ - **`get_team_media_by_tag`** - Get media for a team filtered by tag
174
+ - Parameters: `team_key` (string), `media_tag` (string)
175
+ - Returns: Array of filtered media objects
176
+
177
+ - **`get_team_media_by_tag_year`** - Get media for a team by tag and year
178
+ - Parameters: `team_key` (string), `media_tag` (string), `year` (number)
179
+ - Returns: Array of filtered media objects
180
+
181
+ - **`get_team_social_media`** - Get social media information for a team
182
+ - Parameters: `team_key` (string)
183
+ - Returns: Array of social media links and handles
184
+
185
+ ### Event Information Tools
186
+
187
+ #### Core Event Data
188
+
189
+ - **`get_events`** - Get all FRC events for a specific year
190
+ - Parameters: `year` (number, 1992-current+1)
191
+ - Returns: Array of detailed event objects
192
+
193
+ - **`get_events_simple`** - Get simplified events for a year
194
+ - Parameters: `year` (number)
195
+ - Returns: Array of basic event data
196
+
197
+ - **`get_events_keys`** - Get event keys for a year
198
+ - Parameters: `year` (number)
199
+ - Returns: Array of event key strings
200
+
201
+ - **`get_event`** - Get detailed information about a specific event
202
+ - Parameters: `event_key` (string)
203
+ - Returns: Complete event details including dates, location, webcasts
204
+ - Example: `get_event(event_key="2023casj")`
205
+
206
+ - **`get_event_simple`** - Get simplified event information
207
+ - Parameters: `event_key` (string)
208
+ - Returns: Basic event data
209
+
210
+ #### Event Participants
211
+
212
+ - **`get_event_teams`** - Get teams participating in an event
213
+ - Parameters: `event_key` (string)
214
+ - Returns: Array of detailed team objects
215
+
216
+ - **`get_event_teams_simple`** - Get simplified teams in an event
217
+ - Parameters: `event_key` (string)
218
+ - Returns: Array of basic team data
219
+
220
+ - **`get_event_teams_keys`** - Get team keys in an event
221
+ - Parameters: `event_key` (string)
222
+ - Returns: Array of team key strings
223
+
224
+ #### Event Results & Rankings
225
+
226
+ - **`get_event_rankings`** - Get team rankings for an event
227
+ - Parameters: `event_key` (string)
228
+ - Returns: Rankings object with team standings, records, statistics
229
+
230
+ - **`get_event_alliances`** - Get elimination alliances for an event
231
+ - Parameters: `event_key` (string)
232
+ - Returns: Array of alliance objects with picks, status, records
233
+
234
+ - **`get_event_awards`** - Get awards from a specific event
235
+ - Parameters: `event_key` (string)
236
+ - Returns: Array of award objects
237
+
238
+ #### Event Matches
239
+
240
+ - **`get_event_matches`** - Get detailed matches for an event
241
+ - Parameters: `event_key` (string)
242
+ - Returns: Array of complete match objects
243
+
244
+ - **`get_event_matches_simple`** - Get simplified matches for an event
245
+ - Parameters: `event_key` (string)
246
+ - Returns: Array of basic match data
247
+
248
+ - **`get_event_matches_keys`** - Get match keys for an event
249
+ - Parameters: `event_key` (string)
250
+ - Returns: Array of match key strings
251
+
252
+ #### Event Analytics
253
+
254
+ - **`get_event_insights`** - Get event-specific insights and statistics
255
+ - Parameters: `event_key` (string)
256
+ - Returns: Qualification and playoff statistics and insights
257
+
258
+ - **`get_event_oprs`** - Get OPR, DPR, and CCWM ratings for teams at an event
259
+ - Parameters: `event_key` (string)
260
+ - Returns: Object with OPR (Offensive Power Rating), DPR (Defensive Power Rating), CCWM (Calculated Contribution to Winning Margin)
261
+
262
+ - **`get_event_predictions`** - Get TBA-generated predictions for an event
263
+ - Parameters: `event_key` (string)
264
+ - Returns: Match and ranking predictions
265
+
266
+ - **`get_event_district_points`** - Get district points for teams at an event
267
+ - Parameters: `event_key` (string)
268
+ - Returns: District points breakdown by team
269
+
270
+ ### Match Information Tools
271
+
272
+ - **`get_match`** - Get detailed information about a specific match
273
+ - Parameters: `match_key` (string)
274
+ - Returns: Complete match data with scores, alliances, breakdown
275
+ - Example: `get_match(match_key="2023casj_qm1")`
276
+
277
+ - **`get_match_simple`** - Get simplified match information
278
+ - Parameters: `match_key` (string)
279
+ - Returns: Basic match data
280
+
281
+ - **`get_match_zebra`** - Get Zebra MotionWorks data for a match (robot tracking)
282
+ - Parameters: `match_key` (string)
283
+ - Returns: Robot position tracking data (if available)
284
+
285
+ ### District Tools
286
+
287
+ - **`get_districts`** - Get all districts for a specific year
288
+ - Parameters: `year` (number)
289
+ - Returns: Array of district objects
290
+
291
+ - **`get_district_rankings`** - Get team rankings within a district
292
+ - Parameters: `district_key` (string)
293
+ - Returns: Array of district ranking objects with points breakdown
294
+ - Example: `get_district_rankings(district_key="2023fim")`
295
+
296
+ - **`get_district_events`** - Get events in a specific district
297
+ - Parameters: `district_key` (string)
298
+ - Returns: Array of detailed event objects
299
+
300
+ - **`get_district_events_simple`** - Get simplified events in a district
301
+ - Parameters: `district_key` (string)
302
+ - Returns: Array of basic event data
303
+
304
+ - **`get_district_events_keys`** - Get event keys in a district
305
+ - Parameters: `district_key` (string)
306
+ - Returns: Array of event key strings
307
+
308
+ - **`get_district_teams`** - Get teams in a specific district
309
+ - Parameters: `district_key` (string)
310
+ - Returns: Array of detailed team objects
311
+
312
+ - **`get_district_teams_simple`** - Get simplified teams in a district
313
+ - Parameters: `district_key` (string)
314
+ - Returns: Array of basic team data
315
+
316
+ - **`get_district_teams_keys`** - Get team keys in a district
317
+ - Parameters: `district_key` (string)
318
+ - Returns: Array of team key strings
319
+
320
+ ### General/Utility Tools
321
+
322
+ - **`get_teams`** - Get paginated list of all teams (detailed)
323
+ - Parameters: `page_num` (number, 0-indexed)
324
+ - Returns: Array of complete team objects (500 teams per page)
325
+
326
+ - **`get_teams_simple`** - Get paginated list of teams (simplified)
327
+ - Parameters: `page_num` (number, 0-indexed)
328
+ - Returns: Array of basic team data
329
+
330
+ - **`get_teams_keys`** - Get paginated list of team keys
331
+ - Parameters: `page_num` (number, 0-indexed)
332
+ - Returns: Array of team key strings
333
+
334
+ - **`get_teams_by_year`** - Get teams that competed in a specific year (detailed)
335
+ - Parameters: `year` (number), `page_num` (number, 0-indexed)
336
+ - Returns: Array of complete team objects
337
+
338
+ - **`get_teams_by_year_simple`** - Get teams from a year (simplified)
339
+ - Parameters: `year` (number), `page_num` (number, 0-indexed)
340
+ - Returns: Array of basic team data
341
+
342
+ - **`get_teams_by_year_keys`** - Get team keys from a specific year
343
+ - Parameters: `year` (number), `page_num` (number, 0-indexed)
344
+ - Returns: Array of team key strings
345
+
346
+ - **`get_status`** - Get TBA API status information
347
+ - No parameters required
348
+ - Returns: API status including current season, downtime info, app versions
349
+
350
+ ### Parameter Validation
351
+
352
+ All tools implement strict parameter validation:
353
+
354
+ - **Team Keys**: Must match format `frcXXXX` (e.g., `frc86`, `frc1234`)
355
+ - **Years**: Must be between 1992 and current year + 1
356
+ - **Event Keys**: String format like `2023casj`, `2024week1`
357
+ - **Match Keys**: String format like `2023casj_qm1`, `2024week1_sf1m1`
358
+ - **District Keys**: String format like `2023fim`, `2024pnw`
359
+ - **Page Numbers**: 0-indexed integers (≥ 0)
360
+
361
+ ### Data Response Formats
362
+
363
+ - **Simple**: Basic information for lists and overviews
364
+ - **Detailed**: Complete information including all available fields
365
+ - **Keys**: Just the identifier strings for efficient lookups
366
+
367
+ ### Common Patterns
368
+
369
+ **Find a team's performance at a specific event:**
370
+
371
+ 1. Use `get_team_event_matches` to get their matches
372
+ 2. Use `get_event_rankings` to see their final ranking
373
+
374
+ **Analyze an event:**
375
+
376
+ 1. Use `get_event` for basic event info
377
+ 2. Use `get_event_teams` to see participating teams
378
+ 3. Use `get_event_rankings` for final standings
379
+ 4. Use `get_event_alliances` for elimination results
380
+
381
+ ## Development
382
+
383
+ ### Building
384
+
385
+ ```bash
386
+ npm run build
387
+ ```
388
+
389
+ ### Testing
390
+
391
+ #### Unit Tests (Jest)
392
+
393
+ ```bash
394
+ npm test # Run unit tests
395
+ npm run test:watch # Run unit tests in watch mode
396
+ ```
397
+
398
+ #### Integration Tests (Playwright)
399
+
400
+ ```bash
401
+ npm run test:integration # Run all integration tests
402
+ npm run test:integration:ui # Run with Playwright UI
403
+ npm run test:integration:debug # Debug mode
404
+ ```
405
+
406
+ #### All Tests
407
+
408
+ ```bash
409
+ npm run test:all # Run both unit and integration tests
410
+ ```
411
+
412
+ **Note**: Integration tests require a valid TBA API key set as `TBA_API_KEY` environment variable.
413
+
414
+ ### Linting
415
+
416
+ ```bash
417
+ npm run lint
418
+ npm run lint:fix
419
+ ```
420
+
421
+ ### Development Workflow
422
+
423
+ ```bash
424
+ # Install dependencies
425
+ npm install
426
+
427
+ # Run unit tests in watch mode during development
428
+ npm run test:watch
429
+
430
+ # Build the project
431
+ npm run build
432
+
433
+ # Run all tests (unit + integration)
434
+ npm run test:all
435
+
436
+ # Test with the MCP inspector
437
+ npm run inspect
438
+ ```
439
+
440
+ ## Data Schemas
441
+
442
+ All API responses are validated using Zod schemas ensuring type safety and consistency:
443
+
444
+ ### Core Schemas
445
+
446
+ #### Team Schema
447
+
448
+ Complete team information including:
449
+
450
+ - `key` (string) - Team identifier (e.g., "frc86")
451
+ - `team_number` (number) - Numeric team number
452
+ - `nickname` (string) - Team nickname/informal name
453
+ - `name` (string) - Official team name
454
+ - `city`, `state_prov`, `country` (string) - Location details
455
+ - `website` (string) - Team website URL
456
+ - `rookie_year` (number) - First year of competition
457
+ - `motto` (string) - Team motto/slogan
458
+ - Location data: `lat`, `lng`, `address`, `postal_code`, `gmaps_place_id`, `gmaps_url`
459
+
460
+ #### TeamSimple Schema
461
+
462
+ Simplified team data:
463
+
464
+ - `key`, `team_number`, `nickname`, `name`
465
+ - `city`, `state_prov`, `country`
466
+
467
+ #### Event Schema
468
+
469
+ Complete event information including:
470
+
471
+ - `key` (string) - Event identifier (e.g., "2023casj")
472
+ - `name` (string) - Official event name
473
+ - `event_code` (string) - Short event code
474
+ - `event_type` (number) - Event type identifier
475
+ - `start_date`, `end_date` (string) - ISO date strings
476
+ - `year` (number) - Competition year
477
+ - `week` (number) - Competition week (null for offseason)
478
+ - Location: `city`, `state_prov`, `country`, `address`, `timezone`
479
+ - `district` - District information object (if applicable)
480
+ - `webcasts` - Array of webcast objects with type, channel, date
481
+ - `playoff_type`, `playoff_type_string` - Playoff format information
482
+
483
+ #### EventSimple Schema
484
+
485
+ Basic event data:
486
+
487
+ - `key`, `name`, `event_code`, `event_type`
488
+ - `city`, `state_prov`, `country`
489
+ - `start_date`, `end_date`, `year`
490
+
491
+ #### Match Schema
492
+
493
+ Complete match information:
494
+
495
+ - `key` (string) - Match identifier (e.g., "2023casj_qm1")
496
+ - `comp_level` (string) - Competition level (qm, ef, qf, sf, f)
497
+ - `set_number`, `match_number` (number) - Match identifiers
498
+ - `alliances` - Red and blue alliance objects containing:
499
+ - `score` (number) - Alliance final score
500
+ - `team_keys` (string[]) - Array of team identifiers
501
+ - `surrogate_team_keys`, `dq_team_keys` (string[]) - Special designations
502
+ - `winning_alliance` (string) - "red", "blue", or null for ties
503
+ - `event_key` (string) - Parent event identifier
504
+ - Timing: `time`, `actual_time`, `predicted_time`, `post_result_time`
505
+ - `score_breakdown` - Detailed scoring breakdown object (game-specific)
506
+ - `videos` - Array of video objects with type and key
507
+
508
+ #### MatchSimple Schema
509
+
510
+ Basic match data:
511
+
512
+ - `key`, `comp_level`, `set_number`, `match_number`
513
+ - Simplified `alliances` with score and team_keys only
514
+ - `winning_alliance`, `event_key`
515
+ - Basic timing: `time`, `predicted_time`, `actual_time`
516
+
517
+ #### Award Schema
518
+
519
+ Award information:
520
+
521
+ - `name` (string) - Award name
522
+ - `award_type` (number) - Award type identifier
523
+ - `event_key` (string) - Event where awarded
524
+ - `year` (number) - Competition year
525
+ - `recipient_list` - Array of recipient objects:
526
+ - `team_key` (string) - Team recipient (if applicable)
527
+ - `awardee` (string) - Individual recipient (if applicable)
528
+
529
+ #### Rankings Schema
530
+
531
+ Event ranking information:
532
+
533
+ - `rankings` - Array of ranking objects:
534
+ - `team_key` (string) - Team identifier
535
+ - `rank` (number) - Current ranking position
536
+ - `matches_played` (number) - Number of matches played
537
+ - `record` - Win/loss/tie record object
538
+ - `qual_average` (number) - Average qualification score
539
+ - `extra_stats` (number[]) - Additional statistics
540
+ - `sort_orders` (number[]) - Tiebreaker values
541
+ - `extra_stats_info`, `sort_order_info` - Metadata describing statistics
542
+
543
+ #### Alliance Schema
544
+
545
+ Elimination alliance information:
546
+
547
+ - `name` (string) - Alliance name/number
548
+ - `picks` (string[]) - Array of team keys in pick order
549
+ - `backup` - Backup team information (if applicable)
550
+ - `declines` (string[]) - Teams that declined alliance invitations
551
+ - `status` - Alliance performance object:
552
+ - `level` (string) - Current playoff level
553
+ - `status` (string) - Current status
554
+ - `record` - Overall playoff record
555
+ - `current_level_record` - Record at current level
556
+ - `playoff_average` (number) - Average playoff score
557
+
558
+ #### Additional Schemas
559
+
560
+ - **District Schema**: District information with abbreviation, display name, key, year
561
+ - **Robot Schema**: Robot information with year, name, key, team_key
562
+ - **Media Schema**: Media objects with type, foreign_key, details, URLs
563
+ - **DistrictPoints Schema**: District points breakdown by team
564
+ - **DistrictRanking Schema**: District standings with point totals and event breakdown
565
+ - **TeamEventStatus Schema**: Team status at specific events (qualification rank, alliance, playoff status)
566
+ - **Insights Schema**: Event-specific statistics and insights
567
+ - **EventOPRs Schema**: OPR, DPR, and CCWM ratings
568
+ - **Zebra Schema**: Robot tracking data with position coordinates over time
569
+ - **Prediction Schema**: TBA-generated match and ranking predictions
570
+ - **Status Schema**: API status information
571
+
572
+ ### Schema Validation
573
+
574
+ All responses are validated to ensure:
575
+
576
+ - **Type Safety**: Correct data types for all fields
577
+ - **Required Fields**: Essential data is always present
578
+ - **Null Handling**: Proper handling of optional/missing data
579
+ - **Consistency**: Uniform structure across all endpoints
580
+ - **Error Prevention**: Invalid data is caught before reaching your application
581
+
582
+ ## Error Handling
583
+
584
+ The server provides detailed error messages for:
585
+
586
+ - Missing or invalid API keys
587
+ - Invalid team keys (must be format `frcXXXX`)
588
+ - Invalid years (must be 1992 to current year + 1)
589
+ - TBA API errors (rate limits, not found, etc.)
590
+ - Schema validation failures
591
+
592
+ ## API Rate Limits
593
+
594
+ The Blue Alliance API has rate limits. The server will pass through any rate limiting errors from the TBA API. Consider implementing request caching or throttling in your client application for heavy usage.
595
+
596
+ ## Contributing
597
+
598
+ 1. Fork the repository
599
+ 2. Create a feature branch
600
+ 3. Make your changes
601
+ 4. Add tests for new functionality
602
+ 5. Run the test suite
603
+ 6. Submit a pull request
604
+
605
+ ## License
606
+
607
+ MIT License - see [LICENSE](LICENSE) file for details.
608
+
609
+ ## Related Links
610
+
611
+ - [The Blue Alliance](https://www.thebluealliance.com/) - Official FRC data source
612
+ - [TBA API Documentation](https://www.thebluealliance.com/apidocs/v3) - Official API docs
613
+ - [Model Context Protocol](https://spec.modelcontextprotocol.io/) - MCP specification
614
+ - [FIRST Robotics Competition](https://www.firstinspires.org/robotics/frc) - Official FRC site