awslabs.healthlake-mcp-server 0.0.1__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.
- awslabs/__init__.py +16 -0
- awslabs/healthlake_mcp_server/__init__.py +17 -0
- awslabs/healthlake_mcp_server/fhir_operations.py +701 -0
- awslabs/healthlake_mcp_server/main.py +77 -0
- awslabs/healthlake_mcp_server/models.py +120 -0
- awslabs/healthlake_mcp_server/server.py +665 -0
- awslabs_healthlake_mcp_server-0.0.1.dist-info/METADATA +631 -0
- awslabs_healthlake_mcp_server-0.0.1.dist-info/RECORD +12 -0
- awslabs_healthlake_mcp_server-0.0.1.dist-info/WHEEL +4 -0
- awslabs_healthlake_mcp_server-0.0.1.dist-info/entry_points.txt +2 -0
- awslabs_healthlake_mcp_server-0.0.1.dist-info/licenses/LICENSE +175 -0
- awslabs_healthlake_mcp_server-0.0.1.dist-info/licenses/NOTICE +2 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""Main entry point for the AWS HealthLake MCP server."""
|
|
17
|
+
|
|
18
|
+
# Standard library imports
|
|
19
|
+
import argparse
|
|
20
|
+
import asyncio
|
|
21
|
+
import os
|
|
22
|
+
import sys
|
|
23
|
+
|
|
24
|
+
# Local imports
|
|
25
|
+
from .server import create_healthlake_server
|
|
26
|
+
|
|
27
|
+
# Third-party imports
|
|
28
|
+
from loguru import logger
|
|
29
|
+
from mcp.server.stdio import stdio_server
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Configure logging
|
|
33
|
+
logger.remove()
|
|
34
|
+
logger.add(sys.stderr, level=os.getenv('MCP_LOG_LEVEL', 'WARNING'))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def parse_args():
|
|
38
|
+
"""Parse command line arguments."""
|
|
39
|
+
parser = argparse.ArgumentParser(description='AWS HealthLake MCP Server')
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
'--readonly',
|
|
42
|
+
action='store_true',
|
|
43
|
+
help='Run server in read-only mode (prevents all mutating operations)',
|
|
44
|
+
)
|
|
45
|
+
return parser.parse_args()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def main() -> None:
|
|
49
|
+
"""Main entry point for the server."""
|
|
50
|
+
try:
|
|
51
|
+
# Parse command line arguments
|
|
52
|
+
args = parse_args()
|
|
53
|
+
|
|
54
|
+
# Create the HealthLake MCP server with read-only mode
|
|
55
|
+
server = create_healthlake_server(read_only=args.readonly)
|
|
56
|
+
|
|
57
|
+
# Log server mode
|
|
58
|
+
if args.readonly:
|
|
59
|
+
logger.info('Server started in READ-ONLY mode - mutating operations disabled')
|
|
60
|
+
else:
|
|
61
|
+
logger.info('Server started in FULL ACCESS mode')
|
|
62
|
+
|
|
63
|
+
# Run the server using stdio transport
|
|
64
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
65
|
+
await server.run(read_stream, write_stream, server.create_initialization_options())
|
|
66
|
+
except Exception as e:
|
|
67
|
+
logger.error(f'Server error: {e}')
|
|
68
|
+
raise
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def sync_main() -> None:
|
|
72
|
+
"""Synchronous wrapper for the main function."""
|
|
73
|
+
asyncio.run(main())
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if __name__ == '__main__':
|
|
77
|
+
sync_main()
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Pydantic models for HealthLake MCP server."""
|
|
16
|
+
|
|
17
|
+
# Standard library imports
|
|
18
|
+
# Local imports
|
|
19
|
+
from .fhir_operations import DATASTORE_ID_LENGTH
|
|
20
|
+
|
|
21
|
+
# Third-party imports
|
|
22
|
+
from pydantic import BaseModel, Field, field_validator
|
|
23
|
+
from typing import Any, Dict, Optional
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class FHIRResource(BaseModel):
|
|
27
|
+
"""Base FHIR resource model."""
|
|
28
|
+
|
|
29
|
+
resourceType: str
|
|
30
|
+
id: Optional[str] = None
|
|
31
|
+
meta: Optional[Dict[str, Any]] = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class SearchParameters(BaseModel):
|
|
35
|
+
"""FHIR search parameters."""
|
|
36
|
+
|
|
37
|
+
parameters: Dict[str, str] = Field(default_factory=dict)
|
|
38
|
+
count: int = Field(default=100, ge=1, le=100)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class CreateResourceRequest(BaseModel):
|
|
42
|
+
"""Request to create a FHIR resource."""
|
|
43
|
+
|
|
44
|
+
datastore_id: str = Field(..., min_length=DATASTORE_ID_LENGTH, max_length=DATASTORE_ID_LENGTH)
|
|
45
|
+
resource_type: str
|
|
46
|
+
resource_data: Dict[str, Any]
|
|
47
|
+
|
|
48
|
+
@field_validator('datastore_id')
|
|
49
|
+
@classmethod
|
|
50
|
+
def validate_datastore_id(cls, v):
|
|
51
|
+
"""Validate datastore ID is alphanumeric."""
|
|
52
|
+
if not v.isalnum():
|
|
53
|
+
raise ValueError('Datastore ID must be alphanumeric')
|
|
54
|
+
return v
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class UpdateResourceRequest(BaseModel):
|
|
58
|
+
"""Request to update a FHIR resource."""
|
|
59
|
+
|
|
60
|
+
datastore_id: str = Field(..., min_length=DATASTORE_ID_LENGTH, max_length=DATASTORE_ID_LENGTH)
|
|
61
|
+
resource_type: str
|
|
62
|
+
resource_id: str
|
|
63
|
+
resource_data: Dict[str, Any]
|
|
64
|
+
|
|
65
|
+
@field_validator('datastore_id')
|
|
66
|
+
@classmethod
|
|
67
|
+
def validate_datastore_id(cls, v):
|
|
68
|
+
"""Validate datastore ID is alphanumeric."""
|
|
69
|
+
if not v.isalnum():
|
|
70
|
+
raise ValueError('Datastore ID must be alphanumeric')
|
|
71
|
+
return v
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class DatastoreFilter(BaseModel):
|
|
75
|
+
"""Filter for listing datastores."""
|
|
76
|
+
|
|
77
|
+
status: Optional[str] = Field(None, pattern='^(CREATING|ACTIVE|DELETING|DELETED)$')
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class ImportJobConfig(BaseModel):
|
|
81
|
+
"""Configuration for FHIR import job."""
|
|
82
|
+
|
|
83
|
+
datastore_id: str = Field(..., min_length=DATASTORE_ID_LENGTH, max_length=DATASTORE_ID_LENGTH)
|
|
84
|
+
input_data_config: Dict[str, Any]
|
|
85
|
+
data_access_role_arn: str
|
|
86
|
+
job_name: Optional[str] = None
|
|
87
|
+
|
|
88
|
+
@field_validator('datastore_id')
|
|
89
|
+
@classmethod
|
|
90
|
+
def validate_datastore_id(cls, v):
|
|
91
|
+
"""Validate datastore ID is alphanumeric."""
|
|
92
|
+
if not v.isalnum():
|
|
93
|
+
raise ValueError('Datastore ID must be alphanumeric')
|
|
94
|
+
return v
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class ExportJobConfig(BaseModel):
|
|
98
|
+
"""Configuration for FHIR export job."""
|
|
99
|
+
|
|
100
|
+
datastore_id: str = Field(..., min_length=DATASTORE_ID_LENGTH, max_length=DATASTORE_ID_LENGTH)
|
|
101
|
+
output_data_config: Dict[str, Any]
|
|
102
|
+
data_access_role_arn: str
|
|
103
|
+
job_name: Optional[str] = None
|
|
104
|
+
|
|
105
|
+
@field_validator('datastore_id')
|
|
106
|
+
@classmethod
|
|
107
|
+
def validate_datastore_id(cls, v):
|
|
108
|
+
"""Validate datastore ID is alphanumeric."""
|
|
109
|
+
if not v.isalnum():
|
|
110
|
+
raise ValueError('Datastore ID must be alphanumeric')
|
|
111
|
+
return v
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class JobFilter(BaseModel):
|
|
115
|
+
"""Filter for listing jobs."""
|
|
116
|
+
|
|
117
|
+
job_status: Optional[str] = Field(
|
|
118
|
+
None, pattern='^(SUBMITTED|IN_PROGRESS|COMPLETED|FAILED|STOP_REQUESTED|STOPPED)$'
|
|
119
|
+
)
|
|
120
|
+
job_type: Optional[str] = Field(None, pattern='^(IMPORT|EXPORT)$')
|