Add fastmcp-slim for client-only installs (#4122)

* Add fastmcp-client workspace package

* Fix client package static checks

* Document client-only package

* Harden fastmcp-client package split

* Preserve forwarded headers in full package

* Switch to fastmcp-slim package

* Fix fastmcp-slim release edges

* Match pydantic-style slim layout

* Polish fastmcp-slim packaging
This commit is contained in:
Jeremiah Lowin 2026-05-11 17:13:21 -04:00 committed by GitHub
commit bb4894d215
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
298 changed files with 1259 additions and 438 deletions

View file

@ -7,10 +7,10 @@ on:
push:
branches: ["main"]
paths:
- "src/**"
- "fastmcp_slim/**"
- "tests/**"
- "uv.lock"
- "pyproject.toml"
- "uv.lock"
- ".github/workflows/**"
# run on all pull requests because these checks are required and will block merges otherwise
@ -117,3 +117,102 @@ jobs:
FASTMCP_GITHUB_TOKEN: ${{ secrets.FASTMCP_GITHUB_TOKEN }}
FASTMCP_TEST_AUTH_GITHUB_CLIENT_ID: ${{ secrets.FASTMCP_TEST_AUTH_GITHUB_CLIENT_ID }}
FASTMCP_TEST_AUTH_GITHUB_CLIENT_SECRET: ${{ secrets.FASTMCP_TEST_AUTH_GITHUB_CLIENT_SECRET }}
package_install_smoke:
name: "Package install smoke"
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- name: Setup uv
uses: ./.github/actions/setup-uv
with:
resolution: locked
- name: Build package wheels
run: uv build --all-packages --wheel --out-dir /tmp/fastmcp-dist
- name: Install bare slim wheel
run: |
uv venv /tmp/fastmcp-slim-bare-smoke
SLIM_WHEEL=$(ls /tmp/fastmcp-dist/fastmcp_slim-*.whl)
uv pip install --python /tmp/fastmcp-slim-bare-smoke/bin/python "$SLIM_WHEEL"
/tmp/fastmcp-slim-bare-smoke/bin/python - <<'PY'
from importlib.metadata import entry_points
import fastmcp
import fastmcp.settings
assert not any(ep.name == "fastmcp" for ep in entry_points(group="console_scripts"))
try:
fastmcp.FastMCP
except ImportError as exc:
assert "fastmcp-slim[server]" in str(exc)
else:
raise AssertionError("bare fastmcp-slim unexpectedly imported FastMCP")
PY
- name: Install client slim wheel
run: |
uv venv /tmp/fastmcp-slim-client-smoke
SLIM_WHEEL=$(ls /tmp/fastmcp-dist/fastmcp_slim-*.whl)
uv pip install --python /tmp/fastmcp-slim-client-smoke/bin/python "${SLIM_WHEEL}[client]"
/tmp/fastmcp-slim-client-smoke/bin/python - <<'PY'
from importlib.metadata import entry_points
from fastmcp import Client
from fastmcp.client.transports import StdioTransport, StreamableHttpTransport
from fastmcp.mcp_config import MCPConfig
assert not any(ep.name == "fastmcp" for ep in entry_points(group="console_scripts"))
assert Client("https://example.com/mcp")
assert StreamableHttpTransport("https://example.com/mcp")
assert StdioTransport(command="uvx", args=["demo"])
assert MCPConfig.from_dict({"mcpServers": {"demo": {"url": "https://example.com/mcp"}}})
try:
from fastmcp import FastMCP
except ImportError as exc:
assert "fastmcp-slim[server]" in str(exc)
else:
raise AssertionError(f"client-only slim unexpectedly imported {FastMCP!r}")
PY
- name: Install server slim wheel
run: |
uv venv /tmp/fastmcp-slim-server-smoke
SLIM_WHEEL=$(ls /tmp/fastmcp-dist/fastmcp_slim-*.whl)
uv pip install --python /tmp/fastmcp-slim-server-smoke/bin/python "${SLIM_WHEEL}[server]"
/tmp/fastmcp-slim-server-smoke/bin/python - <<'PY'
from fastmcp import FastMCP
mcp = FastMCP("smoke")
assert mcp.name == "smoke"
PY
- name: Install full package from matching local wheels
run: |
uv venv /tmp/fastmcp-full-smoke
FULL_WHEEL=$(ls /tmp/fastmcp-dist/fastmcp-*.whl)
uv pip install --python /tmp/fastmcp-full-smoke/bin/python --find-links /tmp/fastmcp-dist "$FULL_WHEEL"
/tmp/fastmcp-full-smoke/bin/python - <<'PY'
from importlib.metadata import entry_points
from fastmcp import Client, FastMCP
from fastmcp.client.client import CallToolResult
from fastmcp.exceptions import ToolError
assert any(
ep.name == "fastmcp" and ep.value == "fastmcp.cli:app"
for ep in entry_points(group="console_scripts")
)
assert Client("https://example.com/mcp")
assert FastMCP("smoke").name == "smoke"
assert CallToolResult is not None
assert ToolError is not None
PY