PrefectHQ/fastmcp · error · RuntimeError

app-bridge.js not found in ext-apps tarball

Error message

app-bridge.js not found in ext-apps tarball

What it means

The dev tooling downloads the @modelcontextprotocol/ext-apps npm tarball and extracts package/dist/src/app-bridge.js from it. tar.extractfile returns None when the member path doesn't exist, which is converted into this RuntimeError. It means the tarball layout changed (path moved/renamed) or the wrong/empty tarball was downloaded.

Source

Thrown at fastmcp_slim/fastmcp/cli/apps_dev.py:1355

    # -- Download and patch app-bridge.js (cached per ext-apps + SDK version) -
    app_bridge_cache = (
        Path(tempfile.gettempdir()) / f"fastmcp-ext-apps-{version}-sdk-{sdk_version}.js"
    )
    if app_bridge_cache.exists():
        app_bridge_js = app_bridge_cache.read_text(encoding="utf-8")
        return app_bridge_js, import_map_json

    npm_url = f"https://registry.npmjs.org/@modelcontextprotocol/ext-apps/-/ext-apps-{version}.tgz"
    with httpx2.Client(timeout=30.0) as client:
        resp = client.get(npm_url, follow_redirects=True)
        resp.raise_for_status()
        data = resp.content

    with tarfile.open(fileobj=io.BytesIO(data), mode="r:gz") as tar:
        member = tar.extractfile("package/dist/src/app-bridge.js")
        if member is None:
            raise RuntimeError("app-bridge.js not found in ext-apps tarball")
        app_bridge_js = member.read().decode()

    # Rewrite bare SDK module specifiers to concrete esm.sh URLs
    for sdk_path in ("types.js", "shared/protocol.js"):
        app_bridge_js = app_bridge_js.replace(
            f'from"@modelcontextprotocol/sdk/{sdk_path}"',
            f'from"{sdk_base}/{sdk_path}"',
        )

    app_bridge_cache.write_text(app_bridge_js, encoding="utf-8")
    return app_bridge_js, import_map_json


async def _fetch_app_bridge_bundle(
    version: str,
    sdk_version: str,
) -> tuple[str, str]:
    """Async wrapper around _fetch_app_bridge_bundle_sync."""

View on GitHub (pinned to 1f02114297)

Solutions

  1. Check the ext-apps version being fetched; pin to a known-good version with app-bridge.js at package/dist/src/
  2. List the tarball members to find the new path and update the extractfile path in apps_dev.py
  3. Verify the downloaded bytes are a valid gzip tarball (tar -tzf) — fix registry/proxy issues if not
  4. Retry after clearing any package cache
Defensive patterns

Strategy: validation

Validate before calling

import io, tarfile
with tarfile.open(fileobj=io.BytesIO(data), mode='r:gz') as tar:
    names = tar.getnames()
    assert 'package/dist/src/app-bridge.js' in names, names[:20]

Try / catch

try:
    bundle = _fetch_app_bridge_bundle_sync(...)
except RuntimeError as exc:
    if 'app-bridge.js not found' in str(exc):
        logger.warning('ext-apps tarball layout changed; pin a known-good version')
    else:
        raise

Prevention

When it happens

Trigger: ext-apps published a new version where app-bridge.js lives at a different path (no dist/src/ layout), or the fetched artifact isn't the expected gzipped package tarball.

Common situations: Unpinned ext-apps version pulling a restructured release; npm registry/proxy returning a 404 page saved as a tarball; offline caches serving stale artifacts.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/e454eedcb048b2dc. Report an issue: GitHub.