Using TypedDict for Type-Safe API Response Handling in Python
The Wordle MCP Python server leverages TypedDict subclasses to enforce strict JSON schemas for external API responses, enabling static type checkers to validate data access patterns and eliminate runtime KeyError exceptions before deployment.
The cr2007/mcp-wordle-python repository demonstrates production-grade patterns for external API integration by leveraging Python's typing.TypedDict. By declaring explicit shapes for both success and error payloads from the New York Times Wordle endpoint, the codebase achieves compile-time safety and self-documenting API contracts.
Defining Strict API Contracts with TypedDict
In src/mcp_wordle/main.py (lines 16-27), the server defines two distinct TypedDict subclasses that mirror the Wordle API's JSON format. The WordleAPIData class specifies required string fields including id, solution, print_date, days_since_launch, and editor. Conversely, WordleError captures failure states with status, errors, and results fields.
These declarations serve as executable documentation that static analysis tools like mypy and pyright can verify against actual usage patterns. By separating success and error concerns into distinct types, the code enforces exhaustive handling of both scenarios at the type level.
Annotating Function Signatures for Safety
The get_wordle_data function uses a Union[WordleAPIData, WordleError] return annotation (line 40), making the dual-state nature of the API explicit. This signature forces callers to implement defensive checks rather than assuming successful responses, preventing unhandled exceptions in production environments.
Implementation in the Wordle MCP Server
The actual request logic (lines 64-67) performs a standard requests.get call and returns the parsed JSON. Because the function returns a TypedDict union, type checkers automatically flag invalid key access attempts. Attempting to retrieve result["solution"] without first narrowing the type will generate a mypy error, as that key only exists on WordleAPIData and is absent from WordleError.
The function is registered as an MCP tool using the @mcp.tool decorator from the FastMCP framework. This exposes the typed function to any MCP-compatible client while preserving the strict TypedDict contracts across service boundaries.
Static Type Checking in Practice
When consuming the API, you must narrow the type before accessing payload-specific fields:
from mcp_wordle.main import get_wordle_data, WordleAPIData, WordleError
import asyncio
async def fetch_today():
result = await get_wordle_data() # defaults to today
if "solution" in result: # Type narrowing check
data: WordleAPIData = result
print(f"Today's Wordle solution: {data['solution']}")
else: # Error path handling
err: WordleError = result
print(f"Error {err['status']}: {err['errors']}")
asyncio.run(fetch_today())
Validate your implementation with mypy to catch potential key access violations:
pip install mypy
mypy src/mcp_wordle/main.py
If you mistakenly treat an error response as successful data (e.g., accessing result["solution"] without validation), the type checker flags the invalid key lookup immediately, long before runtime execution.
Packaging and Distribution
The project uses hatchling as its build backend (defined in pyproject.toml), packaging the type-safe server as a console script entry point named mcp-wordle. This allows the typed tool to execute via command line, Docker, or uvx while maintaining strict validation of response shapes defined in the TypedDict classes.
Summary
TypedDictdefinitions insrc/mcp_wordle/main.pycreate formal schemas for JSON responses, documenting the Wordle API contract directly in Python code with zero runtime overhead.- Union return types force explicit handling of both success (
WordleAPIData) and error (WordleError) scenarios at compile time, eliminating unhandledKeyErrorexceptions. - FastMCP integration exposes type-safe tools to external clients while preserving strict type constraints across the MCP protocol boundary.
- Static analysis compatibility with
mypyandpyrightenables immediate feedback on invalid API response handling during development.
Frequently Asked Questions
What is the performance cost of using TypedDict for API responses?
There is no runtime performance penalty. TypedDict exists solely in Python's type system for static analysis by tools like mypy and pyright. At runtime, the objects are standard dictionaries with no additional validation overhead or memory consumption.
How does TypedDict improve error handling compared to regular dictionaries?
Unlike standard dictionaries, TypedDict requires explicit type narrowing through key presence checks or isinstance validation. This forces developers to handle error payloads separately from successful responses, preventing KeyError exceptions when accessing fields that may not exist in error states returned by the Wordle API.
Can TypedDict handle optional fields in API responses?
Yes. The WordleAPIData and WordleError definitions in src/mcp_wordle/main.py can include optional fields using NotRequired or Optional type hints (depending on Python version). This flexibility allows the type system to model APIs where certain keys may be absent without breaking static validation of the fields that are guaranteed to exist.
Which static type checkers support TypedDict structural validation?
Both mypy and pyright (the engine behind VS Code's Pylance extension) fully support TypedDict structural subtyping. These tools validate that code accessing WordleAPIData only uses keys defined in the class (such as solution or print_date) and will flag attempts to access undefined keys or improperly narrow the Union type.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →