aurelian 0.1.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.
Files changed (266) hide show
  1. aurelian/__init__.py +9 -0
  2. aurelian/agents/__init__.py +0 -0
  3. aurelian/agents/amigo/__init__.py +3 -0
  4. aurelian/agents/amigo/amigo_agent.py +77 -0
  5. aurelian/agents/amigo/amigo_config.py +85 -0
  6. aurelian/agents/amigo/amigo_evals.py +73 -0
  7. aurelian/agents/amigo/amigo_gradio.py +52 -0
  8. aurelian/agents/amigo/amigo_mcp.py +152 -0
  9. aurelian/agents/amigo/amigo_tools.py +152 -0
  10. aurelian/agents/biblio/__init__.py +42 -0
  11. aurelian/agents/biblio/biblio_agent.py +95 -0
  12. aurelian/agents/biblio/biblio_config.py +40 -0
  13. aurelian/agents/biblio/biblio_gradio.py +67 -0
  14. aurelian/agents/biblio/biblio_mcp.py +115 -0
  15. aurelian/agents/biblio/biblio_tools.py +164 -0
  16. aurelian/agents/biblio_agent.py +46 -0
  17. aurelian/agents/checklist/__init__.py +44 -0
  18. aurelian/agents/checklist/checklist_agent.py +86 -0
  19. aurelian/agents/checklist/checklist_config.py +28 -0
  20. aurelian/agents/checklist/checklist_gradio.py +70 -0
  21. aurelian/agents/checklist/checklist_mcp.py +86 -0
  22. aurelian/agents/checklist/checklist_tools.py +141 -0
  23. aurelian/agents/checklist/content/checklists.yaml +7 -0
  24. aurelian/agents/checklist/content/streams.csv +136 -0
  25. aurelian/agents/checklist_agent.py +40 -0
  26. aurelian/agents/chemistry/__init__.py +3 -0
  27. aurelian/agents/chemistry/chemistry_agent.py +47 -0
  28. aurelian/agents/chemistry/chemistry_config.py +71 -0
  29. aurelian/agents/chemistry/chemistry_evals.py +79 -0
  30. aurelian/agents/chemistry/chemistry_gradio.py +50 -0
  31. aurelian/agents/chemistry/chemistry_mcp.py +120 -0
  32. aurelian/agents/chemistry/chemistry_tools.py +121 -0
  33. aurelian/agents/chemistry/image_agent.py +15 -0
  34. aurelian/agents/d4d/__init__.py +30 -0
  35. aurelian/agents/d4d/d4d_agent.py +73 -0
  36. aurelian/agents/d4d/d4d_config.py +46 -0
  37. aurelian/agents/d4d/d4d_gradio.py +58 -0
  38. aurelian/agents/d4d/d4d_mcp.py +71 -0
  39. aurelian/agents/d4d/d4d_tools.py +157 -0
  40. aurelian/agents/d4d_agent.py +64 -0
  41. aurelian/agents/diagnosis/__init__.py +33 -0
  42. aurelian/agents/diagnosis/diagnosis_agent.py +54 -0
  43. aurelian/agents/diagnosis/diagnosis_config.py +48 -0
  44. aurelian/agents/diagnosis/diagnosis_evals.py +76 -0
  45. aurelian/agents/diagnosis/diagnosis_gradio.py +52 -0
  46. aurelian/agents/diagnosis/diagnosis_mcp.py +141 -0
  47. aurelian/agents/diagnosis/diagnosis_tools.py +204 -0
  48. aurelian/agents/diagnosis_agent.py +28 -0
  49. aurelian/agents/draw/__init__.py +3 -0
  50. aurelian/agents/draw/draw_agent.py +39 -0
  51. aurelian/agents/draw/draw_config.py +26 -0
  52. aurelian/agents/draw/draw_gradio.py +50 -0
  53. aurelian/agents/draw/draw_mcp.py +94 -0
  54. aurelian/agents/draw/draw_tools.py +100 -0
  55. aurelian/agents/draw/judge_agent.py +18 -0
  56. aurelian/agents/filesystem/__init__.py +0 -0
  57. aurelian/agents/filesystem/filesystem_config.py +27 -0
  58. aurelian/agents/filesystem/filesystem_gradio.py +49 -0
  59. aurelian/agents/filesystem/filesystem_mcp.py +89 -0
  60. aurelian/agents/filesystem/filesystem_tools.py +95 -0
  61. aurelian/agents/filesystem/py.typed +0 -0
  62. aurelian/agents/github/__init__.py +0 -0
  63. aurelian/agents/github/github_agent.py +83 -0
  64. aurelian/agents/github/github_cli.py +248 -0
  65. aurelian/agents/github/github_config.py +22 -0
  66. aurelian/agents/github/github_gradio.py +152 -0
  67. aurelian/agents/github/github_mcp.py +252 -0
  68. aurelian/agents/github/github_tools.py +408 -0
  69. aurelian/agents/github/github_tools.py.tmp +413 -0
  70. aurelian/agents/goann/__init__.py +13 -0
  71. aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines.md +1000 -0
  72. aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines.pdf +0 -0
  73. aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines_Paper.md +693 -0
  74. aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines_Paper.pdf +0 -0
  75. aurelian/agents/goann/goann_agent.py +90 -0
  76. aurelian/agents/goann/goann_config.py +90 -0
  77. aurelian/agents/goann/goann_evals.py +104 -0
  78. aurelian/agents/goann/goann_gradio.py +62 -0
  79. aurelian/agents/goann/goann_mcp.py +0 -0
  80. aurelian/agents/goann/goann_tools.py +65 -0
  81. aurelian/agents/gocam/__init__.py +52 -0
  82. aurelian/agents/gocam/documents/DNA-binding transcription factor activity annotation guidelines.docx +0 -0
  83. aurelian/agents/gocam/documents/DNA-binding transcription factor activity annotation guidelines.pdf +0 -0
  84. aurelian/agents/gocam/documents/DNA-binding_transcription_factor_activity_annotation_guidelines.md +100 -0
  85. aurelian/agents/gocam/documents/E3 ubiquitin ligases.docx +0 -0
  86. aurelian/agents/gocam/documents/E3 ubiquitin ligases.pdf +0 -0
  87. aurelian/agents/gocam/documents/E3_ubiquitin_ligases.md +134 -0
  88. aurelian/agents/gocam/documents/GO-CAM annotation guidelines README.docx +0 -0
  89. aurelian/agents/gocam/documents/GO-CAM annotation guidelines README.pdf +0 -0
  90. aurelian/agents/gocam/documents/GO-CAM modelling guidelines TO DO.docx +0 -0
  91. aurelian/agents/gocam/documents/GO-CAM modelling guidelines TO DO.pdf +0 -0
  92. aurelian/agents/gocam/documents/GO-CAM_annotation_guidelines_README.md +1 -0
  93. aurelian/agents/gocam/documents/GO-CAM_modelling_guidelines_TO_DO.md +3 -0
  94. aurelian/agents/gocam/documents/How to annotate complexes in GO-CAM.docx +0 -0
  95. aurelian/agents/gocam/documents/How to annotate complexes in GO-CAM.pdf +0 -0
  96. aurelian/agents/gocam/documents/How to annotate molecular adaptors.docx +0 -0
  97. aurelian/agents/gocam/documents/How to annotate molecular adaptors.pdf +0 -0
  98. aurelian/agents/gocam/documents/How to annotate sequestering proteins.docx +0 -0
  99. aurelian/agents/gocam/documents/How to annotate sequestering proteins.pdf +0 -0
  100. aurelian/agents/gocam/documents/How_to_annotate_complexes_in_GO-CAM.md +29 -0
  101. aurelian/agents/gocam/documents/How_to_annotate_molecular_adaptors.md +31 -0
  102. aurelian/agents/gocam/documents/How_to_annotate_sequestering_proteins.md +42 -0
  103. aurelian/agents/gocam/documents/Molecular adaptor activity.docx +0 -0
  104. aurelian/agents/gocam/documents/Molecular adaptor activity.pdf +0 -0
  105. aurelian/agents/gocam/documents/Molecular carrier activity.docx +0 -0
  106. aurelian/agents/gocam/documents/Molecular carrier activity.pdf +0 -0
  107. aurelian/agents/gocam/documents/Molecular_adaptor_activity.md +51 -0
  108. aurelian/agents/gocam/documents/Molecular_carrier_activity.md +41 -0
  109. aurelian/agents/gocam/documents/Protein sequestering activity.docx +0 -0
  110. aurelian/agents/gocam/documents/Protein sequestering activity.pdf +0 -0
  111. aurelian/agents/gocam/documents/Protein_sequestering_activity.md +50 -0
  112. aurelian/agents/gocam/documents/Signaling receptor activity annotation guidelines.docx +0 -0
  113. aurelian/agents/gocam/documents/Signaling receptor activity annotation guidelines.pdf +0 -0
  114. aurelian/agents/gocam/documents/Signaling_receptor_activity_annotation_guidelines.md +187 -0
  115. aurelian/agents/gocam/documents/Transcription coregulator activity.docx +0 -0
  116. aurelian/agents/gocam/documents/Transcription coregulator activity.pdf +0 -0
  117. aurelian/agents/gocam/documents/Transcription_coregulator_activity.md +36 -0
  118. aurelian/agents/gocam/documents/Transporter activity annotation annotation guidelines.docx +0 -0
  119. aurelian/agents/gocam/documents/Transporter activity annotation annotation guidelines.pdf +0 -0
  120. aurelian/agents/gocam/documents/Transporter_activity_annotation_annotation_guidelines.md +43 -0
  121. Regulatory Processes in GO-CAM.docx +0 -0
  122. Regulatory Processes in GO-CAM.pdf +0 -0
  123. aurelian/agents/gocam/documents/WIP_-_Regulation_and_Regulatory_Processes_in_GO-CAM.md +31 -0
  124. aurelian/agents/gocam/documents/md/DNA-binding_transcription_factor_activity_annotation_guidelines.md +131 -0
  125. aurelian/agents/gocam/documents/md/E3_ubiquitin_ligases.md +166 -0
  126. aurelian/agents/gocam/documents/md/GO-CAM_annotation_guidelines_README.md +1 -0
  127. aurelian/agents/gocam/documents/md/GO-CAM_modelling_guidelines_TO_DO.md +5 -0
  128. aurelian/agents/gocam/documents/md/How_to_annotate_complexes_in_GO-CAM.md +28 -0
  129. aurelian/agents/gocam/documents/md/How_to_annotate_molecular_adaptors.md +19 -0
  130. aurelian/agents/gocam/documents/md/How_to_annotate_sequestering_proteins.md +38 -0
  131. aurelian/agents/gocam/documents/md/Molecular_adaptor_activity.md +52 -0
  132. aurelian/agents/gocam/documents/md/Molecular_carrier_activity.md +59 -0
  133. aurelian/agents/gocam/documents/md/Protein_sequestering_activity.md +52 -0
  134. aurelian/agents/gocam/documents/md/Signaling_receptor_activity_annotation_guidelines.md +271 -0
  135. aurelian/agents/gocam/documents/md/Transcription_coregulator_activity.md +54 -0
  136. aurelian/agents/gocam/documents/md/Transporter_activity_annotation_annotation_guidelines.md +38 -0
  137. aurelian/agents/gocam/documents/md/WIP_-_Regulation_and_Regulatory_Processes_in_GO-CAM.md +39 -0
  138. aurelian/agents/gocam/documents/pandoc_md/Signaling_receptor_activity_annotation_guidelines.md +334 -0
  139. aurelian/agents/gocam/gocam_agent.py +243 -0
  140. aurelian/agents/gocam/gocam_config.py +85 -0
  141. aurelian/agents/gocam/gocam_curator_agent.py +46 -0
  142. aurelian/agents/gocam/gocam_evals.py +64 -0
  143. aurelian/agents/gocam/gocam_gradio.py +89 -0
  144. aurelian/agents/gocam/gocam_mcp.py +224 -0
  145. aurelian/agents/gocam/gocam_tools.py +294 -0
  146. aurelian/agents/linkml/__init__.py +0 -0
  147. aurelian/agents/linkml/linkml_agent.py +62 -0
  148. aurelian/agents/linkml/linkml_config.py +48 -0
  149. aurelian/agents/linkml/linkml_evals.py +66 -0
  150. aurelian/agents/linkml/linkml_gradio.py +45 -0
  151. aurelian/agents/linkml/linkml_mcp.py +181 -0
  152. aurelian/agents/linkml/linkml_tools.py +102 -0
  153. aurelian/agents/literature/__init__.py +3 -0
  154. aurelian/agents/literature/literature_agent.py +75 -0
  155. aurelian/agents/literature/literature_config.py +35 -0
  156. aurelian/agents/literature/literature_gradio.py +52 -0
  157. aurelian/agents/literature/literature_mcp.py +174 -0
  158. aurelian/agents/literature/literature_tools.py +182 -0
  159. aurelian/agents/monarch/__init__.py +0 -0
  160. aurelian/agents/monarch/monarch_agent.py +45 -0
  161. aurelian/agents/monarch/monarch_config.py +45 -0
  162. aurelian/agents/monarch/monarch_gradio.py +51 -0
  163. aurelian/agents/monarch/monarch_mcp.py +65 -0
  164. aurelian/agents/monarch/monarch_tools.py +112 -0
  165. aurelian/agents/oak/__init__.py +0 -0
  166. aurelian/agents/oak/oak_config.py +27 -0
  167. aurelian/agents/oak/oak_gradio.py +57 -0
  168. aurelian/agents/ontology_mapper/__init__.py +31 -0
  169. aurelian/agents/ontology_mapper/ontology_mapper_agent.py +57 -0
  170. aurelian/agents/ontology_mapper/ontology_mapper_config.py +50 -0
  171. aurelian/agents/ontology_mapper/ontology_mapper_evals.py +108 -0
  172. aurelian/agents/ontology_mapper/ontology_mapper_gradio.py +58 -0
  173. aurelian/agents/ontology_mapper/ontology_mapper_mcp.py +81 -0
  174. aurelian/agents/ontology_mapper/ontology_mapper_tools.py +147 -0
  175. aurelian/agents/paperqa/__init__.py +27 -0
  176. aurelian/agents/paperqa/paperqa_agent.py +66 -0
  177. aurelian/agents/paperqa/paperqa_cli.py +305 -0
  178. aurelian/agents/paperqa/paperqa_config.py +142 -0
  179. aurelian/agents/paperqa/paperqa_gradio.py +90 -0
  180. aurelian/agents/paperqa/paperqa_mcp.py +155 -0
  181. aurelian/agents/paperqa/paperqa_tools.py +566 -0
  182. aurelian/agents/phenopackets/__init__.py +3 -0
  183. aurelian/agents/phenopackets/phenopackets_agent.py +58 -0
  184. aurelian/agents/phenopackets/phenopackets_config.py +72 -0
  185. aurelian/agents/phenopackets/phenopackets_evals.py +99 -0
  186. aurelian/agents/phenopackets/phenopackets_gradio.py +55 -0
  187. aurelian/agents/phenopackets/phenopackets_mcp.py +178 -0
  188. aurelian/agents/phenopackets/phenopackets_tools.py +127 -0
  189. aurelian/agents/rag/__init__.py +40 -0
  190. aurelian/agents/rag/rag_agent.py +84 -0
  191. aurelian/agents/rag/rag_config.py +80 -0
  192. aurelian/agents/rag/rag_gradio.py +67 -0
  193. aurelian/agents/rag/rag_mcp.py +107 -0
  194. aurelian/agents/rag/rag_tools.py +189 -0
  195. aurelian/agents/rag_agent.py +54 -0
  196. aurelian/agents/robot/__init__.py +0 -0
  197. aurelian/agents/robot/assets/__init__.py +3 -0
  198. aurelian/agents/robot/assets/template.md +384 -0
  199. aurelian/agents/robot/robot_config.py +25 -0
  200. aurelian/agents/robot/robot_gradio.py +46 -0
  201. aurelian/agents/robot/robot_mcp.py +100 -0
  202. aurelian/agents/robot/robot_ontology_agent.py +139 -0
  203. aurelian/agents/robot/robot_tools.py +50 -0
  204. aurelian/agents/talisman/__init__.py +3 -0
  205. aurelian/agents/talisman/__main__.py +17 -0
  206. aurelian/agents/talisman/cli.py +70 -0
  207. aurelian/agents/talisman/run_talisman.py +18 -0
  208. aurelian/agents/talisman/talisman_agent.py +143 -0
  209. aurelian/agents/talisman/talisman_config.py +66 -0
  210. aurelian/agents/talisman/talisman_gradio.py +50 -0
  211. aurelian/agents/talisman/talisman_mcp.py +75 -0
  212. aurelian/agents/talisman/talisman_tools.py +962 -0
  213. aurelian/agents/ubergraph/__init__.py +40 -0
  214. aurelian/agents/ubergraph/ubergraph_agent.py +72 -0
  215. aurelian/agents/ubergraph/ubergraph_config.py +79 -0
  216. aurelian/agents/ubergraph/ubergraph_gradio.py +48 -0
  217. aurelian/agents/ubergraph/ubergraph_mcp.py +69 -0
  218. aurelian/agents/ubergraph/ubergraph_tools.py +118 -0
  219. aurelian/agents/uniprot/__init__.py +0 -0
  220. aurelian/agents/uniprot/uniprot_agent.py +43 -0
  221. aurelian/agents/uniprot/uniprot_config.py +43 -0
  222. aurelian/agents/uniprot/uniprot_evals.py +99 -0
  223. aurelian/agents/uniprot/uniprot_gradio.py +48 -0
  224. aurelian/agents/uniprot/uniprot_mcp.py +168 -0
  225. aurelian/agents/uniprot/uniprot_tools.py +136 -0
  226. aurelian/agents/web/__init__.py +0 -0
  227. aurelian/agents/web/web_config.py +27 -0
  228. aurelian/agents/web/web_gradio.py +48 -0
  229. aurelian/agents/web/web_mcp.py +50 -0
  230. aurelian/agents/web/web_tools.py +121 -0
  231. aurelian/chat.py +23 -0
  232. aurelian/cli.py +1004 -0
  233. aurelian/dependencies/__init__.py +0 -0
  234. aurelian/dependencies/workdir.py +78 -0
  235. aurelian/evaluators/model.py +9 -0
  236. aurelian/evaluators/substring_evaluator.py +30 -0
  237. aurelian/mcp/__init__.py +0 -0
  238. aurelian/mcp/amigo_mcp_test.py +86 -0
  239. aurelian/mcp/config_generator.py +123 -0
  240. aurelian/mcp/example_config.json +43 -0
  241. aurelian/mcp/generate_sample_config.py +37 -0
  242. aurelian/mcp/gocam_mcp_test.py +126 -0
  243. aurelian/mcp/linkml_mcp_tools.py +190 -0
  244. aurelian/mcp/mcp_discovery.py +87 -0
  245. aurelian/mcp/mcp_test.py +31 -0
  246. aurelian/mcp/phenopackets_mcp_test.py +103 -0
  247. aurelian/tools/__init__.py +0 -0
  248. aurelian/tools/web/__init__.py +0 -0
  249. aurelian/tools/web/url_download.py +51 -0
  250. aurelian/utils/__init__.py +0 -0
  251. aurelian/utils/async_utils.py +18 -0
  252. aurelian/utils/data_utils.py +32 -0
  253. aurelian/utils/documentation_manager.py +59 -0
  254. aurelian/utils/doi_fetcher.py +238 -0
  255. aurelian/utils/ontology_utils.py +68 -0
  256. aurelian/utils/pdf_fetcher.py +23 -0
  257. aurelian/utils/process_logs.py +100 -0
  258. aurelian/utils/pubmed_utils.py +238 -0
  259. aurelian/utils/pytest_report_to_markdown.py +67 -0
  260. aurelian/utils/robot_ontology_utils.py +112 -0
  261. aurelian/utils/search_utils.py +95 -0
  262. aurelian-0.1.0.dist-info/LICENSE +22 -0
  263. aurelian-0.1.0.dist-info/METADATA +109 -0
  264. aurelian-0.1.0.dist-info/RECORD +266 -0
  265. aurelian-0.1.0.dist-info/WHEEL +4 -0
  266. aurelian-0.1.0.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,190 @@
1
+ """
2
+ MCP tools for creating LinkML schemas and example datasets
3
+ """
4
+ from linkml.generators import JsonSchemaGenerator
5
+ from mcp.server.fastmcp import FastMCP
6
+
7
+ from aurelian.agents.linkml.linkml_agent import LinkMLDependencies
8
+
9
+ # Initialize FastMCP server
10
+ mcp = FastMCP("linkml")
11
+
12
+ import logfire
13
+ from linkml_runtime.loaders import yaml_loader
14
+ from linkml_runtime.linkml_model import SchemaDefinition
15
+ from linkml.validator import validate
16
+ from pydantic_ai import RunContext, ModelRetry
17
+
18
+ from aurelian.dependencies.workdir import WorkDir
19
+
20
+ def deps() -> LinkMLDependencies:
21
+ deps = LinkMLDependencies()
22
+ deps.workdir = WorkDir("/tmp/linkml")
23
+ return deps
24
+
25
+ def ctx() -> RunContext[LinkMLDependencies]:
26
+ rc: RunContext[LinkMLDependencies] = RunContext[LinkMLDependencies](deps=deps())
27
+ return rc
28
+
29
+
30
+ @mcp.tool()
31
+ async def validate_schema(schema: str, save_to_file: str="schema.yaml") -> str:
32
+ """
33
+ Validate a LinkML schema.
34
+
35
+ Args:
36
+ ctx: context
37
+ schema: schema (as yaml) to validate. Do not truncate, always pass the whole schema.
38
+ save_to_file: optional file name to save the schema to. Defaults to schema.yaml
39
+
40
+ Returns:
41
+
42
+ """
43
+ print(f"Validating schema: {schema}")
44
+ try:
45
+ schema = yaml_loader.loads(schema, target_class=SchemaDefinition)
46
+ gen = JsonSchemaGenerator(schema)
47
+ gen.serialize()
48
+ if save_to_file and schema:
49
+ deps().workdir.write_file(save_to_file, schema)
50
+ except Exception as e:
51
+ raise ModelRetry(f"Schema does not validate: {e}")
52
+ return "VALIDATES"
53
+
54
+
55
+ @mcp.tool()
56
+ async def inspect_file(data_file: str) -> str:
57
+ """
58
+ Inspect a file in the working directory.
59
+
60
+ Args:
61
+ ctx:
62
+ data_file: name of file
63
+
64
+ Returns:
65
+
66
+ """
67
+ print(f"Inspecting file: {data_file}")
68
+ return deps().workdir.read_file(data_file)
69
+
70
+
71
+ @mcp.tool()
72
+ async def list_files() -> str:
73
+ """
74
+ List files in the working directory.
75
+
76
+ Args:
77
+ ctx:
78
+
79
+ Returns:
80
+
81
+ """
82
+ return "\n".join(deps().workdir.list_file_names())
83
+
84
+ @mcp.tool()
85
+ async def write_to_file(data: str, file_name: str) -> str:
86
+ """
87
+ Write data to a file in the working directory.
88
+
89
+ Args:
90
+ ctx:
91
+ data:
92
+ file_name:
93
+
94
+ Returns:
95
+
96
+ """
97
+ print(f"Writing data to file: {file_name}")
98
+ deps().workdir.write_file(file_name, data)
99
+ return f"Data written to {file_name}"
100
+
101
+ @mcp.tool()
102
+ async def validate_data(schema: str, data_file: str) -> str:
103
+ """
104
+ Validate data file against a schema.
105
+
106
+ This assumes the data file is present in the working directory.
107
+ You can write data to the working directory using the `write_to_file` tool.
108
+
109
+ Args:
110
+ ctx:
111
+ schema: the schema (as a YAML string)
112
+ data_file: the name of the data file in the working directory
113
+
114
+ Returns:
115
+
116
+ """
117
+ logfire.log(f"Validating data file: {data_file} using schema: {schema}")
118
+ print(f"Validating data file: {data_file} using schema: {schema}")
119
+ try:
120
+ schema = yaml_loader.loads(schema, target_class=SchemaDefinition)
121
+ except Exception as e:
122
+ return f"Schema does not validate: {e}"
123
+ try:
124
+ instances = deps().parse_objects_from_file(data_file)
125
+ for instance in instances:
126
+ print(f"Validating {instance}")
127
+ rpt = validate(instance, schema)
128
+ print(f"Validation report: {rpt}")
129
+ if rpt.results:
130
+ return f"Data does not validate:\n{rpt.results}"
131
+ return f"{len(instances)} instances all validate successfully"
132
+ except Exception as e:
133
+ return f"Data does not validate: {e}"
134
+
135
+
136
+ @mcp.tool()
137
+ async def search_web(query: str) -> str:
138
+ """
139
+ Search the web using a text query.
140
+
141
+ Note, this will not retrieve the full content, for that you
142
+ should use `retrieve_web_page`.
143
+
144
+ Args:
145
+ query: Text query
146
+
147
+ Returns: matching web pages plus summaries
148
+ """
149
+ print(f"Web Search: {query}")
150
+ return web_search(query)
151
+
152
+ @mcp.tool()
153
+ async def retrieve_web_page(url: str) -> str:
154
+ """
155
+ Fetch the contents of a web page.
156
+
157
+ Args:
158
+ url: URL of the web page
159
+
160
+ Returns:
161
+ The contents of the web page.
162
+ """
163
+ print(f"Fetch URL: {url}")
164
+ import aurelian.utils.search_utils as su
165
+ return su.retrieve_web_page(url)
166
+
167
+
168
+ @mcp.tool()
169
+ async def download_web_page(url: str, local_file_name: str) -> str:
170
+ """
171
+ Download contents of a web page.
172
+
173
+ Args:
174
+ ctx:
175
+ url: URL of the web page
176
+ local_file_name: Name of the local file to save the
177
+
178
+ Returns:
179
+ str: message
180
+ """
181
+ print(f"Fetch URL: {url}")
182
+ import aurelian.utils.search_utils as su
183
+ data = su.retrieve_web_page(url)
184
+ deps().workdir.write_file(local_file_name, data)
185
+ return f"Data written to {local_file_name}"
186
+
187
+
188
+ if __name__ == "__main__":
189
+ # Initialize and run the server
190
+ mcp.run(transport='stdio')
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Script for discovering and testing MCP implementations.
4
+ """
5
+
6
+ import argparse
7
+ import importlib
8
+ import inspect
9
+ import sys
10
+ from pathlib import Path
11
+ from typing import List, Optional
12
+
13
+
14
+ def list_mcp_tools(module_path: str) -> List[str]:
15
+ """
16
+ List all MCP tools in a given module.
17
+
18
+ Args:
19
+ module_path: Dot-separated path to the module
20
+
21
+ Returns:
22
+ List of tool names
23
+ """
24
+ try:
25
+ # Import the module
26
+ module = importlib.import_module(module_path)
27
+
28
+ # Find the MCP server instance
29
+ mcp = getattr(module, "mcp", None)
30
+ if not mcp:
31
+ print(f"No 'mcp' instance found in {module_path}")
32
+ return []
33
+
34
+ # Get all functions with the MCP tool decorator
35
+ tools = []
36
+ for name, func in inspect.getmembers(module, inspect.isfunction):
37
+ # Check if this function is an MCP tool
38
+ if hasattr(func, "__mcp_tool__") and func.__mcp_tool__ is True:
39
+ tools.append(name)
40
+
41
+ return tools
42
+ except Exception as e:
43
+ print(f"Error importing {module_path}: {e}")
44
+ return []
45
+
46
+
47
+ def main():
48
+ """Command line interface."""
49
+ parser = argparse.ArgumentParser(description="Discover and test MCP implementations")
50
+ parser.add_argument("--agent", "-a", help="Agent type to test (e.g., 'diagnosis')")
51
+ parser.add_argument("--list", "-l", action="store_true", help="List available MCP modules")
52
+ args = parser.parse_args()
53
+
54
+ # Base path for agent modules
55
+ base_path = Path(__file__).parent.parent
56
+
57
+ if args.list:
58
+ # List all MCP modules
59
+ agents_dir = base_path / "agents"
60
+ print("Available MCP modules:")
61
+ for agent_dir in agents_dir.iterdir():
62
+ if agent_dir.is_dir():
63
+ mcp_file = agent_dir / f"{agent_dir.name}_mcp.py"
64
+ if mcp_file.exists():
65
+ print(f" - {agent_dir.name}")
66
+ return
67
+
68
+ if not args.agent:
69
+ print("Error: Please specify an agent type with --agent")
70
+ sys.exit(1)
71
+
72
+ # Check if the MCP module exists
73
+ agent_type = args.agent
74
+ module_path = f"aurelian.agents.{agent_type}.{agent_type}_mcp"
75
+
76
+ # List the tools
77
+ tools = list_mcp_tools(module_path)
78
+ if tools:
79
+ print(f"MCP tools for {agent_type}:")
80
+ for tool in tools:
81
+ print(f" - {tool}")
82
+ else:
83
+ print(f"No MCP tools found for {agent_type}")
84
+
85
+
86
+ if __name__ == "__main__":
87
+ main()
@@ -0,0 +1,31 @@
1
+ """
2
+ MCP tools for creating LinkML schemas and example datasets
3
+ """
4
+ import sys
5
+
6
+ from mcp.server.fastmcp import FastMCP
7
+
8
+
9
+ # Initialize FastMCP server
10
+ mcp = FastMCP("test")
11
+
12
+ @mcp.tool()
13
+ async def add_two_numbers(n1: int, n2: int) -> int:
14
+ """
15
+ Add two numbers together.
16
+
17
+ Args:
18
+ n1: first number
19
+ n2: second number
20
+
21
+ Returns:
22
+ sum of the two numbers
23
+ """
24
+ return n1 + n2
25
+
26
+
27
+ if __name__ == "__main__":
28
+ print("Running the LinkML MCP tools")
29
+ print("Use Ctrl-C to exit", file=sys.stderr)
30
+ # Initialize and run the server
31
+ mcp.run(transport='stdio')
@@ -0,0 +1,103 @@
1
+ """
2
+ Test for phenopackets MCP functionality
3
+ """
4
+ import os
5
+ import tempfile
6
+ from typing import List, Optional, Dict
7
+
8
+ # try to import, don't die if import fails
9
+ try:
10
+ from mcp import Client
11
+ except ImportError:
12
+ print("mcp package not found. Please install it to run this test.")
13
+ Client = None
14
+ from pydantic import BaseModel
15
+
16
+
17
+ class Message(BaseModel):
18
+ role: str
19
+ content: str
20
+
21
+
22
+ async def test_phenopackets_mcp():
23
+ """Test the phenopackets MCP agent."""
24
+ client = Client("/tmp/phenopackets-mcp", exec_args=["python", "-m", "aurelian.agents.phenopackets.phenopackets_mcp"])
25
+
26
+ import time
27
+ time.sleep(1) # Give the server time to start
28
+
29
+ # Set up a temporary working directory for the test
30
+ tempdir = os.path.join(tempfile.gettempdir(), "test_phenopackets")
31
+ os.makedirs(tempdir, exist_ok=True)
32
+ os.environ["AURELIAN_WORKDIR"] = tempdir
33
+
34
+ # For testing without a real database - would normally come from configuration
35
+ os.environ["PHENOPACKETS_DB_PATH"] = "mongodb://localhost:27017/test_phenopackets"
36
+ os.environ["PHENOPACKETS_DB_NAME"] = "test_phenopackets"
37
+ os.environ["PHENOPACKETS_COLLECTION_NAME"] = "test_main"
38
+
39
+ convo: List[Message] = []
40
+
41
+ def add_to_convo(role: str, content: str) -> Message:
42
+ msg = Message(role=role, content=content)
43
+ convo.append(msg)
44
+ return msg
45
+
46
+ # Make a query
47
+ add_to_convo("user", "What tools are available for working with phenopackets?")
48
+
49
+ message = convo[-1].content
50
+
51
+ response = await client.chat(messages=message)
52
+ print(f"Got response: {response}")
53
+
54
+ # Get available tools
55
+ tool_choices = await client.get_tool_choice(messages=convo)
56
+ print(f"Available tools: {[t['id'] for t in tool_choices]}")
57
+
58
+ # Test the list_files tool
59
+ list_files_tool = next((t for t in tool_choices if t["id"] == "list_files"), None)
60
+ if list_files_tool:
61
+ print(f"Testing list_files tool...")
62
+ tool_input_schema = await client.get_tool_input_schema(tool_id=list_files_tool["id"])
63
+ tool_result = await client.execute_tool(tool_id=list_files_tool["id"], tool_input='{}')
64
+ print(f"list_files result: {tool_result}")
65
+
66
+ # Create a test file
67
+ write_file_tool = next((t for t in tool_choices if t["id"] == "write_to_file"), None)
68
+ if write_file_tool:
69
+ print(f"Testing write_to_file tool...")
70
+ tool_input = '{"file_name": "test.txt", "data": "This is a test file for phenopackets MCP"}'
71
+ tool_result = await client.execute_tool(tool_id=write_file_tool["id"], tool_input=tool_input)
72
+ print(f"write_to_file result: {tool_result}")
73
+
74
+ # Check if the file was created
75
+ if list_files_tool:
76
+ tool_result = await client.execute_tool(tool_id=list_files_tool["id"], tool_input='{}')
77
+ print(f"list_files after writing: {tool_result}")
78
+
79
+ # Read the file
80
+ inspect_file_tool = next((t for t in tool_choices if t["id"] == "inspect_file"), None)
81
+ if inspect_file_tool:
82
+ print(f"Testing inspect_file tool...")
83
+ tool_input = '{"data_file": "test.txt"}'
84
+ tool_result = await client.execute_tool(tool_id=inspect_file_tool["id"], tool_input=tool_input)
85
+ print(f"inspect_file result: {tool_result}")
86
+
87
+ # Try a web search
88
+ search_web_tool = next((t for t in tool_choices if t["id"] == "search_web"), None)
89
+ if search_web_tool:
90
+ print(f"Testing search_web tool...")
91
+ tool_input = '{"query": "phenopackets specification"}'
92
+ try:
93
+ tool_result = await client.execute_tool(tool_id=search_web_tool["id"], tool_input=tool_input)
94
+ print(f"search_web result: {tool_result[:200]}...") # Just show first 200 chars
95
+ except Exception as e:
96
+ print(f"search_web failed (expected in test): {e}")
97
+
98
+ await client.close()
99
+
100
+
101
+ if __name__ == "__main__":
102
+ import asyncio
103
+ asyncio.run(test_phenopackets_mcp())
File without changes
File without changes
@@ -0,0 +1,51 @@
1
+ from dataclasses import dataclass
2
+
3
+ from pydantic import TypeAdapter
4
+ from pydantic_ai.tools import Tool
5
+ from typing_extensions import TypedDict
6
+
7
+ from aurelian.dependencies.workdir import WorkDir
8
+
9
+
10
+ __all__ = ["download_url_tool"]
11
+
12
+ class URLDownloadResult(TypedDict):
13
+ """The result of downloading a URL."""
14
+
15
+ size: int
16
+ """The size of the downloaded content."""
17
+ location: str
18
+ """The location of the downloaded content."""
19
+
20
+ ta = TypeAdapter(list[URLDownloadResult])
21
+
22
+ @dataclass
23
+ class URLDownloadTool:
24
+ """A tool for downloading a URL."""
25
+ workdir: WorkDir
26
+
27
+ async def __call__(self, url:str, local_file_name: str) -> list[dict]:
28
+ """Download the contents of a URL.
29
+
30
+ Args:
31
+ url: URL of the web page
32
+ local_file_name: Name of the local file to save
33
+
34
+ Returns:
35
+ The contents of the web page.
36
+ """
37
+ import asyncio
38
+ import aurelian.utils.search_utils as su
39
+ data = await asyncio.to_thread(su.retrieve_web_page, url)
40
+ self.workdir.write_file(local_file_name, data)
41
+ return ta.validate_python([{"location": local_file_name, "size": len(data)}])
42
+
43
+ def download_url_tool(workdir: WorkDir):
44
+ """Create a URL download tool."""
45
+ udt = URLDownloadTool(workdir=workdir)
46
+ c = udt.__call__
47
+ return Tool(
48
+ udt.__call__,
49
+ name="download_web_page",
50
+ description="Download the contents of a URL.",
51
+ )
File without changes
@@ -0,0 +1,18 @@
1
+ import asyncio
2
+ from typing import Callable, Coroutine
3
+
4
+
5
+ def run_sync(f: Callable | Coroutine):
6
+ loop = asyncio.new_event_loop()
7
+ asyncio.set_event_loop(loop)
8
+ if isinstance(f, Coroutine):
9
+ result = f
10
+ else:
11
+ result = f()
12
+
13
+ # Ensure it's a coroutine before running it
14
+ if asyncio.iscoroutine(result):
15
+ result = loop.run_until_complete(result)
16
+
17
+ loop.close()
18
+ return result
@@ -0,0 +1,32 @@
1
+ from typing import Dict, List, Optional, Union
2
+
3
+ from linkml_runtime.dumpers import json_dumper
4
+ from linkml_runtime.utils.yamlutils import YAMLRoot
5
+ from pydantic import BaseModel
6
+
7
+
8
+ def flatten(d: Dict, preserve_keys: Optional[List] = None) -> Dict:
9
+ """Flatten a dictionary"""
10
+ out = {}
11
+ for k, v in d.items():
12
+ if isinstance(v, list):
13
+ if preserve_keys and k in preserve_keys:
14
+ out[k] = [flatten(x, preserve_keys=preserve_keys) for x in v]
15
+ else:
16
+ out[f"{k}_count"] = len(v)
17
+ elif isinstance(v, dict):
18
+ out[k] = flatten(v, preserve_keys=preserve_keys)
19
+ else:
20
+ out[k] = v
21
+ return out
22
+
23
+
24
+ def obj_to_dict(obj: Union[object, YAMLRoot, BaseModel, Dict]) -> Dict:
25
+ if isinstance(obj, YAMLRoot):
26
+ return json_dumper.to_dict(obj)
27
+ elif isinstance(obj, BaseModel):
28
+ return obj.model_dump()
29
+ elif isinstance(obj, dict):
30
+ return obj
31
+ else:
32
+ raise ValueError(f"Cannot convert object of type {type(obj)} to dict")
@@ -0,0 +1,59 @@
1
+ from pydantic import BaseModel
2
+ from pathlib import Path
3
+ from typing import Dict, Optional, List
4
+ from dataclasses import dataclass
5
+
6
+ class Document(BaseModel):
7
+ """
8
+ A document is a file in the documentation directory.
9
+ """
10
+ id: str
11
+ title: str
12
+ path: str
13
+ metadata: Optional[Dict] = None
14
+
15
+ @dataclass
16
+ class DocumentationManager:
17
+ """
18
+ A manager for the documentation directory.
19
+ """
20
+
21
+ documents_dir: Path
22
+ collection_name: Optional[str] = None
23
+
24
+ def all_documents(self) -> List[Document]:
25
+ """
26
+ Get all available documents.
27
+ """
28
+ return [Document(
29
+ id=file_path.stem,
30
+ title=file_path.stem.replace("_", " "),
31
+ path=str(file_path),
32
+ metadata=None
33
+ ) for file_path in self.documents_dir.glob("*.md")]
34
+
35
+ def get_documents_for_prompt(self, extra_text: str = "") -> str:
36
+ """
37
+ Get the documents for the system prompt.
38
+
39
+ Returns:
40
+ A string containing the list of available GO annotation best practice documents
41
+ """
42
+ docs = self.all_documents()
43
+ if not docs:
44
+ raise AssertionError("No best practice documents are available")
45
+
46
+ docs_text = "\n\nThe following documents are available:\n"
47
+ docs_text += "\n".join([f"- {d.title}" for d in docs])
48
+ docs_text += "\n\n" + extra_text
49
+ return docs_text
50
+
51
+ def fetch_document(self, id_or_title: str) -> Document:
52
+ """
53
+ Fetch a document by its ID or title.
54
+ """
55
+ for document in self.all_documents():
56
+ if document.id == id_or_title or document.title == id_or_title:
57
+ return document
58
+ raise KeyError(f"Document with ID or title '{id_or_title}' not found")
59
+