testmcpy 0.1.2__tar.gz → 0.1.4__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 (25) hide show
  1. {testmcpy-0.1.2 → testmcpy-0.1.4}/PKG-INFO +1 -1
  2. {testmcpy-0.1.2 → testmcpy-0.1.4}/pyproject.toml +1 -1
  3. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/config.py +23 -13
  4. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/src/llm_integration.py +25 -13
  5. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/src/test_runner.py +3 -3
  6. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy.egg-info/PKG-INFO +1 -1
  7. {testmcpy-0.1.2 → testmcpy-0.1.4}/LICENSE +0 -0
  8. {testmcpy-0.1.2 → testmcpy-0.1.4}/README.md +0 -0
  9. {testmcpy-0.1.2 → testmcpy-0.1.4}/setup.cfg +0 -0
  10. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/__init__.py +0 -0
  11. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/cli.py +0 -0
  12. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/evals/__init__.py +0 -0
  13. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/evals/base_evaluators.py +0 -0
  14. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/research/claude_sdk_detailed_exploration.py +0 -0
  15. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/research/claude_sdk_poc.py +0 -0
  16. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/research/claude_sdk_working_poc.py +0 -0
  17. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/research/test_ollama_tools.py +0 -0
  18. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/src/__init__.py +0 -0
  19. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy/src/mcp_client.py +0 -0
  20. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy.egg-info/SOURCES.txt +0 -0
  21. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy.egg-info/dependency_links.txt +0 -0
  22. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy.egg-info/entry_points.txt +0 -0
  23. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy.egg-info/requires.txt +0 -0
  24. {testmcpy-0.1.2 → testmcpy-0.1.4}/testmcpy.egg-info/top_level.txt +0 -0
  25. {testmcpy-0.1.2 → testmcpy-0.1.4}/tests/test_url_protection.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testmcpy
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: A comprehensive testing framework for validating LLM tool calling capabilities with MCP services
5
5
  Author-email: Preset <amin@preset.io>
6
6
  License: Apache-2.0
@@ -11,7 +11,7 @@ include = ["testmcpy*"]
11
11
 
12
12
  [project]
13
13
  name = "testmcpy"
14
- version = "0.1.2"
14
+ version = "0.1.4"
15
15
  description = "A comprehensive testing framework for validating LLM tool calling capabilities with MCP services"
16
16
  authors = [{name = "Preset", email = "amin@preset.io"}]
17
17
  license = {text = "Apache-2.0"}
@@ -192,26 +192,36 @@ class Config:
192
192
  def mcp_auth_token(self) -> Optional[str]:
193
193
  """
194
194
  Get MCP auth token with the following priority:
195
- 1. Static MCP_AUTH_TOKEN or SUPERSET_MCP_TOKEN
196
- 2. Dynamically generated JWT from MCP_AUTH_API_URL if configured
195
+ 1. Dynamically generated JWT from MCP_AUTH_API_URL if configured
196
+ 2. Static MCP_AUTH_TOKEN or SUPERSET_MCP_TOKEN
197
197
 
198
198
  For dynamic tokens, caches the JWT for 50 minutes to avoid excessive API calls.
199
199
  """
200
- # Check for static token first
200
+ # Check if dynamic JWT credentials are configured
201
+ has_dynamic_config = all([
202
+ self.get("MCP_AUTH_API_URL"),
203
+ self.get("MCP_AUTH_API_TOKEN"),
204
+ self.get("MCP_AUTH_API_SECRET")
205
+ ])
206
+
207
+ # If dynamic JWT is configured, use it (with caching)
208
+ if has_dynamic_config:
209
+ # Check if we have a valid cached token
210
+ if self._cached_token and self._token_expiry:
211
+ if time.time() < self._token_expiry:
212
+ return self._cached_token
213
+
214
+ # Try to fetch a new JWT token
215
+ jwt_token = self._fetch_jwt_token()
216
+ if jwt_token:
217
+ return jwt_token
218
+ # If fetch fails, fall through to static token
219
+
220
+ # Fall back to static token
201
221
  static_token = self.get("MCP_AUTH_TOKEN") or self.get("SUPERSET_MCP_TOKEN")
202
222
  if static_token:
203
223
  return static_token
204
224
 
205
- # Check if we have a valid cached token
206
- if self._cached_token and self._token_expiry:
207
- if time.time() < self._token_expiry:
208
- return self._cached_token
209
-
210
- # Try to fetch a new JWT token
211
- jwt_token = self._fetch_jwt_token()
212
- if jwt_token:
213
- return jwt_token
214
-
215
225
  return None
216
226
 
217
227
  @property
@@ -17,12 +17,19 @@ from urllib.parse import urlparse
17
17
  # Import MCP components (we'll handle the import error gracefully)
18
18
  try:
19
19
  from .mcp_client import MCPClient, MCPTool, MCPToolCall, MCPToolResult
20
+ from ..config import get_config
20
21
  except ImportError:
21
22
  # Fallback for when running as script
22
23
  import sys
23
24
  import os
24
25
  sys.path.append(os.path.dirname(os.path.abspath(__file__)))
25
26
  from mcp_client import MCPClient, MCPTool, MCPToolCall, MCPToolResult
27
+ # Config will fall back to environment variables
28
+ def get_config():
29
+ class FallbackConfig:
30
+ def get(self, key, default=None):
31
+ return os.getenv(key, default)
32
+ return FallbackConfig()
26
33
 
27
34
 
28
35
  @dataclass
@@ -271,10 +278,10 @@ class OpenAIProvider(LLMProvider):
271
278
  async def initialize(self):
272
279
  """Initialize OpenAI provider."""
273
280
  if not self.api_key and self.base_url == "https://api.openai.com/v1":
274
- import os
275
- self.api_key = os.environ.get("OPENAI_API_KEY", "")
281
+ config = get_config()
282
+ self.api_key = config.get("OPENAI_API_KEY", "")
276
283
  if not self.api_key:
277
- raise ValueError("OpenAI API key not provided")
284
+ raise ValueError("OpenAI API key not provided. Set OPENAI_API_KEY in ~/.testmcpy or environment.")
278
285
 
279
286
  async def generate_with_tools(
280
287
  self,
@@ -593,18 +600,20 @@ class AnthropicProvider(LLMProvider):
593
600
  mcp_url: Optional[str] = None
594
601
  ):
595
602
  self.model = model
596
- self.api_key = api_key or os.environ.get("ANTHROPIC_API_KEY", "")
603
+ # Use config system for API key
604
+ config = get_config()
605
+ self.api_key = api_key or config.get("ANTHROPIC_API_KEY", "")
597
606
  self.base_url = base_url
598
607
  self.client = httpx.AsyncClient(timeout=60.0)
599
- # Use MCP_URL from environment if not provided
608
+ # Use MCP_URL from config if not provided
600
609
  if mcp_url is None:
601
- mcp_url = os.environ.get("MCP_URL", "http://localhost:5008/mcp")
610
+ mcp_url = config.mcp_url
602
611
  self.tool_discovery = ToolDiscoveryService(mcp_url)
603
612
 
604
613
  async def initialize(self):
605
614
  """Initialize Anthropic provider."""
606
615
  if not self.api_key:
607
- raise ValueError("Anthropic API key not provided. Set ANTHROPIC_API_KEY environment variable.")
616
+ raise ValueError("Anthropic API key not provided. Set ANTHROPIC_API_KEY in ~/.testmcpy, .env, or environment.")
608
617
 
609
618
  # Try to pre-discover tools, but don't fail if MCP service is unavailable
610
619
  try:
@@ -807,10 +816,12 @@ class ClaudeSDKProvider(LLMProvider):
807
816
  mcp_url: Optional[str] = None
808
817
  ):
809
818
  self.model = model
810
- self.api_key = api_key or os.environ.get("ANTHROPIC_API_KEY", "")
811
- # Use MCP_URL from environment if not provided
819
+ # Use config system for API key
820
+ config = get_config()
821
+ self.api_key = api_key or config.get("ANTHROPIC_API_KEY", "")
822
+ # Use MCP_URL from config if not provided
812
823
  if mcp_url is None:
813
- mcp_url = os.environ.get("MCP_URL", "http://localhost:5008/mcp")
824
+ mcp_url = config.mcp_url
814
825
  self.mcp_url = mcp_url
815
826
  self.tool_discovery = ToolDiscoveryService(mcp_url)
816
827
  self._sdk_tools: List[Any] = []
@@ -819,7 +830,7 @@ class ClaudeSDKProvider(LLMProvider):
819
830
  async def initialize(self):
820
831
  """Initialize Claude SDK provider."""
821
832
  if not self.api_key:
822
- raise ValueError("Anthropic API key not provided. Set ANTHROPIC_API_KEY environment variable.")
833
+ raise ValueError("Anthropic API key not provided. Set ANTHROPIC_API_KEY in ~/.testmcpy, .env, or environment.")
823
834
 
824
835
  # IMPORTANT: Claude Agent SDK is designed for stdio-based MCP servers (command-line tools),
825
836
  # not HTTP-based MCP services. For HTTP MCP services, use the 'anthropic' provider instead.
@@ -1015,9 +1026,10 @@ class ClaudeCodeProvider(LLMProvider):
1015
1026
  ):
1016
1027
  self.model = model
1017
1028
  self.claude_cli_path = claude_cli_path or self._find_claude_cli()
1018
- # Use MCP_URL from environment if not provided
1029
+ # Use MCP_URL from config if not provided
1030
+ config = get_config()
1019
1031
  if mcp_url is None:
1020
- mcp_url = os.environ.get("MCP_URL", "http://localhost:5008/mcp")
1032
+ mcp_url = config.mcp_url
1021
1033
  self.tool_discovery = ToolDiscoveryService(mcp_url)
1022
1034
 
1023
1035
  def _find_claude_cli(self) -> str:
@@ -10,9 +10,9 @@ import json
10
10
  import re
11
11
  from datetime import datetime, timedelta
12
12
 
13
- from src.mcp_client import MCPClient, MCPToolCall, MCPToolResult
14
- from src.llm_integration import LLMProvider, create_llm_provider
15
- from evals.base_evaluators import BaseEvaluator, EvalResult, create_evaluator
13
+ from .mcp_client import MCPClient, MCPToolCall, MCPToolResult
14
+ from .llm_integration import LLMProvider, create_llm_provider
15
+ from ..evals.base_evaluators import BaseEvaluator, EvalResult, create_evaluator
16
16
 
17
17
 
18
18
  class RateLimitTracker:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testmcpy
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: A comprehensive testing framework for validating LLM tool calling capabilities with MCP services
5
5
  Author-email: Preset <amin@preset.io>
6
6
  License: Apache-2.0
File without changes
File without changes
File without changes
File without changes
File without changes