|
| 1 | +## 2.0.0-keycardai-mcp (2026-08-07) |
| 2 | + |
| 3 | + |
| 4 | +- feat(keycardai-mcp)!: port to mcp 2.0 (ECO-195) (#218) |
| 5 | +- * feat(keycardai-mcp)!: port to mcp 2.0 |
| 6 | +- mcp 2.0 removed the bundled FastMCP 1.x (mcp.server.fastmcp). Its |
| 7 | +successor in-package is mcp.server.mcpserver.MCPServer, which exposes |
| 8 | +the same two APIs AuthProvider.app() uses (session_manager and |
| 9 | +streamable_http_app), so the retarget is direct. |
| 10 | +- Import moves: |
| 11 | + mcp.server.fastmcp.{Context,FastMCP} -> mcp.server.mcpserver.{Context,MCPServer} |
| 12 | + mcp.shared.context.RequestContext -> mcp.server.context.ServerRequestContext |
| 13 | + streamablehttp_client -> streamable_http_client |
| 14 | +- mcp 2.0 also renamed model fields to snake_case. Constructors still |
| 15 | +accept the camelCase aliases, so only attribute reads broke: |
| 16 | +result.nextCursor and mcp_tool.inputSchema. The agent integrations |
| 17 | +guarded theirs with hasattr(), which under 2.0 returns False and |
| 18 | +silently yields an empty tool schema rather than raising, so those are |
| 19 | +corrected too. |
| 20 | +- Breaking: AuthProvider.app() is typed MCPServer instead of FastMCP. |
| 21 | +Consumers needing mcp 1.x pin the prior keycardai-mcp minor. |
| 22 | +- keycardai-fastmcp is untouched and unaffected. It only imports |
| 23 | +credential types, ClientFactory and exceptions from this package, and |
| 24 | +it stays on fastmcp 3.x / mcp 1.x until fastmcp 4.0 is stable. |
| 25 | +- Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
| 26 | +- * build: split the fastmcp packages out of the uv workspace for mcp 2.0 |
| 27 | +- packages/mcp now requires mcp>=2.0. fastmcp 3.x, openai-agents and crewai |
| 28 | +all still pin mcp<2.0, and a uv workspace resolves to a single lock, so |
| 29 | +they cannot co-resolve. |
| 30 | +- Workspace: packages/fastmcp and packages/mcp-fastmcp move to |
| 31 | +workspace.exclude and carry their own resolution. They pick up |
| 32 | +keycardai-mcp from the index (0.26.0, mcp 1.x) rather than the local |
| 33 | +path, which is the honest arrangement while the two sit on different |
| 34 | +mcp majors. |
| 35 | +- packages/mcp test extra: drops fastmcp, keycardai-mcp-fastmcp, |
| 36 | +openai-agents and crewai. The suites that need them are guarded by |
| 37 | +pytest.importorskip and report SKIPPED, so the gap shows in test output |
| 38 | +instead of disappearing. test_agent_integrations.py gained a guard; it |
| 39 | +was importing agents at module scope and failing collection. |
| 40 | +- Release tooling: scripts/changelog.py enumerated packages from |
| 41 | +workspace.members, so both excluded packages would have silently dropped |
| 42 | +out of version bumps and changelogs. Added tool.keycardai.release |
| 43 | +standalone-members, which it now unions in. Verified all 7 packages are |
| 44 | +still discovered. |
| 45 | +- packages/fastmcp gains real CI coverage for the first time (ECO-172): it |
| 46 | +is added to the justfile test and coverage targets, and its test extra |
| 47 | +was missing pytest-cov and requests, which it had been getting |
| 48 | +incidentally from the shared workspace environment. |
| 49 | +- Coverage gates all pass: oauth 84.38%, starlette 79.57%, mcp 62.60%, |
| 50 | +fastmcp 85.01%, mcp-fastmcp 100%, a2a 45 tests. |
| 51 | +- Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
| 52 | +- * build: drop the mcp<2.0-pinned agent frameworks from packages/mcp |
| 53 | +- Socket blocked the previous commit, correctly. Removing openai-agents |
| 54 | +and crewai was not enough: pydantic-ai also pins mcp<2.0, transitively |
| 55 | +via fastmcp-slim[client]<4. Left in place, the resolver backtracked |
| 56 | +pydantic-ai 2.x -> 1.44.0 to satisfy mcp>=2.0, and 1.44.0 pulled |
| 57 | +fastmcp 2.14.1, which carries the known fastmcp advisory (Socket |
| 58 | +vulnerability score 25). |
| 59 | +- Removed from packages/mcp: |
| 60 | + - test extra: pydantic-ai (alongside openai-agents and crewai) |
| 61 | + - optional-dependencies: the crewai and pydantic-ai convenience extras |
| 62 | +- The extras go because pip install keycardai-mcp[crewai] cannot resolve |
| 63 | +against mcp>=2.0 regardless. The integration modules still ship; bring |
| 64 | +your own framework install on a pre-2.0 keycardai-mcp. |
| 65 | +- Root lock no longer contains fastmcp, pydantic-ai, crewai or |
| 66 | +openai-agents at any version, and resolves mcp 2.0.0. |
| 67 | +- Coverage note, so the number is not misread: packages/mcp reports 75.10% |
| 68 | +here against 62.60% before. That is not an improvement. The four |
| 69 | +*_agents.py integration modules are no longer imported, so coverage.py |
| 70 | +drops them from the report and the denominator shrinks from ~2500 to |
| 71 | +2036 statements. The same code is untested; less of it is now measured. |
| 72 | +- Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
| 73 | +- * fix: address review on the mcp 2.0 split |
| 74 | +- Release blocker. release.yml ran `uv build --package <name>`, which |
| 75 | +resolves against workspace.members -- exactly what the split removed the |
| 76 | +two fastmcp packages from. Verified: `uv build --package |
| 77 | +keycardai-fastmcp` errors with "not found in workspace", same for |
| 78 | +keycardai-mcp-fastmcp. changelog.py being correct made this worse, not |
| 79 | +better: tags get cut and changelogs written, then publish dies. Now |
| 80 | +builds by path using the package-dir output detect-package already |
| 81 | +emits. Verified for both excluded packages and two workspace members. |
| 82 | +- Resolution trap. packages/fastmcp declared keycardai-mcp>=0.15.0 |
| 83 | +unbounded alongside fastmcp>=3.1.0 (mcp<2.0). Since keycardai-mcp 0.27+ |
| 84 | +needs mcp>=2.0, the pair is unsatisfiable, so pip silently backtracked |
| 85 | +keycardai-mcp to 0.26.0 and froze there. Capped <0.27 so the conflict is |
| 86 | +explicit. |
| 87 | +- mcp>=2.0.0 was unbounded, reproducing this exact incident on mcp 3.0. |
| 88 | +Capped <3.0. |
| 89 | +- Sibling isolation. The standalone locks took every keycardai-* package |
| 90 | +from the index, so a breaking change in packages/oauth no longer failed |
| 91 | +packages/fastmcp. keycardai-oauth is now path-linked in both, and |
| 92 | +keycardai-fastmcp is path-linked into the bridge (same mcp<2.0 major). |
| 93 | +Only keycardai-mcp stays on the index, where the major genuinely |
| 94 | +differs. keycardai-starlette also stays: it is transitive via |
| 95 | +keycardai-mcp and tool.uv.sources only redirects direct dependencies. |
| 96 | +- The input_schema fix was unverified. The existing pydantic test sets |
| 97 | +inputSchema on a MagicMock, where hasattr is unconditionally True, so it |
| 98 | +cannot tell the two spellings apart. Added |
| 99 | +test_tool_schema_reads.py, which drives the real |
| 100 | +_convert_mcp_tool_to_langchain with a real mcp.types.Tool and asserts |
| 101 | +the generated args_schema carries the field. Confirmed it fails when the |
| 102 | +camelCase read is restored. |
| 103 | +- tests/conftest.py imported dotenv unguarded. It is a crewai-only shim |
| 104 | +and crewai is no longer installable here, so the single-package flow |
| 105 | +errored at collection. Guarded. |
| 106 | +- Coverage gate stays 60, but the denominator it measures grew to 2679 |
| 107 | +statements against ~2500 before, because the new test imports the |
| 108 | +integration modules and pulls all four back into measurement. Removing |
| 109 | +the frameworks alone had shrunk it to 2036 and inflated the figure to |
| 110 | +~75% on less code. The reviewer's suggested 72 was correct for that |
| 111 | +2036 state and no longer applies. Headroom is thin at 60.88%. |
| 112 | +- Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
| 113 | +- * fix(keycardai-fastmcp): target the 0.27.x line, not below it |
| 114 | +- Rebased onto main now that #219 shipped the mcp<2.0 cap as keycardai-mcp |
| 115 | +0.27.0. |
| 116 | +- That version number invalidates the cap this branch carried. |
| 117 | +packages/fastmcp pinned "keycardai-mcp>=0.15.0,<0.27" on the assumption |
| 118 | +that 0.27 would be the mcp 2.0 port. It is not: 0.27.0 is the cap |
| 119 | +release, and it is the only published version that constrains mcp |
| 120 | +correctly. |
| 121 | +- keycardai-mcp 0.26.0 mcp>=1.13.1 unbounded -> resolves mcp 2.0 |
| 122 | + keycardai-mcp 0.27.0 mcp>=1.28.1,<2.0 safe |
| 123 | +- So "<0.27" excluded the one good version and forced the broken one. |
| 124 | +Now ">=0.27,<0.28": the floor guarantees the mcp cap is present, the |
| 125 | +ceiling excludes the 2.0 line this branch starts. Both standalone locks |
| 126 | +verified resolving keycardai-mcp 0.27.0 with mcp 1.29.0. |
| 127 | +- Also resolved the pyproject conflict against main's cap by keeping this |
| 128 | +branch's mcp>=2.0.0,<3.0, and regenerated all three lockfiles from the |
| 129 | +merged manifests rather than hand-merging them. |
| 130 | +- Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
| 131 | +- * fix(keycardai-fastmcp): pair with the keycardai-mcp 1.x line |
| 132 | +- keycardai-mcp 1.0.0 is on PyPI and release/mcp-v1 exists, so the |
| 133 | +fastmcp cap moves from the interim 0.27.x window to >=1,<2. Both |
| 134 | +standalone locks re-resolved to 1.0.0. |
| 135 | +- Also flips packages/mcp's major_version_zero to false. The package is |
| 136 | +past 1.0.0 and the flag caps breaking changes at minor: left true, this |
| 137 | +PR's feat! merge would release the mcp 2.0 port as keycardai-mcp 1.1.0, |
| 138 | +which is exactly what happened in typescript-sdk's cutover before the |
| 139 | +same fix there. |
| 140 | +- Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
| 141 | +- --------- |
| 142 | +- Co-authored-by: GitHub Action <action@github.com> |
| 143 | +Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
| 144 | + |
1 | 145 | ## 1.0.0-keycardai-mcp (2026-08-06) |
2 | 146 |
|
3 | 147 | ## 0.27.1-keycardai-mcp (2026-07-30) |
|
0 commit comments