AssetDB Results Storage & Handling
Relevant source files
The following files were used as context for generating this wiki page:
AssetDB Results Storage & Handling defines how the MCP server manages, processes, and delivers data retrieved from the Stacklet AssetDB data warehouse. This system manages the lifecycle of SQL query results, from initial execution via the Redash API to delivery as truncated previews or full downloadable datasets.
The system ensures context efficiency for LLMs by providing small inline previews while maintaining access to complete result sets through two primary routes: local filesystem storage or embedded MCP resources.
Architecture and Data Flow
The AssetDB client interacts with a Redash API to execute SQL queries. The server handles both synchronous and asynchronous query execution, polling for results when necessary. Once data is retrieved, the server processes it into a ToolQueryResult structure.
The diagram shows the logic path from query execution to result delivery.
Sources: stacklet/mcp/assetdb/redash.py:157-224, stacklet/mcp/assetdb/tools.py:270-327
Data Delivery Methods
The server returns result data through exactly one of two routes, determined by the STACKLET_MCP_DOWNLOADS_ENABLED setting.
Local File Storage
If downloads are enabled, the server writes the full JSON array of rows to a local directory. This is the default behavior for local deployments.
- Path: Configured via
STACKLET_MCP_DOWNLOADS_PATH. - Filename Pattern:
assetdb_{query_id}_{result_id}.jsonfor saved queries orassetdb_{result_id}.jsonfor ad-hoc queries. - Usage: The tool response contains the file path in the
full_results_saved_tofield.
Embedded MCP Resources
If downloads are disabled, the server attaches the complete rows directly to the MCP response as a JSON resource. This is required for hosted deployments where the caller cannot access the server's filesystem.
- URI Format:
assetdb://query_results/{identity}.json - MIME Type:
application/json
Sources: CLAUDE.md:143-152, stacklet/mcp/assetdb/tools.py:312-327, README.md:65-72
Result Processing Logic
The server performs several transformations on raw Redash data to make it suitable for LLM consumption:
- Truncation: Only the first 20 rows are included in the
some_rowsfield to prevent excessive context window usage. - Schema Definition: Column definitions are preserved in the
columnsfield to ensure the LLM understands the data structure. - Artifact Generation: For saved queries, the server generates download links for multiple formats (CSV, JSON, TSV, XLSX). Ad-hoc queries do not support these alternate formats.
- Identity Tracking: Results are assigned an identity string combining the
query_idandresult_id.
Result Formats
| Format | Availability | Description |
|---|---|---|
| CSV | Saved Queries | Comma-separated values |
| JSON | All Queries | Full results via file or resource |
| TSV | Saved Queries | Tab-separated values |
| XLSX | Saved Queries | Microsoft Excel format |
Sources: stacklet/mcp/assetdb/tools.py:284-306, stacklet/mcp/assetdb/models.py:228-258, stacklet/mcp/assetdb/redash.py:226-249
Configuration Options
Storage behavior is governed by environment variables with the STACKLET_MCP_ prefix.
| Variable | Type | Default | Description |
|---|---|---|---|
DOWNLOADS_PATH | Path | System Temp | Directory for storing result files |
DOWNLOADS_ENABLED | Bool | true | Enables writing files to the local disk |
ASSETDB_DATASOURCE | Int | None | Explicit Redash data source ID |
ASSETDB_DATASOURCE_NAME | String | AssetDB | Name used to look up data source ID |
Sources: README.md:65-72, stacklet/mcp/assetdb/redash.py:53-76
Implementation Detail: Result Processing
The _tool_query_result function in tools.py orchestrates the conversion from a raw QueryResult to a ToolResult.
async def _tool_query_result(
client: AssetDBClient, query_result: QueryResult, query: Query | None
) -> ToolResult:
rows = query_result.data.rows
identity = f"{query.id}_{query_result.id}" if query else f"{query_result.id}"
full_results_saved_to = None
full_results_resource = None
if SETTINGS.downloads_enabled:
full_results_saved_to = await asyncio.to_thread(_write_rows, rows, identity)
else:
full_results_resource = await asyncio.to_thread(_rows_resource, rows, identity)
# ... artifact and result construction ...
content: list[ContentBlock] = [TextContent(type="text", text=result.model_dump_json())]
if full_results_resource:
content.append(full_results_resource)
return ToolResult(content=content, structured_content=result.model_dump(mode="json"))
Sources: stacklet/mcp/assetdb/tools.py:270-327
AssetDB results storage ensures that large datasets are handled efficiently by separating the LLM-readable preview from the full analytical dataset. This architecture prevents context overflow while maintaining full data access for external analysis tools.