Skip to content

🐛 fix(mcp): 统一跨工具驱动值 JSON 序列化 - #162

Merged
ZhaoXingPeng merged 1 commit into
mainfrom
fix/161-shared-json-serialization
Sep 9, 2026
Merged

ZhaoXingPeng merged 1 commit into
mainfrom
fix/161-shared-json-serialization

Conversation

@ZhaoXingPeng

Copy link
Copy Markdown
Owner

关联 Issue

Closes #161

背景(Situation)

MCP 响应序列化规则分散在多个模块。查询结果已有 Decimal、日期时间、UUID、bytes/memoryview 的驱动值编码,但原子 codegen_build_context、代码生成渲染和部分数据库/项目 handler 仍直接调用 json.dumps。真实 MySQL/PostgreSQL metadata 嵌入模板上下文或响应时,非原生值会触发 TypeError,客户端得到不可解析的错误。

任务(Task)

建立无数据库依赖的共享 JSON 编码边界,统一驱动值规则并迁移 mcp_tools.py 与原子 codegen 的成功/错误响应;保持现有 ensure_ascii=False、缩进、字段和错误 envelope,不改变 SQL、事务、权限或 MCP 输入合同。

行动(Action)

  • 新增 src/dbjavagenix/utils/json_serialization.py,集中处理 Decimal 保精度字符串、date/datetime/time ISO 文本、UUID 字符串、bytes/bytearray/memoryview 的 base64 对象和 timedelta 稳定文本;未知对象继续抛 TypeError
  • mcp_tools.py_query_result_json_default 保留为兼容别名并委托共享 default;所有 Raw Response json.dumps 入口改用共享 dumps
  • atomic_codegen_tools.py 的 build context、render、错误响应统一使用共享 dumps,保留缩进和 JSON 字段结构。
  • 新增 utility 类型回归及原子 build context 嵌套驱动值回归;未修改数据库查询、模板内容、权限或依赖。

验证(Verification)

环境:Windows,Python 3.10.1、pytest 9.0.3、pytest-asyncio 1.3.0;项目声明 Python >=3.11。来源提交:5199d51,唯一实现提交。

$env:PYTHONPATH='src'; python -m pytest tests/unit/ -q
683 passed in 4.86s

$env:PYTHONPATH='src'; python -m pytest tests/integration/test_sqlite_mcp_query_contract.py tests/integration/test_sqlite_file_codegen_contract.py -q
3 passed in 3.45s

$env:PYTHONPATH='src'; python -m pytest tests/unit/test_json_serialization.py tests/unit/test_atomic_codegen_tools.py tests/unit/test_mcp_error_json.py -q
45 passed

python -m ruff check src/ tests/ scripts/
All checks passed!

python -m ruff format --check src/dbjavagenix/utils/json_serialization.py src/dbjavagenix/database/mcp_tools.py src/dbjavagenix/database/atomic_codegen_tools.py tests/unit/test_json_serialization.py
3 files already formatted

git diff --check
(no output)

实验与证据(Evidence)

  • 共享 utility 固定输入包含 Decimal 12.30、UTC datetime、date/time、UUID、bytes、bytearray、memoryview 和 timedelta;json.loads(dumps(...)) 结果保留精度、ISO 文本和 base64 身份。
  • 原子 codegen_build_context 的嵌套 context 使用 Decimal、datetime、UUID、memoryview mock 值,Raw Response 可被 json.loads 解析;原子 render 工具的 fileslanguagenote 字段保持可解析。
  • 既有 query execute 驱动值回归和错误 JSON 回归继续通过;未知对象拒绝测试确认不会静默丢失数据。
  • rg -n "json\\.dumps" 在受影响的 mcp_tools.pyatomic_codegen_tools.py 无直接调用;真实 MySQL/PostgreSQL 容器值类型未在本地宣称验证。

兼容性、风险与回滚

  • 兼容性:合法 JSON 基本类型输出、缩进、Raw Response 顶层字段、同步 API、SQL 和错误类型保持不变;mcp_tools._query_result_json_default 继续可供既有测试/调用方使用。
  • 风险:依赖旧序列化失败字符串的客户端现在会得到可解析成功 payload;未知对象仍失败以避免数据损失。跨模块 utility 若被未来工具误用,需继续保持输入边界和脱敏策略。
  • 回滚:恢复单一提交 5199d51,不涉及数据迁移或数据库 schema 变化。
  • 后续:合并前仅对最终 HEAD 检查一次 required checks;可在真实 MySQL/PostgreSQL 容器中补充代表性驱动值类型证据,再盘点 AI/Apps 模块是否有非基础类型输出。

@ZhaoXingPeng

Copy link
Copy Markdown
Owner Author

阶段回帖 1/2:实现完成(2026-09-09)

当前结论

提交 5199d51 将数据库驱动值 JSON 编码从 MCP 局部实现提升为共享 utility。mcp_tools.py 和原子 codegen 的成功/错误响应现在走同一入口,原子 codegen_build_context 不会因嵌套 Decimal、日期时间、UUID 或 memoryview 再次退化为序列化异常。

变更与设计取舍

  • Issue:🐛 fix(mcp): 统一跨工具驱动值 JSON 序列化 #161;PR:🐛 fix(mcp): 统一跨工具驱动值 JSON 序列化 #162;基线:origin/mainbfbf3af)。
  • utils/json_serialization.py 只依赖标准库,集中定义 Decimal -> 字符串、日期时间 -> ISO、UUID -> 字符串、二进制 -> base64 对象、timedelta -> 稳定文本;未知对象显式抛 TypeError
  • mcp_tools._query_result_json_default 保留兼容别名,避免现有测试和外部私有入口突然失效;其余 40 余处 Raw Response 改用共享 dumps
  • atomic_codegen_tools 的 context、render 及错误 payload 保留既有字段、缩进和 ensure_ascii=False 行为;没有引入第三方序列化库或修改数据库查询。

兼容性边界

  • 未改变 SQL、只读安全、事务、权限、模板内容、MCP tool 输入 schema、驱动版本或敏感信息脱敏策略。
  • 未把 Decimal 转 float、未把 bytes 猜测为文本;真实 MySQL/PostgreSQL 驱动线程和类型组合留给容器环境。
  • 下一条回帖记录固定类型输入、嵌套 context、全量 unit 和 SQLite 合同结果。

@ZhaoXingPeng

Copy link
Copy Markdown
Owner Author

阶段回帖 2/2:验证完成(2026-09-09)

当前结论

共享编码和原子上下文回归已在本地通过;完整 unit 与 SQLite 查询/代码生成合同没有回归。结果只证明受控 fixture 的 JSON 合同,不代表 CI 或真实 MySQL/PostgreSQL 服务器已验证。

环境、输入与原始结果

  • Windows;Python 3.10.1;pytest 9.0.3;pytest-asyncio 1.3.0;项目声明 Python >=3.11
  • 固定输入:Decimal 12.30、UTC datetime、date/time、UUID、bytes、bytearray、memoryview、timedelta;原子 context 通过 monkeypatch 模拟驱动 metadata。
$env:PYTHONPATH='src'; python -m pytest tests/unit/ -q
683 passed in 4.86s

$env:PYTHONPATH='src'; python -m pytest tests/integration/test_sqlite_mcp_query_contract.py tests/integration/test_sqlite_file_codegen_contract.py -q
3 passed in 3.45s

$env:PYTHONPATH='src'; python -m pytest tests/unit/test_json_serialization.py tests/unit/test_atomic_codegen_tools.py tests/unit/test_mcp_error_json.py -q
45 passed

python -m ruff check src/ tests/ scripts/
All checks passed!

python -m ruff format --check src/dbjavagenix/utils/json_serialization.py src/dbjavagenix/database/mcp_tools.py src/dbjavagenix/database/atomic_codegen_tools.py tests/unit/test_json_serialization.py
3 files already formatted

git diff --check
(no output)

验收映射

  • json.loads(dumps(payload)) 保留 Decimal 精度、ISO 时间、UUID 文本和 base64 encoding/data
  • codegen_build_context 的嵌套 context.columns[] 驱动值全部可解析;未知类型仍被拒绝。
  • query execute 既有驱动值回归、metadata/error JSON 测试、SQLite MCP/codegen 合同均通过。
  • mcp_tools.pyatomic_codegen_tools.py 不再直接调用 json.dumps;utility 是唯一驱动值 default 实现。

未执行与回滚

  • 未执行 CI、真实 MySQL/PostgreSQL 容器、性能基准和 Docker;无对应证据不写成通过。
  • 用户未跟踪 uv.lock 未纳入提交。
  • 回滚为恢复单一提交 5199d51;合并前按协作约定仅对最终 HEAD 检查一次 required checks。

@ZhaoXingPeng
ZhaoXingPeng force-pushed the fix/161-shared-json-serialization branch from 6ebb683 to 7356eb6 Compare September 9, 2026 02:12
@ZhaoXingPeng
ZhaoXingPeng merged commit f974dbf into main Sep 9, 2026
12 checks passed
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.

🐛 fix(mcp): 统一跨工具驱动值 JSON 序列化

1 participant