tooluniverse 0.2.0__py3-none-any.whl → 1.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 tooluniverse might be problematic. Click here for more details.

Files changed (190) hide show
  1. tooluniverse/__init__.py +340 -4
  2. tooluniverse/admetai_tool.py +84 -0
  3. tooluniverse/agentic_tool.py +563 -0
  4. tooluniverse/alphafold_tool.py +96 -0
  5. tooluniverse/base_tool.py +129 -6
  6. tooluniverse/boltz_tool.py +207 -0
  7. tooluniverse/chem_tool.py +192 -0
  8. tooluniverse/compose_scripts/__init__.py +1 -0
  9. tooluniverse/compose_scripts/biomarker_discovery.py +293 -0
  10. tooluniverse/compose_scripts/comprehensive_drug_discovery.py +186 -0
  11. tooluniverse/compose_scripts/drug_safety_analyzer.py +89 -0
  12. tooluniverse/compose_scripts/literature_tool.py +34 -0
  13. tooluniverse/compose_scripts/output_summarizer.py +279 -0
  14. tooluniverse/compose_scripts/tool_description_optimizer.py +681 -0
  15. tooluniverse/compose_scripts/tool_discover.py +705 -0
  16. tooluniverse/compose_scripts/tool_graph_composer.py +448 -0
  17. tooluniverse/compose_tool.py +371 -0
  18. tooluniverse/ctg_tool.py +1002 -0
  19. tooluniverse/custom_tool.py +81 -0
  20. tooluniverse/dailymed_tool.py +108 -0
  21. tooluniverse/data/admetai_tools.json +155 -0
  22. tooluniverse/data/agentic_tools.json +1156 -0
  23. tooluniverse/data/alphafold_tools.json +87 -0
  24. tooluniverse/data/boltz_tools.json +9 -0
  25. tooluniverse/data/chembl_tools.json +16 -0
  26. tooluniverse/data/clait_tools.json +108 -0
  27. tooluniverse/data/clinicaltrials_gov_tools.json +326 -0
  28. tooluniverse/data/compose_tools.json +202 -0
  29. tooluniverse/data/dailymed_tools.json +70 -0
  30. tooluniverse/data/dataset_tools.json +646 -0
  31. tooluniverse/data/disease_target_score_tools.json +712 -0
  32. tooluniverse/data/efo_tools.json +17 -0
  33. tooluniverse/data/embedding_tools.json +319 -0
  34. tooluniverse/data/enrichr_tools.json +31 -0
  35. tooluniverse/data/europe_pmc_tools.json +22 -0
  36. tooluniverse/data/expert_feedback_tools.json +10 -0
  37. tooluniverse/data/fda_drug_adverse_event_tools.json +491 -0
  38. tooluniverse/data/fda_drug_labeling_tools.json +1 -1
  39. tooluniverse/data/fda_drugs_with_brand_generic_names_for_tool.py +76929 -148860
  40. tooluniverse/data/finder_tools.json +209 -0
  41. tooluniverse/data/gene_ontology_tools.json +113 -0
  42. tooluniverse/data/gwas_tools.json +1082 -0
  43. tooluniverse/data/hpa_tools.json +333 -0
  44. tooluniverse/data/humanbase_tools.json +47 -0
  45. tooluniverse/data/idmap_tools.json +74 -0
  46. tooluniverse/data/mcp_client_tools_example.json +113 -0
  47. tooluniverse/data/mcpautoloadertool_defaults.json +28 -0
  48. tooluniverse/data/medlineplus_tools.json +141 -0
  49. tooluniverse/data/monarch_tools.json +1 -1
  50. tooluniverse/data/openalex_tools.json +36 -0
  51. tooluniverse/data/opentarget_tools.json +1 -1
  52. tooluniverse/data/output_summarization_tools.json +101 -0
  53. tooluniverse/data/packages/bioinformatics_core_tools.json +1756 -0
  54. tooluniverse/data/packages/categorized_tools.txt +206 -0
  55. tooluniverse/data/packages/cheminformatics_tools.json +347 -0
  56. tooluniverse/data/packages/earth_sciences_tools.json +74 -0
  57. tooluniverse/data/packages/genomics_tools.json +776 -0
  58. tooluniverse/data/packages/image_processing_tools.json +38 -0
  59. tooluniverse/data/packages/machine_learning_tools.json +789 -0
  60. tooluniverse/data/packages/neuroscience_tools.json +62 -0
  61. tooluniverse/data/packages/original_tools.txt +0 -0
  62. tooluniverse/data/packages/physics_astronomy_tools.json +62 -0
  63. tooluniverse/data/packages/scientific_computing_tools.json +560 -0
  64. tooluniverse/data/packages/single_cell_tools.json +453 -0
  65. tooluniverse/data/packages/software_tools.json +4954 -0
  66. tooluniverse/data/packages/structural_biology_tools.json +396 -0
  67. tooluniverse/data/packages/visualization_tools.json +399 -0
  68. tooluniverse/data/pubchem_tools.json +215 -0
  69. tooluniverse/data/pubtator_tools.json +68 -0
  70. tooluniverse/data/rcsb_pdb_tools.json +1332 -0
  71. tooluniverse/data/reactome_tools.json +19 -0
  72. tooluniverse/data/semantic_scholar_tools.json +26 -0
  73. tooluniverse/data/special_tools.json +2 -25
  74. tooluniverse/data/tool_composition_tools.json +88 -0
  75. tooluniverse/data/toolfinderkeyword_defaults.json +34 -0
  76. tooluniverse/data/txagent_client_tools.json +9 -0
  77. tooluniverse/data/uniprot_tools.json +211 -0
  78. tooluniverse/data/url_fetch_tools.json +94 -0
  79. tooluniverse/data/uspto_downloader_tools.json +9 -0
  80. tooluniverse/data/uspto_tools.json +811 -0
  81. tooluniverse/data/xml_tools.json +3275 -0
  82. tooluniverse/dataset_tool.py +296 -0
  83. tooluniverse/default_config.py +165 -0
  84. tooluniverse/efo_tool.py +42 -0
  85. tooluniverse/embedding_database.py +630 -0
  86. tooluniverse/embedding_sync.py +396 -0
  87. tooluniverse/enrichr_tool.py +266 -0
  88. tooluniverse/europe_pmc_tool.py +52 -0
  89. tooluniverse/execute_function.py +1775 -95
  90. tooluniverse/extended_hooks.py +444 -0
  91. tooluniverse/gene_ontology_tool.py +194 -0
  92. tooluniverse/graphql_tool.py +158 -36
  93. tooluniverse/gwas_tool.py +358 -0
  94. tooluniverse/hpa_tool.py +1645 -0
  95. tooluniverse/humanbase_tool.py +389 -0
  96. tooluniverse/logging_config.py +254 -0
  97. tooluniverse/mcp_client_tool.py +764 -0
  98. tooluniverse/mcp_integration.py +413 -0
  99. tooluniverse/mcp_tool_registry.py +925 -0
  100. tooluniverse/medlineplus_tool.py +337 -0
  101. tooluniverse/openalex_tool.py +228 -0
  102. tooluniverse/openfda_adv_tool.py +283 -0
  103. tooluniverse/openfda_tool.py +393 -160
  104. tooluniverse/output_hook.py +1122 -0
  105. tooluniverse/package_tool.py +195 -0
  106. tooluniverse/pubchem_tool.py +158 -0
  107. tooluniverse/pubtator_tool.py +168 -0
  108. tooluniverse/rcsb_pdb_tool.py +38 -0
  109. tooluniverse/reactome_tool.py +108 -0
  110. tooluniverse/remote/boltz/boltz_mcp_server.py +50 -0
  111. tooluniverse/remote/depmap_24q2/depmap_24q2_mcp_tool.py +442 -0
  112. tooluniverse/remote/expert_feedback/human_expert_mcp_tools.py +2013 -0
  113. tooluniverse/remote/expert_feedback/simple_test.py +23 -0
  114. tooluniverse/remote/expert_feedback/start_web_interface.py +188 -0
  115. tooluniverse/remote/expert_feedback/web_only_interface.py +0 -0
  116. tooluniverse/remote/expert_feedback_mcp/human_expert_mcp_server.py +1611 -0
  117. tooluniverse/remote/expert_feedback_mcp/simple_test.py +34 -0
  118. tooluniverse/remote/expert_feedback_mcp/start_web_interface.py +91 -0
  119. tooluniverse/remote/immune_compass/compass_tool.py +327 -0
  120. tooluniverse/remote/pinnacle/pinnacle_tool.py +328 -0
  121. tooluniverse/remote/transcriptformer/transcriptformer_tool.py +586 -0
  122. tooluniverse/remote/uspto_downloader/uspto_downloader_mcp_server.py +61 -0
  123. tooluniverse/remote/uspto_downloader/uspto_downloader_tool.py +120 -0
  124. tooluniverse/remote_tool.py +99 -0
  125. tooluniverse/restful_tool.py +53 -30
  126. tooluniverse/scripts/generate_tool_graph.py +408 -0
  127. tooluniverse/scripts/visualize_tool_graph.py +829 -0
  128. tooluniverse/semantic_scholar_tool.py +62 -0
  129. tooluniverse/smcp.py +2452 -0
  130. tooluniverse/smcp_server.py +975 -0
  131. tooluniverse/test/mcp_server_test.py +0 -0
  132. tooluniverse/test/test_admetai_tool.py +370 -0
  133. tooluniverse/test/test_agentic_tool.py +129 -0
  134. tooluniverse/test/test_alphafold_tool.py +71 -0
  135. tooluniverse/test/test_chem_tool.py +37 -0
  136. tooluniverse/test/test_compose_lieraturereview.py +63 -0
  137. tooluniverse/test/test_compose_tool.py +448 -0
  138. tooluniverse/test/test_dailymed.py +69 -0
  139. tooluniverse/test/test_dataset_tool.py +200 -0
  140. tooluniverse/test/test_disease_target_score.py +56 -0
  141. tooluniverse/test/test_drugbank_filter_examples.py +179 -0
  142. tooluniverse/test/test_efo.py +31 -0
  143. tooluniverse/test/test_enrichr_tool.py +21 -0
  144. tooluniverse/test/test_europe_pmc_tool.py +20 -0
  145. tooluniverse/test/test_fda_adv.py +95 -0
  146. tooluniverse/test/test_fda_drug_labeling.py +91 -0
  147. tooluniverse/test/test_gene_ontology_tools.py +66 -0
  148. tooluniverse/test/test_gwas_tool.py +139 -0
  149. tooluniverse/test/test_hpa.py +625 -0
  150. tooluniverse/test/test_humanbase_tool.py +20 -0
  151. tooluniverse/test/test_idmap_tools.py +61 -0
  152. tooluniverse/test/test_mcp_server.py +211 -0
  153. tooluniverse/test/test_mcp_tool.py +247 -0
  154. tooluniverse/test/test_medlineplus.py +220 -0
  155. tooluniverse/test/test_openalex_tool.py +32 -0
  156. tooluniverse/test/test_opentargets.py +28 -0
  157. tooluniverse/test/test_pubchem_tool.py +116 -0
  158. tooluniverse/test/test_pubtator_tool.py +37 -0
  159. tooluniverse/test/test_rcsb_pdb_tool.py +86 -0
  160. tooluniverse/test/test_reactome.py +54 -0
  161. tooluniverse/test/test_semantic_scholar_tool.py +24 -0
  162. tooluniverse/test/test_software_tools.py +147 -0
  163. tooluniverse/test/test_tool_description_optimizer.py +49 -0
  164. tooluniverse/test/test_tool_finder.py +26 -0
  165. tooluniverse/test/test_tool_finder_llm.py +252 -0
  166. tooluniverse/test/test_tools_find.py +195 -0
  167. tooluniverse/test/test_uniprot_tools.py +74 -0
  168. tooluniverse/test/test_uspto_tool.py +72 -0
  169. tooluniverse/test/test_xml_tool.py +113 -0
  170. tooluniverse/tool_finder_embedding.py +267 -0
  171. tooluniverse/tool_finder_keyword.py +693 -0
  172. tooluniverse/tool_finder_llm.py +699 -0
  173. tooluniverse/tool_graph_web_ui.py +955 -0
  174. tooluniverse/tool_registry.py +416 -0
  175. tooluniverse/uniprot_tool.py +155 -0
  176. tooluniverse/url_tool.py +253 -0
  177. tooluniverse/uspto_tool.py +240 -0
  178. tooluniverse/utils.py +369 -41
  179. tooluniverse/xml_tool.py +369 -0
  180. tooluniverse-1.0.0.dist-info/METADATA +377 -0
  181. tooluniverse-1.0.0.dist-info/RECORD +186 -0
  182. tooluniverse-1.0.0.dist-info/entry_points.txt +9 -0
  183. tooluniverse/generate_mcp_tools.py +0 -113
  184. tooluniverse/mcp_server.py +0 -3340
  185. tooluniverse-0.2.0.dist-info/METADATA +0 -139
  186. tooluniverse-0.2.0.dist-info/RECORD +0 -21
  187. tooluniverse-0.2.0.dist-info/entry_points.txt +0 -4
  188. {tooluniverse-0.2.0.dist-info → tooluniverse-1.0.0.dist-info}/WHEEL +0 -0
  189. {tooluniverse-0.2.0.dist-info → tooluniverse-1.0.0.dist-info}/licenses/LICENSE +0 -0
  190. {tooluniverse-0.2.0.dist-info → tooluniverse-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,283 @@
1
+ import os
2
+ import copy
3
+ import requests
4
+ import urllib.parse
5
+ from .base_tool import BaseTool
6
+ from .tool_registry import register_tool
7
+
8
+ # ---- Helper: human readable -> openFDA code mapping ----
9
+ HUMAN_TO_FDA_MAP = {
10
+ "fulfillexpeditecriteria": {"Yes": "1", "No": "2"},
11
+ "patient.patientsex": {"Unknown": "0", "Male": "1", "Female": "2"},
12
+ "patient.patientagegroup": {
13
+ "Neonate": "1",
14
+ "Infant": "2",
15
+ "Child": "3",
16
+ "Adolescent": "4",
17
+ "Adult": "5",
18
+ "Elderly": "6",
19
+ },
20
+ "patientonsetageunit": {
21
+ "Decade": "800",
22
+ "Year": "801",
23
+ "Month": "802",
24
+ "Week": "803",
25
+ "Day": "804",
26
+ "Hour": "805",
27
+ },
28
+ "patient.reaction.reactionoutcome": {
29
+ "Recovered/resolved": "1",
30
+ "Recovering/resolving": "2",
31
+ "Not recovered/not resolved": "3",
32
+ "Recovered/resolved with sequelae": "4",
33
+ "Fatal": "5",
34
+ "Unknown": "6",
35
+ },
36
+ "serious": {"Yes": "1", "No": "2"},
37
+ "seriousnessdeath": {"Yes": "1"},
38
+ "seriousnesshospitalization": {"Yes": "1"},
39
+ "seriousnessdisabling": {"Yes": "1"},
40
+ "seriousnesslifethreatening": {"Yes": "1"},
41
+ "seriousnessother": {"Yes": "1"},
42
+ "primarysource.qualification": {
43
+ "Physician": "1",
44
+ "Pharmacist": "2",
45
+ "Other health professional": "3",
46
+ "Lawyer": "4",
47
+ "Consumer or non-health professional": "5",
48
+ },
49
+ "patient.drug.drugcharacterization": {
50
+ "Suspect": "1",
51
+ "Concomitant": "2",
52
+ "Interacting": "3",
53
+ },
54
+ "patient.drug.drugadministrationroute": {
55
+ "Oral": "048",
56
+ "Intravenous": "042",
57
+ "Intramuscular": "030",
58
+ "Subcutaneous": "058",
59
+ "Rectal": "054",
60
+ "Topical": "061",
61
+ "Respiratory (inhalation)": "055",
62
+ "Ophthalmic": "047",
63
+ "Unknown": "065",
64
+ },
65
+ }
66
+
67
+
68
+ # ---- Base Tool Class ----
69
+ @register_tool("FDADrugAdverseEventTool")
70
+ class FDADrugAdverseEventTool(BaseTool):
71
+ def __init__(
72
+ self,
73
+ tool_config,
74
+ endpoint_url="https://api.fda.gov/drug/event.json",
75
+ api_key=None,
76
+ ):
77
+ super().__init__(tool_config)
78
+ self.endpoint_url = endpoint_url
79
+ self.api_key = api_key or os.getenv("FDA_API_KEY")
80
+ self.search_fields = tool_config.get("fields", {}).get("search_fields", {})
81
+ self.return_fields = tool_config.get("fields", {}).get("return_fields", [])
82
+ self.count_field = tool_config.get("count_field") or (
83
+ self.return_fields[0] if self.return_fields else None
84
+ )
85
+ self.return_fields_mapping = tool_config.get("fields", {}).get(
86
+ "return_fields_mapping", {}
87
+ )
88
+
89
+ if not self.count_field:
90
+ raise ValueError(
91
+ "Either 'count_field' or 'return_fields' must be defined in tool_config."
92
+ )
93
+
94
+ # Store allowed enum values
95
+ self.parameter_enums = {}
96
+ if "parameter" in tool_config and "properties" in tool_config["parameter"]:
97
+ for param_name, param_def in tool_config["parameter"]["properties"].items():
98
+ if "enum" in param_def:
99
+ self.parameter_enums[param_name] = param_def["enum"]
100
+
101
+ def run(self, arguments):
102
+ arguments = copy.deepcopy(arguments)
103
+
104
+ # Validate enum parameters
105
+ validation_error = self.validate_enum_arguments(arguments)
106
+ if validation_error:
107
+ return {"error": validation_error}
108
+
109
+ response = self._search(arguments)
110
+ return self._post_process(response)
111
+
112
+ def validate_enum_arguments(self, arguments):
113
+ """Validate that enum-based arguments match the allowed values"""
114
+ for param_name, value in arguments.items():
115
+ if param_name in self.parameter_enums and value is not None:
116
+ allowed_values = self.parameter_enums[param_name]
117
+ if value not in allowed_values:
118
+ return f"Invalid value '{value}' for parameter '{param_name}'. Allowed values are: {', '.join(allowed_values)}"
119
+ return None
120
+
121
+ def _post_process(self, response):
122
+ if not response or not isinstance(response, list):
123
+ return []
124
+
125
+ if not self.return_fields_mapping:
126
+ return response
127
+
128
+ mapped_results = []
129
+ for item in response:
130
+ try:
131
+ term = item.get("term")
132
+ count = item.get("count", 0)
133
+ mapped_term = self.return_fields_mapping.get(self.count_field, {}).get(
134
+ str(term), term
135
+ )
136
+ mapped_results.append({"term": mapped_term, "count": count})
137
+ except Exception:
138
+ # Keep the original term in case of an exception
139
+ mapped_results.append(item)
140
+
141
+ return mapped_results
142
+
143
+ def _search(self, arguments):
144
+ search_parts = []
145
+ for param_name, value in arguments.items():
146
+ fda_fields = self.search_fields.get(
147
+ param_name, [param_name]
148
+ ) # Map param -> FDA field
149
+
150
+ # Apply value mapping if needed
151
+ mapping_error, mapped_value = self._map_value(param_name, value)
152
+ if mapping_error:
153
+ return [{"error": mapping_error}]
154
+ if mapped_value is None:
155
+ continue # Skip this field if instructed
156
+
157
+ # Build search parts
158
+ for fda_field in fda_fields:
159
+ if isinstance(mapped_value, str) and " " in mapped_value:
160
+ search_parts.append(f'{fda_field}:"{mapped_value}"')
161
+ else:
162
+ search_parts.append(f"{fda_field}:{mapped_value}")
163
+
164
+ # Final search query
165
+ search_query = "+AND+".join(search_parts)
166
+ search_encoded = urllib.parse.quote(search_query, safe='+:"')
167
+
168
+ # Build URL
169
+ if self.api_key:
170
+ url = f"{self.endpoint_url}?api_key={self.api_key}&search={search_encoded}&count={self.count_field}"
171
+ else:
172
+ url = (
173
+ f"{self.endpoint_url}?search={search_encoded}&count={self.count_field}"
174
+ )
175
+
176
+ # API request
177
+ try:
178
+ response = requests.get(url)
179
+ response.raise_for_status()
180
+ response = response.json()
181
+ if "results" in response:
182
+ response = response["results"]
183
+ return response
184
+ except requests.exceptions.RequestException as e:
185
+ return [{"error": f"API request failed: {str(e)}"}]
186
+
187
+ def _map_value(self, param_name, value):
188
+ # Special handling for seriousness fields: if value is "No", skip this field
189
+ seriousness_fields = {
190
+ "seriousnessdeath",
191
+ "seriousnesshospitalization",
192
+ "seriousnessdisabling",
193
+ "seriousnesslifethreatening",
194
+ "seriousnessother",
195
+ }
196
+ if param_name in seriousness_fields:
197
+ if value == "No":
198
+ return None, None # Signal to skip this field
199
+ if value == "Yes":
200
+ return None, "1"
201
+ # If not Yes/No, error
202
+ return (
203
+ f"Invalid value '{value}' for '{param_name}'. Allowed values: ['Yes', 'No']",
204
+ None,
205
+ )
206
+
207
+ if param_name in HUMAN_TO_FDA_MAP:
208
+ value_map = HUMAN_TO_FDA_MAP[param_name]
209
+ if value not in value_map:
210
+ print("No mapping found for value:", value, "skipping")
211
+ allowed_values = list(value_map.keys())
212
+ return (
213
+ f"Invalid value '{value}' for '{param_name}'. Allowed values: {allowed_values}",
214
+ None,
215
+ )
216
+ return None, value_map[value]
217
+ return None, value
218
+
219
+
220
+ @register_tool("FDACountAdditiveReactionsTool")
221
+ class FDACountAdditiveReactionsTool(FDADrugAdverseEventTool):
222
+ """
223
+ Leverage openFDA API to count adverse reaction events across multiple drugs in one request.
224
+ """
225
+
226
+ def __init__(
227
+ self,
228
+ tool_config,
229
+ endpoint_url="https://api.fda.gov/drug/event.json",
230
+ api_key=None,
231
+ ):
232
+ super().__init__(tool_config)
233
+
234
+ def run(self, arguments):
235
+ # Make a copy to avoid modifying the original
236
+ arguments = copy.deepcopy(arguments)
237
+
238
+ # Validate medicinalproducts list first
239
+ drugs = arguments.pop("medicinalproducts", [])
240
+ if not drugs:
241
+ return {"error": "`medicinalproducts` list is required."}
242
+ if not isinstance(drugs, list):
243
+ return {"error": "`medicinalproducts` must be a list of drug names."}
244
+
245
+ # Validate the remaining enum parameters
246
+ validation_error = self.validate_enum_arguments(arguments)
247
+ if validation_error:
248
+ return {"error": validation_error}
249
+
250
+ # Build OR clause for multiple drugs
251
+ escaped = []
252
+ for d in drugs:
253
+ val = urllib.parse.quote(d, safe="")
254
+ escaped.append(f"patient.drug.medicinalproduct:{val}")
255
+ or_clause = "+OR+".join(escaped)
256
+
257
+ # Combine additional filters
258
+ filters = []
259
+ for k, v in arguments.items():
260
+ mapping_error, mapped = self._map_value(k, v)
261
+ if mapping_error:
262
+ return {"error": mapping_error}
263
+ if mapped is None:
264
+ continue # Skip this field if instructed
265
+ filters.append(f"{k}:{mapped}")
266
+
267
+ filter_str = "+AND+".join(filters) if filters else ""
268
+ search_query = f"({or_clause})" + (f"+AND+{filter_str}" if filter_str else "")
269
+
270
+ # Call API
271
+ if self.api_key:
272
+ url = f"{self.endpoint_url}?api_key={self.api_key}&search={search_query}&count={self.count_field}"
273
+ else:
274
+ url = f"{self.endpoint_url}?search={search_query}&count={self.count_field}"
275
+
276
+ try:
277
+ resp = requests.get(url)
278
+ resp.raise_for_status()
279
+ results = resp.json().get("results", [])
280
+ results = self._post_process(results)
281
+ return results
282
+ except requests.exceptions.RequestException as e:
283
+ return {"error": f"API request failed: {str(e)}"}