rowan-mcp 1.0.2__py3-none-any.whl → 2.0.0__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.

Potentially problematic release.


This version of rowan-mcp might be problematic. Click here for more details.

Files changed (70) hide show
  1. rowan_mcp/__init__.py +1 -1
  2. rowan_mcp/__main__.py +3 -5
  3. rowan_mcp/functions_v2/BENCHMARK.md +86 -0
  4. rowan_mcp/functions_v2/molecule_lookup.py +232 -0
  5. rowan_mcp/functions_v2/protein_management.py +141 -0
  6. rowan_mcp/functions_v2/submit_basic_calculation_workflow.py +195 -0
  7. rowan_mcp/functions_v2/submit_conformer_search_workflow.py +158 -0
  8. rowan_mcp/functions_v2/submit_descriptors_workflow.py +52 -0
  9. rowan_mcp/functions_v2/submit_docking_workflow.py +244 -0
  10. rowan_mcp/functions_v2/submit_fukui_workflow.py +114 -0
  11. rowan_mcp/functions_v2/submit_irc_workflow.py +58 -0
  12. rowan_mcp/functions_v2/submit_macropka_workflow.py +99 -0
  13. rowan_mcp/functions_v2/submit_pka_workflow.py +72 -0
  14. rowan_mcp/functions_v2/submit_protein_cofolding_workflow.py +88 -0
  15. rowan_mcp/functions_v2/submit_redox_potential_workflow.py +55 -0
  16. rowan_mcp/functions_v2/submit_scan_workflow.py +82 -0
  17. rowan_mcp/functions_v2/submit_solubility_workflow.py +157 -0
  18. rowan_mcp/functions_v2/submit_tautomer_search_workflow.py +51 -0
  19. rowan_mcp/functions_v2/workflow_management_v2.py +382 -0
  20. rowan_mcp/server.py +109 -144
  21. rowan_mcp/tests/basic_calculation_from_json.py +0 -0
  22. rowan_mcp/tests/basic_calculation_with_constraint.py +33 -0
  23. rowan_mcp/tests/basic_calculation_with_solvent.py +0 -0
  24. rowan_mcp/tests/bde.py +37 -0
  25. rowan_mcp/tests/benchmark_queries.md +120 -0
  26. rowan_mcp/tests/cofolding_screen.py +131 -0
  27. rowan_mcp/tests/conformer_dependent_redox.py +37 -0
  28. rowan_mcp/tests/conformers.py +31 -0
  29. rowan_mcp/tests/data.json +189 -0
  30. rowan_mcp/tests/docking_screen.py +157 -0
  31. rowan_mcp/tests/irc.py +24 -0
  32. rowan_mcp/tests/macropka.py +13 -0
  33. rowan_mcp/tests/multistage_opt.py +13 -0
  34. rowan_mcp/tests/optimization.py +21 -0
  35. rowan_mcp/tests/phenol_pka.py +36 -0
  36. rowan_mcp/tests/pka.py +36 -0
  37. rowan_mcp/tests/protein_cofolding.py +17 -0
  38. rowan_mcp/tests/scan.py +28 -0
  39. {rowan_mcp-1.0.2.dist-info → rowan_mcp-2.0.0.dist-info}/METADATA +41 -33
  40. rowan_mcp-2.0.0.dist-info/RECORD +42 -0
  41. rowan_mcp/functions/admet.py +0 -94
  42. rowan_mcp/functions/bde.py +0 -113
  43. rowan_mcp/functions/calculation_retrieve.py +0 -89
  44. rowan_mcp/functions/conformers.py +0 -80
  45. rowan_mcp/functions/descriptors.py +0 -92
  46. rowan_mcp/functions/docking.py +0 -340
  47. rowan_mcp/functions/docking_enhanced.py +0 -174
  48. rowan_mcp/functions/electronic_properties.py +0 -205
  49. rowan_mcp/functions/folder_management.py +0 -137
  50. rowan_mcp/functions/fukui.py +0 -219
  51. rowan_mcp/functions/hydrogen_bond_basicity.py +0 -94
  52. rowan_mcp/functions/irc.py +0 -125
  53. rowan_mcp/functions/macropka.py +0 -120
  54. rowan_mcp/functions/molecular_converter.py +0 -423
  55. rowan_mcp/functions/molecular_dynamics.py +0 -191
  56. rowan_mcp/functions/molecule_lookup.py +0 -57
  57. rowan_mcp/functions/multistage_opt.py +0 -171
  58. rowan_mcp/functions/pdb_handler.py +0 -200
  59. rowan_mcp/functions/pka.py +0 -88
  60. rowan_mcp/functions/redox_potential.py +0 -352
  61. rowan_mcp/functions/scan.py +0 -536
  62. rowan_mcp/functions/scan_analyzer.py +0 -347
  63. rowan_mcp/functions/solubility.py +0 -277
  64. rowan_mcp/functions/spin_states.py +0 -747
  65. rowan_mcp/functions/system_management.py +0 -368
  66. rowan_mcp/functions/tautomers.py +0 -91
  67. rowan_mcp/functions/workflow_management.py +0 -422
  68. rowan_mcp-1.0.2.dist-info/RECORD +0 -34
  69. {rowan_mcp-1.0.2.dist-info → rowan_mcp-2.0.0.dist-info}/WHEEL +0 -0
  70. {rowan_mcp-1.0.2.dist-info → rowan_mcp-2.0.0.dist-info}/entry_points.txt +0 -0
@@ -1,113 +0,0 @@
1
- """
2
- Calculate bond dissociation energy (BDE) for molecules to determine bond strength - useful for reaction prediction, stability analysis, or understanding molecular fragmentation. Modes: reckless/rapid/careful/meticulous. Input: molecule (SMILES), optional atoms to break.
3
- """
4
-
5
- import os
6
- import rowan
7
- from typing import Optional, List, Union
8
-
9
- # Set up logging
10
- import logging
11
- logger = logging.getLogger(__name__)
12
-
13
- # Configure rowan API key
14
- if not hasattr(rowan, 'api_key') or not rowan.api_key:
15
- api_key = os.getenv("ROWAN_API_KEY")
16
- if api_key:
17
- rowan.api_key = api_key
18
- logger.info("🔑 Rowan API key configured")
19
- else:
20
- logger.error("No ROWAN_API_KEY found in environment")
21
-
22
- def log_rowan_api_call(workflow_type: str, **kwargs):
23
- """Log Rowan API calls and let Rowan handle its own errors."""
24
-
25
- # Simple logging for calculations
26
- logger.info(f" Starting {workflow_type.replace('_', ' ')}...")
27
-
28
- # Let Rowan handle everything - no custom error handling
29
- return rowan.compute(workflow_type=workflow_type, **kwargs)
30
-
31
- def rowan_bde(
32
- name: str,
33
- molecule: str,
34
- mode: str = "rapid",
35
- atoms: Optional[List[int]] = None,
36
- optimize_fragments: Optional[bool] = None,
37
- all_CH: bool = False,
38
- all_CX: bool = False,
39
- folder_uuid: Optional[str] = None,
40
- blocking: bool = True,
41
- ping_interval: int = 5
42
- ) -> str:
43
- """Calculate bond dissociation energy (BDE) for molecules.
44
-
45
- Args:
46
- name: Name for the calculation
47
- molecule: Molecule SMILES string
48
- mode: Calculation mode - reckless/rapid/careful/meticulous (default: rapid)
49
- atoms: Specific atoms to dissociate (1-indexed)
50
- optimize_fragments: Whether to optimize fragments (default depends on mode)
51
- all_CH: Dissociate all C-H bonds (default: False)
52
- all_CX: Dissociate all C-X bonds where X is halogen (default: False)
53
- folder_uuid: UUID of folder to organize calculation in
54
- blocking: Whether to wait for completion (default: True)
55
- ping_interval: How often to check status in seconds (default: 5)
56
-
57
- Returns:
58
- Bond dissociation energy calculation results
59
- """
60
- try:
61
- # Build kwargs for API call
62
- kwargs = {
63
- "workflow_type": "bde",
64
- "name": name,
65
- "molecule": molecule,
66
- "mode": mode.lower(),
67
- "folder_uuid": folder_uuid,
68
- "blocking": blocking,
69
- "ping_interval": ping_interval
70
- }
71
-
72
- # Add optional parameters only if specified
73
- if atoms is not None:
74
- kwargs["atoms"] = atoms
75
- if optimize_fragments is not None:
76
- kwargs["optimize_fragments"] = optimize_fragments
77
- if all_CH:
78
- kwargs["all_CH"] = all_CH
79
- if all_CX:
80
- kwargs["all_CX"] = all_CX
81
-
82
- result = log_rowan_api_call(**kwargs)
83
-
84
- return str(result)
85
-
86
- except Exception as e:
87
- error_response = {
88
- "error": f"BDE calculation failed: {str(e)}",
89
- "name": name,
90
- "molecule": molecule
91
- }
92
- return str(error_response)
93
-
94
-
95
- def test_rowan_bde():
96
- """Test the rowan_bde function."""
97
- try:
98
- # Test with ethane C-C bond
99
- result = rowan_bde(
100
- name="test_ethane_CC",
101
- molecule="CC",
102
- mode="rapid"
103
- )
104
- print("✅ BDE test successful!")
105
- print(f"Result: {result}")
106
- return True
107
- except Exception as e:
108
- print(f"BDE test failed: {e}")
109
- return False
110
-
111
-
112
- if __name__ == "__main__":
113
- test_rowan_bde()
@@ -1,89 +0,0 @@
1
- """
2
- Rowan calculation retrieval functions for MCP tool integration.
3
- """
4
-
5
- from typing import Optional, Dict, Any
6
- import rowan
7
-
8
- def rowan_calculation_retrieve(calculation_uuid: str) -> str:
9
- """Retrieve details of a specific calculation.
10
-
11
- Args:
12
- calculation_uuid: UUID of the calculation to retrieve
13
-
14
- Returns:
15
- Calculation details
16
- """
17
-
18
- try:
19
- calculation = rowan.Calculation.retrieve(uuid=calculation_uuid)
20
- return format_calculation_details(calculation, calculation_uuid)
21
-
22
- except Exception as e:
23
- return f" Error retrieving calculation: {str(e)}"
24
-
25
- # Fallback error handling removed - keeping function simple and focused
26
-
27
- def format_calculation_details(calculation: Dict[str, Any], calculation_uuid: str) -> str:
28
- """Format calculation details for display."""
29
-
30
- formatted = f"⚙ **Calculation Details:**\n\n"
31
- formatted += f" Name: {calculation.get('name', 'N/A')}\n"
32
- formatted += f"UUID: {calculation_uuid}\n"
33
- formatted += f" Status: {calculation.get('status', 'Unknown')}\n"
34
- formatted += f" Elapsed: {calculation.get('elapsed', 0):.3f}s\n"
35
-
36
- # Settings information
37
- settings = calculation.get('settings', {})
38
- if settings:
39
- formatted += f"\n⚙ **Settings:**\n"
40
- formatted += f" Method: {settings.get('method', 'N/A')}\n"
41
- if settings.get('basis_set'):
42
- formatted += f" Basis Set: {settings.get('basis_set')}\n"
43
- if settings.get('tasks'):
44
- formatted += f" Tasks: {', '.join(settings.get('tasks', []))}\n"
45
-
46
- # Molecule information
47
- molecules = calculation.get('molecules', [])
48
- if molecules:
49
- formatted += f"\n **Molecules:** {len(molecules)} structure(s)\n"
50
- if len(molecules) > 0 and isinstance(molecules[0], dict):
51
- first_mol = molecules[0]
52
- if 'smiles' in first_mol:
53
- formatted += f" Primary SMILES: {first_mol['smiles']}\n"
54
-
55
- # Results/output data
56
- if 'output' in calculation:
57
- output = calculation['output']
58
- formatted += f"\n **Results Available:**\n"
59
- if isinstance(output, dict):
60
- for key, value in list(output.items())[:5]: # Show first 5 items
61
- if isinstance(value, (int, float)):
62
- formatted += f" {key}: {value:.4f}\n"
63
- elif isinstance(value, str) and len(value) < 50:
64
- formatted += f" {key}: {value}\n"
65
- elif isinstance(value, list) and len(value) < 10:
66
- formatted += f" {key}: {value}\n"
67
- else:
68
- formatted += f" {key}: <complex data>\n"
69
- else:
70
- formatted += f" Raw output: {str(output)[:200]}...\n"
71
-
72
- return formatted
73
-
74
- # Specialized object data formatting removed - keeping function simple
75
-
76
- def test_rowan_calculation_retrieve():
77
- """Test the calculation retrieve function."""
78
- try:
79
- # Test with a dummy UUID to see error handling
80
- result = rowan_calculation_retrieve("test-uuid-123")
81
- print(" Calculation retrieve test successful!")
82
- print(f"Sample result: {result[:200]}...")
83
- return True
84
- except Exception as e:
85
- print(f" Calculation retrieve test failed: {e}")
86
- return False
87
-
88
- if __name__ == "__main__":
89
- test_rowan_calculation_retrieve()
@@ -1,80 +0,0 @@
1
- """
2
- Rowan conformers function for conformational analysis.
3
- """
4
-
5
- import os
6
- import logging
7
- import time
8
- from typing import Optional
9
-
10
- try:
11
- import rowan
12
- except ImportError:
13
- rowan = None
14
-
15
- # Setup logging
16
- logger = logging.getLogger(__name__)
17
-
18
- # Setup API key
19
- api_key = os.getenv("ROWAN_API_KEY")
20
- if rowan and api_key:
21
- rowan.api_key = api_key
22
-
23
- def log_rowan_api_call(workflow_type: str, **kwargs):
24
- """Log Rowan API calls and let Rowan handle its own errors."""
25
-
26
- # Simple logging for long-running calculations
27
- if workflow_type in ["multistage_opt", "conformer_search"]:
28
- blocking = kwargs.get('blocking', True)
29
- if blocking:
30
- logger.info(f" Starting {workflow_type.replace('_', ' ')}...")
31
- else:
32
- logger.info(f" Submitting {workflow_type.replace('_', ' ')} without waiting")
33
-
34
- # Let Rowan handle everything - no custom error handling
35
- return rowan.compute(workflow_type=workflow_type, **kwargs)
36
-
37
- def rowan_conformers(
38
- name: str,
39
- molecule: str,
40
- max_conformers: int = 50,
41
- mode: str = "rapid",
42
- folder_uuid: Optional[str] = None,
43
- blocking: bool = True,
44
- ping_interval: int = 5
45
- ):
46
- """Generate and optimize molecular conformers using Rowan's conformer_search workflow. Valid modes are "reckless", "rapid", "careful", and "meticulous", and default to using SMILES strings for the "molecule" parameter.
47
-
48
- Args:
49
- name: Name for the calculation
50
- molecule: Molecule SMILES string or common name
51
- max_conformers: Maximum number of conformers to generate (default: 50)
52
- mode: Conformer search mode - "reckless", "rapid", "careful", "meticulous" (default: "rapid")
53
- folder_uuid: UUID of folder to organize calculation in
54
- blocking: Whether to wait for completion (default: True)
55
- ping_interval: How often to check status in seconds (default: 5)
56
-
57
- Returns:
58
- Conformer search results (actual results if blocking=True)
59
- """
60
-
61
- # Validate mode parameter
62
- valid_modes = ["reckless", "rapid", "careful", "meticulous"]
63
- if mode not in valid_modes:
64
- raise ValueError(
65
- f"Invalid mode '{mode}'. Valid modes are: {', '.join(valid_modes)}"
66
- )
67
-
68
- return log_rowan_api_call(
69
- workflow_type="conformer_search",
70
- name=name,
71
- molecule=molecule,
72
- mode=mode,
73
- max_conformers=max_conformers,
74
- folder_uuid=folder_uuid,
75
- blocking=blocking,
76
- ping_interval=ping_interval
77
- )
78
-
79
- if __name__ == "__main__":
80
- pass
@@ -1,92 +0,0 @@
1
- """
2
- Rowan molecular descriptors function for QSAR modeling.
3
- """
4
-
5
- import os
6
- import logging
7
- import time
8
- from typing import Optional
9
-
10
- try:
11
- import rowan
12
- except ImportError:
13
- rowan = None
14
-
15
- # Setup logging
16
- logger = logging.getLogger(__name__)
17
-
18
- # Setup API key
19
- api_key = os.getenv("ROWAN_API_KEY")
20
- if rowan and api_key:
21
- rowan.api_key = api_key
22
-
23
- def log_rowan_api_call(workflow_type: str, **kwargs):
24
- """Log Rowan API calls with detailed parameters."""
25
-
26
- try:
27
- start_time = time.time()
28
- result = rowan.compute(workflow_type=workflow_type, **kwargs)
29
- api_time = time.time() - start_time
30
-
31
- if isinstance(result, dict) and 'uuid' in result:
32
- job_status = result.get('status', result.get('object_status', 'Unknown'))
33
- status_names = {0: "Queued", 1: "Running", 2: "Completed", 3: "Failed", 4: "Stopped", 5: "Awaiting Queue"}
34
- status_text = status_names.get(job_status, f"Unknown ({job_status})")
35
-
36
- return result
37
-
38
- except Exception as e:
39
- api_time = time.time() - start_time
40
- raise e
41
-
42
- def rowan_descriptors(
43
- name: str,
44
- molecule: str,
45
- folder_uuid: Optional[str] = None,
46
- blocking: bool = True,
47
- ping_interval: int = 5
48
- ) -> str:
49
- """Calculate molecular descriptors for data science.
50
-
51
- Generates comprehensive molecular descriptors including:
52
- - Topological and geometric descriptors
53
- - Electronic and physicochemical properties
54
- - Graph-based molecular features
55
- - Machine learning ready feature vectors
56
-
57
- Use this for: QSAR modeling, machine learning, chemical space analysis
58
-
59
- Args:
60
- name: Name for the calculation
61
- molecule: Molecule SMILES string
62
- folder_uuid: Optional folder UUID for organization
63
- blocking: Whether to wait for completion (default: True)
64
- ping_interval: Check status interval in seconds (default: 5)
65
-
66
- Returns:
67
- Molecular descriptors results
68
- """
69
- result = log_rowan_api_call(
70
- workflow_type="descriptors",
71
- name=name,
72
- molecule=molecule,
73
- folder_uuid=folder_uuid,
74
- blocking=blocking,
75
- ping_interval=ping_interval
76
- )
77
- return str(result)
78
-
79
- def test_rowan_descriptors():
80
- """Test the rowan_descriptors function."""
81
- try:
82
- # Test with a simple molecule (non-blocking to avoid long wait)
83
- result = rowan_descriptors("test_descriptors", "CCO", blocking=False)
84
- print(" Descriptors test successful!")
85
- print(f"Result length: {len(result)} characters")
86
- return True
87
- except Exception as e:
88
- print(f" Descriptors test failed: {e}")
89
- return False
90
-
91
- if __name__ == "__main__":
92
- test_rowan_descriptors()