Skip to content

Serve knowledge_base.json gzip-compressed to fix MCP connect timeouts - #148

Merged
lionello merged 2 commits into
mainfrom
fix/147-compress-knowledge-base
Oct 8, 2026
Merged

lionello merged 2 commits into
mainfrom
fix/147-compress-knowledge-base

Conversation

@defangdevs

Copy link
Copy Markdown
Contributor

Problem

https://ask.defang.io/data/knowledge_base.json is served uncompressed at ~35 MB. defang mcp serve downloads it synchronously before answering the MCP initialize request, 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.py now writes a knowledge_base.json.gz sibling next to knowledge_base.json on every rebuild (write_compressed_knowledge_base(), called at the end of recursive_parse_directory), so it's regenerated automatically whenever the knowledge base is rebuilt (manual run or /trigger-rebuild).
  • /data/<name> in app.py now serves that .gz sibling with Content-Encoding: gzip and the correct Content-Type/Content-Disposition when the request sends Accept-Encoding: gzip and 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's net/http client already sends Accept-Encoding: gzip and transparently decodes it.
  • .gz files under app/data/ are gitignored; the ~35 MB production knowledge base is generated at deploy/rebuild time, not committed (the committed knowledge_base.json is 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):

  • Suggestion 2 (conditional requests / ETag) — send_from_directory already sets ETag/Last-Modified locally; the issue notes ETag isn't visible in production responses, which points at something stripping it between the app and the client (proxy/CDN), not at the Flask app.
  • Suggestions 3-4 (CLI-side background fetch, shrinking the file itself) are bigger changes in a different repo (DefangLabs/defang) or touch content generation, respectively.

Testing

  • ruff check / ruff format --check pass on both changed Python files.
  • Existing test_get_knowledge_base.py unit tests still pass.
  • Verified the new route logic end-to-end with a standalone Flask test-client script (not committed, this repo has no Flask route test harness): confirmed the gzip path returns Content-Encoding: gzip + correct Content-Type/Content-Disposition, decompresses to the exact original JSON, and that the no-Accept-Encoding path is byte-identical to the previous behavior.

Fixes #147

🤖 Generated with Claude Code

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
@defangdevs defangdevs self-assigned this Oct 8, 2026
Comment thread app/app.py Fixed
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
lionello merged commit 5e0faa8 into main Oct 8, 2026
6 checks passed
@lionello
lionello deleted the fix/147-compress-knowledge-base branch October 8, 2026 08:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

knowledge_base.json is served uncompressed (~35 MB), causing defang MCP server connect timeouts

3 participants