A Model Context Protocol server that provides access to Kaggle's API functionality, including competitions, datasets, notebooks, and models.
This server has VISIBLE tool definitions with reasonable naming and descriptions, but falls short on several critical dimensions. All four tools have explicit names starting with action verbs (list_, get_, download_, search_) and descriptions of adequate length (34-110 chars). Parameter schemas are present and mostly typed. However, there are significant gaps: (1) Output schemas are not documented, we can see what fields the code returns, but there is no formal specification of the response structure that an LLM can rely on; (2) Parameters lack descriptions in the JSON Schema, the code docstrings contain descriptions, but these are not exposed in the MCP tool registration where the LLM can see them; (3) Error handling is minimal (returns generic {"error": str(e)} dicts with no recovery guidance); (4) No input validation or enum constraints on enum-like parameters (e.g., 'sort_by' accepts free-form strings instead of constrained enums); (5) The download_competition_files tool has a WRITE risk but no confirmation/dry-run pattern. The tools are usable but not optimized for LLM reliability.
Download competition files to a specified directory
Get detailed information about a specific Kaggle competition
List active Kaggle competitions with optional filtering
Search for Kaggle datasets with filtering options
Output schemas not documented. Code returns Dict[str, Any] with fields like 'competitions', 'error', 'total_count', etc., but there is no formal schema specification that an LLM can rely on to plan downstream operations or extract specific fields. This forces LLMs to infer structure from examples.
Parameter descriptions missing from JSON Schema. The Python docstrings contain parameter descriptions (e.g., 'Search term to filter competitions'), but these are not propagated to the MCP tool schema. The LLM sees parameter names and types only, not their semantics. In FastMCP, ensure descriptions are included via the @mcp.tool() decorator or schema builders.
Enum-like parameters accept free-form strings. 'sort_by' (values: deadline, prize, numberOfTeams, recentlyCreated) and 'category' (values: all, featured, research, recruitment) should be declared as JSON Schema enums, not free-form strings. This prevents LLM hallucination of invalid values.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 49 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 19 | - | v1 |
Error handling lacks recovery guidance. All tools return generic {'error': str(e)} responses. Instead, errors should categorize the issue (e.g., 'resource_not_found', 'auth_failed', 'rate_limited') and provide actionable next steps: 'Competition not found. Try search_datasets() or list_competitions() first.' This lets the LLM self-correct.
download_competition_files (destructive tool) lacks confirmation. This tool WRITES to the filesystem with parameters force=false and file_name=optional. An LLM could accidentally overwrite local files. Implement a dry-run mode or require explicit confirmation before proceeding.
Pagination metadata incomplete. list_competitions and search_datasets accept page and page_size parameters and return total_count, but do not return a next_cursor or has_more flag. Without clear pagination signaling, an LLM cannot determine if more results exist or when to stop iterating.
No input validation or format constraints documented. Parameters like 'download_path' accept any string, 'page_size' accepts any int. Rubric requires ranges (e.g., page_size 1 - 100, page ≥1) and format descriptions in parameter metadata. Currently, LLMs could pass invalid values (negative page, download_path='/', page_size=999999).