aind-data-mcp 0.1.2__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.
@@ -0,0 +1,2 @@
1
+ """Init package"""
2
+ __version__ = "0.1.2"
@@ -0,0 +1,42 @@
1
+ """MCP server for AIND data access."""
2
+
3
+ from pathlib import Path
4
+
5
+ # Import tool modules — side-effect registers all @mcp.tool() decorators
6
+ from .mcp_instance import mcp # noqa: F401
7
+ from . import example_tools # noqa: F401
8
+ from . import nwb_tools # noqa: F401
9
+ from . import query_tools # noqa: F401
10
+ from . import schema_tools # noqa: F401
11
+
12
+
13
+ @mcp.resource("resource://aind_api")
14
+ def get_aind_data_access_api() -> str:
15
+ """
16
+ Get context on how to use the AIND data access api to show users how to
17
+ wrap tool calls
18
+ """
19
+ resource_path = Path(__file__).parent / "resources" / "aind_api_prompt.txt"
20
+ with open(resource_path, "r") as file:
21
+ file_content = file.read()
22
+ return file_content
23
+
24
+
25
+ @mcp.resource("resource://load_nwbfile")
26
+ def get_nwbfile_download_script() -> str:
27
+ """
28
+ Get context on how to return an NWBfile from the /data folder in current repository
29
+ """
30
+ resource_path = Path(__file__).parent / "resources" / "load_nwbfile.txt"
31
+ with open(resource_path, "r") as file:
32
+ file_content = file.read()
33
+ return file_content
34
+
35
+
36
+ def main():
37
+ """Main entry point for the MCP server."""
38
+ mcp.run(transport="stdio")
39
+
40
+
41
+ if __name__ == "__main__":
42
+ main()
@@ -0,0 +1,574 @@
1
+ """Schema example tools for each top-level document type."""
2
+
3
+ import json
4
+
5
+ from .mcp_instance import mcp
6
+
7
+
8
+ @mcp.tool()
9
+ def get_acquisition_example() -> dict:
10
+ """
11
+ Example of the acquisition schema.
12
+ ALL data collection uses 'acquisition' regardless of modality
13
+ (imaging or physiology). Contains data_streams, stimulus_epochs,
14
+ subject_details, manipulations, calibrations, and maintenance.
15
+ Access fields like this - acquisition.<field_name>
16
+ """
17
+ sample_acquisition = json.dumps(
18
+ {
19
+ "acquisition": {
20
+ "subject_id": "730945",
21
+ "specimen_id": None,
22
+ "instrument_id": "447-2-B_20240827",
23
+ "acquisition_start_time": "2024-09-03T15:49:53-07:00",
24
+ "acquisition_end_time": "2024-09-03T17:04:59-07:00",
25
+ "acquisition_type": "Behavior",
26
+ "experimenters": ["Bowen Tan"],
27
+ "protocol_id": ["dx.doi.org/10.17504/protocols.io.example"],
28
+ "calibrations": [],
29
+ "maintenance": [],
30
+ "coordinate_system": None,
31
+ "subject_details": {
32
+ "animal_weight_prior": None,
33
+ "animal_weight_post": "23.6",
34
+ "weight_unit": "gram",
35
+ "anaesthesia": None,
36
+ "mouse_platform_name": "mouse_tube_foraging",
37
+ "reward_consumed_total": "372.0",
38
+ "reward_consumed_unit": "microliter",
39
+ },
40
+ "data_streams": [
41
+ {
42
+ "stream_start_time": "2024-09-03T15:49:53-07:00",
43
+ "stream_end_time": "2024-09-03T17:04:59-07:00",
44
+ "modalities": [
45
+ {"name": "Behavior", "abbreviation": "behavior"}
46
+ ],
47
+ "active_devices": [
48
+ "Harp Behavior",
49
+ "Harp Sound",
50
+ "Lick Sensor Left",
51
+ "Lick Sensor Right",
52
+ ],
53
+ "configurations": [],
54
+ "connections": [],
55
+ "code": [
56
+ {
57
+ "name": "dynamic-foraging-task",
58
+ "version": "1.4.4",
59
+ "url": "https://github.com/AllenNeuralDynamics/dynamic-foraging-task.git",
60
+ "parameters": {},
61
+ }
62
+ ],
63
+ "notes": None,
64
+ }
65
+ ],
66
+ "stimulus_epochs": [
67
+ {
68
+ "stimulus_start_time": "2024-09-03T15:49:53-07:00",
69
+ "stimulus_end_time": "2024-09-03T17:04:59-07:00",
70
+ "stimulus_name": "auditory go cue",
71
+ "stimulus_modalities": ["Auditory"],
72
+ "code": [
73
+ {
74
+ "name": "dynamic-foraging-task",
75
+ "version": "1.4.4",
76
+ "url": "https://github.com/AllenNeuralDynamics/dynamic-foraging-task.git",
77
+ "parameters": {},
78
+ }
79
+ ],
80
+ "performance_metrics": {
81
+ "trials_total": 493,
82
+ "trials_finished": 434,
83
+ "trials_rewarded": 186,
84
+ "foraging_efficiency": 0.593,
85
+ },
86
+ "active_devices": [],
87
+ "configurations": [],
88
+ "notes": None,
89
+ }
90
+ ],
91
+ "manipulations": [],
92
+ "notes": None,
93
+ }
94
+ }
95
+ )
96
+ return sample_acquisition
97
+
98
+
99
+ @mcp.tool()
100
+ def get_data_description_example():
101
+ """
102
+ Example of the data description schema.
103
+ Contains modalities (plural), investigators as Person objects, and tags.
104
+ Access fields like this - data_description.<field_name>
105
+ """
106
+ sample_data_description = json.dumps(
107
+ {
108
+ "data_description": {
109
+ "license": "CC-BY-4.0",
110
+ "subject_id": "662616",
111
+ "creation_time": "2023-04-14T15:11:04-07:00",
112
+ "name": "SmartSPIM_662616_2023-04-14_15-11-04",
113
+ "institution": {
114
+ "name": "Allen Institute for Neural Dynamics",
115
+ "abbreviation": "AIND",
116
+ "registry": {
117
+ "name": "Research Organization Registry",
118
+ "abbreviation": "ROR",
119
+ },
120
+ "registry_identifier": "04szwah67",
121
+ },
122
+ "funding_source": [
123
+ {
124
+ "funder": {
125
+ "name": "National Institute of Neurological Disorders and Stroke",
126
+ "abbreviation": "NINDS",
127
+ "registry": {
128
+ "name": "Research Organization Registry",
129
+ "abbreviation": "ROR",
130
+ },
131
+ "registry_identifier": "01s5ya894",
132
+ },
133
+ "grant_number": "NIH1U19NS123714-01",
134
+ "fundee": "Jayaram Chandrashekar, Mathew Summers",
135
+ }
136
+ ],
137
+ "data_level": "raw",
138
+ "group": "MSMA",
139
+ "investigators": [
140
+ {
141
+ "name": "Mathew Summers",
142
+ "registry": None,
143
+ "registry_identifier": None,
144
+ },
145
+ {
146
+ "name": "Jayaram Chandrashekar",
147
+ "registry": None,
148
+ "registry_identifier": None,
149
+ },
150
+ ],
151
+ "project_name": "Thalamus in the middle",
152
+ "restrictions": None,
153
+ "modalities": [
154
+ {
155
+ "name": "Selective plane illumination microscopy",
156
+ "abbreviation": "SPIM",
157
+ }
158
+ ],
159
+ "tags": [],
160
+ "source_data": None,
161
+ "data_summary": None,
162
+ },
163
+ }
164
+ )
165
+ return sample_data_description
166
+
167
+
168
+ @mcp.tool()
169
+ def get_instrument_example():
170
+ """
171
+ Example of the instrument schema.
172
+ All devices are in a single 'components' list.
173
+ Contains 'connections', 'coordinate_system', 'modalities', 'modification_date'.
174
+ Access fields like this - instrument.<field_name>
175
+ """
176
+ sample_instrument = json.dumps(
177
+ {
178
+ "instrument": {
179
+ "instrument_id": "SmartSPIM1-2",
180
+ "location": "615 Westlake",
181
+ "modification_date": "2023-01-15",
182
+ "temperature_control": None,
183
+ "modalities": [
184
+ {
185
+ "name": "Selective plane illumination microscopy",
186
+ "abbreviation": "SPIM",
187
+ }
188
+ ],
189
+ "components": [
190
+ {
191
+ "device_type": "Objective",
192
+ "name": "TL4X-SAP",
193
+ "serial_number": "Unknown",
194
+ "manufacturer": {
195
+ "name": "Thorlabs",
196
+ "abbreviation": None,
197
+ "registry": {
198
+ "name": "Research Organization Registry",
199
+ "abbreviation": "ROR",
200
+ },
201
+ "registry_identifier": "04gsnvb07",
202
+ },
203
+ "model": "TL4X-SAP",
204
+ "notes": "Thorlabs TL4X-SAP with LifeCanvas dipping cap and correction optics",
205
+ "numerical_aperture": 0.2,
206
+ "magnification": 3.6,
207
+ "immersion": "multi",
208
+ },
209
+ {
210
+ "device_type": "Detector",
211
+ "name": "Camera",
212
+ "serial_number": "220302-SYS-060443",
213
+ "manufacturer": {
214
+ "name": "Hamamatsu",
215
+ "abbreviation": None,
216
+ "registry": None,
217
+ "registry_identifier": None,
218
+ },
219
+ "model": "C14440-20UP",
220
+ "notes": None,
221
+ "detector_type": "Camera",
222
+ "data_interface": "USB",
223
+ "cooling": "water",
224
+ },
225
+ {
226
+ "device_type": "Laser",
227
+ "name": "488nm Laser",
228
+ "serial_number": "VL08223M03",
229
+ "manufacturer": {
230
+ "name": "Vortran",
231
+ "abbreviation": None,
232
+ "registry": None,
233
+ "registry_identifier": None,
234
+ },
235
+ "model": "Stradus",
236
+ "notes": "All lasers controlled via Vortran VersaLase System",
237
+ "coupling": "Single-mode fiber",
238
+ "wavelength": 488,
239
+ "wavelength_unit": "nanometer",
240
+ "max_power": 150,
241
+ "power_unit": "milliwatt",
242
+ },
243
+ {
244
+ "device_type": "Filter",
245
+ "name": "469/35 Band Pass",
246
+ "serial_number": "Unknown-0",
247
+ "manufacturer": {
248
+ "name": "Semrock",
249
+ "abbreviation": None,
250
+ "registry": None,
251
+ "registry_identifier": None,
252
+ },
253
+ "model": "FF01-469/35-25",
254
+ "notes": None,
255
+ "filter_type": "Band pass",
256
+ "diameter": 25,
257
+ "diameter_unit": "millimeter",
258
+ "filter_wheel_index": 0,
259
+ },
260
+ {
261
+ "device_type": "Motorized stage",
262
+ "name": "Focus stage",
263
+ "serial_number": "Unknown-0",
264
+ "manufacturer": {
265
+ "name": "Applied Scientific Instrumentation",
266
+ "abbreviation": None,
267
+ "registry": None,
268
+ "registry_identifier": None,
269
+ },
270
+ "model": "LS-100",
271
+ "notes": "Focus stage",
272
+ "travel": 100,
273
+ "travel_unit": "millimeter",
274
+ },
275
+ ],
276
+ "connections": [],
277
+ "coordinate_system": None,
278
+ "notes": None,
279
+ },
280
+ }
281
+ )
282
+ return sample_instrument
283
+
284
+
285
+ @mcp.tool()
286
+ def get_procedures_example():
287
+ """
288
+ Example of the procedures schema.
289
+ Access fields like this - procedures.<field_name>
290
+ """
291
+ sample_procedures = json.dumps(
292
+ {
293
+ "procedures": {
294
+ "subject_id": "662616",
295
+ "subject_procedures": [
296
+ {
297
+ "procedure_type": "Surgery",
298
+ "start_date": "2023-02-03",
299
+ "experimenter_full_name": "30509",
300
+ "iacuc_protocol": None,
301
+ "animal_weight_prior": None,
302
+ "animal_weight_post": None,
303
+ "weight_unit": "gram",
304
+ "anaesthesia": None,
305
+ "workstation_id": None,
306
+ "procedures": [
307
+ {
308
+ "procedure_type": "Perfusion",
309
+ "protocol_id": "dx.doi.org/10.17504/protocols.io.bg5vjy66",
310
+ "output_specimen_ids": ["662616"],
311
+ }
312
+ ],
313
+ "notes": None,
314
+ },
315
+ {
316
+ "procedure_type": "Surgery",
317
+ "start_date": "2023-01-05",
318
+ "experimenter_full_name": "NSB-5756",
319
+ "iacuc_protocol": "2109",
320
+ "animal_weight_prior": "16.6",
321
+ "animal_weight_post": "16.7",
322
+ "weight_unit": "gram",
323
+ "anaesthesia": {
324
+ "type": "isoflurane",
325
+ "duration": "120.0",
326
+ "duration_unit": "minute",
327
+ "level": "1.5",
328
+ },
329
+ "workstation_id": "SWS 1",
330
+ "procedures": [
331
+ {
332
+ "injection_materials": [
333
+ {
334
+ "material_type": "Virus",
335
+ "name": "SL1-hSyn-Cre",
336
+ "tars_identifiers": {
337
+ "virus_tars_id": None,
338
+ "plasmid_tars_alias": None,
339
+ "prep_lot_number": "221118-11",
340
+ "prep_date": None,
341
+ "prep_type": None,
342
+ "prep_protocol": None,
343
+ },
344
+ "addgene_id": None,
345
+ "titer": {
346
+ "$numberLong": "37500000000000"
347
+ },
348
+ "titer_unit": "gc/mL",
349
+ }
350
+ ],
351
+ "recovery_time": "10.0",
352
+ "recovery_time_unit": "minute",
353
+ "injection_duration": None,
354
+ "injection_duration_unit": "minute",
355
+ "instrument_id": "NJ#2",
356
+ "protocol_id": "dx.doi.org/10.17504/protocols.io.bgpujvnw",
357
+ "injection_coordinate_ml": "0.35",
358
+ "injection_coordinate_ap": "2.2",
359
+ "injection_coordinate_depth": ["2.1"],
360
+ "injection_coordinate_unit": "millimeter",
361
+ "injection_coordinate_reference": "Bregma",
362
+ "bregma_to_lambda_distance": "4.362",
363
+ "bregma_to_lambda_unit": "millimeter",
364
+ "injection_angle": "0",
365
+ "injection_angle_unit": "degrees",
366
+ "targeted_structure": "mPFC",
367
+ "injection_hemisphere": "Right",
368
+ "procedure_type": "Nanoject injection",
369
+ "injection_volume": ["200"],
370
+ "injection_volume_unit": "nanoliter",
371
+ },
372
+ {
373
+ "injection_materials": [
374
+ {
375
+ "material_type": "Virus",
376
+ "name": "AAV-Syn-DIO-TVA66T-dTomato-CVS N2cG",
377
+ "tars_identifiers": {
378
+ "virus_tars_id": None,
379
+ "plasmid_tars_alias": None,
380
+ "prep_lot_number": "220916-4",
381
+ "prep_date": None,
382
+ "prep_type": None,
383
+ "prep_protocol": None,
384
+ },
385
+ "addgene_id": None,
386
+ "titer": {
387
+ "$numberLong": "18000000000000"
388
+ },
389
+ "titer_unit": "gc/mL",
390
+ }
391
+ ],
392
+ "recovery_time": "10.0",
393
+ "recovery_time_unit": "minute",
394
+ "injection_duration": None,
395
+ "injection_duration_unit": "minute",
396
+ "instrument_id": "NJ#2",
397
+ "protocol_id": "dx.doi.org/10.17504/protocols.io.bgpujvnw",
398
+ "injection_coordinate_ml": "2.9",
399
+ "injection_coordinate_ap": "-0.6",
400
+ "injection_coordinate_depth": ["3.6"],
401
+ "injection_coordinate_unit": "millimeter",
402
+ "injection_coordinate_reference": "Bregma",
403
+ "bregma_to_lambda_distance": "4.362",
404
+ "bregma_to_lambda_unit": "millimeter",
405
+ "injection_angle": "30",
406
+ "injection_angle_unit": "degrees",
407
+ "targeted_structure": "VM",
408
+ "injection_hemisphere": "Right",
409
+ "procedure_type": "Nanoject injection",
410
+ "injection_volume": ["200"],
411
+ "injection_volume_unit": "nanoliter",
412
+ },
413
+ ],
414
+ "notes": None,
415
+ },
416
+ ],
417
+ "specimen_procedures": [
418
+ {
419
+ "procedure_type": "Fixation",
420
+ "procedure_name": "SHIELD OFF",
421
+ "specimen_id": "662616",
422
+ "start_date": "2023-02-10",
423
+ "end_date": "2023-02-12",
424
+ "experimenter_full_name": "DT",
425
+ "protocol_id": "none",
426
+ "reagents": [
427
+ {
428
+ "name": "SHIELD Epoxy",
429
+ "source": "LiveCanvas Technologies",
430
+ "rrid": None,
431
+ "lot_number": "unknown",
432
+ "expiration_date": None,
433
+ }
434
+ ],
435
+ "hcr_series": None,
436
+ "immunolabeling": None,
437
+ "notes": "None",
438
+ },
439
+ ],
440
+ "notes": None,
441
+ },
442
+ }
443
+ )
444
+ return sample_procedures
445
+
446
+
447
+ @mcp.tool()
448
+ def get_subject_example():
449
+ """
450
+ Example of the subject schema.
451
+ Species, sex, genotype, breeding_info, and housing are nested inside
452
+ 'subject_details' (MouseSubject/HumanSubject/CalibrationObject).
453
+ Access fields like this - subject.<field_name>
454
+ """
455
+ sample_subject = json.dumps(
456
+ {
457
+ "subject": {
458
+ "subject_id": "662616",
459
+ "subject_details": {
460
+ "species": {
461
+ "name": "Mus musculus",
462
+ "abbreviation": None,
463
+ "registry": {
464
+ "name": "National Center for Biotechnology Information",
465
+ "abbreviation": "NCBI",
466
+ },
467
+ "registry_identifier": "10090",
468
+ },
469
+ "strain": {
470
+ "name": "C57BL/6J",
471
+ "registry": None,
472
+ "registry_identifier": None,
473
+ },
474
+ "sex": "Male",
475
+ "date_of_birth": "2022-11-29",
476
+ "genotype": "Emx1-IRES-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-GCaMP6f)/wt",
477
+ "source": {
478
+ "name": "Allen Institute",
479
+ "abbreviation": "AI",
480
+ "registry": None,
481
+ "registry_identifier": None,
482
+ },
483
+ "breeding_info": {
484
+ "breeding_group": "Emx1-IRES-Cre(ND)",
485
+ "maternal_id": "546543",
486
+ "maternal_genotype": "Emx1-IRES-Cre/wt; Camk2a-tTa/Camk2a-tTA",
487
+ "paternal_id": "232323",
488
+ "paternal_genotype": "Ai93(TITL-GCaMP6f)/wt",
489
+ },
490
+ "housing": {
491
+ "home_cage_enrichment": ["Running wheel"],
492
+ "cage_id": "123",
493
+ },
494
+ },
495
+ "notes": None,
496
+ }
497
+ }
498
+ )
499
+ return sample_subject
500
+
501
+
502
+ @mcp.tool()
503
+ def get_processing_example():
504
+ """
505
+ Example of the processing schema.
506
+ Contains 'data_processes' and 'pipelines' lists.
507
+ Access fields like this - processing.<field_name>
508
+ """
509
+ sample_processing = json.dumps(
510
+ {
511
+ "processing": {
512
+ "data_processes": [
513
+ {
514
+ "process_type": "Image tile fusing",
515
+ "name": "Image tile fusing",
516
+ "stage": "Processing",
517
+ "code": {
518
+ "url": "https://github.com/abcd",
519
+ "version": "0.1",
520
+ "parameters": {"size": 7},
521
+ },
522
+ "experimenters": ["Dr. Dan"],
523
+ "start_date_time": "2022-11-22T08:43:00+00:00",
524
+ "end_date_time": "2022-11-22T08:43:00+00:00",
525
+ "output_path": "/path/to/outputs",
526
+ "notes": None,
527
+ }
528
+ ],
529
+ "pipelines": [
530
+ {
531
+ "name": "Imaging processing pipeline",
532
+ "url": "https://url/for/pipeline",
533
+ "version": "0.1.1",
534
+ }
535
+ ],
536
+ "dependency_graph": None,
537
+ "notes": None,
538
+ }
539
+ }
540
+ )
541
+
542
+ return sample_processing
543
+
544
+
545
+ @mcp.tool()
546
+ def get_model_example() -> dict:
547
+ """
548
+ Example of the model schema.
549
+ Describes a machine learning model including architecture, training, and evaluation.
550
+ Access fields like this - model.<field_name>
551
+ """
552
+ sample_model = json.dumps(
553
+ {
554
+ "model": {
555
+ "name": "Example segmentation model",
556
+ "version": "1.0.0",
557
+ "example_run_code": {
558
+ "url": "https://github.com/example/model",
559
+ "version": "1.0.0",
560
+ "parameters": {"input_shape": [256, 256, 3]},
561
+ },
562
+ "architecture": "UNet",
563
+ "software_framework": {"name": "PyTorch", "version": "2.0"},
564
+ "architecture_parameters": {"layers": 5, "filters": 64},
565
+ "intended_use": "Cell segmentation in calcium imaging data",
566
+ "limitations": "Trained only on mouse visual cortex data",
567
+ "training": [],
568
+ "evaluations": [],
569
+ "notes": None,
570
+ }
571
+ }
572
+ )
573
+ return sample_model
574
+
@@ -0,0 +1,16 @@
1
+ """Central MCP instance and MongoDB client factory."""
2
+
3
+ from aind_data_access_api.document_db import MetadataDbClient
4
+ from fastmcp import FastMCP
5
+
6
+ mcp = FastMCP("aind_data_mcp")
7
+
8
+
9
+ def setup_mongodb_client():
10
+ """Set up and return the MongoDB client"""
11
+
12
+ return MetadataDbClient(
13
+ host="api.allenneuraldynamics.org",
14
+ version="v2",
15
+ )
16
+