Repository navigation
Serve knowledge_base.json gzip-compressed to fix MCP connect timeouts - #148
Merged
Merged
Conversation
The Defang MCP server downloads ask.defang.io/data/knowledge_base.json synchronously before answering initialize. At ~35 MB uncompressed, the download regularly exceeds client-side MCP connect timeouts (e.g. Claude Code's 30s), causing "Request timed out" failures. - get_knowledge_base.py now writes a .gz sibling alongside knowledge_base.json on every rebuild. - /data/<name> serves that sibling with Content-Encoding: gzip when the client sends Accept-Encoding: gzip, falling back to the uncompressed file otherwise (e.g. before the first rebuild has run). Fixes #147 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7NwVhzqJ1bAp9PhmERXBJ
CodeQL (github-advanced-security) flagged the new os.path.exists() check on PR 148: it joined the data directory with the user-controlled `name` path parameter directly, without the traversal guard that send_from_directory applies internally via safe_join. The check itself only influenced a branch (send_from_directory still blocks traversal before returning any content), but it's still an uncontrolled path expression and worth closing. safe_join returns None for a path that would escape data_dir, so the existence check is now skipped instead of probing outside the data directory. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7NwVhzqJ1bAp9PhmERXBJ
lionello
approved these changes
Oct 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
https://ask.defang.io/data/knowledge_base.jsonis served uncompressed at ~35 MB.defang mcp servedownloads it synchronously before answering the MCPinitializerequest, which regularly exceeds client-side MCP connect timeouts (e.g. Claude Code's 30s), so the Defang MCP server fails to connect.Fix
This implements suggestion 1 from the issue: serve the file gzip-compressed.
get_knowledge_base.pynow writes aknowledge_base.json.gzsibling next toknowledge_base.jsonon every rebuild (write_compressed_knowledge_base(), called at the end ofrecursive_parse_directory), so it's regenerated automatically whenever the knowledge base is rebuilt (manual run or/trigger-rebuild)./data/<name>inapp.pynow serves that.gzsibling withContent-Encoding: gzipand the correctContent-Type/Content-Dispositionwhen the request sendsAccept-Encoding: gzipand the sibling exists, falling back to the uncompressed file otherwise (e.g. right after a fresh deploy, before the first rebuild has produced a.gz). No CLI-side change is needed — Go'snet/httpclient already sendsAccept-Encoding: gzipand transparently decodes it..gzfiles underapp/data/are gitignored; the ~35 MB production knowledge base is generated at deploy/rebuild time, not committed (the committedknowledge_base.jsonis a small dev seed).Per the issue's own measurement, gzip gets ~4x smaller on this content, which should bring the download well under typical MCP connect timeouts.
Out of scope here (left for follow-up, possibly separate issues):
ETag) —send_from_directoryalready setsETag/Last-Modifiedlocally; the issue notesETagisn't visible in production responses, which points at something stripping it between the app and the client (proxy/CDN), not at the Flask app.Testing
ruff check/ruff format --checkpass on both changed Python files.test_get_knowledge_base.pyunit tests still pass.Content-Encoding: gzip+ correctContent-Type/Content-Disposition, decompresses to the exact original JSON, and that the no-Accept-Encodingpath is byte-identical to the previous behavior.Fixes #147
🤖 Generated with Claude Code