testmcpy 0.3.1__tar.gz → 0.3.2__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 (178) hide show
  1. {testmcpy-0.3.1/testmcpy.egg-info → testmcpy-0.3.2}/PKG-INFO +1 -1
  2. {testmcpy-0.3.1 → testmcpy-0.3.2}/pyproject.toml +1 -1
  3. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/__init__.py +1 -1
  4. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/evals/base_evaluators.py +12 -4
  5. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/test_runner.py +15 -18
  6. {testmcpy-0.3.1 → testmcpy-0.3.2/testmcpy.egg-info}/PKG-INFO +1 -1
  7. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy.egg-info/SOURCES.txt +0 -3
  8. testmcpy-0.3.1/testmcpy/ui/dist/assets/index-B1_waOsr.js +0 -289
  9. testmcpy-0.3.1/testmcpy/ui/dist/assets/index-Do693nG2.css +0 -1
  10. testmcpy-0.3.1/testmcpy/ui/dist/index.html +0 -22
  11. {testmcpy-0.3.1 → testmcpy-0.3.2}/LICENSE +0 -0
  12. {testmcpy-0.3.1 → testmcpy-0.3.2}/MANIFEST.in +0 -0
  13. {testmcpy-0.3.1 → testmcpy-0.3.2}/NOTICE +0 -0
  14. {testmcpy-0.3.1 → testmcpy-0.3.2}/README.md +0 -0
  15. {testmcpy-0.3.1 → testmcpy-0.3.2}/setup.cfg +0 -0
  16. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/agent/__init__.py +0 -0
  17. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/agent/hooks.py +0 -0
  18. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/agent/models.py +0 -0
  19. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/agent/orchestrator.py +0 -0
  20. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/agent/prompts.py +0 -0
  21. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/agent/tools.py +0 -0
  22. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/auth_debugger.py +0 -0
  23. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/auth_flow_recorder.py +0 -0
  24. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/__init__.py +0 -0
  25. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/app.py +0 -0
  26. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/__init__.py +0 -0
  27. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/agent.py +0 -0
  28. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/baseline.py +0 -0
  29. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/export_db.py +0 -0
  30. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/mcp.py +0 -0
  31. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/metamorphic.py +0 -0
  32. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/multi_env.py +0 -0
  33. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/mutate.py +0 -0
  34. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/push.py +0 -0
  35. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/run.py +0 -0
  36. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/server.py +0 -0
  37. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/tools.py +0 -0
  38. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/tui.py +0 -0
  39. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/cli/commands/wizard.py +0 -0
  40. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/config.py +0 -0
  41. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/core/__init__.py +0 -0
  42. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/core/chat_session.py +0 -0
  43. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/core/docs_optimizer.py +0 -0
  44. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/core/mcp_manager.py +0 -0
  45. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/core/tool_comparison.py +0 -0
  46. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/core/tool_discovery.py +0 -0
  47. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/db.py +0 -0
  48. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/error_handlers.py +0 -0
  49. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/evals/__init__.py +0 -0
  50. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/evals/auth_evaluators.py +0 -0
  51. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/evals/evaluator_packs.py +0 -0
  52. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/__init__.py +0 -0
  53. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/base.py +0 -0
  54. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/curl.py +0 -0
  55. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/graphql.py +0 -0
  56. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/javascript_client.py +0 -0
  57. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/json_yaml.py +0 -0
  58. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/protobuf.py +0 -0
  59. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/python.py +0 -0
  60. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/python_client.py +0 -0
  61. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/thrift.py +0 -0
  62. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/typescript.py +0 -0
  63. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/formatters/typescript_client.py +0 -0
  64. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/llm_profiles.py +0 -0
  65. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/mcp_profiles.py +0 -0
  66. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/migrate_json.py +0 -0
  67. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/models.py +0 -0
  68. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/research/claude_sdk_detailed_exploration.py +0 -0
  69. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/research/claude_sdk_poc.py +0 -0
  70. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/research/claude_sdk_working_poc.py +0 -0
  71. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/research/test_ollama_tools.py +0 -0
  72. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/__init__.py +0 -0
  73. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/api.py +0 -0
  74. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/api.py.bak +0 -0
  75. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/auth_middleware.py +0 -0
  76. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/helpers/__init__.py +0 -0
  77. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/helpers/mcp_config.py +0 -0
  78. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/models.py +0 -0
  79. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/__init__.py +0 -0
  80. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/agent.py +0 -0
  81. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/auth.py +0 -0
  82. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/compare.py +0 -0
  83. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/compatibility.py +0 -0
  84. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/generation_logs.py +0 -0
  85. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/health.py +0 -0
  86. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/llm.py +0 -0
  87. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/mcp_profiles.py +0 -0
  88. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/metrics.py +0 -0
  89. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/results.py +0 -0
  90. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/search.py +0 -0
  91. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/security.py +0 -0
  92. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/smoke_reports.py +0 -0
  93. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/test_profiles.py +0 -0
  94. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/tests.py +0 -0
  95. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/routers/tools.py +0 -0
  96. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/state.py +0 -0
  97. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/server/websocket.py +0 -0
  98. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/smoke_test.py +0 -0
  99. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/__init__.py +0 -0
  100. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/baseline.py +0 -0
  101. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/ci_gate.py +0 -0
  102. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/comparison_runner.py +0 -0
  103. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/coverage_analyzer.py +0 -0
  104. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/html_report.py +0 -0
  105. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/llm_integration.py +0 -0
  106. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/mcp_client.py +0 -0
  107. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/metamorphic.py +0 -0
  108. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/model_registry.py +0 -0
  109. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/models.py +0 -0
  110. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/multi_env.py +0 -0
  111. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/oauth_flows.py +0 -0
  112. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/prompt_mutation.py +0 -0
  113. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/report_generator.py +0 -0
  114. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/runner_tools.py +0 -0
  115. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/schema_diff.py +0 -0
  116. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/src/token_manager.py +0 -0
  117. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/storage.py +0 -0
  118. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/test_profiles.py +0 -0
  119. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/README.md +0 -0
  120. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/index.html +0 -0
  121. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/package-lock.json +0 -0
  122. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/package.json +0 -0
  123. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/postcss.config.js +0 -0
  124. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/App.jsx +0 -0
  125. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/CommandPalette.jsx +0 -0
  126. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/CompareToolsTab.jsx +0 -0
  127. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/ErrorAlert.jsx +0 -0
  128. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/ErrorBoundary.jsx +0 -0
  129. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/LLMProfileSelector.jsx +0 -0
  130. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/LoadingSpinner.jsx +0 -0
  131. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/MCPProfileSelector.jsx +0 -0
  132. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/NotificationProvider.jsx +0 -0
  133. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/OptimizeDocsModal.jsx +0 -0
  134. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/OutputDiff.jsx +0 -0
  135. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/ParameterCard.jsx +0 -0
  136. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/SchemaCodeViewer.jsx +0 -0
  137. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/SkeletonLoader.jsx +0 -0
  138. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/StreamingLogViewer.jsx +0 -0
  139. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/TestGenerationModal.jsx +0 -0
  140. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/TestProfileSelector.jsx +0 -0
  141. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/TestResultPanel.jsx +0 -0
  142. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/TestStatusIndicator.jsx +0 -0
  143. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/ToolCallTimeline.jsx +0 -0
  144. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/ToolComparison.jsx +0 -0
  145. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/ToolDebugModal.jsx +0 -0
  146. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/TraceView.jsx +0 -0
  147. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/TypeBadge.jsx +0 -0
  148. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/components/Wizard.jsx +0 -0
  149. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/contexts/TestRunContext.jsx +0 -0
  150. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/contexts/ThemeContext.jsx +0 -0
  151. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/hooks/useEditorTheme.js +0 -0
  152. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/hooks/useKeyboardShortcuts.js +0 -0
  153. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/hooks/useSafeFetch.js +0 -0
  154. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/index.css +0 -0
  155. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/main.jsx +0 -0
  156. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/AuthDebugger.jsx +0 -0
  157. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/ChatInterface.jsx +0 -0
  158. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/CompatibilityMatrix.jsx +0 -0
  159. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/Configuration.jsx +0 -0
  160. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/GenerationHistory.jsx +0 -0
  161. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/LLMProfiles.jsx +0 -0
  162. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/MCPExplorer.jsx +0 -0
  163. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/MCPHealth.jsx +0 -0
  164. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/MCPProfiles.jsx +0 -0
  165. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/MetricsDashboard.jsx +0 -0
  166. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/ProfilesManager.jsx +0 -0
  167. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/Reports.jsx +0 -0
  168. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/RunComparison.jsx +0 -0
  169. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/SecurityDashboard.jsx +0 -0
  170. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/pages/TestManager.jsx +0 -0
  171. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/utils/__tests__/formatConverters.test.js +0 -0
  172. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/src/utils/formatConverters.js +0 -0
  173. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/tailwind.config.js +0 -0
  174. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy/ui/vite.config.js +0 -0
  175. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy.egg-info/dependency_links.txt +0 -0
  176. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy.egg-info/entry_points.txt +0 -0
  177. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy.egg-info/requires.txt +0 -0
  178. {testmcpy-0.3.1 → testmcpy-0.3.2}/testmcpy.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testmcpy
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: A comprehensive testing framework for validating LLM tool calling capabilities with MCP services
5
5
  Author: Amin Ghadersohi
6
6
  License-Expression: Apache-2.0
@@ -93,7 +93,7 @@ testmcpy = [
93
93
 
94
94
  [project]
95
95
  name = "testmcpy"
96
- version = "0.3.1"
96
+ version = "0.3.2"
97
97
  description = "A comprehensive testing framework for validating LLM tool calling capabilities with MCP services"
98
98
  authors = [{name = "Amin Ghadersohi"}]
99
99
  license = "Apache-2.0"
@@ -11,6 +11,6 @@ try:
11
11
  __version__ = version("testmcpy")
12
12
  except Exception:
13
13
  # Fallback for development or when package not installed
14
- __version__ = "0.3.1"
14
+ __version__ = "0.3.2"
15
15
 
16
16
  __author__ = "testmcpy Contributors"
@@ -4,6 +4,7 @@ Base evaluation functions for testmcpy.
4
4
  These evaluators can be used to validate LLM responses and tool calling behavior.
5
5
  """
6
6
 
7
+ import json
7
8
  import re
8
9
  from abc import ABC, abstractmethod
9
10
  from dataclasses import dataclass
@@ -2531,11 +2532,11 @@ class UnnecessaryToolCalls(BaseEvaluator):
2531
2532
  continue
2532
2533
 
2533
2534
  if self.check_args:
2534
- # Include args in the signature (sorted for consistency)
2535
+ # Canonical serialization for stable duplicate detection
2535
2536
  args = tc.get("arguments", {})
2536
2537
  try:
2537
- args_key = str(sorted(args.items())) if isinstance(args, dict) else str(args)
2538
- except TypeError:
2538
+ args_key = json.dumps(args, sort_keys=True, default=str)
2539
+ except (TypeError, ValueError):
2539
2540
  args_key = str(args)
2540
2541
  sig = f"{tool_name}({args_key})"
2541
2542
  else:
@@ -2560,11 +2561,18 @@ class UnnecessaryToolCalls(BaseEvaluator):
2560
2561
  total_calls = len(tool_calls)
2561
2562
  score = max(0.0, 1.0 - (total_excess / total_calls))
2562
2563
 
2564
+ # Truncate signatures in reason to avoid leaking large args
2565
+ short_sigs = []
2566
+ for sig, count in duplicates.items():
2567
+ if len(sig) > 80:
2568
+ sig = sig[:77] + "..."
2569
+ short_sigs.append(f"{sig} ({count}x)")
2570
+
2563
2571
  return EvalResult(
2564
2572
  passed=False,
2565
2573
  score=score,
2566
2574
  reason=f"Found {len(duplicates)} duplicate tool call pattern(s): "
2567
- + ", ".join(f"{sig} ({count}x)" for sig, count in duplicates.items()),
2575
+ + ", ".join(short_sigs),
2568
2576
  details={
2569
2577
  "duplicates": duplicates,
2570
2578
  "total_excess_calls": total_excess,
@@ -419,21 +419,6 @@ class TestRunner:
419
419
  # Ensure initialized
420
420
  await self.initialize()
421
421
 
422
- # Run setup hooks (MCP tool calls before test)
423
- if test_case.setup:
424
- for setup_call in test_case.setup:
425
- tool_name = setup_call.get("tool", "")
426
- tool_args = setup_call.get("args", {})
427
- if tool_name and self.mcp_client:
428
- try:
429
- mcp_call = MCPToolCall(name=tool_name, arguments=tool_args)
430
- await self.mcp_client.call_tool(mcp_call)
431
- if self.verbose:
432
- self._log(f" Setup: {tool_name}({tool_args})")
433
- except Exception as setup_err:
434
- if self.verbose:
435
- self._log(f" Setup failed: {tool_name}: {setup_err}")
436
-
437
422
  # If test has auth config, create a temporary MCP client with that auth
438
423
  test_mcp_client = self.mcp_client
439
424
  if test_case.auth:
@@ -484,6 +469,17 @@ class TestRunner:
484
469
  if self.verbose:
485
470
  print(f" Authentication failed: {auth_error}")
486
471
 
472
+ # Run setup hooks against the resolved MCP client (after auth)
473
+ if test_case.setup:
474
+ for setup_call in test_case.setup:
475
+ tool_name = setup_call.get("tool", "")
476
+ tool_args = setup_call.get("args", {})
477
+ if tool_name and test_mcp_client:
478
+ mcp_call = MCPToolCall(name=tool_name, arguments=tool_args)
479
+ await test_mcp_client.call_tool(mcp_call)
480
+ if self.verbose:
481
+ self._log(f" Setup: {tool_name}({tool_args})")
482
+
487
483
  # Get available MCP tools
488
484
  mcp_tools = await test_mcp_client.list_tools()
489
485
 
@@ -729,15 +725,16 @@ class TestRunner:
729
725
  )
730
726
 
731
727
  finally:
732
- # Run teardown hooks (MCP tool calls after test)
733
- if test_case.teardown and self.mcp_client:
728
+ # Run teardown hooks against the same client used for the test
729
+ teardown_client = test_mcp_client if "test_mcp_client" in locals() else self.mcp_client
730
+ if test_case.teardown and teardown_client:
734
731
  for teardown_call in test_case.teardown:
735
732
  tool_name = teardown_call.get("tool", "")
736
733
  tool_args = teardown_call.get("args", {})
737
734
  if tool_name:
738
735
  try:
739
736
  mcp_call = MCPToolCall(name=tool_name, arguments=tool_args)
740
- await self.mcp_client.call_tool(mcp_call)
737
+ await teardown_client.call_tool(mcp_call)
741
738
  if self.verbose:
742
739
  self._log(f" Teardown: {tool_name}({tool_args})")
743
740
  except Exception as teardown_err:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testmcpy
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: A comprehensive testing framework for validating LLM tool calling capabilities with MCP services
5
5
  Author: Amin Ghadersohi
6
6
  License-Expression: Apache-2.0
@@ -122,9 +122,6 @@ testmcpy/ui/package.json
122
122
  testmcpy/ui/postcss.config.js
123
123
  testmcpy/ui/tailwind.config.js
124
124
  testmcpy/ui/vite.config.js
125
- testmcpy/ui/dist/index.html
126
- testmcpy/ui/dist/assets/index-B1_waOsr.js
127
- testmcpy/ui/dist/assets/index-Do693nG2.css
128
125
  testmcpy/ui/src/App.jsx
129
126
  testmcpy/ui/src/index.css
130
127
  testmcpy/ui/src/main.jsx