mcp-server-taxcode 0.7.1__tar.gz → 0.8.0__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 (204) hide show
  1. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/.github/dependabot.yml +0 -11
  2. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/.github/workflows/ci.yml +43 -9
  3. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/.github/workflows/dependabot-automerge.yml +15 -1
  4. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/.github/workflows/drift-monitor.yml +4 -2
  5. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/.github/workflows/release.yml +3 -1
  6. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/AGENTS.md +8 -3
  7. mcp_server_taxcode-0.8.0/Dockerfile +83 -0
  8. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/PKG-INFO +6 -4
  9. mcp_server_taxcode-0.8.0/SECURITY.md +18 -0
  10. mcp_server_taxcode-0.8.0/docker/pip-bootstrap.txt +5 -0
  11. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/llms-full.txt +112 -10
  12. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/llms.txt +29 -4
  13. mcp_server_taxcode-0.8.0/docs/pr/ley60_1020_02.md +33 -0
  14. mcp_server_taxcode-0.8.0/docs/pr/ley60_2021_01.md +17 -0
  15. mcp_server_taxcode-0.8.0/docs/pr/ley60_2022_01.md +22 -0
  16. mcp_server_taxcode-0.8.0/docs/pr/ley60_2022_01_2019.md +17 -0
  17. mcp_server_taxcode-0.8.0/docs/pr/ley60_2022_02.md +21 -0
  18. mcp_server_taxcode-0.8.0/docs/pr/ley60_6020_03.md +21 -0
  19. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pr/ley60_6020_10.md +3 -2
  20. mcp_server_taxcode-0.8.0/docs/pr/ley60_6020_10_2019.md +30 -0
  21. mcp_server_taxcode-0.8.0/docs/pr/ley60_6020_10_2025.md +31 -0
  22. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/fastmcp.json +2 -1
  23. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/pyproject.toml +12 -3
  24. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/scripts/check_openapi_drift.py +33 -4
  25. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/scripts/ingest_statutes.py +1118 -81
  26. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/scripts/setup_repo_governance.sh +1 -0
  27. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/client.py +126 -14
  28. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/db.py +1319 -53
  29. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/ssrf.py +14 -9
  30. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/conftest.py +53 -0
  31. mcp_server_taxcode-0.8.0/tests/fake_network.py +150 -0
  32. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_client.py +209 -0
  33. mcp_server_taxcode-0.8.0/tests/test_conftest_auth_env.py +35 -0
  34. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_db.py +98 -1
  35. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_disclaimers.py +5 -1
  36. mcp_server_taxcode-0.8.0/tests/test_dockerfile.py +141 -0
  37. mcp_server_taxcode-0.8.0/tests/test_drift.py +235 -0
  38. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_ingest.py +135 -19
  39. mcp_server_taxcode-0.8.0/tests/test_network_guard.py +25 -0
  40. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_search_normalize.py +3 -2
  41. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_search_snippets.py +10 -2
  42. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_ssrf.py +18 -4
  43. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/uv.lock +187 -153
  44. mcp_server_taxcode-0.7.1/Dockerfile +0 -50
  45. mcp_server_taxcode-0.7.1/SECURITY.md +0 -14
  46. mcp_server_taxcode-0.7.1/docs/pr/ley60_2021_01.md +0 -17
  47. mcp_server_taxcode-0.7.1/docs/pr/ley60_2022_01.md +0 -17
  48. mcp_server_taxcode-0.7.1/docs/pr/ley60_2022_01_2019.md +0 -17
  49. mcp_server_taxcode-0.7.1/tests/test_conftest_auth_env.py +0 -20
  50. mcp_server_taxcode-0.7.1/tests/test_drift.py +0 -141
  51. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/.gitignore +0 -0
  52. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/CHANGELOG.md +0 -0
  53. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/CODE_OF_CONDUCT.md +0 -0
  54. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/CONTRIBUTING.md +0 -0
  55. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/LICENSE +0 -0
  56. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/README.md +0 -0
  57. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/conformance-baseline.yml +0 -0
  58. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ak/alaska stat._43_05_080.md +0 -0
  59. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/al/ala. code_40_18_2.md +0 -0
  60. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ar/a.c.a._26_51_201.md +0 -0
  61. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/az/a.r.s._43_1011.md +0 -0
  62. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/az/a.r.s._43_104.md +0 -0
  63. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ca/caccr_17014.md +0 -0
  64. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ca/rtc_17014.md +0 -0
  65. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ca/rtc_17041.md +0 -0
  66. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ca/rtc_17951.md +0 -0
  67. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/co/c.r.s._39_22_103.md +0 -0
  68. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/co/c.r.s._39_22_104.md +0 -0
  69. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ct/c.g.s._12_700.md +0 -0
  70. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ct/c.g.s._12_701.md +0 -0
  71. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ct/c.g.s._12_711.md +0 -0
  72. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/dc/d.c. code_47_1806_03.md +0 -0
  73. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/de/del. code_1102.md +0 -0
  74. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/fl/flconst_art__vii_sec__5.md +0 -0
  75. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/fl/flstat_196_031.md +0 -0
  76. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/fl/flstat_222_17.md +0 -0
  77. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ga/gareg_560_7_3__01.md +0 -0
  78. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ga/ocga_48_7_1.md +0 -0
  79. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ga/ocga_48_7_20.md +0 -0
  80. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ga/ocga_48_7_20_2024.md +0 -0
  81. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ga/ocga_48_7_20_2025.md +0 -0
  82. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ga/ocga_48_7_27.md +0 -0
  83. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ga/ocga_48_7_30.md +0 -0
  84. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/hi/hrs_235_51.md +0 -0
  85. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ia/iowa code_422_5.md +0 -0
  86. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/id/idaho code_63_3024.md +0 -0
  87. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/il/ilcs_5_1501_a_20.md +0 -0
  88. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/il/ilcs_5_201.md +0 -0
  89. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/il/ilcs_5_301.md +0 -0
  90. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/in/ind. code_6_3_2_1.md +0 -0
  91. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ks/k.s.a._79_32,110.md +0 -0
  92. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ky/krs_141_020.md +0 -0
  93. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/la/la. r.s._47_32.md +0 -0
  94. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/la/la. r.s._47_32_2022.md +0 -0
  95. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ma/maconst_art__xliv.md +0 -0
  96. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ma/mgl_62_1_f.md +0 -0
  97. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ma/mgl_62_4.md +0 -0
  98. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/md/md. code_10_101.md +0 -0
  99. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/md/md. code_10_105.md +0 -0
  100. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/md/md. code_10_106.md +0 -0
  101. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/me/36 m.r.s._5111.md +0 -0
  102. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/mi/mcl_206_51.md +0 -0
  103. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/mn/minn. stat._290_06.md +0 -0
  104. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/mo/rsmo_143_011.md +0 -0
  105. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ms/miss. code_27_7_5.md +0 -0
  106. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/mt/mca_15_30_2103.md +0 -0
  107. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/nc/n.c.g.s._105_153_3.md +0 -0
  108. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/nc/n.c.g.s._105_153_7.md +0 -0
  109. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/nd/n.d.c.c._57_38_30_3.md +0 -0
  110. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ne/neb. rev. stat._77_2715_03.md +0 -0
  111. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/nh/rsa_77_1_2024.md +0 -0
  112. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/nj/njac_18_35_5_2.md +0 -0
  113. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/nj/njsa_54a_1_2.md +0 -0
  114. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/nj/njsa_54a_2_1.md +0 -0
  115. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/nm/nmsa_7_2_7.md +0 -0
  116. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/nv/nev. const._art__10,_/302/247_1.md" +0 -0
  117. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ny/nycrr_105_20.md +0 -0
  118. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ny/nycrr_132_18.md +0 -0
  119. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ny/nytax_601.md +0 -0
  120. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ny/nytax_605.md +0 -0
  121. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/oh/r.c._5747_02.md +0 -0
  122. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/oh/r.c._5747_24.md +0 -0
  123. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ok/68 o.s._2355.md +0 -0
  124. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/or/ors_316_037.md +0 -0
  125. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pa/p.s._7301.md +0 -0
  126. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pa/p.s._7302.md +0 -0
  127. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pa/pa. code_109_8.md +0 -0
  128. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pr/cri_1010_01.md +0 -0
  129. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pr/cri_1031_01.md +0 -0
  130. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pr/cri_1031_02.md +0 -0
  131. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pr/cri_1062_01.md +0 -0
  132. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pr/cri_1062_03.md +0 -0
  133. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pr/ley22_3_2012.md +0 -0
  134. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pr/ley60_2031_01.md +0 -0
  135. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pr/ley60_2032_01.md +0 -0
  136. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/pr/ley60_6070_55.md +0 -0
  137. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ri/r.i.g.l._44_30_1.md +0 -0
  138. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/sc/s.c. code_12_6_510.md +0 -0
  139. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/sd/s.d. const._art__xi,_/302/247_2.md" +0 -0
  140. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/tn/tenn. const._art__ii,_/302/247_28.md" +0 -0
  141. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/tx/txconst_art__viii_sec__24_a.md +0 -0
  142. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/tx/txtax_171_001.md +0 -0
  143. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/cfr_1_937_1.md +0 -0
  144. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/cfr_1_937_2.md +0 -0
  145. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/cfr_1_937_3.md +0 -0
  146. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_1.md +0 -0
  147. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_1411.md +0 -0
  148. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_24.md +0 -0
  149. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_32.md +0 -0
  150. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_6012.md +0 -0
  151. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_61.md +0 -0
  152. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_62.md +0 -0
  153. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_63.md +0 -0
  154. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_6688.md +0 -0
  155. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_865.md +0 -0
  156. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_911.md +0 -0
  157. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_933.md +0 -0
  158. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_937.md +0 -0
  159. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/us/irc_957.md +0 -0
  160. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/ut/utah code_59_10_104.md +0 -0
  161. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/va/va. code_58_1_302.md +0 -0
  162. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/va/va. code_58_1_320.md +0 -0
  163. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/va/va. code_58_1_342.md +0 -0
  164. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/vt/32 v.s.a._5822.md +0 -0
  165. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/wa/rcw_82_87_020.md +0 -0
  166. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/wa/rcw_82_87_040.md +0 -0
  167. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/wa/waconst_art__vii_sec__1.md +0 -0
  168. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/wi/wis. stat._71_06.md +0 -0
  169. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/wv/w. va. code_11_21_4e.md +0 -0
  170. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/docs/wy/wyo. const._art__15,_/302/247_18.md" +0 -0
  171. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/scripts/check_conformance.sh +0 -0
  172. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/scripts/check_tool_contract.py +0 -0
  173. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/scripts/check_version.py +0 -0
  174. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/scripts/release_notes.py +0 -0
  175. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/server.json +0 -0
  176. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/skills/taxcode-mcp/SKILL.md +0 -0
  177. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/__init__.py +0 -0
  178. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/auth.py +0 -0
  179. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/config.py +0 -0
  180. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/disclaimers.py +0 -0
  181. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/errors.py +0 -0
  182. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/middleware.py +0 -0
  183. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/profiles.py +0 -0
  184. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/server.py +0 -0
  185. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/tools/__init__.py +0 -0
  186. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/tools/compliance.py +0 -0
  187. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/tools/statutes.py +0 -0
  188. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/src/taxcode_mcp/tools/system.py +0 -0
  189. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/fixtures/usc26_sample.xml +0 -0
  190. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_batch.py +0 -0
  191. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_check_version.py +0 -0
  192. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_code_mode_extra.py +0 -0
  193. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_config.py +0 -0
  194. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_e2e_live.py +0 -0
  195. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_errors.py +0 -0
  196. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_federal.py +0 -0
  197. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_http_auth.py +0 -0
  198. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_layered.py +0 -0
  199. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_otel_spans.py +0 -0
  200. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_profiles.py +0 -0
  201. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_protocol.py +0 -0
  202. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_release_notes.py +0 -0
  203. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_server.py +0 -0
  204. {mcp_server_taxcode-0.7.1 → mcp_server_taxcode-0.8.0}/tests/test_version.py +0 -0
@@ -1,13 +1,4 @@
1
1
  version: 2
2
- # The Dockerfile pulls its base from public.ecr.aws. Declaring that host
3
- # under registries (no credentials; it allows anonymous pulls) lets the
4
- # docker update job reach it. See "Configuring access to private registries
5
- # for Dependabot" on docs.github.com.
6
- registries:
7
- public-ecr:
8
- type: docker-registry
9
- url: https://public.ecr.aws
10
-
11
2
  updates:
12
3
  - package-ecosystem: "uv"
13
4
  directory: "/"
@@ -43,5 +34,3 @@ updates:
43
34
  time: "04:30"
44
35
  timezone: "Etc/UTC"
45
36
  open-pull-requests-limit: 10
46
- registries:
47
- - public-ecr
@@ -35,9 +35,11 @@ jobs:
35
35
  persist-credentials: false
36
36
 
37
37
  - name: Install uv
38
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
38
+ uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
39
39
  with:
40
- version: "latest"
40
+ # Newest uv that meets pyproject.toml's [tool.uv] required-version (>=0.13.4, from
41
+ # FastMCP's October 2026 certificate authority incident notice).
42
+ version-file: "pyproject.toml"
41
43
  enable-cache: true
42
44
 
43
45
  - name: Set up Python
@@ -63,7 +65,7 @@ jobs:
63
65
  strategy:
64
66
  fail-fast: false
65
67
  matrix:
66
- python-version: ["3.10", "3.11", "3.12", "3.13"]
68
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
67
69
  steps:
68
70
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
69
71
  with:
@@ -71,9 +73,11 @@ jobs:
71
73
  persist-credentials: false
72
74
 
73
75
  - name: Install uv
74
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
76
+ uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
75
77
  with:
76
- version: "latest"
78
+ # Newest uv that meets pyproject.toml's [tool.uv] required-version (>=0.13.4, from
79
+ # FastMCP's October 2026 certificate authority incident notice).
80
+ version-file: "pyproject.toml"
77
81
  enable-cache: true
78
82
 
79
83
  - name: Set up Python ${{ matrix.python-version }}
@@ -101,9 +105,11 @@ jobs:
101
105
  persist-credentials: false
102
106
 
103
107
  - name: Install uv
104
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
108
+ uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
105
109
  with:
106
- version: "latest"
110
+ # Newest uv that meets pyproject.toml's [tool.uv] required-version (>=0.13.4, from
111
+ # FastMCP's October 2026 certificate authority incident notice).
112
+ version-file: "pyproject.toml"
107
113
  enable-cache: true
108
114
 
109
115
  - name: Set up Python
@@ -138,9 +144,11 @@ jobs:
138
144
  persist-credentials: false
139
145
 
140
146
  - name: Install uv
141
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
147
+ uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
142
148
  with:
143
- version: "latest"
149
+ # Newest uv that meets pyproject.toml's [tool.uv] required-version (>=0.13.4, from
150
+ # FastMCP's October 2026 certificate authority incident notice).
151
+ version-file: "pyproject.toml"
144
152
 
145
153
  - name: Set up Python
146
154
  uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
@@ -184,3 +192,29 @@ jobs:
184
192
  exit 1
185
193
  fi
186
194
  echo "Image label matches ${EXPECTED}"
195
+
196
+ - name: Builder fails below the ca-certificates floor
197
+ # Raising CA_CERTIFICATES_FLOOR above any real Debian version makes the installed
198
+ # package older than the floor, whatever version the base image or trixie-security
199
+ # ships, so this is deterministic. The build must fail at the builder's floor check,
200
+ # with its message, and before the pip bootstrap step starts.
201
+ run: |
202
+ set +e
203
+ docker build --target builder --progress=plain \
204
+ --build-arg CA_CERTIFICATES_FLOOR=99991231 . > ca-floor.log 2>&1
205
+ status=$?
206
+ set -e
207
+ cat ca-floor.log
208
+ if [ "$status" -eq 0 ]; then
209
+ echo "::error::builder built with a ca-certificates floor above the installed version"
210
+ exit 1
211
+ fi
212
+ if ! grep -q "is older than the floor 99991231" ca-floor.log; then
213
+ echo "::error::builder failed, but not at the ca-certificates floor check"
214
+ exit 1
215
+ fi
216
+ if grep -q -- "--require-hashes" ca-floor.log; then
217
+ echo "::error::the pip bootstrap step started before the ca-certificates floor check failed"
218
+ exit 1
219
+ fi
220
+ echo "Builder stops at the ca-certificates floor check before any pip step"
@@ -28,11 +28,25 @@ jobs:
28
28
  with:
29
29
  github-token: "${{ secrets.GITHUB_TOKEN }}"
30
30
 
31
+ # Docker base image updates never auto-merge. The docker ecosystem can move the tag
32
+ # (python:3.12-slim -> 3.14-slim is a Python runtime upgrade that Dependabot labels
33
+ # semver-minor), so these PRs stay open for a human review.
34
+ - name: Leave Docker base image updates for review
35
+ if: steps.metadata.outputs.package-ecosystem == 'docker'
36
+ run: echo "::notice title=Not auto-merged::Docker base image update ($DEPS $PREV -> $NEW). Docker updates always wait for a human review."
37
+ env:
38
+ DEPS: ${{ steps.metadata.outputs.dependency-names }}
39
+ PREV: ${{ steps.metadata.outputs.previous-version }}
40
+ NEW: ${{ steps.metadata.outputs.new-version }}
41
+
31
42
  # Allowlist, not a major-version denylist: update-type is the highest change in the PR
32
43
  # (a grouped PR with one major is skipped), and it is empty when the PR carries a
33
44
  # non-Dependabot commit, so only minor and patch updates are auto-merged.
34
45
  - name: Enable auto-merge for semver-minor and semver-patch updates
35
- if: steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch'
46
+ if: >-
47
+ steps.metadata.outputs.package-ecosystem != 'docker' &&
48
+ (steps.metadata.outputs.update-type == 'version-update:semver-minor' ||
49
+ steps.metadata.outputs.update-type == 'version-update:semver-patch')
36
50
  run: gh pr merge --auto --squash "$PR_URL"
37
51
  env:
38
52
  PR_URL: ${{ github.event.pull_request.html_url }}
@@ -28,9 +28,11 @@ jobs:
28
28
  persist-credentials: false
29
29
 
30
30
  - name: Install uv
31
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
31
+ uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
32
32
  with:
33
- version: "latest"
33
+ # Newest uv that meets pyproject.toml's [tool.uv] required-version (>=0.13.4, from
34
+ # FastMCP's October 2026 certificate authority incident notice).
35
+ version-file: "pyproject.toml"
34
36
  enable-cache: true
35
37
 
36
38
  - name: Set up Python
@@ -28,7 +28,9 @@ jobs:
28
28
  - name: Install uv
29
29
  uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
30
30
  with:
31
- version: "latest"
31
+ # Newest uv that meets pyproject.toml's [tool.uv] required-version (>=0.13.4, from
32
+ # FastMCP's October 2026 certificate authority incident notice).
33
+ version-file: "pyproject.toml"
32
34
  enable-cache: false
33
35
 
34
36
  - name: Set up Python
@@ -136,7 +136,10 @@ When translating an API documentation page, `llm.txt`, or OpenAPI specification
136
136
  - Tool execution errors reach the client as `tools/call` results with `isError: true` and the redacted message (`tool_error`, raised `from None` after the `except` block ends, so neither `__cause__` nor `__context__` holds the original exception); `ParentAuditMiddleware` logs the same redacted message. A batch tool's per-item errors and its `batch_failed` error (`tool_failure`, raised `from None` outside any `except` block) carry redacted messages too.
137
137
  - An unknown tool stays FastMCP 4.0.11's tool result (`isError: true`). The spec's JSON-RPC `-32602` (`Unknown tool: invalid_tool_name`) is a known gap; do not change the wire format. See `COOKBOOK.md` Recipe 12.
138
138
  3. **Multi-Stage Non-Root Containers**:
139
- - The `Dockerfile` must use a multi-stage build (`python:3.12-slim AS builder` $\rightarrow$ runtime, pulled from the ECR Public mirror of Docker Official Images and pinned by digest) creating and executing under non-root `USER mcp` with virtual environment `/opt/venv`. The runtime stage carries `LABEL io.modelcontextprotocol.server.name` equal to the `server.json` `name` (MCP Registry OCI ownership check), and the default command stays stdio.
139
+ - The `Dockerfile` must use a multi-stage build (`python:3.14-slim AS builder` $\rightarrow$ runtime, pulled from Docker Hub and pinned by digest) creating and executing under non-root `USER mcp` with virtual environment `/opt/venv`. The runtime stage carries `LABEL io.modelcontextprotocol.server.name` equal to the `server.json` `name` (MCP Registry OCI ownership check), and the default command stays stdio.
140
+ - Trust stores follow FastMCP's [certificate authority incident notice (October 2026)](https://github.com/PrefectHQ/fastmcp/blob/main/SECURITY.md#certificate-authority-incident-october-2026): both stages upgrade the OS `ca-certificates` package and fail the build below the patched Debian version (`ARG CA_CERTIFICATES_FLOOR`, declared once), the builder does so before any pip runs because pip trusts the OS store as well as its bundled certifi, the builder bootstraps pip 26.2.2, and `certifi>=2026.10.19` is a direct dependency. `tests/test_dockerfile.py` and CI's `docker-build` job enforce the order and the floor.
141
+ - The pip bootstrap is hash-pinned in `docker/pip-bootstrap.txt` and installed with `--require-hashes`, so it does not depend on the TLS trust of the base image's older pip and certifi; whoever raises the pip floor updates that pin and its sha256 from PyPI (`https://pypi.org/pypi/pip/<version>/json`, the `py3-none-any` wheel's `digests.sha256`), because Dependabot does not track the file.
142
+ - Lowering `CA_CERTIFICATES_FLOOR` with `--build-arg` is unsupported; the build-arg exists only so CI can raise it for the negative floor check, and CI and the release workflow never pass it otherwise.
140
143
  4. **Registry Metadata Constraint**:
141
144
  - In `server.json`, the root `description` must be **strictly $\le$ 100 characters** to pass MCP Registry schema validation (longer strings trigger HTTP 422 errors).
142
145
  - The default package transport is `stdio`, and packages must specify `"runtimeHint": "uvx"`.
@@ -144,7 +147,7 @@ When translating an API documentation page, `llm.txt`, or OpenAPI specification
144
147
  - `<NAME>_MCP_AUTH_TOKEN` is read with `.strip()`; empty or whitespace-only means no auth plus a warning. When set, every HTTP entry point (`main()`, `fastmcp run`, `http_app()`) requires `Authorization: Bearer <token>` (`SharedTokenVerifier`: constant-time compare, token hidden from `repr`, blank tokens refused).
145
148
  - An HTTP transport on a host other than `127.0.0.1`, `::1` or `localhost` refuses to start without a token unless `<NAME>_MCP_ALLOW_UNAUTHENTICATED_BIND=1`. Stdio is unaffected and stays the image default (`COOKBOOK.md` Recipe 8).
146
149
  6. **SSRF & DNS Rebinding Defense**:
147
- - Outbound requests must enforce HTTPS, disallow loopback/private/internal IP addresses, and offload DNS hostname verification to worker threads via `asyncio.to_thread` in `SSRFSafeAsyncTransport` to protect event loop responsiveness.
150
+ - Outbound requests must enforce HTTPS, disallow loopback/private/internal IP addresses, and offload DNS hostname verification to worker threads via `asyncio.to_thread` in `SSRFSafeAsyncTransport` to protect event loop responsiveness. The transport then connects only to an address it checked, trying the next checked address if a connect fails, and keeps the hostname in the URL for the Host header, TLS SNI, certificate verification and per-hostname connection pooling, so the name is never looked up a second time. The client, the drift fetch (`--spec-url`) and `ingest_statutes.py --check-upstream` all use it, and none follows redirects. httpx ignores env proxies whenever a transport is passed (`allow_env_proxies = trust_env and transport is None`), so connections always go direct through the pin; egress-proxy deployments need a proxy-aware transport, which isn't provided; `trust_env=False` on the drift fetch and the `--check-upstream` probe is belt-and-braces.
148
151
  7. **Defensive API Contracts & Payload Hardening**:
149
152
  - Guard against polymorphic nulls and missing keys with typed extraction helpers (`extract_dict`, `extract_list`); never chain naked `.get()` calls without type assertions. Status-classification and selection-loop patterns are in **`COOKBOOK.md`** Recipe 10.
150
153
  8. **Git Safety & Streamlined Releases**:
@@ -163,6 +166,8 @@ When translating an API documentation page, `llm.txt`, or OpenAPI specification
163
166
 
164
167
  ## 🛠️ Development & Verification Commands
165
168
 
169
+ uv 0.13.4 or later is required (`[tool.uv] required-version` in `pyproject.toml`, from FastMCP's certificate authority incident notice); older uv refuses to run, and CI's `setup-uv` installs from that setting.
170
+
166
171
  ```bash
167
172
  # Install editable with dev dependencies
168
173
  uv sync --locked --extra dev
@@ -199,6 +204,6 @@ coderabbit review --agent --uncommitted
199
204
 
200
205
  ## 🔄 CI & Releases
201
206
 
202
- CI is defined in `.github/workflows/ci.yml` (jobs: `lint-and-types`, `test` on Python 3.10–3.13, `tool-contract`, `build-check`, `docker-build` (builds the image without pushing and checks its MCP server-name label against `server.json`)). It runs on pushes and pull requests to `main`, daily on `main` at 09:29 UTC (`schedule`), and on manual dispatch (`workflow_dispatch`); the daily run exists because merges by `dependabot-automerge.yml` use `GITHUB_TOKEN`, and pushes made with `GITHUB_TOKEN` don't trigger push workflows, so those merges get no `push` run. Run the commands above before opening a PR. Scheduled upstream drift runs in `drift-monitor.yml`. `dependabot-automerge.yml` turns on squash auto-merge only for Dependabot PRs whose highest update is minor or patch; major updates wait for a human review.
207
+ CI is defined in `.github/workflows/ci.yml` (jobs: `lint-and-types`, `test` on Python 3.10–3.14, `tool-contract`, `build-check`, `docker-build` (builds the image without pushing, checks its MCP server-name label against `server.json`, and checks that the builder stage fails at its `ca-certificates` floor check, before any pip step, when the floor is above the installed version)). It runs on pushes and pull requests to `main`, daily on `main` at 09:29 UTC (`schedule`), and on manual dispatch (`workflow_dispatch`); the daily run exists because merges by `dependabot-automerge.yml` use `GITHUB_TOKEN`, and pushes made with `GITHUB_TOKEN` don't trigger push workflows, so those merges get no `push` run. Run the commands above before opening a PR. Scheduled upstream drift runs in `drift-monitor.yml`. `dependabot-automerge.yml` turns on squash auto-merge only for Dependabot PRs whose highest update is minor or patch; major updates wait for a human review. Docker base image updates (`package-ecosystem` `docker`) never auto-merge and always wait for a human review: Dependabot's docker ecosystem can move the image tag, not just its digest (for example `python:3.12-slim` to `python:3.14-slim`, a Python runtime upgrade that Dependabot labels a minor update), so the job logs a notice and leaves the PR open.
203
208
 
204
209
  `release.yml` runs on `v*` tag pushes only: it creates the GitHub Release, then builds the container image, pushes it to GHCR, attests it, and publishes to the MCP Registry. In the template repo the image is built only (no push), and the attest and registry jobs skip. Release procedure (tag-based versioning, release notes, pre-tag checks): **`COOKBOOK.md`** Recipes 1–2; product-repo migration steps: Recipe 9.
@@ -0,0 +1,83 @@
1
+ # Multi-stage build for mcp-server-taxcode
2
+ # Produces a minimal runtime image (~150MB) with no dev tooling.
3
+ #
4
+ # The base image is the Docker Official python image pulled from Docker Hub,
5
+ # pinned by its multi-arch index digest. Dependabot's docker ecosystem keeps the
6
+ # digest current.
7
+ # No `# syntax=` line: the Dockerfile uses only features of BuildKit's built-in
8
+ # frontend, so no frontend image is pulled.
9
+
10
+ # FastMCP's October 2026 certificate authority incident notice says to update the
11
+ # container's OS trust store: older base images ship a ca-certificates that predates the fix.
12
+ # Debian shipped 20250419+deb13u1 in trixie-security. Both stages upgrade the package and
13
+ # fail the build if the installed version is older than this floor, so a base image change
14
+ # cannot drop the fix. The builder does it before any pip runs, because pip trusts the OS
15
+ # store as well as its bundled certifi.
16
+ # https://github.com/PrefectHQ/fastmcp/pull/5945 (notice) and
17
+ # https://security-tracker.debian.org/tracker/DSA-6572-1 (Debian floor)
18
+ ARG CA_CERTIFICATES_FLOOR=20250419+deb13u1
19
+
20
+ # ─── Stage 1: Builder ─────────────────────────────────────────────────────────
21
+ FROM python:3.14-slim@sha256:fbecd461fc72d21b2143c6eaba25143738079154a6d0ea3da3aec724f50eed4a AS builder
22
+
23
+ ARG CA_CERTIFICATES_FLOOR
24
+ RUN apt-get update && \
25
+ apt-get install -y --no-install-recommends --only-upgrade ca-certificates && \
26
+ rm -rf /var/lib/apt/lists/* && \
27
+ installed="$(dpkg-query -W -f='${Version}' ca-certificates)" && \
28
+ { dpkg --compare-versions "$installed" ge "$CA_CERTIFICATES_FLOOR" || \
29
+ { echo "ca-certificates $installed is older than the floor $CA_CERTIFICATES_FLOOR" >&2; exit 1; }; }
30
+
31
+ WORKDIR /app
32
+
33
+ # Install build deps in a virtualenv so we can copy it cleanly
34
+ RUN python -m venv /opt/venv
35
+ ENV PATH="/opt/venv/bin:$PATH"
36
+
37
+ COPY docker/pip-bootstrap.txt /tmp/pip-bootstrap.txt
38
+ COPY pyproject.toml README.md LICENSE ./
39
+ COPY src/ src/
40
+
41
+ # The build context has no .git, so uv-dynamic-versioning cannot read the tag and
42
+ # falls back to 0.0.0. Release builds pass the tag version, for example
43
+ # --build-arg UV_DYNAMIC_VERSIONING_BYPASS=1.3.1 (an unset or empty value keeps 0.0.0).
44
+ ARG UV_DYNAMIC_VERSIONING_BYPASS
45
+ ENV UV_DYNAMIC_VERSIONING_BYPASS=${UV_DYNAMIC_VERSIONING_BYPASS}
46
+
47
+ # pip 26.2.2 updates the certificates pip bundles, per FastMCP's October 2026 certificate
48
+ # authority incident notice. This image builds with pip, not uv, so pip carries the floor.
49
+ # https://github.com/PrefectHQ/fastmcp/blob/main/SECURITY.md#certificate-authority-incident-october-2026
50
+ # The bootstrap installs pip from a hash-pinned wheel (docker/pip-bootstrap.txt, --require-hashes),
51
+ # so it does not depend on the TLS trust of the base image's older pip and certifi; the maintainer
52
+ # who raises the pip floor updates that pin and its sha256 (Dependabot does not track the file).
53
+ RUN pip install --no-cache-dir --require-hashes --only-binary=:all: -r /tmp/pip-bootstrap.txt && \
54
+ pip install --no-cache-dir .
55
+
56
+ # ─── Stage 2: Runtime ─────────────────────────────────────────────────────────
57
+ FROM python:3.14-slim@sha256:fbecd461fc72d21b2143c6eaba25143738079154a6d0ea3da3aec724f50eed4a AS runtime
58
+
59
+ # MCP Registry ownership check for the OCI package: must equal server.json "name".
60
+ # https://modelcontextprotocol.io/registry/package-types#docker%2Foci-images
61
+ LABEL io.modelcontextprotocol.server.name="io.github.christianclaudio/taxcode"
62
+
63
+ # OS trust store update and floor check, the same as the builder (see CA_CERTIFICATES_FLOOR).
64
+ ARG CA_CERTIFICATES_FLOOR
65
+ RUN apt-get update && \
66
+ apt-get install -y --no-install-recommends --only-upgrade ca-certificates && \
67
+ rm -rf /var/lib/apt/lists/* && \
68
+ installed="$(dpkg-query -W -f='${Version}' ca-certificates)" && \
69
+ { dpkg --compare-versions "$installed" ge "$CA_CERTIFICATES_FLOOR" || \
70
+ { echo "ca-certificates $installed is older than the floor $CA_CERTIFICATES_FLOOR" >&2; exit 1; }; }
71
+
72
+ # Security: run as non-root
73
+ RUN useradd --create-home --shell /bin/bash mcp
74
+ USER mcp
75
+ WORKDIR /home/mcp
76
+
77
+ # Copy the pre-built virtualenv from builder
78
+ COPY --from=builder /opt/venv /opt/venv
79
+ ENV PATH="/opt/venv/bin:$PATH"
80
+
81
+ # Default transport is stdio, so no port is exposed
82
+ ENTRYPOINT ["taxcode-mcp"]
83
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: mcp-server-taxcode
3
- Version: 0.7.1
3
+ Version: 0.8.0
4
4
  Summary: Enterprise Model Context Protocol (MCP) server for Tax Code
5
5
  Project-URL: Homepage, https://github.com/christianclaudio/mcp-server-taxcode
6
6
  Project-URL: Documentation, https://github.com/christianclaudio/mcp-server-taxcode#readme
@@ -20,18 +20,20 @@ Classifier: Programming Language :: Python :: 3.10
20
20
  Classifier: Programming Language :: Python :: 3.11
21
21
  Classifier: Programming Language :: Python :: 3.12
22
22
  Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
23
24
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
25
  Requires-Python: >=3.10
26
+ Requires-Dist: certifi>=2026.10.19
25
27
  Requires-Dist: duckdb>=1.5.6
26
- Requires-Dist: fastmcp>=4.1.0
28
+ Requires-Dist: fastmcp>=4.1.3
27
29
  Requires-Dist: httpx>=0.28.1
28
30
  Requires-Dist: mcp>=2.3.0
29
31
  Requires-Dist: pydantic-settings>=2.15.0
30
32
  Requires-Dist: pydantic>=2.13.5
31
33
  Provides-Extra: code-mode
32
- Requires-Dist: fastmcp[code-mode]>=4.1.0; extra == 'code-mode'
34
+ Requires-Dist: fastmcp[code-mode]>=4.1.3; extra == 'code-mode'
33
35
  Provides-Extra: dev
34
- Requires-Dist: fastmcp[code-mode]>=4.1.0; extra == 'dev'
36
+ Requires-Dist: fastmcp[code-mode]>=4.1.3; extra == 'dev'
35
37
  Requires-Dist: mypy>=2.4.0; extra == 'dev'
36
38
  Requires-Dist: opentelemetry-sdk>=1.45.1; extra == 'dev'
37
39
  Requires-Dist: pytest-asyncio>=1.4.0; extra == 'dev'
@@ -0,0 +1,18 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ Only the latest release receives security fixes. Upgrade to the newest version on [Releases](https://github.com/christianclaudio/mcp-server-taxcode/releases).
6
+
7
+ ## Outbound Connections and Proxies
8
+
9
+ Every outbound request (the upstream API client, the drift monitor's `--spec-url` fetch and `ingest_statutes.py --check-upstream`) goes through `SSRFSafeAsyncTransport`. It looks the host up once per request, checks every address against the private, loopback, link-local, reserved and metadata ranges, and connects only to a checked address, keeping the hostname for the Host header, TLS SNI and certificate verification. Redirects are not followed. httpx ignores env proxies whenever a transport is passed (httpx `AsyncClient`: `allow_env_proxies = trust_env and transport is None`), so connections always go direct through the pin; egress-proxy deployments need a proxy-aware transport, which isn't provided. `trust_env=False` on the drift fetch and the `--check-upstream` probe is belt-and-braces.
10
+
11
+ ## Reporting a Vulnerability
12
+
13
+ If you discover a security vulnerability, please do NOT open a public GitHub issue.
14
+
15
+ Please report vulnerabilities directly to the maintainer:
16
+ * **Email**: `christianclaudio@mail.com`
17
+
18
+ All reports will be acknowledged within 24 hours, and patches will be published with high priority.
@@ -0,0 +1,5 @@
1
+ # pip for the Dockerfile builder's bootstrap, installed with --require-hashes so the install
2
+ # does not depend on TLS trust. Hash of pip-26.2.2-py3-none-any.whl from PyPI's JSON API
3
+ # (digests.sha256). Bump this pin and hash together with the pip floor; Dependabot does not.
4
+ pip==26.2.2 \
5
+ --hash=sha256:fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70