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.
- aurelian/__init__.py +9 -0
- aurelian/agents/__init__.py +0 -0
- aurelian/agents/amigo/__init__.py +3 -0
- aurelian/agents/amigo/amigo_agent.py +77 -0
- aurelian/agents/amigo/amigo_config.py +85 -0
- aurelian/agents/amigo/amigo_evals.py +73 -0
- aurelian/agents/amigo/amigo_gradio.py +52 -0
- aurelian/agents/amigo/amigo_mcp.py +152 -0
- aurelian/agents/amigo/amigo_tools.py +152 -0
- aurelian/agents/biblio/__init__.py +42 -0
- aurelian/agents/biblio/biblio_agent.py +95 -0
- aurelian/agents/biblio/biblio_config.py +40 -0
- aurelian/agents/biblio/biblio_gradio.py +67 -0
- aurelian/agents/biblio/biblio_mcp.py +115 -0
- aurelian/agents/biblio/biblio_tools.py +164 -0
- aurelian/agents/biblio_agent.py +46 -0
- aurelian/agents/checklist/__init__.py +44 -0
- aurelian/agents/checklist/checklist_agent.py +86 -0
- aurelian/agents/checklist/checklist_config.py +28 -0
- aurelian/agents/checklist/checklist_gradio.py +70 -0
- aurelian/agents/checklist/checklist_mcp.py +86 -0
- aurelian/agents/checklist/checklist_tools.py +141 -0
- aurelian/agents/checklist/content/checklists.yaml +7 -0
- aurelian/agents/checklist/content/streams.csv +136 -0
- aurelian/agents/checklist_agent.py +40 -0
- aurelian/agents/chemistry/__init__.py +3 -0
- aurelian/agents/chemistry/chemistry_agent.py +47 -0
- aurelian/agents/chemistry/chemistry_config.py +71 -0
- aurelian/agents/chemistry/chemistry_evals.py +79 -0
- aurelian/agents/chemistry/chemistry_gradio.py +50 -0
- aurelian/agents/chemistry/chemistry_mcp.py +120 -0
- aurelian/agents/chemistry/chemistry_tools.py +121 -0
- aurelian/agents/chemistry/image_agent.py +15 -0
- aurelian/agents/d4d/__init__.py +30 -0
- aurelian/agents/d4d/d4d_agent.py +73 -0
- aurelian/agents/d4d/d4d_config.py +46 -0
- aurelian/agents/d4d/d4d_gradio.py +58 -0
- aurelian/agents/d4d/d4d_mcp.py +71 -0
- aurelian/agents/d4d/d4d_tools.py +157 -0
- aurelian/agents/d4d_agent.py +64 -0
- aurelian/agents/diagnosis/__init__.py +33 -0
- aurelian/agents/diagnosis/diagnosis_agent.py +54 -0
- aurelian/agents/diagnosis/diagnosis_config.py +48 -0
- aurelian/agents/diagnosis/diagnosis_evals.py +76 -0
- aurelian/agents/diagnosis/diagnosis_gradio.py +52 -0
- aurelian/agents/diagnosis/diagnosis_mcp.py +141 -0
- aurelian/agents/diagnosis/diagnosis_tools.py +204 -0
- aurelian/agents/diagnosis_agent.py +28 -0
- aurelian/agents/draw/__init__.py +3 -0
- aurelian/agents/draw/draw_agent.py +39 -0
- aurelian/agents/draw/draw_config.py +26 -0
- aurelian/agents/draw/draw_gradio.py +50 -0
- aurelian/agents/draw/draw_mcp.py +94 -0
- aurelian/agents/draw/draw_tools.py +100 -0
- aurelian/agents/draw/judge_agent.py +18 -0
- aurelian/agents/filesystem/__init__.py +0 -0
- aurelian/agents/filesystem/filesystem_config.py +27 -0
- aurelian/agents/filesystem/filesystem_gradio.py +49 -0
- aurelian/agents/filesystem/filesystem_mcp.py +89 -0
- aurelian/agents/filesystem/filesystem_tools.py +95 -0
- aurelian/agents/filesystem/py.typed +0 -0
- aurelian/agents/github/__init__.py +0 -0
- aurelian/agents/github/github_agent.py +83 -0
- aurelian/agents/github/github_cli.py +248 -0
- aurelian/agents/github/github_config.py +22 -0
- aurelian/agents/github/github_gradio.py +152 -0
- aurelian/agents/github/github_mcp.py +252 -0
- aurelian/agents/github/github_tools.py +408 -0
- aurelian/agents/github/github_tools.py.tmp +413 -0
- aurelian/agents/goann/__init__.py +13 -0
- aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines.md +1000 -0
- aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines.pdf +0 -0
- aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines_Paper.md +693 -0
- aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines_Paper.pdf +0 -0
- aurelian/agents/goann/goann_agent.py +90 -0
- aurelian/agents/goann/goann_config.py +90 -0
- aurelian/agents/goann/goann_evals.py +104 -0
- aurelian/agents/goann/goann_gradio.py +62 -0
- aurelian/agents/goann/goann_mcp.py +0 -0
- aurelian/agents/goann/goann_tools.py +65 -0
- aurelian/agents/gocam/__init__.py +52 -0
- aurelian/agents/gocam/documents/DNA-binding transcription factor activity annotation guidelines.docx +0 -0
- aurelian/agents/gocam/documents/DNA-binding transcription factor activity annotation guidelines.pdf +0 -0
- aurelian/agents/gocam/documents/DNA-binding_transcription_factor_activity_annotation_guidelines.md +100 -0
- aurelian/agents/gocam/documents/E3 ubiquitin ligases.docx +0 -0
- aurelian/agents/gocam/documents/E3 ubiquitin ligases.pdf +0 -0
- aurelian/agents/gocam/documents/E3_ubiquitin_ligases.md +134 -0
- aurelian/agents/gocam/documents/GO-CAM annotation guidelines README.docx +0 -0
- aurelian/agents/gocam/documents/GO-CAM annotation guidelines README.pdf +0 -0
- aurelian/agents/gocam/documents/GO-CAM modelling guidelines TO DO.docx +0 -0
- aurelian/agents/gocam/documents/GO-CAM modelling guidelines TO DO.pdf +0 -0
- aurelian/agents/gocam/documents/GO-CAM_annotation_guidelines_README.md +1 -0
- aurelian/agents/gocam/documents/GO-CAM_modelling_guidelines_TO_DO.md +3 -0
- aurelian/agents/gocam/documents/How to annotate complexes in GO-CAM.docx +0 -0
- aurelian/agents/gocam/documents/How to annotate complexes in GO-CAM.pdf +0 -0
- aurelian/agents/gocam/documents/How to annotate molecular adaptors.docx +0 -0
- aurelian/agents/gocam/documents/How to annotate molecular adaptors.pdf +0 -0
- aurelian/agents/gocam/documents/How to annotate sequestering proteins.docx +0 -0
- aurelian/agents/gocam/documents/How to annotate sequestering proteins.pdf +0 -0
- aurelian/agents/gocam/documents/How_to_annotate_complexes_in_GO-CAM.md +29 -0
- aurelian/agents/gocam/documents/How_to_annotate_molecular_adaptors.md +31 -0
- aurelian/agents/gocam/documents/How_to_annotate_sequestering_proteins.md +42 -0
- aurelian/agents/gocam/documents/Molecular adaptor activity.docx +0 -0
- aurelian/agents/gocam/documents/Molecular adaptor activity.pdf +0 -0
- aurelian/agents/gocam/documents/Molecular carrier activity.docx +0 -0
- aurelian/agents/gocam/documents/Molecular carrier activity.pdf +0 -0
- aurelian/agents/gocam/documents/Molecular_adaptor_activity.md +51 -0
- aurelian/agents/gocam/documents/Molecular_carrier_activity.md +41 -0
- aurelian/agents/gocam/documents/Protein sequestering activity.docx +0 -0
- aurelian/agents/gocam/documents/Protein sequestering activity.pdf +0 -0
- aurelian/agents/gocam/documents/Protein_sequestering_activity.md +50 -0
- aurelian/agents/gocam/documents/Signaling receptor activity annotation guidelines.docx +0 -0
- aurelian/agents/gocam/documents/Signaling receptor activity annotation guidelines.pdf +0 -0
- aurelian/agents/gocam/documents/Signaling_receptor_activity_annotation_guidelines.md +187 -0
- aurelian/agents/gocam/documents/Transcription coregulator activity.docx +0 -0
- aurelian/agents/gocam/documents/Transcription coregulator activity.pdf +0 -0
- aurelian/agents/gocam/documents/Transcription_coregulator_activity.md +36 -0
- aurelian/agents/gocam/documents/Transporter activity annotation annotation guidelines.docx +0 -0
- aurelian/agents/gocam/documents/Transporter activity annotation annotation guidelines.pdf +0 -0
- aurelian/agents/gocam/documents/Transporter_activity_annotation_annotation_guidelines.md +43 -0
- Regulatory Processes in GO-CAM.docx +0 -0
- Regulatory Processes in GO-CAM.pdf +0 -0
- aurelian/agents/gocam/documents/WIP_-_Regulation_and_Regulatory_Processes_in_GO-CAM.md +31 -0
- aurelian/agents/gocam/documents/md/DNA-binding_transcription_factor_activity_annotation_guidelines.md +131 -0
- aurelian/agents/gocam/documents/md/E3_ubiquitin_ligases.md +166 -0
- aurelian/agents/gocam/documents/md/GO-CAM_annotation_guidelines_README.md +1 -0
- aurelian/agents/gocam/documents/md/GO-CAM_modelling_guidelines_TO_DO.md +5 -0
- aurelian/agents/gocam/documents/md/How_to_annotate_complexes_in_GO-CAM.md +28 -0
- aurelian/agents/gocam/documents/md/How_to_annotate_molecular_adaptors.md +19 -0
- aurelian/agents/gocam/documents/md/How_to_annotate_sequestering_proteins.md +38 -0
- aurelian/agents/gocam/documents/md/Molecular_adaptor_activity.md +52 -0
- aurelian/agents/gocam/documents/md/Molecular_carrier_activity.md +59 -0
- aurelian/agents/gocam/documents/md/Protein_sequestering_activity.md +52 -0
- aurelian/agents/gocam/documents/md/Signaling_receptor_activity_annotation_guidelines.md +271 -0
- aurelian/agents/gocam/documents/md/Transcription_coregulator_activity.md +54 -0
- aurelian/agents/gocam/documents/md/Transporter_activity_annotation_annotation_guidelines.md +38 -0
- aurelian/agents/gocam/documents/md/WIP_-_Regulation_and_Regulatory_Processes_in_GO-CAM.md +39 -0
- aurelian/agents/gocam/documents/pandoc_md/Signaling_receptor_activity_annotation_guidelines.md +334 -0
- aurelian/agents/gocam/gocam_agent.py +243 -0
- aurelian/agents/gocam/gocam_config.py +85 -0
- aurelian/agents/gocam/gocam_curator_agent.py +46 -0
- aurelian/agents/gocam/gocam_evals.py +64 -0
- aurelian/agents/gocam/gocam_gradio.py +89 -0
- aurelian/agents/gocam/gocam_mcp.py +224 -0
- aurelian/agents/gocam/gocam_tools.py +294 -0
- aurelian/agents/linkml/__init__.py +0 -0
- aurelian/agents/linkml/linkml_agent.py +62 -0
- aurelian/agents/linkml/linkml_config.py +48 -0
- aurelian/agents/linkml/linkml_evals.py +66 -0
- aurelian/agents/linkml/linkml_gradio.py +45 -0
- aurelian/agents/linkml/linkml_mcp.py +181 -0
- aurelian/agents/linkml/linkml_tools.py +102 -0
- aurelian/agents/literature/__init__.py +3 -0
- aurelian/agents/literature/literature_agent.py +75 -0
- aurelian/agents/literature/literature_config.py +35 -0
- aurelian/agents/literature/literature_gradio.py +52 -0
- aurelian/agents/literature/literature_mcp.py +174 -0
- aurelian/agents/literature/literature_tools.py +182 -0
- aurelian/agents/monarch/__init__.py +0 -0
- aurelian/agents/monarch/monarch_agent.py +45 -0
- aurelian/agents/monarch/monarch_config.py +45 -0
- aurelian/agents/monarch/monarch_gradio.py +51 -0
- aurelian/agents/monarch/monarch_mcp.py +65 -0
- aurelian/agents/monarch/monarch_tools.py +112 -0
- aurelian/agents/oak/__init__.py +0 -0
- aurelian/agents/oak/oak_config.py +27 -0
- aurelian/agents/oak/oak_gradio.py +57 -0
- aurelian/agents/ontology_mapper/__init__.py +31 -0
- aurelian/agents/ontology_mapper/ontology_mapper_agent.py +57 -0
- aurelian/agents/ontology_mapper/ontology_mapper_config.py +50 -0
- aurelian/agents/ontology_mapper/ontology_mapper_evals.py +108 -0
- aurelian/agents/ontology_mapper/ontology_mapper_gradio.py +58 -0
- aurelian/agents/ontology_mapper/ontology_mapper_mcp.py +81 -0
- aurelian/agents/ontology_mapper/ontology_mapper_tools.py +147 -0
- aurelian/agents/paperqa/__init__.py +27 -0
- aurelian/agents/paperqa/paperqa_agent.py +66 -0
- aurelian/agents/paperqa/paperqa_cli.py +305 -0
- aurelian/agents/paperqa/paperqa_config.py +142 -0
- aurelian/agents/paperqa/paperqa_gradio.py +90 -0
- aurelian/agents/paperqa/paperqa_mcp.py +155 -0
- aurelian/agents/paperqa/paperqa_tools.py +566 -0
- aurelian/agents/phenopackets/__init__.py +3 -0
- aurelian/agents/phenopackets/phenopackets_agent.py +58 -0
- aurelian/agents/phenopackets/phenopackets_config.py +72 -0
- aurelian/agents/phenopackets/phenopackets_evals.py +99 -0
- aurelian/agents/phenopackets/phenopackets_gradio.py +55 -0
- aurelian/agents/phenopackets/phenopackets_mcp.py +178 -0
- aurelian/agents/phenopackets/phenopackets_tools.py +127 -0
- aurelian/agents/rag/__init__.py +40 -0
- aurelian/agents/rag/rag_agent.py +84 -0
- aurelian/agents/rag/rag_config.py +80 -0
- aurelian/agents/rag/rag_gradio.py +67 -0
- aurelian/agents/rag/rag_mcp.py +107 -0
- aurelian/agents/rag/rag_tools.py +189 -0
- aurelian/agents/rag_agent.py +54 -0
- aurelian/agents/robot/__init__.py +0 -0
- aurelian/agents/robot/assets/__init__.py +3 -0
- aurelian/agents/robot/assets/template.md +384 -0
- aurelian/agents/robot/robot_config.py +25 -0
- aurelian/agents/robot/robot_gradio.py +46 -0
- aurelian/agents/robot/robot_mcp.py +100 -0
- aurelian/agents/robot/robot_ontology_agent.py +139 -0
- aurelian/agents/robot/robot_tools.py +50 -0
- aurelian/agents/talisman/__init__.py +3 -0
- aurelian/agents/talisman/__main__.py +17 -0
- aurelian/agents/talisman/cli.py +70 -0
- aurelian/agents/talisman/run_talisman.py +18 -0
- aurelian/agents/talisman/talisman_agent.py +143 -0
- aurelian/agents/talisman/talisman_config.py +66 -0
- aurelian/agents/talisman/talisman_gradio.py +50 -0
- aurelian/agents/talisman/talisman_mcp.py +75 -0
- aurelian/agents/talisman/talisman_tools.py +962 -0
- aurelian/agents/ubergraph/__init__.py +40 -0
- aurelian/agents/ubergraph/ubergraph_agent.py +72 -0
- aurelian/agents/ubergraph/ubergraph_config.py +79 -0
- aurelian/agents/ubergraph/ubergraph_gradio.py +48 -0
- aurelian/agents/ubergraph/ubergraph_mcp.py +69 -0
- aurelian/agents/ubergraph/ubergraph_tools.py +118 -0
- aurelian/agents/uniprot/__init__.py +0 -0
- aurelian/agents/uniprot/uniprot_agent.py +43 -0
- aurelian/agents/uniprot/uniprot_config.py +43 -0
- aurelian/agents/uniprot/uniprot_evals.py +99 -0
- aurelian/agents/uniprot/uniprot_gradio.py +48 -0
- aurelian/agents/uniprot/uniprot_mcp.py +168 -0
- aurelian/agents/uniprot/uniprot_tools.py +136 -0
- aurelian/agents/web/__init__.py +0 -0
- aurelian/agents/web/web_config.py +27 -0
- aurelian/agents/web/web_gradio.py +48 -0
- aurelian/agents/web/web_mcp.py +50 -0
- aurelian/agents/web/web_tools.py +121 -0
- aurelian/chat.py +23 -0
- aurelian/cli.py +1004 -0
- aurelian/dependencies/__init__.py +0 -0
- aurelian/dependencies/workdir.py +78 -0
- aurelian/evaluators/model.py +9 -0
- aurelian/evaluators/substring_evaluator.py +30 -0
- aurelian/mcp/__init__.py +0 -0
- aurelian/mcp/amigo_mcp_test.py +86 -0
- aurelian/mcp/config_generator.py +123 -0
- aurelian/mcp/example_config.json +43 -0
- aurelian/mcp/generate_sample_config.py +37 -0
- aurelian/mcp/gocam_mcp_test.py +126 -0
- aurelian/mcp/linkml_mcp_tools.py +190 -0
- aurelian/mcp/mcp_discovery.py +87 -0
- aurelian/mcp/mcp_test.py +31 -0
- aurelian/mcp/phenopackets_mcp_test.py +103 -0
- aurelian/tools/__init__.py +0 -0
- aurelian/tools/web/__init__.py +0 -0
- aurelian/tools/web/url_download.py +51 -0
- aurelian/utils/__init__.py +0 -0
- aurelian/utils/async_utils.py +18 -0
- aurelian/utils/data_utils.py +32 -0
- aurelian/utils/documentation_manager.py +59 -0
- aurelian/utils/doi_fetcher.py +238 -0
- aurelian/utils/ontology_utils.py +68 -0
- aurelian/utils/pdf_fetcher.py +23 -0
- aurelian/utils/process_logs.py +100 -0
- aurelian/utils/pubmed_utils.py +238 -0
- aurelian/utils/pytest_report_to_markdown.py +67 -0
- aurelian/utils/robot_ontology_utils.py +112 -0
- aurelian/utils/search_utils.py +95 -0
- aurelian-0.1.0.dist-info/LICENSE +22 -0
- aurelian-0.1.0.dist-info/METADATA +109 -0
- aurelian-0.1.0.dist-info/RECORD +266 -0
- aurelian-0.1.0.dist-info/WHEEL +4 -0
- 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()
|
aurelian/mcp/mcp_test.py
ADDED
@@ -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
|
+
|