rowan-mcp 1.0.2__tar.gz → 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (77) hide show
  1. rowan_mcp-2.0.0/.gitignore +19 -0
  2. {rowan_mcp-1.0.2 → rowan_mcp-2.0.0}/PKG-INFO +41 -33
  3. {rowan_mcp-1.0.2 → rowan_mcp-2.0.0}/README.md +36 -29
  4. {rowan_mcp-1.0.2 → rowan_mcp-2.0.0}/ROWAN_MCP_TEST_QUERIES.md +1 -1
  5. {rowan_mcp-1.0.2 → rowan_mcp-2.0.0}/pyproject.toml +5 -4
  6. {rowan_mcp-1.0.2 → rowan_mcp-2.0.0}/rowan-dxt.dxt +0 -0
  7. {rowan_mcp-1.0.2 → rowan_mcp-2.0.0}/rowan_mcp/__init__.py +1 -1
  8. rowan_mcp-2.0.0/rowan_mcp/__main__.py +12 -0
  9. rowan_mcp-2.0.0/rowan_mcp/functions_v2/BENCHMARK.md +86 -0
  10. rowan_mcp-2.0.0/rowan_mcp/functions_v2/molecule_lookup.py +232 -0
  11. rowan_mcp-2.0.0/rowan_mcp/functions_v2/protein_management.py +141 -0
  12. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_basic_calculation_workflow.py +195 -0
  13. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_conformer_search_workflow.py +158 -0
  14. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_descriptors_workflow.py +52 -0
  15. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_docking_workflow.py +244 -0
  16. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_fukui_workflow.py +114 -0
  17. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_irc_workflow.py +58 -0
  18. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_macropka_workflow.py +99 -0
  19. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_pka_workflow.py +72 -0
  20. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_protein_cofolding_workflow.py +88 -0
  21. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_redox_potential_workflow.py +55 -0
  22. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_scan_workflow.py +82 -0
  23. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_solubility_workflow.py +157 -0
  24. rowan_mcp-2.0.0/rowan_mcp/functions_v2/submit_tautomer_search_workflow.py +51 -0
  25. rowan_mcp-2.0.0/rowan_mcp/functions_v2/workflow_management_v2.py +382 -0
  26. rowan_mcp-2.0.0/rowan_mcp/server.py +134 -0
  27. rowan_mcp-2.0.0/rowan_mcp/tests/basic_calculation_from_json.py +0 -0
  28. rowan_mcp-2.0.0/rowan_mcp/tests/basic_calculation_with_constraint.py +33 -0
  29. rowan_mcp-2.0.0/rowan_mcp/tests/basic_calculation_with_solvent.py +0 -0
  30. rowan_mcp-2.0.0/rowan_mcp/tests/bde.py +37 -0
  31. rowan_mcp-2.0.0/rowan_mcp/tests/benchmark_queries.md +120 -0
  32. rowan_mcp-2.0.0/rowan_mcp/tests/cofolding_screen.py +131 -0
  33. rowan_mcp-2.0.0/rowan_mcp/tests/conformer_dependent_redox.py +37 -0
  34. rowan_mcp-2.0.0/rowan_mcp/tests/conformers.py +31 -0
  35. rowan_mcp-2.0.0/rowan_mcp/tests/data.json +189 -0
  36. rowan_mcp-2.0.0/rowan_mcp/tests/docking_screen.py +157 -0
  37. rowan_mcp-2.0.0/rowan_mcp/tests/irc.py +24 -0
  38. rowan_mcp-2.0.0/rowan_mcp/tests/macropka.py +13 -0
  39. rowan_mcp-2.0.0/rowan_mcp/tests/multistage_opt.py +13 -0
  40. rowan_mcp-2.0.0/rowan_mcp/tests/optimization.py +21 -0
  41. rowan_mcp-2.0.0/rowan_mcp/tests/phenol_pka.py +36 -0
  42. rowan_mcp-2.0.0/rowan_mcp/tests/pka.py +36 -0
  43. rowan_mcp-2.0.0/rowan_mcp/tests/protein_cofolding.py +17 -0
  44. rowan_mcp-2.0.0/rowan_mcp/tests/scan.py +28 -0
  45. rowan_mcp-2.0.0/uv.lock +1890 -0
  46. rowan_mcp-1.0.2/.gitignore +0 -12
  47. rowan_mcp-1.0.2/rowan_mcp/__main__.py +0 -14
  48. rowan_mcp-1.0.2/rowan_mcp/functions/admet.py +0 -94
  49. rowan_mcp-1.0.2/rowan_mcp/functions/bde.py +0 -113
  50. rowan_mcp-1.0.2/rowan_mcp/functions/calculation_retrieve.py +0 -89
  51. rowan_mcp-1.0.2/rowan_mcp/functions/conformers.py +0 -80
  52. rowan_mcp-1.0.2/rowan_mcp/functions/descriptors.py +0 -92
  53. rowan_mcp-1.0.2/rowan_mcp/functions/docking.py +0 -340
  54. rowan_mcp-1.0.2/rowan_mcp/functions/docking_enhanced.py +0 -174
  55. rowan_mcp-1.0.2/rowan_mcp/functions/electronic_properties.py +0 -205
  56. rowan_mcp-1.0.2/rowan_mcp/functions/folder_management.py +0 -137
  57. rowan_mcp-1.0.2/rowan_mcp/functions/fukui.py +0 -219
  58. rowan_mcp-1.0.2/rowan_mcp/functions/hydrogen_bond_basicity.py +0 -94
  59. rowan_mcp-1.0.2/rowan_mcp/functions/irc.py +0 -125
  60. rowan_mcp-1.0.2/rowan_mcp/functions/macropka.py +0 -120
  61. rowan_mcp-1.0.2/rowan_mcp/functions/molecular_converter.py +0 -423
  62. rowan_mcp-1.0.2/rowan_mcp/functions/molecular_dynamics.py +0 -191
  63. rowan_mcp-1.0.2/rowan_mcp/functions/molecule_lookup.py +0 -57
  64. rowan_mcp-1.0.2/rowan_mcp/functions/multistage_opt.py +0 -171
  65. rowan_mcp-1.0.2/rowan_mcp/functions/pdb_handler.py +0 -200
  66. rowan_mcp-1.0.2/rowan_mcp/functions/pka.py +0 -88
  67. rowan_mcp-1.0.2/rowan_mcp/functions/redox_potential.py +0 -352
  68. rowan_mcp-1.0.2/rowan_mcp/functions/scan.py +0 -536
  69. rowan_mcp-1.0.2/rowan_mcp/functions/scan_analyzer.py +0 -347
  70. rowan_mcp-1.0.2/rowan_mcp/functions/solubility.py +0 -277
  71. rowan_mcp-1.0.2/rowan_mcp/functions/spin_states.py +0 -747
  72. rowan_mcp-1.0.2/rowan_mcp/functions/system_management.py +0 -368
  73. rowan_mcp-1.0.2/rowan_mcp/functions/tautomers.py +0 -91
  74. rowan_mcp-1.0.2/rowan_mcp/functions/workflow_management.py +0 -422
  75. rowan_mcp-1.0.2/rowan_mcp/server.py +0 -169
  76. rowan_mcp-1.0.2/uv.lock +0 -1655
  77. {rowan_mcp-1.0.2 → rowan_mcp-2.0.0}/ROWAN_MCP_TOOLS.md +0 -0
@@ -0,0 +1,19 @@
1
+ /.venv
2
+ /rowan-dxt
3
+ .env
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+ *.so
8
+ .DS_Store
9
+
10
+ .claude
11
+ CLAUDE.md
12
+ /dist
13
+
14
+ # MCP configuration (may contain tokens)
15
+ .mcp.json
16
+
17
+ # Personal compatibility notes
18
+ GEMINI_MCP_COMPATIBILITY.md
19
+ MCP_CHATGPT_GEMINI_COMPATIBILITY_ANALYSIS.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rowan-mcp
3
- Version: 1.0.2
3
+ Version: 2.0.0
4
4
  Summary: Model Context Protocol server for Rowan computational chemistry platform
5
5
  Project-URL: Homepage, https://github.com/k-yenko/rowan-mcp
6
6
  Author-email: Katherine Yenko <katherineayenko@gmail.com>
@@ -13,14 +13,15 @@ Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Topic :: Scientific/Engineering :: Chemistry
16
- Requires-Python: >=3.10
16
+ Requires-Python: >=3.11
17
+ Requires-Dist: aiohttp>=3.12.15
17
18
  Requires-Dist: fastapi>=0.104.0
18
- Requires-Dist: fastmcp>=0.2.0
19
+ Requires-Dist: fastmcp>=2.11.3
19
20
  Requires-Dist: pubchempy>=1.0.4
20
21
  Requires-Dist: pydantic>=2.0.0
21
22
  Requires-Dist: python-dotenv>=1.0.0
22
23
  Requires-Dist: rdkit>=2025.3.2
23
- Requires-Dist: rowan-python>=0.1.0
24
+ Requires-Dist: rowan-python>=2.1.1
24
25
  Requires-Dist: typing-extensions>=4.0.0
25
26
  Requires-Dist: uvicorn>=0.24.0
26
27
  Provides-Extra: dev
@@ -32,7 +33,7 @@ Description-Content-Type: text/markdown
32
33
 
33
34
  # Rowan MCP Server
34
35
 
35
- This project wraps an MCP (Model Context Protocol) around Rowan's tools, making it easy for users to design molecuels and run simulations in natural everyday language.
36
+ MCP server for making it easy to run Rowan's molecular design and simulation tools.
36
37
 
37
38
  ---
38
39
 
@@ -56,34 +57,25 @@ That's it - no command line setup needed!
56
57
 
57
58
  Just add this to your MCP configuration and it will automatically install and run:
58
59
 
59
- **Using uvx (simplest):**
60
+ **HTTP/SSE configuration:**
60
61
  ```json
61
62
  {
62
63
  "mcpServers": {
63
64
  "rowan": {
64
- "command": "uvx",
65
- "args": ["--from", "rowan-mcp", "rowan-mcp"],
66
- "env": {
67
- "ROWAN_API_KEY": "your_api_key_here"
68
- }
65
+ "type": "http",
66
+ "url": "http://127.0.0.1:6276/sse"
69
67
  }
70
68
  }
71
69
  }
72
70
  ```
73
71
 
74
- **Using uv run (alternative):**
75
- ```json
76
- {
77
- "mcpServers": {
78
- "rowan": {
79
- "command": "uv",
80
- "args": ["run", "--with", "rowan-mcp", "-m", "rowan_mcp"],
81
- "env": {
82
- "ROWAN_API_KEY": "your_api_key_here"
83
- }
84
- }
85
- }
86
- }
72
+ Then start the server:
73
+ ```bash
74
+ # Set your API key
75
+ export ROWAN_API_KEY="your_api_key_here"
76
+
77
+ # Start the HTTP server
78
+ uvx --from rowan-mcp rowan-mcp
87
79
  ```
88
80
 
89
81
  ### **Option 2: Manual Installation**
@@ -100,20 +92,24 @@ uv add rowan-mcp
100
92
  pip install rowan-mcp
101
93
  ```
102
94
 
103
- Then use this configuration:
95
+ Then configure and start:
104
96
  ```json
105
97
  {
106
98
  "mcpServers": {
107
99
  "rowan": {
108
- "command": "rowan-mcp",
109
- "env": {
110
- "ROWAN_API_KEY": "your_api_key_here"
111
- }
100
+ "type": "http",
101
+ "url": "http://127.0.0.1:6276/sse"
112
102
  }
113
103
  }
114
104
  }
115
105
  ```
116
106
 
107
+ ```bash
108
+ # Set API key and start server
109
+ export ROWAN_API_KEY="your_api_key_here"
110
+ rowan-mcp
111
+ ```
112
+
117
113
  ### **Get API Key**
118
114
 
119
115
  Visit [labs.rowansci.com](https://labs.rowansci.com) → Create account → Generate API key
@@ -142,7 +138,8 @@ Ask the LLM to:
142
138
  **Development commands** (if you cloned the repo):
143
139
  ```bash
144
140
  # Run from source
145
- uv run python -m rowan_mcp --http
141
+ export ROWAN_API_KEY="your_api_key_here"
142
+ uv run python -m rowan_mcp
146
143
  ```
147
144
 
148
145
  ---
@@ -189,16 +186,18 @@ uv run python -m rowan_mcp --http
189
186
 
190
187
  ## **Todo**
191
188
 
192
- - [ ] Remove unnecessary AI spaghetti formatting 🙃
189
+ - [X] Remove unnecessary AI spaghetti formatting
190
+ - [X] Remove no longer necessary API config lines
193
191
  - [ ] Some complex conformer searches hang on "running"
194
- - [ ] Edit MCP one-liner context
192
+ - [X] Edit MCP one-liner context
195
193
  - [ ] Transition state finding and IRC
196
194
  - [X] `rowan_scan` - Potential energy surfaces
197
195
  - [ ] `rowan_docking` - Protein-ligand docking
198
196
  - [X] add in h-bond, BDE and macroscopic pka, logD, BBB
199
197
  - [ ] Folder listing API bug (returns 500 error) - Rowan side?
200
198
  - [ ] Multistage optimization sometimes shows unexpected imaginary frequencies
201
- - [ ] Some calculations show as finished in logs but not in Rowan UI
199
+ - [X] Some calculations show as finished in logs but not in Rowan UI
200
+ - [ ] Can you hook up Rowan's visual capabilites?
202
201
 
203
202
  ## **Citation**
204
203
 
@@ -233,3 +232,12 @@ To update the dxt file:
233
232
  # Then update the desktop extension
234
233
  dxt pack rowan-dxt
235
234
  ```
235
+ ### MCP inspector
236
+ ```bash
237
+ # Start the server first
238
+ export ROWAN_API_KEY="your_api_key_here"
239
+ uv run python -m rowan_mcp &
240
+
241
+ # Then inspect
242
+ npx @modelcontextprotocol/inspector http://127.0.0.1:6276/sse
243
+ ```
@@ -1,6 +1,6 @@
1
1
  # Rowan MCP Server
2
2
 
3
- This project wraps an MCP (Model Context Protocol) around Rowan's tools, making it easy for users to design molecuels and run simulations in natural everyday language.
3
+ MCP server for making it easy to run Rowan's molecular design and simulation tools.
4
4
 
5
5
  ---
6
6
 
@@ -24,34 +24,25 @@ That's it - no command line setup needed!
24
24
 
25
25
  Just add this to your MCP configuration and it will automatically install and run:
26
26
 
27
- **Using uvx (simplest):**
27
+ **HTTP/SSE configuration:**
28
28
  ```json
29
29
  {
30
30
  "mcpServers": {
31
31
  "rowan": {
32
- "command": "uvx",
33
- "args": ["--from", "rowan-mcp", "rowan-mcp"],
34
- "env": {
35
- "ROWAN_API_KEY": "your_api_key_here"
36
- }
32
+ "type": "http",
33
+ "url": "http://127.0.0.1:6276/sse"
37
34
  }
38
35
  }
39
36
  }
40
37
  ```
41
38
 
42
- **Using uv run (alternative):**
43
- ```json
44
- {
45
- "mcpServers": {
46
- "rowan": {
47
- "command": "uv",
48
- "args": ["run", "--with", "rowan-mcp", "-m", "rowan_mcp"],
49
- "env": {
50
- "ROWAN_API_KEY": "your_api_key_here"
51
- }
52
- }
53
- }
54
- }
39
+ Then start the server:
40
+ ```bash
41
+ # Set your API key
42
+ export ROWAN_API_KEY="your_api_key_here"
43
+
44
+ # Start the HTTP server
45
+ uvx --from rowan-mcp rowan-mcp
55
46
  ```
56
47
 
57
48
  ### **Option 2: Manual Installation**
@@ -68,20 +59,24 @@ uv add rowan-mcp
68
59
  pip install rowan-mcp
69
60
  ```
70
61
 
71
- Then use this configuration:
62
+ Then configure and start:
72
63
  ```json
73
64
  {
74
65
  "mcpServers": {
75
66
  "rowan": {
76
- "command": "rowan-mcp",
77
- "env": {
78
- "ROWAN_API_KEY": "your_api_key_here"
79
- }
67
+ "type": "http",
68
+ "url": "http://127.0.0.1:6276/sse"
80
69
  }
81
70
  }
82
71
  }
83
72
  ```
84
73
 
74
+ ```bash
75
+ # Set API key and start server
76
+ export ROWAN_API_KEY="your_api_key_here"
77
+ rowan-mcp
78
+ ```
79
+
85
80
  ### **Get API Key**
86
81
 
87
82
  Visit [labs.rowansci.com](https://labs.rowansci.com) → Create account → Generate API key
@@ -110,7 +105,8 @@ Ask the LLM to:
110
105
  **Development commands** (if you cloned the repo):
111
106
  ```bash
112
107
  # Run from source
113
- uv run python -m rowan_mcp --http
108
+ export ROWAN_API_KEY="your_api_key_here"
109
+ uv run python -m rowan_mcp
114
110
  ```
115
111
 
116
112
  ---
@@ -157,16 +153,18 @@ uv run python -m rowan_mcp --http
157
153
 
158
154
  ## **Todo**
159
155
 
160
- - [ ] Remove unnecessary AI spaghetti formatting 🙃
156
+ - [X] Remove unnecessary AI spaghetti formatting
157
+ - [X] Remove no longer necessary API config lines
161
158
  - [ ] Some complex conformer searches hang on "running"
162
- - [ ] Edit MCP one-liner context
159
+ - [X] Edit MCP one-liner context
163
160
  - [ ] Transition state finding and IRC
164
161
  - [X] `rowan_scan` - Potential energy surfaces
165
162
  - [ ] `rowan_docking` - Protein-ligand docking
166
163
  - [X] add in h-bond, BDE and macroscopic pka, logD, BBB
167
164
  - [ ] Folder listing API bug (returns 500 error) - Rowan side?
168
165
  - [ ] Multistage optimization sometimes shows unexpected imaginary frequencies
169
- - [ ] Some calculations show as finished in logs but not in Rowan UI
166
+ - [X] Some calculations show as finished in logs but not in Rowan UI
167
+ - [ ] Can you hook up Rowan's visual capabilites?
170
168
 
171
169
  ## **Citation**
172
170
 
@@ -201,3 +199,12 @@ To update the dxt file:
201
199
  # Then update the desktop extension
202
200
  dxt pack rowan-dxt
203
201
  ```
202
+ ### MCP inspector
203
+ ```bash
204
+ # Start the server first
205
+ export ROWAN_API_KEY="your_api_key_here"
206
+ uv run python -m rowan_mcp &
207
+
208
+ # Then inspect
209
+ npx @modelcontextprotocol/inspector http://127.0.0.1:6276/sse
210
+ ```
@@ -28,7 +28,7 @@ An unexpected large imaginary frequency was encountered, meaning that the calcul
28
28
  - What are the molecular orbitals of methanol? ✅
29
29
 
30
30
  ### conformational analysis
31
- - Find the stable conformers of glucose ❌ - stuck on "running"
31
+ - can you test a ❌ - stuck on "running"
32
32
  - Generate 5 conformers of butane ✅
33
33
  - What are the different shapes ethanol can adopt? ✅
34
34
 
@@ -4,14 +4,14 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "rowan-mcp"
7
- version = "1.0.2"
7
+ version = "2.0.0"
8
8
  description = "Model Context Protocol server for Rowan computational chemistry platform"
9
9
  authors = [
10
10
  {name = "Katherine Yenko", email = "katherineayenko@gmail.com"}
11
11
  ]
12
12
  license = {text = "MIT"}
13
13
  readme = "README.md"
14
- requires-python = ">=3.10"
14
+ requires-python = ">=3.11"
15
15
  urls = {Homepage = "https://github.com/k-yenko/rowan-mcp"}
16
16
  classifiers = [
17
17
  "Development Status :: 3 - Alpha",
@@ -24,8 +24,8 @@ classifiers = [
24
24
  "Topic :: Scientific/Engineering :: Chemistry",
25
25
  ]
26
26
  dependencies = [
27
- "fastmcp>=0.2.0",
28
- "rowan-python>=0.1.0",
27
+ "fastmcp>=2.11.3",
28
+ "rowan-python>=2.1.1",
29
29
  "pydantic>=2.0.0",
30
30
  "typing-extensions>=4.0.0",
31
31
  "uvicorn>=0.24.0",
@@ -33,6 +33,7 @@ dependencies = [
33
33
  "python-dotenv>=1.0.0",
34
34
  "pubchempy>=1.0.4",
35
35
  "rdkit>=2025.3.2",
36
+ "aiohttp>=3.12.15",
36
37
  ]
37
38
 
38
39
  [project.optional-dependencies]
@@ -5,7 +5,7 @@ This package provides MCP (Model Context Protocol) server functionality
5
5
  for integrating with Rowan's computational chemistry platform.
6
6
  """
7
7
 
8
- __version__ = "1.0.0"
8
+ __version__ = "1.0.2"
9
9
  __author__ = "Kat Yenko"
10
10
  __description__ = "MCP server for Rowan computational chemistry platform"
11
11
 
@@ -0,0 +1,12 @@
1
+ """
2
+ Main entry point for Rowan MCP Server when run as a module.
3
+
4
+ Usage:
5
+ python -m rowan_mcp # HTTP/SSE mode
6
+ python -m rowan_mcp --help # Show help
7
+ """
8
+
9
+ if __name__ == "__main__":
10
+ # HTTP transport only
11
+ from .server import main
12
+ main()
@@ -0,0 +1,86 @@
1
+ # Rowan MCP Benchmark Suite
2
+
3
+ ## Overview
4
+ Systematic evaluation of the Rowan MCP server's ability to handle chemistry workflows through natural language queries.
5
+
6
+ ## Evaluation Tiers
7
+
8
+ ### Tier 1: Single Tool Calls
9
+ **Tests**: Basic tool invocation and parameter passing
10
+ **Characteristics**:
11
+ - Single workflow submission
12
+ - Explicit parameters
13
+ - No dependencies
14
+ - Direct SMILES or common molecule names
15
+
16
+ **Example Queries**:
17
+ - "Calculate the pKa of phenol"
18
+ - "Optimize water geometry with GFN2-xTB"
19
+ - "Find conformers of ethanol"
20
+
21
+ ### Tier 2: Parameter Interpretation
22
+ **Tests**: Natural language to parameter mapping, molecule name resolution
23
+ **Characteristics**:
24
+ - Requires interpreting descriptive terms into API parameters
25
+ - Mode selection (rapid/careful/meticulous)
26
+ - Element specification by name vs atomic number
27
+ - Common name to SMILES conversion
28
+
29
+ **Example Queries**:
30
+ - "Calculate the oxidation potential of caffeine using careful mode"
31
+ - "Find the pKa of aspirin, only considering oxygen atoms"
32
+ - "Dock ibuprofen to CDK2 without optimization"
33
+
34
+ ### Tier 3: Batch Operations
35
+ **Tests**: Multiple independent calculations, result organization
36
+ **Characteristics**:
37
+ - Multiple molecules or methods
38
+ - Parallel workflow submission
39
+ - Result comparison/aggregation
40
+ - Folder organization
41
+
42
+ **Example Queries**:
43
+ - "Calculate pKa for phenol, p-nitrophenol, and p-chlorophenol"
44
+ - "Optimize butane with GFN2-xTB, UMA, and R2SCAN-3c methods"
45
+ - "Screen 5 molecules for docking against CDK2"
46
+
47
+ ### Tier 4: Workflow Chaining
48
+ **Tests**: Sequential dependent calculations, data extraction from results
49
+ **Characteristics**:
50
+ - Output from one workflow feeds into next
51
+ - Requires waiting for completion
52
+ - UUID and result extraction
53
+ - Proper async handling
54
+
55
+ **Example Queries**:
56
+ - "Find conformers of benzophenone, then calculate redox potential for top 3"
57
+ - "Optimize this transition state, then run IRC from the result"
58
+ - "Calculate pKa, then run conformer search at the predicted pKa value"
59
+
60
+ ### Tier 5: Conditional Logic
61
+ **Tests**: Decision-making based on results, complex multi-step analysis
62
+ **Characteristics**:
63
+ - Conditional branching based on results
64
+ - Threshold-based decisions
65
+ - Error handling and retries
66
+ - Statistical analysis of results
67
+
68
+ **Example Queries**:
69
+ - "Screen molecules for docking, only run detailed analysis if score < -8.0"
70
+ - "Calculate conformer energies, identify outliers (>2 kcal/mol from lowest), recalculate outliers with meticulous mode"
71
+ - "Find pKa sites, if any are between 6-8, run pH-dependent calculations at those values"
72
+
73
+ ## Scoring Criteria
74
+
75
+ ### Per Query
76
+ - **Success**: Workflow submitted correctly (1 point)
77
+ - **Parameters**: All parameters correctly mapped (1 point)
78
+ - **Completion**: Workflow completes without error (1 point)
79
+ - **Chaining**: Dependencies handled correctly (1 point, Tier 4-5 only)
80
+ - **Logic**: Conditional logic executed correctly (1 point, Tier 5 only)
81
+
82
+ ### Overall Metrics
83
+ - Success rate per tier
84
+ - Average time to completion
85
+ - Error recovery rate
86
+ - Parameter accuracy rate
@@ -0,0 +1,232 @@
1
+ """
2
+ Molecule name to SMILES converter using Chemical Identifier Resolver (CIR).
3
+ Enables natural language molecule input for Rowan workflows.
4
+ """
5
+
6
+ from typing import List, Dict, Annotated
7
+ from urllib.request import urlopen
8
+ from urllib.parse import quote
9
+ import logging
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ def molecule_lookup(
15
+ molecule_name: Annotated[str, "Common name, IUPAC name, or CAS number of molecule (e.g., 'aspirin', 'caffeine', '50-78-2')"],
16
+ fallback_to_input: Annotated[bool, "If lookup fails, return the input string assuming it might be SMILES"] = False
17
+ ) -> str:
18
+ """Convert molecule names to SMILES using Chemical Identifier Resolver (CIR).
19
+
20
+ Args:
21
+ molecule_name: Common name, IUPAC name, or CAS number of molecule (e.g., 'aspirin', 'caffeine', '50-78-2')
22
+ fallback_to_input: If lookup fails, return the input string assuming it might be SMILES
23
+
24
+ This tool enables natural language input for molecules by converting common names,
25
+ IUPAC names, CAS numbers, and other identifiers to SMILES strings that can be
26
+ used with Rowan workflows.
27
+
28
+ Supported Input Types:
29
+ - Common names: 'aspirin', 'caffeine', 'benzene', 'glucose'
30
+ - IUPAC names: '2-acetoxybenzoic acid', '1,3,7-trimethylpurine-2,6-dione'
31
+ - CAS numbers: '50-78-2' (aspirin), '58-08-2' (caffeine)
32
+ - InChI strings
33
+ - Already valid SMILES (will be validated)
34
+
35
+ Returns:
36
+ SMILES string if successful, error message if not found
37
+
38
+ Examples:
39
+ # Common drug name
40
+ result = molecule_lookup("aspirin")
41
+ # Returns: "CC(=O)Oc1ccccc1C(=O)O"
42
+
43
+ # IUPAC name
44
+ result = molecule_lookup("2-acetoxybenzoic acid")
45
+ # Returns: "CC(=O)Oc1ccccc1C(=O)O"
46
+
47
+ # CAS number
48
+ result = molecule_lookup("50-78-2")
49
+ # Returns: "CC(=O)Oc1ccccc1C(=O)O"
50
+
51
+ # Complex molecule
52
+ result = molecule_lookup("paracetamol")
53
+ # Returns: "CC(=O)Nc1ccc(O)cc1"
54
+ """
55
+ try:
56
+ # Clean input
57
+ molecule_name = molecule_name.strip()
58
+
59
+ # Check if already SMILES-like (contains typical SMILES characters)
60
+ smiles_chars = {'=', '#', '(', ')', '[', ']', '@', '+', '-'}
61
+ if any(char in molecule_name for char in smiles_chars):
62
+ logger.info(f"Input '{molecule_name}' appears to be SMILES, returning as-is")
63
+ return molecule_name
64
+
65
+ # Query CIR service
66
+ logger.info(f"Looking up molecule: {molecule_name}")
67
+ url = f'http://cactus.nci.nih.gov/chemical/structure/{quote(molecule_name)}/smiles'
68
+
69
+ response = urlopen(url, timeout=10)
70
+ smiles = response.read().decode('utf8').strip()
71
+
72
+ # CIR may return multiple SMILES for some queries, take the first one
73
+ if '\n' in smiles:
74
+ smiles = smiles.split('\n')[0]
75
+
76
+ logger.info(f"Successfully converted '{molecule_name}' to SMILES: {smiles}")
77
+ return smiles
78
+
79
+ except Exception as e:
80
+ logger.warning(f"Failed to lookup '{molecule_name}': {e}")
81
+
82
+ if fallback_to_input:
83
+ logger.info(f"Returning original input as fallback: {molecule_name}")
84
+ return molecule_name
85
+ else:
86
+ return f"Could not find SMILES for '{molecule_name}'. Please check the name or provide a valid SMILES string."
87
+
88
+
89
+ def batch_molecule_lookup(
90
+ molecule_names: Annotated[List[str], "List of molecule names to convert to SMILES"],
91
+ skip_failures: Annotated[bool, "Skip molecules that fail lookup instead of stopping"] = True
92
+ ) -> Dict[str, str]:
93
+ """Convert multiple molecule names to SMILES in batch.
94
+
95
+ Args:
96
+ molecule_names: List of molecule names to convert to SMILES
97
+ skip_failures: Skip molecules that fail lookup instead of stopping
98
+
99
+ Useful for preparing multiple molecules for workflows or screening.
100
+
101
+ Returns:
102
+ Dictionary mapping input names to SMILES strings (or error messages)
103
+
104
+ Examples:
105
+ # Drug screening set
106
+ result = batch_molecule_lookup([
107
+ "aspirin",
108
+ "ibuprofen",
109
+ "paracetamol",
110
+ "caffeine"
111
+ ])
112
+ # Returns: {
113
+ # "aspirin": "CC(=O)Oc1ccccc1C(=O)O",
114
+ # "ibuprofen": "CC(C)Cc1ccc(C(C)C(=O)O)cc1",
115
+ # "paracetamol": "CC(=O)Nc1ccc(O)cc1",
116
+ # "caffeine": "CN1C=NC2=C1C(=O)N(C(=O)N2C)C"
117
+ # }
118
+
119
+ # Mixed input types
120
+ result = batch_molecule_lookup([
121
+ "benzene", # Common name
122
+ "50-78-2", # CAS number
123
+ "ethanoic acid" # IUPAC name
124
+ ])
125
+ """
126
+ results = {}
127
+
128
+ for name in molecule_names:
129
+ try:
130
+ smiles = molecule_lookup(name, fallback_to_input=False)
131
+ results[name] = smiles
132
+ except Exception as e:
133
+ error_msg = f"Lookup failed: {str(e)}"
134
+ if skip_failures:
135
+ logger.warning(f"Skipping {name}: {error_msg}")
136
+ results[name] = error_msg
137
+ else:
138
+ raise ValueError(f"Failed to lookup '{name}': {error_msg}")
139
+
140
+ return results
141
+
142
+
143
+ def validate_smiles(
144
+ smiles: Annotated[str, "SMILES string to validate"]
145
+ ) -> Dict[str, any]:
146
+ """Validate a SMILES string and return basic molecular properties.
147
+
148
+ Args:
149
+ smiles: SMILES string to validate
150
+
151
+ Uses RDKit to validate SMILES and extract basic properties.
152
+
153
+ Returns:
154
+ Dictionary with validation status and properties if valid
155
+
156
+ Examples:
157
+ result = validate_smiles("CC(=O)O")
158
+ # Returns: {
159
+ # "valid": True,
160
+ # "canonical_smiles": "CC(=O)O",
161
+ # "molecular_formula": "C2H4O2",
162
+ # "molecular_weight": 60.05
163
+ # }
164
+ """
165
+ try:
166
+ from rdkit import Chem
167
+ from rdkit.Chem import Descriptors
168
+
169
+ mol = Chem.MolFromSmiles(smiles)
170
+
171
+ if mol is None:
172
+ return {
173
+ "valid": False,
174
+ "error": "Invalid SMILES string"
175
+ }
176
+
177
+ return {
178
+ "valid": True,
179
+ "canonical_smiles": Chem.MolToSmiles(mol),
180
+ "molecular_formula": Chem.rdMolDescriptors.CalcMolFormula(mol),
181
+ "molecular_weight": round(Descriptors.MolWt(mol), 2),
182
+ "num_atoms": mol.GetNumAtoms(),
183
+ "num_bonds": mol.GetNumBonds()
184
+ }
185
+
186
+ except ImportError:
187
+ return {
188
+ "valid": "unknown",
189
+ "error": "RDKit not available for validation"
190
+ }
191
+ except Exception as e:
192
+ return {
193
+ "valid": False,
194
+ "error": str(e)
195
+ }
196
+
197
+
198
+ # Common molecules reference (for documentation)
199
+ COMMON_MOLECULES = {
200
+ # Drugs
201
+ "aspirin": "CC(=O)Oc1ccccc1C(=O)O",
202
+ "paracetamol": "CC(=O)Nc1ccc(O)cc1",
203
+ "acetaminophen": "CC(=O)Nc1ccc(O)cc1", # Same as paracetamol
204
+ "ibuprofen": "CC(C)Cc1ccc(C(C)C(=O)O)cc1",
205
+ "caffeine": "CN1C=NC2=C1C(=O)N(C(=O)N2C)C",
206
+ "penicillin": "CC1(C)SC2C(NC(=O)Cc3ccccc3)C(=O)N2C1C(=O)O",
207
+
208
+ # Solvents
209
+ "water": "O",
210
+ "ethanol": "CCO",
211
+ "methanol": "CO",
212
+ "acetone": "CC(=O)C",
213
+ "dmso": "CS(=O)C",
214
+ "chloroform": "C(Cl)(Cl)Cl",
215
+ "benzene": "c1ccccc1",
216
+ "toluene": "Cc1ccccc1",
217
+
218
+ # Organic compounds
219
+ "glucose": "C(C1C(C(C(C(O1)O)O)O)O)O",
220
+ "acetic acid": "CC(=O)O",
221
+ "ethanoic acid": "CC(=O)O", # IUPAC for acetic acid
222
+ "phenol": "Oc1ccccc1",
223
+ "aniline": "Nc1ccccc1",
224
+ "naphthalene": "c1ccc2c(c1)cccc2",
225
+
226
+ # Amino acids
227
+ "glycine": "C(C(=O)O)N",
228
+ "alanine": "CC(C(=O)O)N",
229
+ "valine": "CC(C)C(C(=O)O)N",
230
+ "leucine": "CC(C)CC(C(=O)O)N",
231
+ "lysine": "C(CCN)CC(C(=O)O)N",
232
+ }