awslabs.s3-tables-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 +15 -0
- awslabs/s3_tables_mcp_server/__init__.py +18 -0
- awslabs/s3_tables_mcp_server/constants.py +167 -0
- awslabs/s3_tables_mcp_server/database.py +140 -0
- awslabs/s3_tables_mcp_server/engines/__init__.py +13 -0
- awslabs/s3_tables_mcp_server/engines/pyiceberg.py +239 -0
- awslabs/s3_tables_mcp_server/file_processor.py +485 -0
- awslabs/s3_tables_mcp_server/models.py +274 -0
- awslabs/s3_tables_mcp_server/namespaces.py +63 -0
- awslabs/s3_tables_mcp_server/resources.py +231 -0
- awslabs/s3_tables_mcp_server/s3_operations.py +43 -0
- awslabs/s3_tables_mcp_server/server.py +821 -0
- awslabs/s3_tables_mcp_server/table_buckets.py +136 -0
- awslabs/s3_tables_mcp_server/tables.py +307 -0
- awslabs/s3_tables_mcp_server/utils.py +139 -0
- awslabs_s3_tables_mcp_server-0.0.1.dist-info/METADATA +216 -0
- awslabs_s3_tables_mcp_server-0.0.1.dist-info/RECORD +21 -0
- awslabs_s3_tables_mcp_server-0.0.1.dist-info/WHEEL +4 -0
- awslabs_s3_tables_mcp_server-0.0.1.dist-info/entry_points.txt +2 -0
- awslabs_s3_tables_mcp_server-0.0.1.dist-info/licenses/LICENSE +175 -0
- awslabs_s3_tables_mcp_server-0.0.1.dist-info/licenses/NOTICE +2 -0
@@ -0,0 +1,274 @@
|
|
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
|
+
"""AWS S3 Tables MCP Server models."""
|
16
|
+
|
17
|
+
from awslabs.s3_tables_mcp_server.constants import (
|
18
|
+
TABLE_ARN_PATTERN,
|
19
|
+
TABLE_BUCKET_ARN_PATTERN,
|
20
|
+
TABLE_BUCKET_NAME_PATTERN,
|
21
|
+
TABLE_NAME_PATTERN,
|
22
|
+
)
|
23
|
+
from datetime import datetime
|
24
|
+
from enum import Enum
|
25
|
+
from pydantic import BaseModel, Field, model_validator
|
26
|
+
from typing import List, Optional, Union
|
27
|
+
|
28
|
+
|
29
|
+
# Enums
|
30
|
+
class OpenTableFormat(str, Enum):
|
31
|
+
"""Supported open table formats."""
|
32
|
+
|
33
|
+
ICEBERG = 'ICEBERG'
|
34
|
+
|
35
|
+
|
36
|
+
class TableBucketType(str, Enum):
|
37
|
+
"""Table bucket type."""
|
38
|
+
|
39
|
+
CUSTOMER = 'customer'
|
40
|
+
AWS = 'aws'
|
41
|
+
|
42
|
+
|
43
|
+
class TableType(str, Enum):
|
44
|
+
"""Table type."""
|
45
|
+
|
46
|
+
CUSTOMER = 'customer'
|
47
|
+
AWS = 'aws'
|
48
|
+
|
49
|
+
|
50
|
+
class MaintenanceStatus(str, Enum):
|
51
|
+
"""Maintenance status."""
|
52
|
+
|
53
|
+
ENABLED = 'enabled'
|
54
|
+
DISABLED = 'disabled'
|
55
|
+
|
56
|
+
|
57
|
+
class JobStatus(str, Enum):
|
58
|
+
"""Job status."""
|
59
|
+
|
60
|
+
NOT_YET_RUN = 'Not_Yet_Run'
|
61
|
+
SUCCESSFUL = 'Successful'
|
62
|
+
FAILED = 'Failed'
|
63
|
+
DISABLED = 'Disabled'
|
64
|
+
|
65
|
+
|
66
|
+
class TableBucketMaintenanceType(str, Enum):
|
67
|
+
"""Table bucket maintenance type."""
|
68
|
+
|
69
|
+
ICEBERG_UNREFERENCED_FILE_REMOVAL = 'icebergUnreferencedFileRemoval'
|
70
|
+
|
71
|
+
|
72
|
+
class TableMaintenanceType(str, Enum):
|
73
|
+
"""Table maintenance type."""
|
74
|
+
|
75
|
+
ICEBERG_COMPACTION = 'icebergCompaction'
|
76
|
+
ICEBERG_SNAPSHOT_MANAGEMENT = 'icebergSnapshotManagement'
|
77
|
+
|
78
|
+
|
79
|
+
class TableMaintenanceJobType(str, Enum):
|
80
|
+
"""Table maintenance job type."""
|
81
|
+
|
82
|
+
ICEBERG_COMPACTION = 'icebergCompaction'
|
83
|
+
ICEBERG_SNAPSHOT_MANAGEMENT = 'icebergSnapshotManagement'
|
84
|
+
ICEBERG_UNREFERENCED_FILE_REMOVAL = 'icebergUnreferencedFileRemoval'
|
85
|
+
|
86
|
+
|
87
|
+
# Core Models
|
88
|
+
class TableBucketSummary(BaseModel):
|
89
|
+
"""Table bucket summary."""
|
90
|
+
|
91
|
+
arn: str = Field(pattern=TABLE_BUCKET_ARN_PATTERN)
|
92
|
+
name: str = Field(min_length=3, max_length=63, pattern=TABLE_BUCKET_NAME_PATTERN)
|
93
|
+
owner_account_id: str = Field(min_length=12, max_length=12, pattern=r'[0-9].*')
|
94
|
+
created_at: datetime
|
95
|
+
table_bucket_id: Optional[str] = None
|
96
|
+
type: Optional[TableBucketType] = None
|
97
|
+
|
98
|
+
|
99
|
+
class TableBucket(BaseModel):
|
100
|
+
"""Complete table bucket information."""
|
101
|
+
|
102
|
+
arn: str = Field(pattern=TABLE_BUCKET_ARN_PATTERN)
|
103
|
+
name: str = Field(min_length=3, max_length=63, pattern=TABLE_BUCKET_NAME_PATTERN)
|
104
|
+
owner_account_id: str = Field(min_length=12, max_length=12, pattern=r'[0-9].*')
|
105
|
+
created_at: datetime
|
106
|
+
table_bucket_id: Optional[str] = None
|
107
|
+
type: Optional[TableBucketType] = None
|
108
|
+
|
109
|
+
|
110
|
+
class NamespaceSummary(BaseModel):
|
111
|
+
"""Namespace summary."""
|
112
|
+
|
113
|
+
namespace: List[str]
|
114
|
+
created_at: datetime
|
115
|
+
created_by: str = Field(min_length=12, max_length=12, pattern=r'[0-9].*')
|
116
|
+
owner_account_id: str = Field(min_length=12, max_length=12, pattern=r'[0-9].*')
|
117
|
+
namespace_id: Optional[str] = None
|
118
|
+
table_bucket_id: Optional[str] = None
|
119
|
+
|
120
|
+
|
121
|
+
class TableSummary(BaseModel):
|
122
|
+
"""Table summary."""
|
123
|
+
|
124
|
+
namespace: List[str]
|
125
|
+
name: str = Field(min_length=1, max_length=255, pattern=TABLE_NAME_PATTERN)
|
126
|
+
type: TableType
|
127
|
+
table_arn: str = Field(pattern=TABLE_ARN_PATTERN)
|
128
|
+
created_at: datetime
|
129
|
+
modified_at: datetime
|
130
|
+
namespace_id: Optional[str] = None
|
131
|
+
table_bucket_id: Optional[str] = None
|
132
|
+
|
133
|
+
|
134
|
+
class Table(BaseModel):
|
135
|
+
"""Complete table information."""
|
136
|
+
|
137
|
+
name: str = Field(min_length=1, max_length=255, pattern=TABLE_NAME_PATTERN)
|
138
|
+
type: TableType
|
139
|
+
table_arn: str = Field(pattern=TABLE_ARN_PATTERN, alias='tableARN')
|
140
|
+
namespace: List[str]
|
141
|
+
namespace_id: Optional[str] = None
|
142
|
+
version_token: str = Field(min_length=1, max_length=2048)
|
143
|
+
metadata_location: Optional[str] = Field(None, min_length=1, max_length=2048)
|
144
|
+
warehouse_location: str = Field(min_length=1, max_length=2048)
|
145
|
+
created_at: datetime
|
146
|
+
created_by: str = Field(min_length=12, max_length=12, pattern=r'[0-9].*')
|
147
|
+
managed_by_service: Optional[str] = None
|
148
|
+
modified_at: datetime
|
149
|
+
modified_by: str = Field(min_length=12, max_length=12, pattern=r'[0-9].*')
|
150
|
+
owner_account_id: str = Field(min_length=12, max_length=12, pattern=r'[0-9].*')
|
151
|
+
format: OpenTableFormat
|
152
|
+
table_bucket_id: Optional[str] = None
|
153
|
+
|
154
|
+
|
155
|
+
# Maintenance Models
|
156
|
+
class IcebergCompactionSettings(BaseModel):
|
157
|
+
"""Settings for Iceberg compaction."""
|
158
|
+
|
159
|
+
target_file_size_mb: Optional[int] = Field(None, ge=1, le=2147483647)
|
160
|
+
|
161
|
+
|
162
|
+
class IcebergSnapshotManagementSettings(BaseModel):
|
163
|
+
"""Settings for Iceberg snapshot management."""
|
164
|
+
|
165
|
+
min_snapshots_to_keep: Optional[int] = Field(None, ge=1, le=2147483647)
|
166
|
+
max_snapshot_age_hours: Optional[int] = Field(None, ge=1, le=2147483647)
|
167
|
+
|
168
|
+
|
169
|
+
class TableMaintenanceJobStatusValue(BaseModel):
|
170
|
+
"""Table maintenance job status value."""
|
171
|
+
|
172
|
+
status: JobStatus
|
173
|
+
last_run_timestamp: Optional[datetime] = None
|
174
|
+
failure_message: Optional[str] = None
|
175
|
+
|
176
|
+
|
177
|
+
class TableMaintenanceConfigurationValue(BaseModel):
|
178
|
+
"""Table maintenance configuration value."""
|
179
|
+
|
180
|
+
status: Optional[MaintenanceStatus] = None
|
181
|
+
settings: Optional[Union[IcebergCompactionSettings, IcebergSnapshotManagementSettings]] = None
|
182
|
+
|
183
|
+
|
184
|
+
class IcebergUnreferencedFileRemovalSettings(BaseModel):
|
185
|
+
"""Settings for unreferenced file removal."""
|
186
|
+
|
187
|
+
unreferenced_days: Optional[int] = Field(None, ge=1, le=2147483647)
|
188
|
+
non_current_days: Optional[int] = Field(None, ge=1, le=2147483647)
|
189
|
+
|
190
|
+
|
191
|
+
class TableBucketMaintenanceSettings(BaseModel):
|
192
|
+
"""Contains details about the maintenance settings for the table bucket."""
|
193
|
+
|
194
|
+
iceberg_unreferenced_file_removal: Optional[IcebergUnreferencedFileRemovalSettings] = Field(
|
195
|
+
None, description='Settings for unreferenced file removal.'
|
196
|
+
)
|
197
|
+
|
198
|
+
@model_validator(mode='after')
|
199
|
+
def validate_only_one_setting(self) -> 'TableBucketMaintenanceSettings':
|
200
|
+
"""Validate that only one setting is specified."""
|
201
|
+
settings = [self.iceberg_unreferenced_file_removal]
|
202
|
+
if sum(1 for s in settings if s is not None) > 1:
|
203
|
+
raise ValueError('Only one maintenance setting can be specified')
|
204
|
+
return self
|
205
|
+
|
206
|
+
|
207
|
+
class TableBucketMaintenanceConfigurationValue(BaseModel):
|
208
|
+
"""Details about the values that define the maintenance configuration for a table bucket."""
|
209
|
+
|
210
|
+
settings: Optional[TableBucketMaintenanceSettings] = Field(
|
211
|
+
None, description='Contains details about the settings of the maintenance configuration.'
|
212
|
+
)
|
213
|
+
status: Optional[MaintenanceStatus] = Field(
|
214
|
+
None, description='The status of the maintenance configuration.'
|
215
|
+
)
|
216
|
+
|
217
|
+
|
218
|
+
# Resource Models
|
219
|
+
class TableBucketsResource(BaseModel):
|
220
|
+
"""Resource containing all table buckets."""
|
221
|
+
|
222
|
+
table_buckets: List[TableBucketSummary]
|
223
|
+
total_count: int
|
224
|
+
|
225
|
+
|
226
|
+
class NamespacesResource(BaseModel):
|
227
|
+
"""Resource containing all namespaces."""
|
228
|
+
|
229
|
+
namespaces: List[NamespaceSummary]
|
230
|
+
total_count: int
|
231
|
+
|
232
|
+
|
233
|
+
class TablesResource(BaseModel):
|
234
|
+
"""Resource containing all tables."""
|
235
|
+
|
236
|
+
tables: List[TableSummary]
|
237
|
+
total_count: int
|
238
|
+
|
239
|
+
|
240
|
+
# Error Models
|
241
|
+
class S3TablesError(BaseModel):
|
242
|
+
"""S3 Tables error response."""
|
243
|
+
|
244
|
+
error_code: str
|
245
|
+
error_message: str
|
246
|
+
request_id: Optional[str] = None
|
247
|
+
resource_name: Optional[str] = None
|
248
|
+
|
249
|
+
|
250
|
+
# Schema Models
|
251
|
+
class SchemaField(BaseModel):
|
252
|
+
"""Iceberg schema field."""
|
253
|
+
|
254
|
+
name: str
|
255
|
+
type: str
|
256
|
+
required: Optional[bool] = None
|
257
|
+
|
258
|
+
|
259
|
+
class IcebergSchema(BaseModel):
|
260
|
+
"""Iceberg table schema."""
|
261
|
+
|
262
|
+
fields: List[SchemaField]
|
263
|
+
|
264
|
+
|
265
|
+
class IcebergMetadata(BaseModel):
|
266
|
+
"""Iceberg table metadata."""
|
267
|
+
|
268
|
+
table_schema: IcebergSchema = Field(alias='schema')
|
269
|
+
|
270
|
+
|
271
|
+
class TableMetadata(BaseModel):
|
272
|
+
"""Table metadata union."""
|
273
|
+
|
274
|
+
iceberg: Optional[IcebergMetadata] = None
|
@@ -0,0 +1,63 @@
|
|
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
|
+
"""Namespace Management tools for S3 Tables MCP Server."""
|
16
|
+
|
17
|
+
from .utils import get_s3tables_client, handle_exceptions
|
18
|
+
from typing import Any, Dict, Optional
|
19
|
+
|
20
|
+
|
21
|
+
@handle_exceptions
|
22
|
+
async def create_namespace(
|
23
|
+
table_bucket_arn: str,
|
24
|
+
namespace: str,
|
25
|
+
region_name: Optional[str] = None,
|
26
|
+
) -> Dict[str, Any]:
|
27
|
+
"""Create a new namespace."""
|
28
|
+
client = get_s3tables_client(region_name)
|
29
|
+
response = client.create_namespace(tableBucketARN=table_bucket_arn, namespace=[namespace])
|
30
|
+
|
31
|
+
return dict(response)
|
32
|
+
|
33
|
+
|
34
|
+
@handle_exceptions
|
35
|
+
async def delete_namespace(
|
36
|
+
table_bucket_arn: str,
|
37
|
+
namespace: str,
|
38
|
+
region_name: Optional[str] = None,
|
39
|
+
) -> Dict[str, Any]:
|
40
|
+
"""Delete a namespace.
|
41
|
+
|
42
|
+
Permissions:
|
43
|
+
You must have the s3tables:DeleteNamespace permission to use this operation.
|
44
|
+
"""
|
45
|
+
client = get_s3tables_client(region_name)
|
46
|
+
response = client.delete_namespace(tableBucketARN=table_bucket_arn, namespace=namespace)
|
47
|
+
return dict(response)
|
48
|
+
|
49
|
+
|
50
|
+
@handle_exceptions
|
51
|
+
async def get_namespace(
|
52
|
+
table_bucket_arn: str, namespace: str, region_name: Optional[str] = None
|
53
|
+
) -> Dict[str, Any]:
|
54
|
+
"""Get details about a namespace.
|
55
|
+
|
56
|
+
Gets details about a namespace.
|
57
|
+
|
58
|
+
Permissions:
|
59
|
+
You must have the s3tables:GetNamespace permission to use this operation.
|
60
|
+
"""
|
61
|
+
client = get_s3tables_client(region_name)
|
62
|
+
response = client.get_namespace(tableBucketARN=table_bucket_arn, namespace=namespace)
|
63
|
+
return dict(response)
|
@@ -0,0 +1,231 @@
|
|
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
|
+
"""MCP resource definitions for S3 Tables MCP Server."""
|
16
|
+
|
17
|
+
import json
|
18
|
+
from .models import (
|
19
|
+
NamespacesResource,
|
20
|
+
NamespaceSummary,
|
21
|
+
TableBucketsResource,
|
22
|
+
TableBucketSummary,
|
23
|
+
TablesResource,
|
24
|
+
TableSummary,
|
25
|
+
)
|
26
|
+
from .utils import get_s3tables_client
|
27
|
+
from pydantic import BaseModel
|
28
|
+
from typing import Any, Callable, Dict, List, Optional, Type, TypeVar
|
29
|
+
|
30
|
+
|
31
|
+
T = TypeVar('T')
|
32
|
+
ResourceT = TypeVar('ResourceT', bound=BaseModel)
|
33
|
+
|
34
|
+
|
35
|
+
def create_error_response(error: Exception, resource_name: str) -> str:
|
36
|
+
"""Create a standardized error response.
|
37
|
+
|
38
|
+
Args:
|
39
|
+
error: The exception that occurred
|
40
|
+
resource_name: The name of the resource being accessed
|
41
|
+
|
42
|
+
Returns:
|
43
|
+
A JSON string containing the error response
|
44
|
+
"""
|
45
|
+
return json.dumps({'error': str(error), resource_name: [], 'total_count': 0})
|
46
|
+
|
47
|
+
|
48
|
+
async def paginate_and_collect(
|
49
|
+
paginator: Any,
|
50
|
+
collection_key: str,
|
51
|
+
item_constructor: Callable[[Dict[str, Any]], T],
|
52
|
+
**pagination_args,
|
53
|
+
) -> List[T]:
|
54
|
+
"""Collect items from a paginated response.
|
55
|
+
|
56
|
+
Args:
|
57
|
+
paginator: The paginator to use
|
58
|
+
collection_key: The key in the response that contains the items
|
59
|
+
item_constructor: A function that constructs an item from a response
|
60
|
+
**pagination_args: Additional arguments to pass to the paginator
|
61
|
+
|
62
|
+
Returns:
|
63
|
+
A list of constructed items
|
64
|
+
"""
|
65
|
+
items = []
|
66
|
+
for page in paginator.paginate(**pagination_args):
|
67
|
+
for item in page.get(collection_key, []):
|
68
|
+
items.append(item_constructor(item))
|
69
|
+
return items
|
70
|
+
|
71
|
+
|
72
|
+
async def create_resource_response(
|
73
|
+
items: List[T], resource_class: Type[ResourceT], resource_name: str
|
74
|
+
) -> str:
|
75
|
+
"""Create a resource response.
|
76
|
+
|
77
|
+
Args:
|
78
|
+
items: The items to include in the resource
|
79
|
+
resource_class: The resource class to use
|
80
|
+
resource_name: The name of the resource
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
A JSON string containing the resource response
|
84
|
+
"""
|
85
|
+
try:
|
86
|
+
resource = resource_class(**{resource_name: items, 'total_count': len(items)})
|
87
|
+
return resource.model_dump_json()
|
88
|
+
except Exception as e:
|
89
|
+
return create_error_response(e, resource_name)
|
90
|
+
|
91
|
+
|
92
|
+
async def list_table_buckets_resource(region_name: Optional[str] = None) -> str:
|
93
|
+
"""List all S3 Tables buckets.
|
94
|
+
|
95
|
+
Lists table buckets for your account. Requires s3tables:ListTableBuckets permission.
|
96
|
+
The API supports pagination with continuationToken and filtering with prefix.
|
97
|
+
|
98
|
+
Returns:
|
99
|
+
A JSON string containing the list of table buckets and total count.
|
100
|
+
"""
|
101
|
+
try:
|
102
|
+
client = get_s3tables_client(region_name)
|
103
|
+
paginator = client.get_paginator('list_table_buckets')
|
104
|
+
|
105
|
+
table_buckets = await paginate_and_collect(
|
106
|
+
paginator=paginator,
|
107
|
+
collection_key='tableBuckets',
|
108
|
+
item_constructor=lambda bucket: TableBucketSummary(
|
109
|
+
arn=bucket['arn'],
|
110
|
+
name=bucket['name'],
|
111
|
+
owner_account_id=bucket['ownerAccountId'],
|
112
|
+
created_at=bucket['createdAt'],
|
113
|
+
table_bucket_id=bucket.get('tableBucketId'),
|
114
|
+
type=bucket.get('type'),
|
115
|
+
),
|
116
|
+
)
|
117
|
+
|
118
|
+
return await create_resource_response(
|
119
|
+
items=table_buckets, resource_class=TableBucketsResource, resource_name='table_buckets'
|
120
|
+
)
|
121
|
+
|
122
|
+
except Exception as e:
|
123
|
+
return create_error_response(e, 'table_buckets')
|
124
|
+
|
125
|
+
|
126
|
+
async def get_table_buckets(region_name: Optional[str] = None) -> List[TableBucketSummary]:
|
127
|
+
"""Get all table buckets as TableBucketSummary objects.
|
128
|
+
|
129
|
+
Returns:
|
130
|
+
A list of TableBucketSummary objects
|
131
|
+
"""
|
132
|
+
response = await list_table_buckets_resource(region_name=region_name)
|
133
|
+
data = json.loads(response)
|
134
|
+
if 'error' in data:
|
135
|
+
raise Exception(data['error'])
|
136
|
+
return [TableBucketSummary(**bucket) for bucket in data['table_buckets']]
|
137
|
+
|
138
|
+
|
139
|
+
async def list_namespaces_resource(region_name: Optional[str] = None) -> str:
|
140
|
+
"""List all namespaces across all table buckets.
|
141
|
+
|
142
|
+
Lists the namespaces within table buckets. Requires s3tables:ListNamespaces permission.
|
143
|
+
The API supports pagination with continuationToken and filtering with prefix.
|
144
|
+
|
145
|
+
Returns:
|
146
|
+
A JSON string containing the list of namespaces and total count.
|
147
|
+
"""
|
148
|
+
try:
|
149
|
+
client = get_s3tables_client(region_name)
|
150
|
+
|
151
|
+
# Get all table buckets
|
152
|
+
table_buckets = await get_table_buckets(region_name=region_name)
|
153
|
+
|
154
|
+
# Then get namespaces for each bucket
|
155
|
+
all_namespaces = []
|
156
|
+
for bucket in table_buckets:
|
157
|
+
try:
|
158
|
+
namespace_paginator = client.get_paginator('list_namespaces')
|
159
|
+
namespaces = await paginate_and_collect(
|
160
|
+
paginator=namespace_paginator,
|
161
|
+
collection_key='namespaces',
|
162
|
+
item_constructor=lambda namespace: NamespaceSummary(
|
163
|
+
namespace=namespace['namespace'],
|
164
|
+
created_at=namespace['createdAt'],
|
165
|
+
created_by=namespace['createdBy'],
|
166
|
+
owner_account_id=namespace['ownerAccountId'],
|
167
|
+
namespace_id=namespace.get('namespaceId'),
|
168
|
+
table_bucket_id=namespace.get('tableBucketId'),
|
169
|
+
),
|
170
|
+
tableBucketARN=bucket.arn,
|
171
|
+
)
|
172
|
+
all_namespaces.extend(namespaces)
|
173
|
+
except Exception as e:
|
174
|
+
return create_error_response(e, 'namespaces')
|
175
|
+
|
176
|
+
return await create_resource_response(
|
177
|
+
items=all_namespaces, resource_class=NamespacesResource, resource_name='namespaces'
|
178
|
+
)
|
179
|
+
|
180
|
+
except Exception as e:
|
181
|
+
return create_error_response(e, 'namespaces')
|
182
|
+
|
183
|
+
|
184
|
+
async def list_tables_resource(region_name: Optional[str] = None) -> str:
|
185
|
+
"""List all Iceberg tables across all table buckets and namespaces.
|
186
|
+
|
187
|
+
Lists tables in the given table bucket. Requires s3tables:ListTables permission.
|
188
|
+
The API supports pagination with continuationToken, filtering with prefix and namespace,
|
189
|
+
and limiting results with maxTables.
|
190
|
+
|
191
|
+
Returns:
|
192
|
+
A JSON string containing the list of tables and total count.
|
193
|
+
"""
|
194
|
+
try:
|
195
|
+
client = get_s3tables_client(region_name)
|
196
|
+
|
197
|
+
# Get all table buckets
|
198
|
+
table_buckets = await get_table_buckets(region_name=region_name)
|
199
|
+
|
200
|
+
# Then get tables for each bucket
|
201
|
+
all_tables = []
|
202
|
+
for bucket in table_buckets:
|
203
|
+
try:
|
204
|
+
table_paginator = client.get_paginator('list_tables')
|
205
|
+
|
206
|
+
tables = await paginate_and_collect(
|
207
|
+
paginator=table_paginator,
|
208
|
+
collection_key='tables',
|
209
|
+
item_constructor=lambda table: TableSummary(
|
210
|
+
namespace=table['namespace'],
|
211
|
+
name=table['name'],
|
212
|
+
type=table['type'],
|
213
|
+
table_arn=table['tableARN'],
|
214
|
+
created_at=table['createdAt'],
|
215
|
+
modified_at=table['modifiedAt'],
|
216
|
+
namespace_id=table.get('namespaceId'),
|
217
|
+
table_bucket_id=table.get('tableBucketId'),
|
218
|
+
),
|
219
|
+
tableBucketARN=bucket.arn,
|
220
|
+
)
|
221
|
+
|
222
|
+
all_tables.extend(tables)
|
223
|
+
except Exception as e:
|
224
|
+
return create_error_response(e, 'tables')
|
225
|
+
|
226
|
+
return await create_resource_response(
|
227
|
+
items=all_tables, resource_class=TablesResource, resource_name='tables'
|
228
|
+
)
|
229
|
+
|
230
|
+
except Exception as e:
|
231
|
+
return create_error_response(e, 'tables')
|
@@ -0,0 +1,43 @@
|
|
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
|
+
"""S3 Operations tools for S3 Tables MCP Server."""
|
16
|
+
|
17
|
+
from .utils import get_s3_client, handle_exceptions
|
18
|
+
from typing import Any, Dict, Optional
|
19
|
+
|
20
|
+
|
21
|
+
@handle_exceptions
|
22
|
+
async def get_bucket_metadata_table_configuration(
|
23
|
+
bucket: str, region_name: Optional[str] = None
|
24
|
+
) -> Dict[str, Any]:
|
25
|
+
"""Get the metadata table configuration for an S3 bucket.
|
26
|
+
|
27
|
+
Gets the metadata table configuration for an S3 bucket. This configuration
|
28
|
+
determines how metadata is stored and managed for the bucket.
|
29
|
+
|
30
|
+
Permissions:
|
31
|
+
You must have the s3:GetBucketMetadataTableConfiguration permission to use this operation.
|
32
|
+
|
33
|
+
Args:
|
34
|
+
bucket: The name of the S3 bucket
|
35
|
+
region_name: Optional AWS region name. If not provided, uses AWS_REGION environment variable
|
36
|
+
or defaults to 'us-east-1'.
|
37
|
+
|
38
|
+
Returns:
|
39
|
+
Dict containing the bucket metadata table configuration
|
40
|
+
"""
|
41
|
+
client = get_s3_client(region_name)
|
42
|
+
response = client.get_bucket_metadata_table_configuration(Bucket=bucket)
|
43
|
+
return dict(response)
|