nene2-python 1.8.25__tar.gz → 1.8.26__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. {nene2_python-1.8.25 → nene2_python-1.8.26}/CHANGELOG.md +11 -0
  2. {nene2_python-1.8.25 → nene2_python-1.8.26}/PKG-INFO +1 -1
  3. nene2_python-1.8.26/docs/field-trials/2026-05-field-trial-80.md +176 -0
  4. {nene2_python-1.8.25 → nene2_python-1.8.26}/pyproject.toml +1 -1
  5. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/mcp/server.py +16 -0
  6. nene2_python-1.8.26/tests/nene2/mcp/test_server.py +51 -0
  7. {nene2_python-1.8.25 → nene2_python-1.8.26}/uv.lock +1 -1
  8. {nene2_python-1.8.25 → nene2_python-1.8.26}/.env.example +0 -0
  9. {nene2_python-1.8.25 → nene2_python-1.8.26}/.github/workflows/ci.yml +0 -0
  10. {nene2_python-1.8.25 → nene2_python-1.8.26}/.github/workflows/docs.yml +0 -0
  11. {nene2_python-1.8.25 → nene2_python-1.8.26}/.github/workflows/publish.yml +0 -0
  12. {nene2_python-1.8.25 → nene2_python-1.8.26}/.gitignore +0 -0
  13. {nene2_python-1.8.25 → nene2_python-1.8.26}/.vitepress/config.mts +0 -0
  14. {nene2_python-1.8.25 → nene2_python-1.8.26}/.vitepress/theme/custom.css +0 -0
  15. {nene2_python-1.8.25 → nene2_python-1.8.26}/.vitepress/theme/index.ts +0 -0
  16. {nene2_python-1.8.25 → nene2_python-1.8.26}/AGENTS.md +0 -0
  17. {nene2_python-1.8.25 → nene2_python-1.8.26}/CLAUDE.md +0 -0
  18. {nene2_python-1.8.25 → nene2_python-1.8.26}/Dockerfile +0 -0
  19. {nene2_python-1.8.25 → nene2_python-1.8.26}/LICENSE +0 -0
  20. {nene2_python-1.8.25 → nene2_python-1.8.26}/README.md +0 -0
  21. {nene2_python-1.8.25 → nene2_python-1.8.26}/alembic/README +0 -0
  22. {nene2_python-1.8.25 → nene2_python-1.8.26}/alembic/env.py +0 -0
  23. {nene2_python-1.8.25 → nene2_python-1.8.26}/alembic/script.py.mako +0 -0
  24. {nene2_python-1.8.25 → nene2_python-1.8.26}/alembic/versions/001_create_notes_and_tags_tables.py +0 -0
  25. {nene2_python-1.8.25 → nene2_python-1.8.26}/alembic.ini +0 -0
  26. {nene2_python-1.8.25 → nene2_python-1.8.26}/compose.yaml +0 -0
  27. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/adr/0001-toolchain.md +0 -0
  28. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/adr/0002-clean-architecture.md +0 -0
  29. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/adr/0003-security-first.md +0 -0
  30. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/adr/0004-ai-first-design.md +0 -0
  31. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/adr/0005-logging.md +0 -0
  32. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/adr/0006-rate-limiting.md +0 -0
  33. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/adr/0009-mcp-design.md +0 -0
  34. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/adr/0010-async-use-case.md +0 -0
  35. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/adr/0011-mcp-as-core-dependency.md +0 -0
  36. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/de/index.md +0 -0
  37. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/de/tutorials/getting-started.md +0 -0
  38. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/explanation/architecture.md +0 -0
  39. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/explanation/design-philosophy.md +0 -0
  40. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-1.md +0 -0
  41. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-10.md +0 -0
  42. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-11.md +0 -0
  43. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-12.md +0 -0
  44. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-13.md +0 -0
  45. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-14.md +0 -0
  46. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-15.md +0 -0
  47. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-16.md +0 -0
  48. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-17.md +0 -0
  49. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-18.md +0 -0
  50. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-19.md +0 -0
  51. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-2.md +0 -0
  52. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-20.md +0 -0
  53. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-21.md +0 -0
  54. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-22.md +0 -0
  55. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-23.md +0 -0
  56. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-24.md +0 -0
  57. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-25.md +0 -0
  58. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-26.md +0 -0
  59. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-27.md +0 -0
  60. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-28.md +0 -0
  61. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-29.md +0 -0
  62. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-3.md +0 -0
  63. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-30.md +0 -0
  64. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-31.md +0 -0
  65. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-32.md +0 -0
  66. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-33.md +0 -0
  67. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-34.md +0 -0
  68. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-35.md +0 -0
  69. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-36.md +0 -0
  70. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-37.md +0 -0
  71. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-38.md +0 -0
  72. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-39.md +0 -0
  73. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-4.md +0 -0
  74. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-40.md +0 -0
  75. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-41.md +0 -0
  76. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-42.md +0 -0
  77. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-43.md +0 -0
  78. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-44.md +0 -0
  79. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-45.md +0 -0
  80. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-46.md +0 -0
  81. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-47.md +0 -0
  82. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-48.md +0 -0
  83. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-49.md +0 -0
  84. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-5.md +0 -0
  85. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-50.md +0 -0
  86. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-51.md +0 -0
  87. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-52.md +0 -0
  88. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-53.md +0 -0
  89. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-54.md +0 -0
  90. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-55.md +0 -0
  91. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-56.md +0 -0
  92. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-57.md +0 -0
  93. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-58.md +0 -0
  94. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-59.md +0 -0
  95. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-6.md +0 -0
  96. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-60.md +0 -0
  97. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-61.md +0 -0
  98. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-62.md +0 -0
  99. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-63.md +0 -0
  100. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-64.md +0 -0
  101. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-65.md +0 -0
  102. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-66.md +0 -0
  103. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-67.md +0 -0
  104. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-68.md +0 -0
  105. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-69.md +0 -0
  106. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-7.md +0 -0
  107. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-70.md +0 -0
  108. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-71.md +0 -0
  109. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-72.md +0 -0
  110. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-73.md +0 -0
  111. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-74.md +0 -0
  112. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-75.md +0 -0
  113. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-76.md +0 -0
  114. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-77.md +0 -0
  115. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-78.md +0 -0
  116. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-79.md +0 -0
  117. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-8.md +0 -0
  118. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/field-trials/2026-05-field-trial-9.md +0 -0
  119. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/fr/index.md +0 -0
  120. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/fr/tutorials/getting-started.md +0 -0
  121. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/how-to/add-new-domain.md +0 -0
  122. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/how-to/async-use-case.md +0 -0
  123. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/how-to/configure-auth.md +0 -0
  124. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/how-to/middleware-stack.md +0 -0
  125. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/how-to/new-project.md +0 -0
  126. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/how-to/problem-details.md +0 -0
  127. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/how-to/run-tests.md +0 -0
  128. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/how-to/sqlalchemy-repository.md +0 -0
  129. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/how-to/validation.md +0 -0
  130. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/howto/mcp-setup.md +0 -0
  131. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/index.md +0 -0
  132. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/explanation/architecture.md +0 -0
  133. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/explanation/design-philosophy.md +0 -0
  134. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/how-to/add-new-domain.md +0 -0
  135. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/how-to/configure-auth.md +0 -0
  136. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/how-to/new-project.md +0 -0
  137. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/how-to/run-tests.md +0 -0
  138. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/how-to/sqlalchemy-repository.md +0 -0
  139. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/howto/mcp-setup.md +0 -0
  140. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/index.md +0 -0
  141. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/reference/api.md +0 -0
  142. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/reference/configuration.md +0 -0
  143. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/reference/framework-modules.md +0 -0
  144. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/tutorials/first-domain.md +0 -0
  145. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/ja/tutorials/getting-started.md +0 -0
  146. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/pt-br/index.md +0 -0
  147. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/pt-br/tutorials/getting-started.md +0 -0
  148. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/reference/api.md +0 -0
  149. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/reference/configuration.md +0 -0
  150. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/reference/framework-modules.md +0 -0
  151. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/roadmap.md +0 -0
  152. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/todo/current.md +0 -0
  153. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/tutorials/first-domain.md +0 -0
  154. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/tutorials/getting-started.md +0 -0
  155. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/zh/index.md +0 -0
  156. {nene2_python-1.8.25 → nene2_python-1.8.26}/docs/zh/tutorials/getting-started.md +0 -0
  157. {nene2_python-1.8.25 → nene2_python-1.8.26}/package-lock.json +0 -0
  158. {nene2_python-1.8.25 → nene2_python-1.8.26}/package.json +0 -0
  159. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/__init__.py +0 -0
  160. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/__main__.py +0 -0
  161. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/app.py +0 -0
  162. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/comment/__init__.py +0 -0
  163. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/comment/entity.py +0 -0
  164. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/comment/exceptions.py +0 -0
  165. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/comment/handler.py +0 -0
  166. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/comment/repository.py +0 -0
  167. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/comment/sqlalchemy_repository.py +0 -0
  168. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/comment/use_case.py +0 -0
  169. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/mcp.py +0 -0
  170. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/note/__init__.py +0 -0
  171. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/note/async_use_case.py +0 -0
  172. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/note/entity.py +0 -0
  173. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/note/exceptions.py +0 -0
  174. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/note/handler.py +0 -0
  175. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/note/repository.py +0 -0
  176. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/note/sqlalchemy_repository.py +0 -0
  177. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/note/use_case.py +0 -0
  178. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/schema.py +0 -0
  179. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/tag/__init__.py +0 -0
  180. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/tag/entity.py +0 -0
  181. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/tag/exceptions.py +0 -0
  182. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/tag/handler.py +0 -0
  183. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/tag/repository.py +0 -0
  184. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/tag/sqlalchemy_repository.py +0 -0
  185. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/example/tag/use_case.py +0 -0
  186. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/__init__.py +0 -0
  187. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/auth/__init__.py +0 -0
  188. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/auth/api_key.py +0 -0
  189. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/auth/bearer_token.py +0 -0
  190. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/auth/exceptions.py +0 -0
  191. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/auth/interfaces.py +0 -0
  192. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/auth/local_verifier.py +0 -0
  193. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/config/__init__.py +0 -0
  194. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/config/settings.py +0 -0
  195. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/database/__init__.py +0 -0
  196. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/database/exceptions.py +0 -0
  197. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/database/health.py +0 -0
  198. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/database/interfaces.py +0 -0
  199. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/database/sqlalchemy_executor.py +0 -0
  200. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/database/utils.py +0 -0
  201. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/http/__init__.py +0 -0
  202. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/http/health.py +0 -0
  203. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/http/pagination.py +0 -0
  204. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/http/problem_details.py +0 -0
  205. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/log/__init__.py +0 -0
  206. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/log/setup.py +0 -0
  207. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/mcp/__init__.py +0 -0
  208. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/mcp/http_client.py +0 -0
  209. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/middleware/__init__.py +0 -0
  210. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/middleware/domain_exception.py +0 -0
  211. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/middleware/error_handler.py +0 -0
  212. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/middleware/request_id.py +0 -0
  213. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/middleware/request_logging.py +0 -0
  214. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/middleware/request_size_limit.py +0 -0
  215. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/middleware/security_headers.py +0 -0
  216. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/middleware/setup.py +0 -0
  217. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/middleware/throttle.py +0 -0
  218. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/py.typed +0 -0
  219. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/use_case/__init__.py +0 -0
  220. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/use_case/protocols.py +0 -0
  221. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/validation/__init__.py +0 -0
  222. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/nene2/validation/exceptions.py +0 -0
  223. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/scripts/__init__.py +0 -0
  224. {nene2_python-1.8.25 → nene2_python-1.8.26}/src/scripts/export_openapi.py +0 -0
  225. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/__init__.py +0 -0
  226. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/__init__.py +0 -0
  227. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/comment/__init__.py +0 -0
  228. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/comment/test_comment_http.py +0 -0
  229. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/comment/test_comment_repository.py +0 -0
  230. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/comment/test_comment_use_case.py +0 -0
  231. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/conftest.py +0 -0
  232. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/note/__init__.py +0 -0
  233. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/note/test_async_note_use_case.py +0 -0
  234. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/note/test_list_notes.py +0 -0
  235. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/note/test_note_repository.py +0 -0
  236. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/tag/__init__.py +0 -0
  237. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/tag/test_tag_repository.py +0 -0
  238. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/tag/test_tags.py +0 -0
  239. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/test_cors.py +0 -0
  240. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/example/test_mcp.py +0 -0
  241. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/__init__.py +0 -0
  242. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/auth/__init__.py +0 -0
  243. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/auth/test_api_key.py +0 -0
  244. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/auth/test_bearer_token.py +0 -0
  245. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/auth/test_token_issuer.py +0 -0
  246. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/config/__init__.py +0 -0
  247. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/config/test_settings.py +0 -0
  248. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/database/__init__.py +0 -0
  249. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/database/test_transaction.py +0 -0
  250. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/database/test_utils.py +0 -0
  251. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/http/__init__.py +0 -0
  252. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/http/test_health.py +0 -0
  253. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/http/test_pagination.py +0 -0
  254. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/http/test_problem_details.py +0 -0
  255. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/log/__init__.py +0 -0
  256. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/log/test_setup.py +0 -0
  257. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/mcp/__init__.py +0 -0
  258. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/mcp/test_http_client.py +0 -0
  259. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/middleware/__init__.py +0 -0
  260. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/middleware/test_error_handler.py +0 -0
  261. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/middleware/test_request_id.py +0 -0
  262. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/middleware/test_request_logging.py +0 -0
  263. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/middleware/test_request_size_limit.py +0 -0
  264. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/middleware/test_security_headers.py +0 -0
  265. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/middleware/test_setup_middlewares.py +0 -0
  266. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/middleware/test_simple_domain_handler.py +0 -0
  267. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/middleware/test_throttle.py +0 -0
  268. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/use_case/__init__.py +0 -0
  269. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/use_case/test_protocols.py +0 -0
  270. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/use_case/test_run_in_threadpool.py +0 -0
  271. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/validation/__init__.py +0 -0
  272. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/nene2/validation/test_exceptions.py +0 -0
  273. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/scripts/__init__.py +0 -0
  274. {nene2_python-1.8.25 → nene2_python-1.8.26}/tests/scripts/test_export_openapi.py +0 -0
@@ -5,6 +5,17 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
6
  ---
7
7
 
8
+ ## [1.8.25] — 2026-05-20
9
+
10
+ FT79 フィールドトライアル — RequestLoggingMiddleware の構造化ログ検証と context_extractor 追加。
11
+
12
+ ### Added
13
+ - `RequestLoggingMiddleware` に `context_extractor` コールバックパラメーターを追加 (#339) (FT79)
14
+ — リクエストごとの動的なログコンテキスト(user_id、テナントID等)を注入できる
15
+ - Field trial report: `docs/field-trials/2026-05-field-trial-79.md` (FT79)
16
+
17
+ ---
18
+
8
19
  ## [1.8.24] — 2026-05-20
9
20
 
10
21
  FT78 フィールドトライアル — ThrottleMiddleware の境界動作検証とドキュメント強化。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nene2-python
3
- Version: 1.8.25
3
+ Version: 1.8.26
4
4
  Summary: NENE2 Python — minimal API framework following NENE2's design philosophy
5
5
  Project-URL: Homepage, https://github.com/hideyukiMORI/nene2-python
6
6
  Project-URL: Repository, https://github.com/hideyukiMORI/nene2-python
@@ -0,0 +1,176 @@
1
+ # FT80: MCP E2E — LocalMcpServer + HttpxMcpClient
2
+
3
+ **日付**: 2026-05-20
4
+ **テーマ**: LocalMcpServer にツールを登録し FastAPI アプリと連携する完全往復の検証
5
+ **バージョン**: v1.8.25
6
+ **FTディレクトリ**: `/home/xi/docker/nene2-python-FT/ft80-mcp-e2e/`
7
+
8
+ ---
9
+
10
+ ## 概要
11
+
12
+ nene2 の MCP 機能(`LocalMcpServer` / `HttpxMcpClient`)を実際に使って
13
+ FastAPI アプリと MCP ツールを組み合わせるパターンを検証した。
14
+ 基本機能は期待通り動作するが、MCP ツールから型付きオブジェクトを返す際の
15
+ 手動 JSON 変換の要求と、ツール一覧取得 API の欠如が摩擦点として判明した。
16
+
17
+ ---
18
+
19
+ ## 実装パターン
20
+
21
+ ### FastAPI + LocalMcpServer 共存
22
+
23
+ ```python
24
+ from nene2.mcp import LocalMcpServer
25
+
26
+ app = FastAPI()
27
+ mcp_server = LocalMcpServer("recipe-assistant", "Recipe management assistant")
28
+
29
+ @app.post("/recipes")
30
+ def create_recipe(body: RecipeBody) -> JSONResponse:
31
+ ...
32
+
33
+ @mcp_server.tool("Create a new recipe")
34
+ def create_new_recipe(title: str, ingredients: list[str]) -> str:
35
+ r = api_client.post("/recipes", json={"title": title, "ingredients": ingredients})
36
+ return r.text # JSON 文字列を返す
37
+ ```
38
+
39
+ ### McpHttpError を使ったエラーハンドリング
40
+
41
+ ```python
42
+ @mcp_server.tool("Get a recipe by ID")
43
+ def get_recipe_by_id(recipe_id: int) -> str:
44
+ r = client.get(f"/recipes/{recipe_id}")
45
+ if r.status_code == 404:
46
+ raise McpHttpError(404, f"Recipe {recipe_id} not found")
47
+ return r.text
48
+ ```
49
+
50
+ ### HttpxMcpClient をテストトランスポートでモック
51
+
52
+ ```python
53
+ transport = httpx.MockTransport(handler=lambda req: httpx.Response(200, json={}))
54
+ http_client = HttpxMcpClient(transport=transport)
55
+ response = http_client.get("http://testserver", "/recipes")
56
+ ```
57
+
58
+ ---
59
+
60
+ ## 発見した問題
61
+
62
+ ### 問題1: MCP ツールは文字列しか返せない(手動 JSON 変換が必要)
63
+
64
+ ```python
65
+ # ❌ UseCase の Output dataclass を直接返せない
66
+ @mcp_server.tool("Get recipe")
67
+ def get_recipe() -> RecipeOutput: # 型エラー
68
+ ...
69
+
70
+ # ✅ JSON 文字列に変換して返す(手動変換が必要)
71
+ @mcp_server.tool("Get recipe")
72
+ def get_recipe() -> str:
73
+ output = use_case.execute(input_)
74
+ return json.dumps(dataclasses.asdict(output))
75
+ ```
76
+
77
+ UseCase の型安全性が MCP ツール境界で失われる。
78
+ FastAPI の `response_model` のような仕組みが MCP にはない。
79
+
80
+ ### 問題2: ツール一覧取得 API がない
81
+
82
+ ```python
83
+ mcp_server = LocalMcpServer("test-server")
84
+
85
+ @mcp_server.tool("Tool 1")
86
+ def tool_one() -> str:
87
+ return "one"
88
+
89
+ # 登録済みツールの確認手段がない
90
+ # mcp_server.list_tools() → 存在しない
91
+ # mcp_server.tools → 存在しない
92
+ ```
93
+
94
+ デバッグ時に「このサーバーに何のツールが登録されているか」を確認できない。
95
+
96
+ ### 問題3: Pydantic の `max_items` 非推奨警告
97
+
98
+ ```python
99
+ # ⚠ PydanticDeprecatedSince20 警告
100
+ ingredients: list[str] = Field(max_items=20)
101
+
102
+ # ✅ 正しい書き方(nene2 ドキュメントに記載が必要)
103
+ ingredients: list[str] = Field(max_length=20)
104
+ ```
105
+
106
+ nene2 のドキュメント/例に `max_items` が残っている可能性がある。
107
+
108
+ ---
109
+
110
+ ## テスト結果(全17件パス)
111
+
112
+ ```
113
+ test_create_recipe_returns_201 PASSED
114
+ test_get_recipe_returns_200 PASSED
115
+ test_get_nonexistent_recipe_returns_404 PASSED
116
+ test_list_recipes_empty PASSED
117
+ test_delete_recipe_returns_204 PASSED
118
+ test_mcp_get_all_recipes_returns_json_string PASSED # ツールが JSON 文字列を返す
119
+ test_mcp_create_recipe_tool PASSED
120
+ test_mcp_get_recipe_by_id_found PASSED
121
+ test_mcp_get_recipe_by_id_not_found_raises PASSED # McpHttpError 正常動作
122
+ test_mcp_delete_recipe_tool PASSED
123
+ test_mcp_delete_nonexistent_raises PASSED
124
+ test_mcp_server_is_importable PASSED
125
+ test_mcp_server_tool_registration PASSED
126
+ test_http_mcp_client_with_test_transport PASSED # MockTransport で DI テスト
127
+ test_http_mcp_client_raise_for_error PASSED
128
+ test_friction_mcp_tool_cannot_return_typed_object PASSED
129
+ test_friction_no_mcp_tool_discovery_api PASSED
130
+ ```
131
+
132
+ ---
133
+
134
+ ## 摩擦ポイント一覧
135
+
136
+ | ID | 内容 | 深刻度 |
137
+ |---|---|---|
138
+ | F80-1 | MCP ツールは文字列を返す必要があり、UseCase の型付き Output を直接渡せない | 中 |
139
+ | F80-2 | LocalMcpServer に登録済みツールの一覧取得 API がない | 低 |
140
+ | F80-3 | Pydantic v2 の `max_items` 非推奨(`max_length` に変更必要) | 低 |
141
+
142
+ ---
143
+
144
+ ## 使用感(主観評価)
145
+
146
+ ### 直感性 ★★★★☆
147
+
148
+ `@mcp_server.tool("description")` デコレーターは非常に直感的で、
149
+ FastAPI の `@app.get("/path")` と同じ感覚で使える。
150
+ `McpHttpError` と `raise_for_error()` のパターンも明瞭。
151
+
152
+ ### 実害の深刻さ ★★☆☆☆
153
+
154
+ 文字列変換の必要性は設計上仕方ない(MCP プロトコルの制約)。
155
+ `json.dumps(dataclasses.asdict(output))` は1行で書けるので実際の摩擦は小さい。
156
+ ツール一覧確認はデバッグ時の不便さのみで、本番には影響しない。
157
+
158
+ ### 修正のしやすさ ★★★★★
159
+
160
+ どれも小さな改善で対応できる:
161
+ - `list_tools()` メソッドを `LocalMcpServer` に追加するだけ
162
+ - ドキュメントに `json.dumps(dataclasses.asdict(output))` のパターンを記載するだけ
163
+
164
+ ### 総合コメント
165
+
166
+ MCP 機能は他の Python フレームワークにはない nene2 の差別化ポイント。
167
+ FastAPI との共存パターン、`McpHttpError` のエラーハンドリング、
168
+ `HttpxMcpClient` の `MockTransport` DI テストパターンは非常によくできている。
169
+ 「他のフレームワークに乗り換えようと思わない」と思わせる独自の価値がある。
170
+
171
+ ---
172
+
173
+ ## 推奨アクション
174
+
175
+ 1. **Issue**: `LocalMcpServer` に `list_tools()` メソッドを追加(デバッグ用)
176
+ 2. **minor**: Pydantic v2 の `max_items` → `max_length` への更新(ドキュメント確認)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nene2-python"
3
- version = "1.8.25"
3
+ version = "1.8.26"
4
4
  description = "NENE2 Python — minimal API framework following NENE2's design philosophy"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -27,6 +27,22 @@ class LocalMcpServer:
27
27
  """Register a function as an MCP tool."""
28
28
  return self._mcp.tool(description=description)
29
29
 
30
+ def list_tools(self) -> list[str]:
31
+ """Return the names of all registered tools.
32
+
33
+ Useful for debugging and introspection::
34
+
35
+ server = LocalMcpServer("my-server")
36
+
37
+
38
+ @server.tool("Get data")
39
+ def get_data() -> str: ...
40
+
41
+
42
+ print(server.list_tools()) # ["get_data"]
43
+ """
44
+ return [t.name for t in self._mcp._tool_manager.list_tools()]
45
+
30
46
  def run(self, transport: Literal["stdio", "sse", "streamable-http"] = "stdio") -> None:
31
47
  """Start the MCP server. Blocks until the client disconnects."""
32
48
  self._mcp.run(transport=transport)
@@ -0,0 +1,51 @@
1
+ """Tests for LocalMcpServer."""
2
+
3
+ from nene2.mcp import LocalMcpServer
4
+
5
+
6
+ def _make_server_with_tools() -> LocalMcpServer:
7
+ server = LocalMcpServer("test-server")
8
+
9
+ @server.tool("Get data")
10
+ def get_data() -> str:
11
+ return "data"
12
+
13
+ @server.tool("Post data")
14
+ def post_data(value: str) -> str:
15
+ return f"posted: {value}"
16
+
17
+ return server
18
+
19
+
20
+ def test_list_tools_returns_registered_names() -> None:
21
+ server = _make_server_with_tools()
22
+ tools = server.list_tools()
23
+ assert "get_data" in tools
24
+ assert "post_data" in tools
25
+
26
+
27
+ def test_list_tools_empty_server() -> None:
28
+ server = LocalMcpServer("empty-server")
29
+ assert server.list_tools() == []
30
+
31
+
32
+ def test_list_tools_count() -> None:
33
+ server = _make_server_with_tools()
34
+ assert len(server.list_tools()) == 2
35
+
36
+
37
+ def test_list_tools_returns_list_of_str() -> None:
38
+ server = _make_server_with_tools()
39
+ tools = server.list_tools()
40
+ assert all(isinstance(name, str) for name in tools)
41
+
42
+
43
+ def test_tool_function_still_callable() -> None:
44
+ """tool() デコレーターが関数の呼び出し可能性を壊さない。"""
45
+ server = LocalMcpServer("callable-test")
46
+
47
+ @server.tool("Square")
48
+ def square(x: int) -> str:
49
+ return str(x * x)
50
+
51
+ assert square(3) == "9"
@@ -925,7 +925,7 @@ wheels = [
925
925
 
926
926
  [[package]]
927
927
  name = "nene2-python"
928
- version = "1.8.25"
928
+ version = "1.8.26"
929
929
  source = { editable = "." }
930
930
  dependencies = [
931
931
  { name = "alembic" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes