docagent-cli 0.0.35__py3-none-any.whl

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 (300) hide show
  1. docagent_cli/__init__.py +36 -0
  2. docagent_cli/__main__.py +6 -0
  3. docagent_cli/_ask_user_types.py +90 -0
  4. docagent_cli/_cli_context.py +27 -0
  5. docagent_cli/_debug.py +52 -0
  6. docagent_cli/_env_vars.py +56 -0
  7. docagent_cli/_server_config.py +352 -0
  8. docagent_cli/_session_stats.py +114 -0
  9. docagent_cli/_testing_models.py +144 -0
  10. docagent_cli/_version.py +17 -0
  11. docagent_cli/agent.py +1193 -0
  12. docagent_cli/app.py +4979 -0
  13. docagent_cli/app.tcss +283 -0
  14. docagent_cli/ask_user.py +301 -0
  15. docagent_cli/built_in_skills/__init__.py +5 -0
  16. docagent_cli/built_in_skills/doc-coauthoring/SKILL.md +375 -0
  17. docagent_cli/built_in_skills/docx/LICENSE.txt +30 -0
  18. docagent_cli/built_in_skills/docx/SKILL.md +590 -0
  19. docagent_cli/built_in_skills/docx/scripts/__init__.py +1 -0
  20. docagent_cli/built_in_skills/docx/scripts/accept_changes.py +135 -0
  21. docagent_cli/built_in_skills/docx/scripts/comment.py +318 -0
  22. docagent_cli/built_in_skills/docx/scripts/office/helpers/__init__.py +0 -0
  23. docagent_cli/built_in_skills/docx/scripts/office/helpers/merge_runs.py +199 -0
  24. docagent_cli/built_in_skills/docx/scripts/office/helpers/simplify_redlines.py +197 -0
  25. docagent_cli/built_in_skills/docx/scripts/office/pack.py +159 -0
  26. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  27. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  28. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  29. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  30. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  31. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  32. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  33. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  34. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  35. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  36. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  37. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  38. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  39. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  40. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  41. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  42. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  43. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  44. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  45. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  46. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  47. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  48. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  49. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  50. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  51. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  52. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  53. docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  54. docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  55. docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  56. docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  57. docagent_cli/built_in_skills/docx/scripts/office/schemas/mce/mc.xsd +75 -0
  58. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  59. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  60. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  61. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  62. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  63. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  64. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  65. docagent_cli/built_in_skills/docx/scripts/office/soffice.py +183 -0
  66. docagent_cli/built_in_skills/docx/scripts/office/unpack.py +132 -0
  67. docagent_cli/built_in_skills/docx/scripts/office/validate.py +111 -0
  68. docagent_cli/built_in_skills/docx/scripts/office/validators/__init__.py +15 -0
  69. docagent_cli/built_in_skills/docx/scripts/office/validators/base.py +847 -0
  70. docagent_cli/built_in_skills/docx/scripts/office/validators/docx.py +446 -0
  71. docagent_cli/built_in_skills/docx/scripts/office/validators/pptx.py +275 -0
  72. docagent_cli/built_in_skills/docx/scripts/office/validators/redlining.py +247 -0
  73. docagent_cli/built_in_skills/docx/scripts/templates/comments.xml +3 -0
  74. docagent_cli/built_in_skills/docx/scripts/templates/commentsExtended.xml +3 -0
  75. docagent_cli/built_in_skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  76. docagent_cli/built_in_skills/docx/scripts/templates/commentsIds.xml +3 -0
  77. docagent_cli/built_in_skills/docx/scripts/templates/people.xml +3 -0
  78. docagent_cli/built_in_skills/pdf/LICENSE.txt +30 -0
  79. docagent_cli/built_in_skills/pdf/SKILL.md +314 -0
  80. docagent_cli/built_in_skills/pdf/forms.md +294 -0
  81. docagent_cli/built_in_skills/pdf/reference.md +612 -0
  82. docagent_cli/built_in_skills/pdf/scripts/check_bounding_boxes.py +65 -0
  83. docagent_cli/built_in_skills/pdf/scripts/check_fillable_fields.py +11 -0
  84. docagent_cli/built_in_skills/pdf/scripts/convert_pdf_to_images.py +33 -0
  85. docagent_cli/built_in_skills/pdf/scripts/create_validation_image.py +37 -0
  86. docagent_cli/built_in_skills/pdf/scripts/extract_form_field_info.py +122 -0
  87. docagent_cli/built_in_skills/pdf/scripts/extract_form_structure.py +115 -0
  88. docagent_cli/built_in_skills/pdf/scripts/fill_fillable_fields.py +98 -0
  89. docagent_cli/built_in_skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  90. docagent_cli/built_in_skills/pptx/LICENSE.txt +30 -0
  91. docagent_cli/built_in_skills/pptx/SKILL.md +232 -0
  92. docagent_cli/built_in_skills/pptx/editing.md +205 -0
  93. docagent_cli/built_in_skills/pptx/pptxgenjs.md +420 -0
  94. docagent_cli/built_in_skills/pptx/scripts/__init__.py +0 -0
  95. docagent_cli/built_in_skills/pptx/scripts/add_slide.py +195 -0
  96. docagent_cli/built_in_skills/pptx/scripts/clean.py +286 -0
  97. docagent_cli/built_in_skills/pptx/scripts/office/helpers/__init__.py +0 -0
  98. docagent_cli/built_in_skills/pptx/scripts/office/helpers/merge_runs.py +199 -0
  99. docagent_cli/built_in_skills/pptx/scripts/office/helpers/simplify_redlines.py +197 -0
  100. docagent_cli/built_in_skills/pptx/scripts/office/pack.py +159 -0
  101. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  102. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  103. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  104. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  105. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  106. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  107. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  108. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  109. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  110. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  111. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  112. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  113. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  114. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  115. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  116. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  117. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  118. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  119. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  120. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  121. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  122. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  123. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  124. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  125. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  126. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  127. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  128. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  129. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  130. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  131. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  132. docagent_cli/built_in_skills/pptx/scripts/office/schemas/mce/mc.xsd +75 -0
  133. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  134. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  135. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  136. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  137. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  138. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  139. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  140. docagent_cli/built_in_skills/pptx/scripts/office/soffice.py +183 -0
  141. docagent_cli/built_in_skills/pptx/scripts/office/unpack.py +132 -0
  142. docagent_cli/built_in_skills/pptx/scripts/office/validate.py +111 -0
  143. docagent_cli/built_in_skills/pptx/scripts/office/validators/__init__.py +15 -0
  144. docagent_cli/built_in_skills/pptx/scripts/office/validators/base.py +847 -0
  145. docagent_cli/built_in_skills/pptx/scripts/office/validators/docx.py +446 -0
  146. docagent_cli/built_in_skills/pptx/scripts/office/validators/pptx.py +275 -0
  147. docagent_cli/built_in_skills/pptx/scripts/office/validators/redlining.py +247 -0
  148. docagent_cli/built_in_skills/pptx/scripts/thumbnail.py +289 -0
  149. docagent_cli/built_in_skills/remember/SKILL.md +118 -0
  150. docagent_cli/built_in_skills/skill-creator/LICENSE.txt +202 -0
  151. docagent_cli/built_in_skills/skill-creator/SKILL.md +485 -0
  152. docagent_cli/built_in_skills/skill-creator/agents/analyzer.md +274 -0
  153. docagent_cli/built_in_skills/skill-creator/agents/comparator.md +202 -0
  154. docagent_cli/built_in_skills/skill-creator/agents/grader.md +223 -0
  155. docagent_cli/built_in_skills/skill-creator/assets/eval_review.html +146 -0
  156. docagent_cli/built_in_skills/skill-creator/eval-viewer/generate_review.py +471 -0
  157. docagent_cli/built_in_skills/skill-creator/eval-viewer/viewer.html +1325 -0
  158. docagent_cli/built_in_skills/skill-creator/references/schemas.md +430 -0
  159. docagent_cli/built_in_skills/skill-creator/scripts/__init__.py +0 -0
  160. docagent_cli/built_in_skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  161. docagent_cli/built_in_skills/skill-creator/scripts/generate_report.py +326 -0
  162. docagent_cli/built_in_skills/skill-creator/scripts/improve_description.py +247 -0
  163. docagent_cli/built_in_skills/skill-creator/scripts/package_skill.py +136 -0
  164. docagent_cli/built_in_skills/skill-creator/scripts/quick_validate.py +103 -0
  165. docagent_cli/built_in_skills/skill-creator/scripts/run_eval.py +310 -0
  166. docagent_cli/built_in_skills/skill-creator/scripts/run_loop.py +328 -0
  167. docagent_cli/built_in_skills/skill-creator/scripts/utils.py +47 -0
  168. docagent_cli/built_in_skills/theme-factory/LICENSE.txt +202 -0
  169. docagent_cli/built_in_skills/theme-factory/SKILL.md +59 -0
  170. docagent_cli/built_in_skills/theme-factory/theme-showcase.pdf +0 -0
  171. docagent_cli/built_in_skills/theme-factory/themes/arctic-frost.md +19 -0
  172. docagent_cli/built_in_skills/theme-factory/themes/botanical-garden.md +19 -0
  173. docagent_cli/built_in_skills/theme-factory/themes/desert-rose.md +19 -0
  174. docagent_cli/built_in_skills/theme-factory/themes/forest-canopy.md +19 -0
  175. docagent_cli/built_in_skills/theme-factory/themes/golden-hour.md +19 -0
  176. docagent_cli/built_in_skills/theme-factory/themes/midnight-galaxy.md +19 -0
  177. docagent_cli/built_in_skills/theme-factory/themes/modern-minimalist.md +19 -0
  178. docagent_cli/built_in_skills/theme-factory/themes/ocean-depths.md +19 -0
  179. docagent_cli/built_in_skills/theme-factory/themes/sunset-boulevard.md +19 -0
  180. docagent_cli/built_in_skills/theme-factory/themes/tech-innovation.md +19 -0
  181. docagent_cli/built_in_skills/xlsx/LICENSE.txt +30 -0
  182. docagent_cli/built_in_skills/xlsx/SKILL.md +292 -0
  183. docagent_cli/built_in_skills/xlsx/scripts/office/helpers/__init__.py +0 -0
  184. docagent_cli/built_in_skills/xlsx/scripts/office/helpers/merge_runs.py +199 -0
  185. docagent_cli/built_in_skills/xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
  186. docagent_cli/built_in_skills/xlsx/scripts/office/pack.py +159 -0
  187. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  188. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  189. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  190. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  191. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  192. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  193. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  194. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  195. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  196. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  197. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  198. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  199. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  200. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  201. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  202. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  203. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  204. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  205. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  206. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  207. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  208. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  209. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  210. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  211. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  212. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  213. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  214. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  215. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  216. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  217. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  218. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
  219. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  220. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  221. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  222. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  223. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  224. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  225. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  226. docagent_cli/built_in_skills/xlsx/scripts/office/soffice.py +183 -0
  227. docagent_cli/built_in_skills/xlsx/scripts/office/unpack.py +132 -0
  228. docagent_cli/built_in_skills/xlsx/scripts/office/validate.py +111 -0
  229. docagent_cli/built_in_skills/xlsx/scripts/office/validators/__init__.py +15 -0
  230. docagent_cli/built_in_skills/xlsx/scripts/office/validators/base.py +847 -0
  231. docagent_cli/built_in_skills/xlsx/scripts/office/validators/docx.py +446 -0
  232. docagent_cli/built_in_skills/xlsx/scripts/office/validators/pptx.py +275 -0
  233. docagent_cli/built_in_skills/xlsx/scripts/office/validators/redlining.py +247 -0
  234. docagent_cli/built_in_skills/xlsx/scripts/recalc.py +184 -0
  235. docagent_cli/clipboard.py +128 -0
  236. docagent_cli/command_registry.py +284 -0
  237. docagent_cli/config.py +2418 -0
  238. docagent_cli/configurable_model.py +162 -0
  239. docagent_cli/default_agent_prompt.md +12 -0
  240. docagent_cli/editor.py +142 -0
  241. docagent_cli/file_ops.py +473 -0
  242. docagent_cli/formatting.py +28 -0
  243. docagent_cli/hooks.py +206 -0
  244. docagent_cli/input.py +787 -0
  245. docagent_cli/integrations/__init__.py +1 -0
  246. docagent_cli/integrations/sandbox_factory.py +873 -0
  247. docagent_cli/integrations/sandbox_provider.py +71 -0
  248. docagent_cli/local_context.py +718 -0
  249. docagent_cli/main.py +1641 -0
  250. docagent_cli/mcp_tools.py +707 -0
  251. docagent_cli/mcp_trust.py +168 -0
  252. docagent_cli/media_utils.py +478 -0
  253. docagent_cli/model_config.py +1620 -0
  254. docagent_cli/non_interactive.py +948 -0
  255. docagent_cli/offload.py +371 -0
  256. docagent_cli/output.py +69 -0
  257. docagent_cli/project_utils.py +188 -0
  258. docagent_cli/py.typed +0 -0
  259. docagent_cli/remote_client.py +515 -0
  260. docagent_cli/server.py +520 -0
  261. docagent_cli/server_graph.py +196 -0
  262. docagent_cli/server_manager.py +365 -0
  263. docagent_cli/sessions.py +1262 -0
  264. docagent_cli/skills/__init__.py +18 -0
  265. docagent_cli/skills/commands.py +1090 -0
  266. docagent_cli/skills/load.py +192 -0
  267. docagent_cli/subagents.py +173 -0
  268. docagent_cli/system_prompt.md +247 -0
  269. docagent_cli/textual_adapter.py +1352 -0
  270. docagent_cli/theme.py +842 -0
  271. docagent_cli/token_state.py +31 -0
  272. docagent_cli/tool_display.py +298 -0
  273. docagent_cli/tools.py +236 -0
  274. docagent_cli/ui.py +420 -0
  275. docagent_cli/unicode_security.py +516 -0
  276. docagent_cli/update_check.py +454 -0
  277. docagent_cli/widgets/__init__.py +9 -0
  278. docagent_cli/widgets/_links.py +63 -0
  279. docagent_cli/widgets/approval.py +442 -0
  280. docagent_cli/widgets/ask_user.py +398 -0
  281. docagent_cli/widgets/autocomplete.py +691 -0
  282. docagent_cli/widgets/chat_input.py +1827 -0
  283. docagent_cli/widgets/diff.py +248 -0
  284. docagent_cli/widgets/history.py +188 -0
  285. docagent_cli/widgets/loading.py +177 -0
  286. docagent_cli/widgets/mcp_viewer.py +362 -0
  287. docagent_cli/widgets/message_store.py +675 -0
  288. docagent_cli/widgets/messages.py +1751 -0
  289. docagent_cli/widgets/model_selector.py +964 -0
  290. docagent_cli/widgets/status.py +372 -0
  291. docagent_cli/widgets/theme_selector.py +164 -0
  292. docagent_cli/widgets/thread_selector.py +1905 -0
  293. docagent_cli/widgets/tool_renderers.py +148 -0
  294. docagent_cli/widgets/tool_widgets.py +274 -0
  295. docagent_cli/widgets/welcome.py +339 -0
  296. docagent_cli-0.0.35.data/data/docagent_cli/default_agent_prompt.md +12 -0
  297. docagent_cli-0.0.35.dist-info/METADATA +200 -0
  298. docagent_cli-0.0.35.dist-info/RECORD +300 -0
  299. docagent_cli-0.0.35.dist-info/WHEEL +4 -0
  300. docagent_cli-0.0.35.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,707 @@
1
+ """MCP (Model Context Protocol) tools loader for docagent CLI.
2
+
3
+ This module provides async functions to load and manage MCP servers using
4
+ `langchain-mcp-adapters`, supporting Claude Desktop style JSON configs.
5
+ It also supports automatic discovery of `.mcp.json` files from user-level
6
+ and project-level locations.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import logging
13
+ import shutil
14
+ from contextlib import AsyncExitStack
15
+ from dataclasses import dataclass, field
16
+ from pathlib import Path
17
+ from typing import TYPE_CHECKING, Any
18
+
19
+ if TYPE_CHECKING:
20
+ from langchain_core.tools import BaseTool
21
+ from langchain_mcp_adapters.client import Connection, MultiServerMCPClient
22
+
23
+ from docagent_cli.project_utils import ProjectContext
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ @dataclass
29
+ class MCPToolInfo:
30
+ """Metadata for a single MCP tool."""
31
+
32
+ name: str
33
+ """Tool name (may include server name prefix)."""
34
+
35
+ description: str
36
+ """Human-readable description of what the tool does."""
37
+
38
+
39
+ @dataclass
40
+ class MCPServerInfo:
41
+ """Metadata for a connected MCP server and its tools."""
42
+
43
+ name: str
44
+ """Server name from the MCP configuration."""
45
+
46
+ transport: str
47
+ """Transport type (`stdio`, `sse`, or `http`)."""
48
+
49
+ tools: list[MCPToolInfo] = field(default_factory=list)
50
+ """Tools exposed by this server."""
51
+
52
+
53
+ _SUPPORTED_REMOTE_TYPES = {"sse", "http"}
54
+ """Supported transport types for remote MCP servers (SSE and HTTP)."""
55
+
56
+
57
+ def _resolve_server_type(server_config: dict[str, Any]) -> str:
58
+ """Determine the transport type for a server config.
59
+
60
+ Supports both `type` and `transport` field names, defaulting to `stdio`.
61
+
62
+ Args:
63
+ server_config: Server configuration dictionary.
64
+
65
+ Returns:
66
+ Transport type string (`stdio`, `sse`, or `http`).
67
+ """
68
+ t = server_config.get("type")
69
+ if t is not None:
70
+ return t
71
+ return server_config.get("transport", "stdio")
72
+
73
+
74
+ def _validate_server_config(server_name: str, server_config: dict[str, Any]) -> None:
75
+ """Validate a single server configuration.
76
+
77
+ Args:
78
+ server_name: Name of the server.
79
+ server_config: Server configuration dictionary.
80
+
81
+ Raises:
82
+ TypeError: If config fields have wrong types.
83
+ ValueError: If required fields are missing or server type is unsupported.
84
+ """
85
+ if not isinstance(server_config, dict):
86
+ error_msg = f"Server '{server_name}' config must be a dictionary"
87
+ raise TypeError(error_msg)
88
+
89
+ server_type = _resolve_server_type(server_config)
90
+
91
+ if server_type in _SUPPORTED_REMOTE_TYPES:
92
+ # SSE/HTTP server validation - requires url field
93
+ if "url" not in server_config:
94
+ error_msg = (
95
+ f"Server '{server_name}' with type '{server_type}'"
96
+ " missing required 'url' field"
97
+ )
98
+ raise ValueError(error_msg)
99
+
100
+ # headers is optional but must be correct type if present
101
+ headers = server_config.get("headers")
102
+ if headers is not None and not isinstance(headers, dict):
103
+ error_msg = f"Server '{server_name}' 'headers' must be a dictionary"
104
+ raise TypeError(error_msg)
105
+ elif server_type == "stdio":
106
+ # stdio server validation
107
+ if "command" not in server_config:
108
+ error_msg = f"Server '{server_name}' missing required 'command' field"
109
+ raise ValueError(error_msg)
110
+
111
+ # args and env are optional but must be correct type if present
112
+ if "args" in server_config and not isinstance(server_config["args"], list):
113
+ error_msg = f"Server '{server_name}' 'args' must be a list"
114
+ raise TypeError(error_msg)
115
+
116
+ if "env" in server_config and not isinstance(server_config["env"], dict):
117
+ error_msg = f"Server '{server_name}' 'env' must be a dictionary"
118
+ raise TypeError(error_msg)
119
+ else:
120
+ error_msg = (
121
+ f"Server '{server_name}' has unsupported transport type '{server_type}'. "
122
+ "Supported types: stdio, sse, http"
123
+ )
124
+ raise ValueError(error_msg)
125
+
126
+
127
+ def load_mcp_config(config_path: str) -> dict[str, Any]:
128
+ """Load and validate MCP configuration from JSON file.
129
+
130
+ Supports multiple server types:
131
+
132
+ - stdio: Process-based servers with `command`, `args`, `env` fields (default)
133
+ - sse: Server-Sent Events servers with `type: "sse"`, `url`, and optional `headers`
134
+ - http: HTTP-based servers with `type: "http"`, `url`, and optional `headers`
135
+
136
+ Args:
137
+ config_path: Path to MCP JSON configuration file (Claude Desktop format).
138
+
139
+ Returns:
140
+ Parsed configuration dictionary.
141
+
142
+ Raises:
143
+ FileNotFoundError: If config file doesn't exist.
144
+ json.JSONDecodeError: If config file contains invalid JSON.
145
+ TypeError: If config fields have wrong types.
146
+ ValueError: If config is missing required fields.
147
+ """
148
+ path = Path(config_path)
149
+
150
+ if not path.exists():
151
+ error_msg = f"MCP config file not found: {config_path}"
152
+ raise FileNotFoundError(error_msg)
153
+
154
+ try:
155
+ with path.open(encoding="utf-8") as f:
156
+ config = json.load(f)
157
+ except json.JSONDecodeError as e:
158
+ error_msg = f"Invalid JSON in MCP config file: {e.msg}"
159
+ raise json.JSONDecodeError(error_msg, e.doc, e.pos) from e
160
+
161
+ # Validate required fields
162
+ if "mcpServers" not in config:
163
+ error_msg = (
164
+ "MCP config must contain 'mcpServers' field. "
165
+ 'Expected format: {"mcpServers": {"server-name": {...}}}'
166
+ )
167
+ raise ValueError(error_msg)
168
+
169
+ if not isinstance(config["mcpServers"], dict):
170
+ error_msg = "'mcpServers' field must be a dictionary"
171
+ raise TypeError(error_msg)
172
+
173
+ if not config["mcpServers"]:
174
+ error_msg = "'mcpServers' field is empty - no servers configured"
175
+ raise ValueError(error_msg)
176
+
177
+ # Validate each server config
178
+ for server_name, server_config in config["mcpServers"].items():
179
+ _validate_server_config(server_name, server_config)
180
+
181
+ return config
182
+
183
+
184
+ def _resolve_project_config_base(project_context: ProjectContext | None) -> Path:
185
+ """Resolve the base directory for project-level MCP configuration lookup.
186
+
187
+ Args:
188
+ project_context: Explicit project path context, if available.
189
+
190
+ Returns:
191
+ Project root when one exists, otherwise the user working directory.
192
+ """
193
+ if project_context is not None:
194
+ return project_context.project_root or project_context.user_cwd
195
+
196
+ from docagent_cli.project_utils import find_project_root
197
+
198
+ return find_project_root() or Path.cwd()
199
+
200
+
201
+ def discover_mcp_configs(
202
+ *, project_context: ProjectContext | None = None
203
+ ) -> list[Path]:
204
+ """Find MCP config files from standard locations.
205
+
206
+ Checks three paths in precedence order (lowest to highest):
207
+
208
+ 1. `~/.docagent/.mcp.json` (user-level global)
209
+ 2. `<project-root>/.docagent/.mcp.json` (project subdir)
210
+ 3. `<project-root>/.mcp.json` (project root, Claude Code compat)
211
+
212
+ Project root is determined from `project_context` when provided, otherwise
213
+ by `find_project_root()`, falling back to CWD.
214
+
215
+ Returns:
216
+ List of existing config file paths, ordered lowest-to-highest precedence.
217
+ """
218
+ user_dir = Path.home() / ".docagent"
219
+ project_root = _resolve_project_config_base(project_context)
220
+
221
+ candidates = [
222
+ user_dir / ".mcp.json",
223
+ project_root / ".docagent" / ".mcp.json",
224
+ project_root / ".mcp.json",
225
+ ]
226
+
227
+ found: list[Path] = []
228
+ for path in candidates:
229
+ try:
230
+ if path.is_file():
231
+ found.append(path)
232
+ except OSError:
233
+ logger.warning("Could not check MCP config %s", path, exc_info=True)
234
+ return found
235
+
236
+
237
+ def classify_discovered_configs(
238
+ config_paths: list[Path],
239
+ ) -> tuple[list[Path], list[Path]]:
240
+ """Split discovered config paths into user-level and project-level.
241
+
242
+ User-level configs live under `~/.docagent/`. Everything else is
243
+ considered project-level.
244
+
245
+ Args:
246
+ config_paths: Paths returned by `discover_mcp_configs`.
247
+
248
+ Returns:
249
+ Tuple of `(user_configs, project_configs)`.
250
+ """
251
+ user_dir = Path.home() / ".docagent"
252
+ user: list[Path] = []
253
+ project: list[Path] = []
254
+ for path in config_paths:
255
+ try:
256
+ if path.resolve().is_relative_to(user_dir.resolve()):
257
+ user.append(path)
258
+ else:
259
+ project.append(path)
260
+ except (OSError, ValueError):
261
+ project.append(path)
262
+ return user, project
263
+
264
+
265
+ def extract_stdio_server_commands(
266
+ config: dict[str, Any],
267
+ ) -> list[tuple[str, str, list[str]]]:
268
+ """Extract stdio server entries from a parsed MCP config.
269
+
270
+ Args:
271
+ config: Parsed MCP config dict with `mcpServers` key.
272
+
273
+ Returns:
274
+ List of `(server_name, command, args)` for each stdio server.
275
+ """
276
+ results: list[tuple[str, str, list[str]]] = []
277
+ servers = config.get("mcpServers", {})
278
+ if not isinstance(servers, dict):
279
+ return results
280
+ for name, srv in servers.items():
281
+ if not isinstance(srv, dict):
282
+ continue
283
+ if _resolve_server_type(srv) == "stdio":
284
+ results.append((name, srv.get("command", ""), srv.get("args", [])))
285
+ return results
286
+
287
+
288
+ def _filter_project_stdio_servers(config: dict[str, Any]) -> dict[str, Any]:
289
+ """Return a copy of *config* with stdio servers removed.
290
+
291
+ Remote (SSE/HTTP) servers are kept because they don't execute local code.
292
+
293
+ Args:
294
+ config: Parsed MCP config dict.
295
+
296
+ Returns:
297
+ Filtered config dict.
298
+ """
299
+ servers = config.get("mcpServers", {})
300
+ if not isinstance(servers, dict):
301
+ return config
302
+ filtered = {
303
+ name: srv
304
+ for name, srv in servers.items()
305
+ if isinstance(srv, dict) and _resolve_server_type(srv) != "stdio"
306
+ }
307
+ return {"mcpServers": filtered}
308
+
309
+
310
+ def merge_mcp_configs(configs: list[dict[str, Any]]) -> dict[str, Any]:
311
+ """Merge multiple MCP config dicts by server name.
312
+
313
+ Later entries override earlier ones for the same server name
314
+ (simple `dict.update` on `mcpServers`).
315
+
316
+ Args:
317
+ configs: Ordered list of parsed config dicts (each with `mcpServers` key).
318
+
319
+ Returns:
320
+ Merged config with combined `mcpServers`.
321
+ """
322
+ merged: dict[str, Any] = {}
323
+ for cfg in configs:
324
+ servers = cfg.get("mcpServers")
325
+ if isinstance(servers, dict):
326
+ merged.update(servers)
327
+ return {"mcpServers": merged}
328
+
329
+
330
+ def load_mcp_config_lenient(config_path: Path) -> dict[str, Any] | None:
331
+ """Load an MCP config file, returning None on any error.
332
+
333
+ Wraps `load_mcp_config` with lenient error handling suitable for
334
+ auto-discovery. Missing files are skipped silently; parse and validation
335
+ errors are logged as warnings.
336
+
337
+ Args:
338
+ config_path: Path to the MCP config file.
339
+
340
+ Returns:
341
+ Parsed config dict, or None if the file is missing or invalid.
342
+ """
343
+ try:
344
+ return load_mcp_config(str(config_path))
345
+ except FileNotFoundError:
346
+ return None
347
+ except OSError as e:
348
+ logger.warning("Skipping unreadable MCP config %s: %s", config_path, e)
349
+ return None
350
+ except (json.JSONDecodeError, ValueError, TypeError) as e:
351
+ logger.warning("Skipping invalid MCP config %s: %s", config_path, e)
352
+ return None
353
+
354
+
355
+ class MCPSessionManager:
356
+ """Manages persistent MCP sessions for stateful stdio servers.
357
+
358
+ This manager creates and maintains persistent sessions for stdio MCP
359
+ servers, preventing server restarts on every tool call. Sessions are kept
360
+ alive until explicitly cleaned up.
361
+ """
362
+
363
+ def __init__(self) -> None:
364
+ """Initialize the session manager."""
365
+ self.client: MultiServerMCPClient | None = None
366
+ self.exit_stack = AsyncExitStack()
367
+
368
+ async def cleanup(self) -> None:
369
+ """Clean up all managed sessions and close connections."""
370
+ await self.exit_stack.aclose()
371
+
372
+
373
+ def _check_stdio_server(server_name: str, server_config: dict[str, Any]) -> None:
374
+ """Verify that a stdio server's command exists on PATH.
375
+
376
+ Args:
377
+ server_name: Name of the server (for error messages).
378
+ server_config: Server configuration dictionary with `command` key.
379
+
380
+ Raises:
381
+ RuntimeError: If the command is missing from config or not found on PATH.
382
+ """
383
+ command = server_config.get("command")
384
+ if command is None:
385
+ msg = f"MCP server '{server_name}': missing 'command' in config."
386
+ raise RuntimeError(msg)
387
+ if shutil.which(command) is None:
388
+ msg = (
389
+ f"MCP server '{server_name}': command '{command}' not found on PATH. "
390
+ "Install it or check your MCP config."
391
+ )
392
+ raise RuntimeError(msg)
393
+
394
+
395
+ async def _check_remote_server(server_name: str, server_config: dict[str, Any]) -> None:
396
+ """Check network connectivity to a remote MCP server URL.
397
+
398
+ Sends a lightweight HEAD request with a 2-second timeout to detect DNS
399
+ failures, refused connections, and network timeouts early, before the MCP
400
+ session handshake. HTTP error responses (4xx, 5xx) are not treated as
401
+ failures — only transport errors, invalid URLs, and OS-level socket
402
+ errors raise.
403
+
404
+ Args:
405
+ server_name: Name of the server (for error messages).
406
+ server_config: Server configuration dictionary with `url` key.
407
+
408
+ Raises:
409
+ RuntimeError: If the server URL is unreachable or invalid.
410
+ """
411
+ import httpx
412
+
413
+ url = server_config.get("url")
414
+ if url is None:
415
+ msg = f"MCP server '{server_name}': missing 'url' in config."
416
+ raise RuntimeError(msg)
417
+ try:
418
+ async with httpx.AsyncClient() as client:
419
+ await client.head(url, timeout=2)
420
+ except (httpx.TransportError, httpx.InvalidURL, OSError) as exc:
421
+ msg = (
422
+ f"MCP server '{server_name}': URL '{url}' is unreachable: {exc}. "
423
+ "Check that the URL is correct and the server is running."
424
+ )
425
+ raise RuntimeError(msg) from exc
426
+
427
+
428
+ async def _load_tools_from_config(
429
+ config: dict[str, Any],
430
+ ) -> tuple[list[BaseTool], MCPSessionManager, list[MCPServerInfo]]:
431
+ """Build MCP connections from a validated config and load tools.
432
+
433
+ This is the shared implementation used by both `get_mcp_tools` (explicit
434
+ path) and `resolve_and_load_mcp_tools` (auto-discovery).
435
+
436
+ Args:
437
+ config: Validated MCP configuration dict with `mcpServers` key.
438
+
439
+ Returns:
440
+ Tuple of `(tools_list, session_manager, server_infos)`.
441
+
442
+ Raises:
443
+ RuntimeError: If MCP server fails to spawn or connect.
444
+ """
445
+ from langchain_mcp_adapters.client import MultiServerMCPClient
446
+ from langchain_mcp_adapters.sessions import (
447
+ SSEConnection,
448
+ StdioConnection,
449
+ StreamableHttpConnection,
450
+ )
451
+ from langchain_mcp_adapters.tools import load_mcp_tools
452
+
453
+ # Pre-flight health checks (best-effort early detection; the session setup
454
+ # below has its own error handling for TOCTOU races).
455
+ errors: list[str] = []
456
+ for server_name, server_config in config["mcpServers"].items():
457
+ server_type = _resolve_server_type(server_config)
458
+ try:
459
+ if server_type in _SUPPORTED_REMOTE_TYPES:
460
+ await _check_remote_server(server_name, server_config)
461
+ elif server_type == "stdio":
462
+ _check_stdio_server(server_name, server_config)
463
+ except RuntimeError as exc:
464
+ errors.append(str(exc))
465
+ if errors:
466
+ msg = "Pre-flight health check(s) failed:\n" + "\n".join(
467
+ f" - {e}" for e in errors
468
+ )
469
+ raise RuntimeError(msg)
470
+
471
+ # Create connections dict for MultiServerMCPClient
472
+ # Convert Claude Desktop format to langchain-mcp-adapters format
473
+ connections: dict[str, Connection] = {}
474
+ for server_name, server_config in config["mcpServers"].items():
475
+ server_type = _resolve_server_type(server_config)
476
+
477
+ if server_type in _SUPPORTED_REMOTE_TYPES:
478
+ # langchain-mcp-adapters uses "streamable_http" for HTTP transport
479
+ if server_type == "http":
480
+ conn: Connection = StreamableHttpConnection(
481
+ transport="streamable_http",
482
+ url=server_config["url"],
483
+ )
484
+ else:
485
+ conn = SSEConnection(
486
+ transport="sse",
487
+ url=server_config["url"],
488
+ )
489
+ if "headers" in server_config:
490
+ conn["headers"] = server_config["headers"]
491
+ connections[server_name] = conn
492
+ else:
493
+ # stdio server connection (default)
494
+ connections[server_name] = StdioConnection(
495
+ command=server_config["command"],
496
+ args=server_config.get("args", []),
497
+ env=server_config.get("env") or None,
498
+ transport="stdio",
499
+ )
500
+
501
+ # Create session manager to track persistent sessions
502
+ manager = MCPSessionManager()
503
+
504
+ try:
505
+ client = MultiServerMCPClient(connections=connections)
506
+ manager.client = client
507
+ except Exception as e:
508
+ await manager.cleanup()
509
+ error_msg = f"Failed to initialize MCP client: {e}"
510
+ raise RuntimeError(error_msg) from e
511
+
512
+ try:
513
+ all_tools: list[BaseTool] = []
514
+ server_infos: list[MCPServerInfo] = []
515
+ for server_name, server_config in config["mcpServers"].items():
516
+ session = await manager.exit_stack.enter_async_context(
517
+ client.session(server_name)
518
+ )
519
+ tools = await load_mcp_tools(
520
+ session, server_name=server_name, tool_name_prefix=True
521
+ )
522
+ all_tools.extend(tools)
523
+ server_infos.append(
524
+ MCPServerInfo(
525
+ name=server_name,
526
+ transport=_resolve_server_type(server_config),
527
+ tools=[
528
+ MCPToolInfo(name=t.name, description=t.description or "")
529
+ for t in tools
530
+ ],
531
+ )
532
+ )
533
+ except Exception as e:
534
+ await manager.cleanup()
535
+ error_msg = (
536
+ f"Failed to load tools from MCP server '{server_name}': {e}\n"
537
+ "For stdio servers: Check that the command and args are correct,"
538
+ " and that the MCP server is installed"
539
+ " (e.g., run 'npx -y <package>' manually to test).\n"
540
+ "For sse/http servers: Check that the URL is correct"
541
+ " and the server is running."
542
+ )
543
+ raise RuntimeError(error_msg) from e
544
+
545
+ return all_tools, manager, server_infos
546
+
547
+
548
+ async def get_mcp_tools(
549
+ config_path: str,
550
+ ) -> tuple[list[BaseTool], MCPSessionManager, list[MCPServerInfo]]:
551
+ """Load MCP tools from configuration file with stateful sessions.
552
+
553
+ Supports multiple server types:
554
+ - stdio: Spawns MCP servers as subprocesses with persistent sessions
555
+ - sse/http: Connects to remote MCP servers via URL
556
+
557
+ For stdio servers, this creates persistent sessions that remain active
558
+ across tool calls, avoiding server restarts. Sessions are managed by
559
+ `MCPSessionManager` and should be cleaned up with
560
+ `session_manager.cleanup()` when done.
561
+
562
+ Args:
563
+ config_path: Path to MCP JSON configuration file.
564
+
565
+ Returns:
566
+ Tuple of `(tools_list, session_manager, server_infos)` where:
567
+ - tools_list: List of LangChain `BaseTool` objects
568
+ - session_manager: `MCPSessionManager` instance
569
+ (call `cleanup()` when done)
570
+ - server_infos: List of `MCPServerInfo` with per-server metadata
571
+ """
572
+ config = load_mcp_config(config_path)
573
+ return await _load_tools_from_config(config)
574
+
575
+
576
+ async def resolve_and_load_mcp_tools(
577
+ *,
578
+ explicit_config_path: str | None = None,
579
+ no_mcp: bool = False,
580
+ trust_project_mcp: bool | None = None,
581
+ project_context: ProjectContext | None = None,
582
+ ) -> tuple[list[BaseTool], MCPSessionManager | None, list[MCPServerInfo]]:
583
+ """Resolve MCP config and load tools.
584
+
585
+ Auto-discovers configs from standard locations and merges them.
586
+ When `explicit_config_path` is provided it is added as the
587
+ highest-precedence source (errors in that file are fatal).
588
+
589
+ Args:
590
+ explicit_config_path: Extra config file to layer on top of
591
+ auto-discovered configs (highest precedence). Errors are
592
+ fatal.
593
+ no_mcp: If True, disable all MCP loading.
594
+ trust_project_mcp: Controls project-level stdio server trust:
595
+
596
+ - `True`: allow all project stdio servers (flag/prompt approved).
597
+ - `False`: filter out project stdio servers, log warning.
598
+ - `None` (default): check the persistent trust store; if the
599
+ fingerprint matches, allow; otherwise filter + warn.
600
+ project_context: Explicit project path context for config discovery
601
+ and trust resolution.
602
+
603
+ Returns:
604
+ Tuple of `(tools_list, session_manager, server_infos)`.
605
+
606
+ When no tools are loaded, returns `([], None, [])`.
607
+
608
+ Raises:
609
+ RuntimeError: If an MCP server config is invalid or fails to
610
+ spawn/connect.
611
+ """
612
+ if no_mcp:
613
+ return [], None, []
614
+
615
+ # Auto-discovery
616
+ try:
617
+ config_paths = discover_mcp_configs(project_context=project_context)
618
+ except (OSError, RuntimeError):
619
+ logger.warning("MCP config auto-discovery failed", exc_info=True)
620
+ config_paths = []
621
+
622
+ # Classify discovered configs and apply trust filtering
623
+ user_configs, project_configs = classify_discovered_configs(config_paths)
624
+
625
+ configs: list[dict[str, Any]] = []
626
+
627
+ # User-level configs are always trusted
628
+ for path in user_configs:
629
+ cfg = load_mcp_config_lenient(path)
630
+ if cfg is not None:
631
+ configs.append(cfg)
632
+
633
+ # Project-level configs need trust gating for stdio servers
634
+ for path in project_configs:
635
+ cfg = load_mcp_config_lenient(path)
636
+ if cfg is None:
637
+ continue
638
+
639
+ stdio_servers = extract_stdio_server_commands(cfg)
640
+ if not stdio_servers:
641
+ # No stdio servers — safe to load (remote only)
642
+ configs.append(cfg)
643
+ continue
644
+
645
+ if trust_project_mcp is True:
646
+ configs.append(cfg)
647
+ elif trust_project_mcp is False:
648
+ filtered = _filter_project_stdio_servers(cfg)
649
+ if filtered.get("mcpServers"):
650
+ configs.append(filtered)
651
+ skipped = [
652
+ f"{name}: {cmd} {' '.join(args)}" for name, cmd, args in stdio_servers
653
+ ]
654
+ logger.warning(
655
+ "Skipped untrusted project stdio MCP servers: %s",
656
+ "; ".join(skipped),
657
+ )
658
+ else:
659
+ # None — check trust store
660
+ from docagent_cli.mcp_trust import (
661
+ compute_config_fingerprint,
662
+ is_project_mcp_trusted,
663
+ )
664
+
665
+ project_root = str(_resolve_project_config_base(project_context).resolve())
666
+ fingerprint = compute_config_fingerprint(project_configs)
667
+ if is_project_mcp_trusted(project_root, fingerprint):
668
+ configs.append(cfg)
669
+ else:
670
+ filtered = _filter_project_stdio_servers(cfg)
671
+ if filtered.get("mcpServers"):
672
+ configs.append(filtered)
673
+ skipped = [
674
+ f"{name}: {cmd} {' '.join(args)}"
675
+ for name, cmd, args in stdio_servers
676
+ ]
677
+ logger.warning(
678
+ "Skipped untrusted project stdio MCP servers "
679
+ "(config changed or not yet approved): %s",
680
+ "; ".join(skipped),
681
+ )
682
+
683
+ # Explicit path is highest precedence — errors are fatal
684
+ if explicit_config_path:
685
+ config_path = (
686
+ str(project_context.resolve_user_path(explicit_config_path))
687
+ if project_context is not None
688
+ else explicit_config_path
689
+ )
690
+ configs.append(load_mcp_config(config_path))
691
+
692
+ if not configs:
693
+ return [], None, []
694
+
695
+ merged = merge_mcp_configs(configs)
696
+ if not merged.get("mcpServers"):
697
+ return [], None, []
698
+
699
+ # Validate each server in the merged config
700
+ try:
701
+ for server_name, server_config in merged["mcpServers"].items():
702
+ _validate_server_config(server_name, server_config)
703
+ except (TypeError, ValueError) as e:
704
+ msg = f"Invalid MCP server configuration: {e}"
705
+ raise RuntimeError(msg) from e
706
+
707
+ return await _load_tools_from_config(merged)