Skip to content

🐛 fix(mcp): 统一元数据响应 JSON 序列化 - #158

Merged
ZhaoXingPeng merged 1 commit into
mainfrom
fix/157-metadata-response-json
Sep 9, 2026
Merged

ZhaoXingPeng merged 1 commit into
mainfrom
fix/157-metadata-response-json

Conversation

@ZhaoXingPeng

@ZhaoXingPeng ZhaoXingPeng commented Sep 8, 2026

Copy link
Copy Markdown
Owner

关联 Issue

Closes #157

本 PR 统一元数据和代码生成成功响应的 JSON 序列化,避免驱动值导致 MCP 返回 generic error。

背景(Situation)

元数据 handler 仍有多条裸 json.dumps 路径。MySQL/PostgreSQL 驱动可能返回 Decimal、date/datetime、UUID、bytes 或 memoryview,使 describe、columns、primary keys、foreign keys、indexes 和 codegen analyze 的 Raw Response 序列化失败。

任务(Task)

复用查询工具已有的值编码合同,在不改变 SQL、元数据字段、文本摘要、错误类型或同步 API 的前提下,保留 Decimal 精度与二进制身份,并补齐可复现回归测试。

行动(Action)

  • 集中使用 _json_dumps 与驱动值 default:Decimal 字符串、日期时间 ISO、UUID 字符串、二进制 base64 对象、timedelta 稳定文本。
  • 将受影响的元数据和 codegen analyze 成功响应接入共享入口。
  • 增加 Decimal、datetime、UUID、memoryview 和未知对象回归。
  • 没有做:未改变 SQL、分页、安全规则、事务、权限、metadata schema 或驱动版本。

验证(Verification)

环境:Windows;Python 3.10.1;pytest 9.0.3;pytest-asyncio 1.3.0。

  • 单元测试:682 passed in 5.29s。
  • SQLite MCP 查询与文件 codegen 合同:3 passed in 3.42s。
  • MCP error JSON 回归:9 passed。
  • Ruff check:All checks passed;修改文件格式检查通过;git diff --check 无输出。

实验与证据(Evidence)

固定 PostgreSQL mock 元数据注入 Decimal 12.30、UTC datetime、UUID 和 memoryview。五类 metadata handler 的 Raw Response 均可 json.loads;memoryview 编码为 encoding=base64 对象;codegen analyze 的嵌套 Decimal 也可编码。未知对象继续进入显式 TypeError。无真实 MySQL/PostgreSQL 驱动值结论。

兼容性、风险与回滚

公共工具名、输入 schema、响应字段和人类可读文本保持不变;合法 JSON 基本类型输出不变。依赖旧序列化失败字符串的客户端会收到可解析成功 payload,这是预期修复;未知对象仍失败。恢复提交 52a1eca 可回滚,不涉及数据迁移;后续在容器中补充 MySQL/PostgreSQL 驱动值类型证据。

@ZhaoXingPeng

Copy link
Copy Markdown
Owner Author

阶段回帖 1/2:实现完成

来源与问题复现

实现证据

  • mcp_tools.py#L60-L80

    • 新增 _json_dumps,统一委托既有 _query_result_json_default
    • 保留 Decimal 字符串精度、日期时间稳定文本、UUID 字符串和二进制 base64 对象编码。
    • 未知对象仍抛明确 TypeError,没有静默丢弃。
  • mcp_tools.py#L1159-L1790

    • db_table_describedb_table_columnsdb_table_primary_keysdb_table_foreign_keysdb_table_indexes 的成功 Raw Response 全部改用统一入口。
    • 既有文本摘要、字段名、空结果行为和错误分支未改动;primary/foreign/index 的结构化字段仍保持原类型。
  • mcp_tools.py#L1037-L1084

    • db_query_execute 复用同一入口,确认查询结果的既有编码规则没有第二份实现。
  • mcp_tools.py#L1943-L2060

    • db_codegen_analyze 的嵌套 table_info / template payload 也经过统一编码,避免 metadata 已成功但 codegen Raw Response 再次失败。
  • test_mcp_error_json.py#L144-L286

    • 新增 PostgreSQL mock 元数据回归,依次调用五个 metadata handler。
    • 新增 codegen analyze 回归,验证嵌套 Decimal 不会破坏 Raw Response。
    • 输入包含 Decimal、UTC datetime、UUID、memoryview;断言 JSON 可解析且二进制有明确 encoding/data 标记。

兼容性边界

本 PR 只改变序列化入口,不改变 SQL、分页、安全规则、事务、权限、metadata 字段语义、同步 API 或 Raw Response 顶层字段。合法 JSON 基本类型的输出保持一致;没有真实 MySQL/PostgreSQL 吞吐或生产值类型的未经证实声明。

@ZhaoXingPeng

Copy link
Copy Markdown
Owner Author

阶段回帖 2/2:验证完成

环境与固定输入

  • Windows,Python 3.10.1,pytest 9.0.3,pytest-asyncio 1.3.0;项目声明 Python >=3.11。
  • PostgreSQL mock metadata:表 events,一列 amount,输入 Decimal(12.30)、UTC datetime、UUID、memoryview。
  • SQLite 文件/查询 fixture 沿用仓库现有集成合同。
  • 代码提交:52a1eca;用户未跟踪文件 uv.lock 未纳入提交。

命令与原始结果

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

$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.42s

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

ruff check src/dbjavagenix/database/mcp_tools.py tests/unit/test_mcp_error_json.py
All checks passed!

ruff format --check tests/unit/test_mcp_error_json.py
1 file already formatted

git diff --check
(no output)

验收结果

  • metadata describe:Raw Response 可解析;Decimal 保留为 "12.30",datetime 为 2026-09-08T10:00:00+00:00,UUID 为字符串。
  • metadata columns:memoryview 为一个带 encoding=base64、data=dmlldw== 的对象。
  • primary keys、foreign keys、indexes:原有字段和值仍可解析,摘要文本保持通过。
  • codegen analyze:嵌套 table_info.columns[].default_value 的 Decimal 可编码。
  • query execute:既有 Decimal/date/time/UUID/bytes/bytearray/memoryview/timedelta 回归仍通过。
  • unknown object:编码器继续抛 TypeError,避免静默数据损失。
  • SQLite MCP 查询和文件 codegen 合同未回归。

未执行与风险

  • 没有真实 MySQL/PostgreSQL 容器值类型结果,因此不宣称生产驱动已验证。
  • 未查询 CI;按协作规范,只有准备 squash merge 前才检查最终 HEAD 的 required checks。
  • 全仓库 Ruff format 会触及历史 legacy 文件,本 PR 仅检查本次改动文件,避免无关格式化提交。

@ZhaoXingPeng
ZhaoXingPeng merged commit 16e17e5 into main Sep 9, 2026
23 of 36 checks passed
@ZhaoXingPeng
ZhaoXingPeng deleted the fix/157-metadata-response-json branch September 9, 2026 01:51
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