Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,11 @@ jobs:
run: uv sync --all-extras --all-packages

- name: Build package
# Build by path, not --package: `uv build --package` resolves against
# workspace.members, and packages/fastmcp + packages/mcp-fastmcp are
# deliberately excluded from the workspace (see ECO-198).
run: |
uv build --package ${{ needs.detect-package.outputs.package }}
uv build --out-dir dist "${{ needs.detect-package.outputs.package-dir }}"

- name: Publish to PyPI
run: |
Expand Down
17 changes: 13 additions & 4 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@ dev-setup:
uv run pre-commit install
uv sync --all-extras --all-packages

# Build the project
# Build the project. packages/fastmcp and packages/mcp-fastmcp sit outside the
# uv workspace (they hold mcp<2.0; see ECO-198), so they sync separately.
build:
uv sync --all-packages
cd packages/fastmcp && uv sync --extra test
cd packages/mcp-fastmcp && uv sync --extra test

# Run tests for all packages
test: build
just test-package oauth
just test-package starlette
just test-package mcp
just test-package fastmcp
just test-package mcp-fastmcp
just test-package a2a

Expand All @@ -23,13 +27,18 @@ test-package PACKAGE:
test-file PACKAGE FILE:
cd packages/{{PACKAGE}} && uv run --extra test pytest tests/{{FILE}} -v

# Run tests with coverage enforcement. mcp sits at 60% because well-tested server
# primitives moved to oauth/starlette, leaving the under-tested client integrations
# (CrewAI, LangChain, OpenAI) as the dominant share of what remains.
# Run tests with coverage enforcement. mcp stays at 60%, but the denominator it
# measures grew: 2679 statements against ~2500 before, because all four
# *_agents.py client integrations are now imported by
# tests/.../test_tool_schema_reads.py and so are counted. Dropping the agent
# frameworks alone would have shrunk it to 2036 and inflated the percentage to
# ~75 on less measured code; that test is what keeps the gate honest. Headroom
# is thin (60.88% actual) -- if it dips, add coverage rather than lowering this.
test-coverage: build
cd packages/oauth && uv run --extra test pytest tests/ -v --cov=src --cov-report=term-missing --cov-fail-under=70
cd packages/starlette && uv run --extra test pytest tests/ -v --cov=src --cov-report=term-missing --cov-fail-under=55
cd packages/mcp && uv run --extra test pytest tests/ -v --cov=src --cov-report=term-missing --cov-fail-under=60
cd packages/fastmcp && uv run --extra test pytest tests/ -v --cov=src --cov-report=term-missing --cov-fail-under=60
cd packages/mcp-fastmcp && uv run --extra test pytest tests/ -v --cov=src --cov-report=term-missing --cov-fail-under=70
cd packages/a2a && uv run --extra test pytest tests/ -v --cov=src --cov-report=term-missing --cov-fail-under=55

Expand Down
17 changes: 16 additions & 1 deletion packages/fastmcp/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ dependencies = [
"httpx>=0.27.2",
"keycardai-oauth>=0.7.0",
"fastmcp>=3.1.0",
"keycardai-mcp>=0.15.0",
# Pinned to the 1.x line, both ends load-bearing. fastmcp 3.x pins
# mcp<2.0, and keycardai-mcp 1.x is the release line that agrees (2.x
# requires mcp>=2.0). 0.x releases before 0.27 declare an unbounded mcp
# floor and resolve onto mcp 2.0, which fails to import. Move both ends
# together with the fastmcp 4.x bump (ECO-198).
"keycardai-mcp>=1,<2",
]
keywords = ["fastmcp", "mcp", "model-context-protocol", "oauth", "token-exchange", "authentication", "keycard"]
classifiers = [
Expand All @@ -35,6 +40,8 @@ classifiers = [
test = [
"pytest>=8.4.1",
"pytest-asyncio>=1.1.0",
"pytest-cov>=6.2.1",
"requests>=2.32.0",
]

[project.urls]
Expand All @@ -43,6 +50,14 @@ Repository = "https://github.com/keycardai/python-sdk"
Documentation = "https://docs.keycardai.com"
Issues = "https://github.com/keycardai/python-sdk/issues"

[tool.uv.sources]
# Only keycardai-mcp comes from the index: it is on mcp>=2.0 and this package is
# on mcp<2.0, so the local copy is genuinely unusable here. Everything else is
# path-linked so a breaking change in a sibling still fails this package's CI.
keycardai-oauth = { path = "../oauth", editable = true }
# keycardai-starlette stays on the index: it is a transitive dependency via
# keycardai-mcp, and tool.uv.sources only redirects direct dependencies.

[build-system]
requires = ["hatchling", "uv-dynamic-versioning"]
build-backend = "hatchling.build"
Expand Down
2,855 changes: 2,855 additions & 0 deletions packages/fastmcp/uv.lock

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions packages/mcp-fastmcp/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ Repository = "https://github.com/keycardai/python-sdk"
Documentation = "https://docs.keycardai.com"
Issues = "https://github.com/keycardai/python-sdk/issues"

[tool.uv.sources]
# keycardai-fastmcp is path-linked: it sits on the same mcp<2.0 major as this
# bridge, so testing against the local copy is both possible and correct.
keycardai-fastmcp = { path = "../fastmcp", editable = true }
keycardai-oauth = { path = "../oauth", editable = true }
# keycardai-starlette stays on the index: it is a transitive dependency via
# keycardai-mcp, and tool.uv.sources only redirects direct dependencies.

[build-system]
requires = ["hatchling", "uv-dynamic-versioning"]
build-backend = "hatchling.build"
Expand Down
Loading
Loading