awslabs.dynamodb-mcp-server 1.0.9__py3-none-any.whl → 2.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.

Potentially problematic release.


This version of awslabs.dynamodb-mcp-server might be problematic. Click here for more details.

@@ -14,4 +14,4 @@
14
14
 
15
15
  """awslabs.dynamodb-mcp-server"""
16
16
 
17
- __version__ = '1.0.9'
17
+ __version__ = '2.0.1'
@@ -14,8 +14,7 @@
14
14
 
15
15
  import os
16
16
  from functools import wraps
17
- from typing import Any, Callable, Dict, List, Literal, Optional
18
- from typing_extensions import TypedDict
17
+ from typing import Callable
19
18
 
20
19
 
21
20
  def handle_exceptions(func: Callable) -> Callable:
@@ -52,283 +51,3 @@ def mutation_check(func):
52
51
  return await func(*args, **kwargs)
53
52
 
54
53
  return wrapper
55
-
56
-
57
- # Type definitions
58
- AttributeValue = Dict[Literal['S', 'N', 'B', 'BOOL', 'NULL', 'L', 'M', 'SS', 'NS', 'BS'], Any]
59
- KeyAttributeValue = Dict[Literal['S', 'N', 'B'], Any]
60
-
61
- # Return value enums
62
- ReturnValue = Literal['NONE', 'ALL_OLD', 'UPDATED_OLD', 'ALL_NEW', 'UPDATED_NEW']
63
- ReturnConsumedCapacity = Literal['INDEXES', 'TOTAL', 'NONE']
64
- ReturnItemCollectionMetrics = Literal['SIZE', 'NONE']
65
- Select = Literal['ALL_ATTRIBUTES', 'ALL_PROJECTED_ATTRIBUTES', 'SPECIFIC_ATTRIBUTES', 'COUNT']
66
-
67
-
68
- class ScanInput(TypedDict, total=False):
69
- """Parameters for Scan operation."""
70
-
71
- TableName: str # required
72
- IndexName: Optional[str]
73
- AttributesToGet: Optional[List[str]] # Legacy parameter
74
- Limit: Optional[int]
75
- Select: Optional[Select]
76
- ScanFilter: Optional[
77
- Dict[str, AttributeValue]
78
- ] # Legacy parameter (must use AttributeValue format e.g. {'S': 'value'})
79
- ConditionalOperator: Optional[Literal['AND', 'OR']] # Legacy parameter
80
- ExclusiveStartKey: Optional[
81
- Dict[str, KeyAttributeValue]
82
- ] # Primary key attributes in AttributeValue format e.g. {'S': 'value'}
83
- ReturnConsumedCapacity: Optional[ReturnConsumedCapacity]
84
- TotalSegments: Optional[int]
85
- Segment: Optional[int]
86
- ProjectionExpression: Optional[str]
87
- FilterExpression: Optional[str]
88
- ExpressionAttributeNames: Optional[Dict[str, str]]
89
- ExpressionAttributeValues: Optional[
90
- Dict[str, AttributeValue]
91
- ] # values must use AttributeValue format e.g. {'S': 'value'}
92
- ConsistentRead: Optional[bool]
93
-
94
-
95
- class QueryInput(TypedDict, total=False):
96
- """Parameters for Query operation."""
97
-
98
- TableName: str # required
99
- IndexName: Optional[str]
100
- Select: Optional[Select]
101
- AttributesToGet: Optional[List[str]] # Legacy parameter
102
- Limit: Optional[int]
103
- ConsistentRead: Optional[bool]
104
- KeyConditionExpression: Optional[str]
105
- FilterExpression: Optional[str]
106
- ProjectionExpression: Optional[str]
107
- ExpressionAttributeNames: Optional[Dict[str, str]]
108
- ExpressionAttributeValues: Optional[
109
- Dict[str, AttributeValue]
110
- ] # values must use AttributeValue format e.g. {'S': 'value'}
111
- ScanIndexForward: Optional[bool]
112
- ExclusiveStartKey: Optional[
113
- Dict[str, KeyAttributeValue]
114
- ] # Primary key attributes in AttributeValue format e.g. {'S': 'value'}
115
- ReturnConsumedCapacity: Optional[ReturnConsumedCapacity]
116
-
117
-
118
- class DeleteItemInput(TypedDict, total=False):
119
- """Parameters for DeleteItem operation."""
120
-
121
- TableName: str # required
122
- Key: Dict[
123
- str, KeyAttributeValue
124
- ] # required - primary key attributes in AttributeValue format e.g. {'S': 'value'}
125
- ConditionExpression: Optional[str]
126
- ExpressionAttributeNames: Optional[Dict[str, str]]
127
- ExpressionAttributeValues: Optional[
128
- Dict[str, AttributeValue]
129
- ] # values must use AttributeValue format e.g. {'S': 'value'}
130
- ReturnConsumedCapacity: Optional[ReturnConsumedCapacity]
131
- ReturnItemCollectionMetrics: Optional[ReturnItemCollectionMetrics]
132
- ReturnValues: Optional[ReturnValue]
133
- ReturnValuesOnConditionCheckFailure: Optional[Literal['ALL_OLD', 'NONE']]
134
-
135
-
136
- class UpdateItemInput(TypedDict, total=False):
137
- """Parameters for UpdateItem operation."""
138
-
139
- TableName: str # required
140
- Key: Dict[
141
- str, KeyAttributeValue
142
- ] # required - primary key attributes in AttributeValue format e.g. {'S': 'value'}
143
- UpdateExpression: Optional[str]
144
- ConditionExpression: Optional[str]
145
- ExpressionAttributeNames: Optional[Dict[str, str]]
146
- ExpressionAttributeValues: Optional[
147
- Dict[str, AttributeValue]
148
- ] # values must use AttributeValue format e.g. {'S': 'value'}
149
- ReturnConsumedCapacity: Optional[ReturnConsumedCapacity]
150
- ReturnItemCollectionMetrics: Optional[ReturnItemCollectionMetrics]
151
- ReturnValues: Optional[ReturnValue]
152
- ReturnValuesOnConditionCheckFailure: Optional[Literal['ALL_OLD', 'NONE']]
153
-
154
-
155
- class GetItemInput(TypedDict, total=False):
156
- """Parameters for GetItem operation."""
157
-
158
- TableName: str # required
159
- Key: Dict[
160
- str, KeyAttributeValue
161
- ] # required - primary key attributes in AttributeValue format e.g. {'S': 'value'}
162
- AttributesToGet: Optional[List[str]]
163
- ConsistentRead: Optional[bool]
164
- ExpressionAttributeNames: Optional[Dict[str, str]]
165
- ProjectionExpression: Optional[str]
166
- ReturnConsumedCapacity: Optional[ReturnConsumedCapacity]
167
-
168
-
169
- class PutItemInput(TypedDict, total=False):
170
- """Parameters for PutItem operation."""
171
-
172
- TableName: str # required
173
- Item: Dict[
174
- str, AttributeValue
175
- ] # required - maps attribute name to AttributeValue (must use AttributeValue format e.g. {'S': 'value'})
176
- ConditionExpression: Optional[str]
177
- ExpressionAttributeNames: Optional[Dict[str, str]]
178
- ExpressionAttributeValues: Optional[
179
- Dict[str, AttributeValue]
180
- ] # values must use AttributeValue format e.g. {'S': 'value'}
181
- ReturnConsumedCapacity: Optional[ReturnConsumedCapacity]
182
- ReturnItemCollectionMetrics: Optional[ReturnItemCollectionMetrics]
183
- ReturnValues: Optional[ReturnValue]
184
- ReturnValuesOnConditionCheckFailure: Optional[Literal['ALL_OLD', 'NONE']]
185
-
186
-
187
- class AttributeDefinition(TypedDict):
188
- AttributeName: str
189
- AttributeType: Literal['S', 'N', 'B']
190
-
191
-
192
- class KeySchemaElement(TypedDict):
193
- AttributeName: str
194
- KeyType: Literal['HASH', 'RANGE']
195
-
196
-
197
- class ProvisionedThroughput(TypedDict):
198
- ReadCapacityUnits: int
199
- WriteCapacityUnits: int
200
-
201
-
202
- class Projection(TypedDict, total=False):
203
- ProjectionType: Literal['KEYS_ONLY', 'INCLUDE', 'ALL']
204
- NonKeyAttributes: List[str]
205
-
206
-
207
- class OnDemandThroughput(TypedDict, total=False):
208
- MaxReadRequestUnits: int
209
- MaxWriteRequestUnits: int
210
-
211
-
212
- class WarmThroughput(TypedDict, total=False):
213
- ReadUnitsPerSecond: int
214
- WriteUnitsPerSecond: int
215
-
216
-
217
- class GlobalSecondaryIndex(TypedDict, total=False):
218
- IndexName: str # required
219
- KeySchema: List[KeySchemaElement] # required
220
- Projection: Projection # required
221
- ProvisionedThroughput: ProvisionedThroughput
222
- OnDemandThroughput: OnDemandThroughput
223
-
224
-
225
- class GlobalSecondaryIndexUpdateAction(TypedDict, total=False):
226
- IndexName: str
227
- ProvisionedThroughput: ProvisionedThroughput
228
- OnDemandThroughput: OnDemandThroughput
229
- WarmThroughput: WarmThroughput
230
-
231
-
232
- class GlobalSecondaryIndexDeleteAction(TypedDict):
233
- IndexName: str
234
-
235
-
236
- class GlobalSecondaryIndexUpdate(TypedDict, total=False):
237
- Create: GlobalSecondaryIndex
238
- Delete: GlobalSecondaryIndexDeleteAction
239
- Update: GlobalSecondaryIndexUpdateAction
240
-
241
-
242
- class StreamSpecification(TypedDict, total=False):
243
- StreamEnabled: bool
244
- StreamViewType: Literal['KEYS_ONLY', 'NEW_IMAGE', 'OLD_IMAGE', 'NEW_AND_OLD_IMAGES']
245
-
246
-
247
- class Tag(TypedDict):
248
- Key: str
249
- Value: str
250
-
251
-
252
- class SSESpecification(TypedDict, total=False):
253
- """Set Enabled to true for AWS managed key (KMS charges apply). set it to false for AWS owned key."""
254
-
255
- Enabled: bool
256
- SSEType: Literal['KMS']
257
- KMSMasterKeyId: str
258
-
259
-
260
- class TimeToLiveSpecification(TypedDict):
261
- AttributeName: str # The name of the TTL attribute used to store the expiration time for items
262
- Enabled: bool # Indicates whether TTL is enabled (true) or disabled (false) on the table
263
-
264
-
265
- class GetResourcePolicyInput(TypedDict):
266
- ResourceArn: str # The Amazon Resource Name (ARN) of the DynamoDB resource to which the policy is attached
267
-
268
-
269
- class PutResourcePolicyInput(TypedDict, total=False):
270
- Policy: str # An AWS resource-based policy document in JSON format
271
- ResourceArn: str # The Amazon Resource Name (ARN) of the DynamoDB resource to which the policy will be attached
272
- ConfirmRemoveSelfResourceAccess: (
273
- bool # Set to true to confirm removing your permissions to change the policy in the future
274
- )
275
- ExpectedRevisionId: str # A string value for conditional updates of your policy
276
-
277
-
278
- class OnDemandThroughputOverride(TypedDict):
279
- MaxReadRequestUnits: int
280
-
281
-
282
- class ProvisionedThroughputOverride(TypedDict):
283
- ReadCapacityUnits: int
284
-
285
-
286
- class ReplicaCreate(TypedDict, total=False):
287
- RegionName: str
288
- KMSMasterKeyId: str
289
-
290
-
291
- class ReplicaDelete(TypedDict):
292
- RegionName: str
293
-
294
-
295
- class ReplicaUpdate(TypedDict, total=False):
296
- KMSMasterKeyId: str
297
- OnDemandThroughputOverride: OnDemandThroughputOverride
298
- ProvisionedThroughputOverride: ProvisionedThroughputOverride
299
- RegionName: str
300
- TableClassOverride: Literal['STANDARD', 'STANDARD_INFREQUENT_ACCESS']
301
-
302
-
303
- class ReplicationGroupUpdate(TypedDict, total=False):
304
- Create: ReplicaCreate
305
- Update: ReplicaUpdate
306
- Delete: ReplicaDelete
307
-
308
-
309
- class CreateTableInput(TypedDict, total=False):
310
- """Parameters for CreateTable operation."""
311
-
312
- TableName: str # required
313
- AttributeDefinitions: List[AttributeDefinition] # required
314
- KeySchema: List[KeySchemaElement] # required
315
- BillingMode: Literal['PROVISIONED', 'PAY_PER_REQUEST']
316
- GlobalSecondaryIndexes: List[GlobalSecondaryIndex]
317
- ProvisionedThroughput: ProvisionedThroughput
318
-
319
-
320
- class UpdateTableInput(TypedDict, total=False):
321
- """Parameters for UpdateTable operation."""
322
-
323
- TableName: str # required
324
- AttributeDefinitions: List[AttributeDefinition]
325
- BillingMode: Literal['PROVISIONED', 'PAY_PER_REQUEST']
326
- DeletionProtectionEnabled: bool
327
- GlobalSecondaryIndexUpdates: List[GlobalSecondaryIndexUpdate]
328
- OnDemandThroughput: OnDemandThroughput
329
- ProvisionedThroughput: ProvisionedThroughput
330
- ReplicaUpdates: List[ReplicationGroupUpdate]
331
- SSESpecification: SSESpecification
332
- StreamSpecification: StreamSpecification
333
- TableClass: Literal['STANDARD', 'STANDARD_INFREQUENT_ACCESS']
334
- WarmThroughput: WarmThroughput
@@ -14,174 +14,40 @@
14
14
 
15
15
  #!/usr/bin/env python3
16
16
 
17
- import boto3
18
- import json
19
- import os
20
- from awslabs.dynamodb_mcp_server.common import (
21
- AttributeDefinition,
22
- AttributeValue,
23
- CreateTableInput,
24
- DeleteItemInput,
25
- GetItemInput,
26
- GetResourcePolicyInput,
27
- GlobalSecondaryIndex,
28
- GlobalSecondaryIndexUpdate,
29
- KeyAttributeValue,
30
- KeySchemaElement,
31
- OnDemandThroughput,
32
- ProvisionedThroughput,
33
- PutItemInput,
34
- PutResourcePolicyInput,
35
- QueryInput,
36
- ReplicationGroupUpdate,
37
- ScanInput,
38
- Select,
39
- SSESpecification,
40
- StreamSpecification,
41
- Tag,
42
- TimeToLiveSpecification,
43
- UpdateItemInput,
44
- UpdateTableInput,
45
- WarmThroughput,
46
- handle_exceptions,
47
- mutation_check,
48
- )
49
- from botocore.config import Config
17
+ from awslabs.dynamodb_mcp_server.common import handle_exceptions
50
18
  from mcp.server.fastmcp import FastMCP
51
19
  from pathlib import Path
52
- from pydantic import Field
53
- from typing import Any, Dict, List, Literal, Union
54
20
 
55
21
 
56
22
  # Define server instructions and dependencies
57
- SERVER_INSTRUCTIONS = """The official MCP Server for interacting with AWS DynamoDB
23
+ SERVER_INSTRUCTIONS = """The official MCP Server for AWS DynamoDB design and modeling guidance
58
24
 
59
- This server provides comprehensive DynamoDB capabilities with over 30 operational tools for managing DynamoDB tables,
60
- items, indexes, backups, and more, plus expert data modeling guidance through DynamoDB data modeling expert prompt
25
+ This server provides DynamoDB design and modeling expertise.
61
26
 
62
- IMPORTANT: DynamoDB Attribute Value Format
63
- -----------------------------------------
64
- When working with DynamoDB, all attribute values must be specified with their data types.
65
- Each attribute value is represented as a dictionary with a single key-value pair where the key
66
- is the data type and the value is the data itself:
67
-
68
- - S: String
69
- Example: {"S": "Hello"}
70
-
71
- - N: Number (sent as a string)
72
- Example: {"N": "123.45"}
73
-
74
- - B: Binary data (Base64-encoded)
75
- Example: {"B": "dGhpcyB0ZXh0IGlzIGJhc2U2NC1lbmNvZGVk"}
76
-
77
- - BOOL: Boolean value
78
- Example: {"BOOL": true}
79
-
80
- - NULL: Null value
81
- Example: {"NULL": true}
82
-
83
- - L: List of AttributeValue objects
84
- Example: {"L": [{"S": "Cookies"}, {"S": "Coffee"}, {"N": "3.14159"}]}
85
-
86
- - M: Map of attribute name/value pairs
87
- Example: {"M": {"Name": {"S": "Joe"}, "Age": {"N": "35"}}}
88
-
89
- - SS: String Set (array of strings)
90
- Example: {"SS": ["Giraffe", "Hippo", "Zebra"]}
91
-
92
- - NS: Number Set (array of strings representing numbers)
93
- Example: {"NS": ["42.2", "-19", "7.5", "3.14"]}
94
-
95
- - BS: Binary Set (array of Base64-encoded binary data objects)
96
- Example: {"BS": ["U3Vubnk=", "UmFpbnk=", "U25vd3k="]}
97
-
98
- Common usage examples:
99
- - Primary key: {"userId": {"S": "user123"}}
100
- - Composite key: {"userId": {"S": "user123"}, "timestamp": {"N": "1612345678"}}
101
- - Expression attribute values: {":minScore": {"N": "100"}, ":active": {"BOOL": true}}
102
- - Complete item: {"userId": {"S": "user123"}, "score": {"N": "100"}, "data": {"B": "binarydata=="}}
27
+ When users ask for dynamodb operational tasks, provide EXACTLY these two options:
28
+ Option 1(RECOMMENDED): AWS API MCP Server
29
+ Migration guide: https://github.com/awslabs/mcp/tree/main/src/aws-api-mcp-server
30
+ Option 2(NOT RECOMMENDED): Legacy version 1.0.9
103
31
 
32
+ Available Tool:
33
+ --------------
104
34
  Use the `dynamodb_data_modeling` tool to access enterprise-level DynamoDB design expertise.
105
35
  This tool provides systematic methodology for creating production-ready multi-table design with
106
36
  advanced optimizations, cost analysis, and integration patterns.
107
37
  """
108
38
 
109
- SERVER_DEPENDENCIES = [
110
- 'boto3',
111
- 'botocore',
112
- 'pydantic',
113
- ]
114
-
115
39
 
116
40
  def create_server():
117
41
  """Create and configure the MCP server instance."""
118
42
  return FastMCP(
119
43
  'awslabs.dynamodb-mcp-server',
120
44
  instructions=SERVER_INSTRUCTIONS,
121
- dependencies=SERVER_DEPENDENCIES,
122
45
  )
123
46
 
124
47
 
125
48
  app = create_server()
126
49
 
127
50
 
128
- def get_dynamodb_client(region_name: str | None):
129
- """Create a boto3 DynamoDB client using credentials from environment variables. Falls back to 'us-west-2' if no region is specified or found in environment."""
130
- # Use provided region, or get from env, or fall back to us-west-2
131
- region = region_name or os.getenv('AWS_REGION') or 'us-west-2'
132
-
133
- # Configure custom user agent to identify requests from LLM/MCP
134
- config = Config(user_agent_extra='MCP/DynamoDBServer')
135
-
136
- # Create a new session to force credentials to reload
137
- # so that if user changes credential, it will be reflected immediately in the next call
138
- session = boto3.Session()
139
-
140
- # boto3 will automatically load credentials from environment variables:
141
- # AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
142
- return session.client('dynamodb', region_name=region, config=config)
143
-
144
-
145
- table_name = Field(description='Table Name or Amazon Resource Name (ARN)')
146
- index_name = Field(
147
- default=None,
148
- description='The name of a GSI',
149
- )
150
- key: Dict[str, KeyAttributeValue] = Field(
151
- description='The primary key of an item. Must use DynamoDB attribute value format (see IMPORTANT note about DynamoDB Attribute Value Format).'
152
- )
153
- filter_expression: str = Field(
154
- default=None,
155
- description='Filter conditions expression that DynamoDB applies to filter out data',
156
- )
157
- projection_expression: str = Field(
158
- default=None,
159
- description='Attributes to retrieve, can include scalars, sets, or elements of a JSON document.',
160
- )
161
- expression_attribute_names: Dict[str, str] = Field(
162
- default=None, description='Substitution tokens for attribute names in an expression.'
163
- )
164
- expression_attribute_values: Dict[str, AttributeValue] = Field(
165
- default=None,
166
- description='Values that can be substituted in an expression. Must use DynamoDB attribute value format (see IMPORTANT note about DynamoDB Attribute Value Format).',
167
- )
168
- select: Select = Field(
169
- default=None,
170
- description='The attributes to be returned. Valid values: ALL_ATTRIBUTES, ALL_PROJECTED_ATTRIBUTES, SPECIFIC_ATTRIBUTES, COUNT',
171
- )
172
- limit: int = Field(default=None, description='The maximum number of items to evaluate', ge=1)
173
- exclusive_start_key: Dict[str, KeyAttributeValue] = Field(
174
- default=None,
175
- description='Use the LastEvaluatedKey from the previous call. Must use DynamoDB attribute value format (see IMPORTANT note about DynamoDB Attribute Value Format).',
176
- )
177
-
178
- billing_mode: Literal['PROVISIONED', 'PAY_PER_REQUEST'] = Field(
179
- default=None,
180
- description='Specifies if billing is PAY_PER_REQUEST or by provisioned throughput',
181
- )
182
- resource_arn: str = Field(description='The Amazon Resource Name (ARN) of the DynamoDB resource')
183
-
184
-
185
51
  @app.tool()
186
52
  @handle_exceptions
187
53
  async def dynamodb_data_modeling() -> str:
@@ -206,742 +72,6 @@ async def dynamodb_data_modeling() -> str:
206
72
  return architect_prompt
207
73
 
208
74
 
209
- @app.tool()
210
- @handle_exceptions
211
- @mutation_check
212
- async def put_resource_policy(
213
- resource_arn: str = resource_arn,
214
- policy: Union[str, Dict[str, Any]] = Field(
215
- description='An AWS resource-based policy document in JSON format or dictionary.'
216
- ),
217
- region_name: str = Field(default=None, description='The aws region to run the tool'),
218
- ) -> dict:
219
- """Attaches a resource-based policy document (max 20 KB) to a DynamoDB table or stream. You can control permissions for both tables and their indexes through the policy."""
220
- client = get_dynamodb_client(region_name)
221
- # Convert policy to string if it's a dictionary
222
- policy_str = json.dumps(policy) if isinstance(policy, dict) else policy
223
-
224
- params: PutResourcePolicyInput = {'ResourceArn': resource_arn, 'Policy': policy_str}
225
-
226
- response = client.put_resource_policy(**params)
227
- return {'RevisionId': response.get('RevisionId')}
228
-
229
-
230
- @app.tool()
231
- @handle_exceptions
232
- async def get_resource_policy(
233
- resource_arn: str = resource_arn,
234
- region_name: str = Field(default=None, description='The aws region to run the tool'),
235
- ) -> dict:
236
- """Returns the resource-based policy document attached to a DynamoDB table or stream in JSON format."""
237
- client = get_dynamodb_client(region_name)
238
- params: GetResourcePolicyInput = {'ResourceArn': resource_arn}
239
-
240
- response = client.get_resource_policy(**params)
241
- return {'Policy': response.get('Policy'), 'RevisionId': response.get('RevisionId')}
242
-
243
-
244
- @app.tool()
245
- @handle_exceptions
246
- async def scan(
247
- table_name: str = table_name,
248
- index_name: str = index_name,
249
- filter_expression: str = filter_expression,
250
- projection_expression: str = projection_expression,
251
- expression_attribute_names: Dict[str, str] = expression_attribute_names,
252
- expression_attribute_values: Dict[str, AttributeValue] = expression_attribute_values,
253
- select: Select = select,
254
- limit: int = limit,
255
- exclusive_start_key: Dict[str, KeyAttributeValue] = exclusive_start_key,
256
- region_name: str = Field(default=None, description='The aws region to run the tool'),
257
- ) -> dict:
258
- """Returns items and attributes by scanning a table or secondary index. Reads up to Limit items or 1 MB of data, with optional FilterExpression to reduce results."""
259
- client = get_dynamodb_client(region_name)
260
- params: ScanInput = {'TableName': table_name}
261
-
262
- if index_name:
263
- params['IndexName'] = index_name
264
- if filter_expression:
265
- params['FilterExpression'] = filter_expression
266
- if projection_expression:
267
- params['ProjectionExpression'] = projection_expression
268
- if expression_attribute_names:
269
- params['ExpressionAttributeNames'] = expression_attribute_names
270
- if expression_attribute_values:
271
- params['ExpressionAttributeValues'] = expression_attribute_values
272
- if select:
273
- params['Select'] = select
274
- if limit:
275
- params['Limit'] = limit
276
- if exclusive_start_key:
277
- params['ExclusiveStartKey'] = exclusive_start_key
278
- params['ReturnConsumedCapacity'] = 'TOTAL'
279
-
280
- response = client.scan(**params)
281
- return {
282
- 'Items': response.get('Items', []),
283
- 'Count': response.get('Count'),
284
- 'ScannedCount': response.get('ScannedCount'),
285
- 'LastEvaluatedKey': response.get('LastEvaluatedKey'),
286
- 'ConsumedCapacity': response.get('ConsumedCapacity'),
287
- }
288
-
289
-
290
- @app.tool()
291
- @handle_exceptions
292
- async def query(
293
- table_name: str = table_name,
294
- key_condition_expression: str = Field(
295
- description='Key condition expression. Must perform an equality test on partition key value.'
296
- ),
297
- index_name: str = index_name,
298
- filter_expression: str = filter_expression,
299
- projection_expression: str = projection_expression,
300
- expression_attribute_names: Dict[str, str] = expression_attribute_names,
301
- expression_attribute_values: Dict[str, AttributeValue] = expression_attribute_values,
302
- select: Select = select,
303
- limit: int = limit,
304
- scan_index_forward: bool = Field(
305
- default=None, description='Ascending (true) or descending (false).'
306
- ),
307
- exclusive_start_key: Dict[str, KeyAttributeValue] = exclusive_start_key,
308
- region_name: str = Field(default=None, description='The aws region to run the tool'),
309
- ) -> dict:
310
- """Returns items from a table or index matching a partition key value, with optional sort key filtering."""
311
- client = get_dynamodb_client(region_name)
312
- params: QueryInput = {
313
- 'TableName': table_name,
314
- 'KeyConditionExpression': key_condition_expression,
315
- }
316
-
317
- if index_name:
318
- params['IndexName'] = index_name
319
- if filter_expression:
320
- params['FilterExpression'] = filter_expression
321
- if projection_expression:
322
- params['ProjectionExpression'] = projection_expression
323
- if expression_attribute_names:
324
- params['ExpressionAttributeNames'] = expression_attribute_names
325
- if expression_attribute_values:
326
- params['ExpressionAttributeValues'] = expression_attribute_values
327
- if select:
328
- params['Select'] = select
329
- if limit:
330
- params['Limit'] = limit
331
- if scan_index_forward is not None:
332
- params['ScanIndexForward'] = scan_index_forward
333
- if exclusive_start_key:
334
- params['ExclusiveStartKey'] = exclusive_start_key
335
- params['ReturnConsumedCapacity'] = 'TOTAL'
336
-
337
- response = client.query(**params)
338
- return {
339
- 'Items': response.get('Items', []),
340
- 'Count': response.get('Count'),
341
- 'ScannedCount': response.get('ScannedCount'),
342
- 'LastEvaluatedKey': response.get('LastEvaluatedKey'),
343
- 'ConsumedCapacity': response.get('ConsumedCapacity'),
344
- }
345
-
346
-
347
- @app.tool()
348
- @handle_exceptions
349
- @mutation_check
350
- async def update_item(
351
- table_name: str = table_name,
352
- key: Dict[str, KeyAttributeValue] = key,
353
- update_expression: str = Field(
354
- default=None,
355
- description="""Defines the attributes to be updated, the action to be performed on them, and new value(s) for them. The following actions are available:
356
- * SET - Adds one or more attributes and values to an item. If any of these attributes already exist, they are replaced by the new values.
357
- * REMOVE - Removes one or more attributes from an item.
358
- * ADD - Only supports Number and Set data types. Adds a value to a number attribute or adds elements to a set.
359
- * DELETE - Only supports Set data type. Removes elements from a set.
360
- For example: 'SET a=:value1, b=:value2 DELETE :value3, :value4, :value5'""",
361
- ),
362
- condition_expression: str = Field(
363
- default=None,
364
- description='A condition that must be satisfied in order for a conditional update to succeed.',
365
- ),
366
- expression_attribute_names: Dict[str, str] = expression_attribute_names,
367
- expression_attribute_values: Dict[str, AttributeValue] = expression_attribute_values,
368
- region_name: str = Field(default=None, description='The aws region to run the tool'),
369
- ) -> dict:
370
- """Edits an existing item's attributes, or adds a new item to the table if it does not already exist."""
371
- client = get_dynamodb_client(region_name)
372
- params: UpdateItemInput = {'TableName': table_name, 'Key': key}
373
-
374
- if update_expression:
375
- params['UpdateExpression'] = update_expression
376
- if condition_expression:
377
- params['ConditionExpression'] = condition_expression
378
- if expression_attribute_names:
379
- params['ExpressionAttributeNames'] = expression_attribute_names
380
- if expression_attribute_values:
381
- params['ExpressionAttributeValues'] = expression_attribute_values
382
- params['ReturnConsumedCapacity'] = 'TOTAL'
383
- params['ReturnValuesOnConditionCheckFailure'] = 'ALL_OLD'
384
-
385
- response = client.update_item(**params)
386
- return {
387
- 'Attributes': response.get('Attributes'),
388
- 'ConsumedCapacity': response.get('ConsumedCapacity'),
389
- }
390
-
391
-
392
- @app.tool()
393
- @handle_exceptions
394
- async def get_item(
395
- table_name: str = table_name,
396
- key: Dict[str, KeyAttributeValue] = key,
397
- expression_attribute_names: Dict[str, str] = expression_attribute_names,
398
- projection_expression: str = projection_expression,
399
- region_name: str = Field(default=None, description='The aws region to run the tool'),
400
- ) -> dict:
401
- """Returns attributes for an item with the given primary key. Uses eventually consistent reads by default, or set ConsistentRead=true for strongly consistent reads."""
402
- client = get_dynamodb_client(region_name)
403
- params: GetItemInput = {'TableName': table_name, 'Key': key}
404
-
405
- if expression_attribute_names:
406
- params['ExpressionAttributeNames'] = expression_attribute_names
407
- if projection_expression:
408
- params['ProjectionExpression'] = projection_expression
409
- params['ReturnConsumedCapacity'] = 'TOTAL'
410
-
411
- response = client.get_item(**params)
412
- return {'Item': response.get('Item'), 'ConsumedCapacity': response.get('ConsumedCapacity')}
413
-
414
-
415
- @app.tool()
416
- @handle_exceptions
417
- @mutation_check
418
- async def put_item(
419
- table_name: str = table_name,
420
- item: Dict[str, AttributeValue] = Field(
421
- description='A map of attribute name/value pairs, one for each attribute. Must use DynamoDB attribute value format (see IMPORTANT note about DynamoDB Attribute Value Format).'
422
- ),
423
- condition_expression: str = Field(
424
- default=None,
425
- description='A condition that must be satisfied in order for a conditional put operation to succeed.',
426
- ),
427
- expression_attribute_names: Dict[str, str] = expression_attribute_names,
428
- expression_attribute_values: Dict[str, Any] = expression_attribute_values,
429
- region_name: str = Field(default=None, description='The aws region to run the tool'),
430
- ) -> dict:
431
- """Creates a new item or replaces an existing item in a table. Use condition expressions to control whether to create new items or update existing ones."""
432
- client = get_dynamodb_client(region_name)
433
- params: PutItemInput = {'TableName': table_name, 'Item': item}
434
-
435
- if condition_expression:
436
- params['ConditionExpression'] = condition_expression
437
- if expression_attribute_names:
438
- params['ExpressionAttributeNames'] = expression_attribute_names
439
- if expression_attribute_values:
440
- params['ExpressionAttributeValues'] = expression_attribute_values
441
- params['ReturnConsumedCapacity'] = 'TOTAL'
442
-
443
- response = client.put_item(**params)
444
- return {
445
- 'Attributes': response.get('Attributes'),
446
- 'ConsumedCapacity': response.get('ConsumedCapacity'),
447
- }
448
-
449
-
450
- @app.tool()
451
- @handle_exceptions
452
- @mutation_check
453
- async def delete_item(
454
- table_name: str = table_name,
455
- key: Dict[str, KeyAttributeValue] = key,
456
- condition_expression: str = Field(
457
- default=None,
458
- description='The condition that must be satisfied in order for delete to succeed.',
459
- ),
460
- expression_attribute_names: Dict[str, str] = expression_attribute_names,
461
- expression_attribute_values: Dict[str, AttributeValue] = expression_attribute_values,
462
- region_name: str = Field(default=None, description='The aws region to run the tool'),
463
- ) -> dict:
464
- """Deletes a single item in a table by primary key. You can perform a conditional delete operation that deletes the item if it exists, or if it has an expected attribute value."""
465
- client = get_dynamodb_client(region_name)
466
- params: DeleteItemInput = {'TableName': table_name, 'Key': key}
467
-
468
- if condition_expression:
469
- params['ConditionExpression'] = condition_expression
470
- if expression_attribute_names:
471
- params['ExpressionAttributeNames'] = expression_attribute_names
472
- if expression_attribute_values:
473
- params['ExpressionAttributeValues'] = expression_attribute_values
474
- params['ReturnConsumedCapacity'] = 'TOTAL'
475
-
476
- response = client.delete_item(**params)
477
- return {
478
- 'Attributes': response.get('Attributes'),
479
- 'ConsumedCapacity': response.get('ConsumedCapacity'),
480
- 'ItemCollectionMetrics': response.get('ItemCollectionMetrics'),
481
- }
482
-
483
-
484
- @app.tool()
485
- @handle_exceptions
486
- @mutation_check
487
- async def update_time_to_live(
488
- table_name: str = table_name,
489
- time_to_live_specification: TimeToLiveSpecification = Field(
490
- description='The new TTL settings'
491
- ),
492
- region_name: str = Field(default=None, description='The aws region to run the tool'),
493
- ) -> dict:
494
- """Enables or disables Time to Live (TTL) for the specified table. Note: The epoch time format is the number of seconds elapsed since 12:00:00 AM January 1, 1970 UTC."""
495
- client = get_dynamodb_client(region_name)
496
- response = client.update_time_to_live(
497
- TableName=table_name, TimeToLiveSpecification=time_to_live_specification
498
- )
499
- return response['TimeToLiveSpecification']
500
-
501
-
502
- @app.tool()
503
- @handle_exceptions
504
- @mutation_check
505
- async def update_table(
506
- table_name: str = table_name,
507
- attribute_definitions: List[AttributeDefinition] = Field(
508
- default=None,
509
- description='Describe the key schema for the table and indexes. Required when adding a new GSI.',
510
- ),
511
- billing_mode: Literal['PROVISIONED', 'PAY_PER_REQUEST'] = billing_mode,
512
- deletion_protection_enabled: bool = Field(
513
- default=None, description='Indicates whether deletion protection is to be enabled'
514
- ),
515
- global_secondary_index_updates: List[GlobalSecondaryIndexUpdate] = Field(
516
- default=None, description='List of GSIs to be added, updated or deleted.'
517
- ),
518
- on_demand_throughput: OnDemandThroughput = Field(
519
- default=None, description='Set the max number of read and write units.'
520
- ),
521
- provisioned_throughput: ProvisionedThroughput = Field(
522
- default=None, description='The new provisioned throughput settings.'
523
- ),
524
- replica_updates: List[ReplicationGroupUpdate] = Field(
525
- default=None, description='A list of replica update actions (create, delete, or update).'
526
- ),
527
- sse_specification: SSESpecification = Field(
528
- default=None, description='The new server-side encryption settings.'
529
- ),
530
- stream_specification: StreamSpecification = Field(
531
- default=None, description='DynamoDB Streams configuration.'
532
- ),
533
- table_class: Literal['STANDARD', 'STANDARD_INFREQUENT_ACCESS'] = Field(
534
- default=None, description='The new table class.'
535
- ),
536
- warm_throughput: WarmThroughput = Field(
537
- default=None, description='The new warm throughput settings.'
538
- ),
539
- region_name: str = Field(default=None, description='The aws region to run the tool'),
540
- ) -> dict:
541
- """Modifies table settings including provisioned throughput, global secondary indexes, and DynamoDB Streams configuration. This is an asynchronous operation."""
542
- client = get_dynamodb_client(region_name)
543
- params: UpdateTableInput = {'TableName': table_name}
544
-
545
- if attribute_definitions:
546
- params['AttributeDefinitions'] = attribute_definitions
547
- if billing_mode:
548
- params['BillingMode'] = billing_mode
549
- if deletion_protection_enabled is not None:
550
- params['DeletionProtectionEnabled'] = deletion_protection_enabled
551
- if global_secondary_index_updates:
552
- params['GlobalSecondaryIndexUpdates'] = global_secondary_index_updates
553
- if on_demand_throughput:
554
- params['OnDemandThroughput'] = on_demand_throughput
555
- if provisioned_throughput:
556
- params['ProvisionedThroughput'] = provisioned_throughput
557
- if replica_updates:
558
- params['ReplicaUpdates'] = replica_updates
559
- if sse_specification:
560
- params['SSESpecification'] = sse_specification
561
- if stream_specification:
562
- params['StreamSpecification'] = stream_specification
563
- if table_class:
564
- params['TableClass'] = table_class
565
- if warm_throughput:
566
- params['WarmThroughput'] = warm_throughput
567
-
568
- response = client.update_table(**params)
569
- return response['TableDescription']
570
-
571
-
572
- @app.tool()
573
- @handle_exceptions
574
- async def list_tables(
575
- exclusive_start_table_name: str = Field(
576
- default=None,
577
- description='The LastEvaluatedTableName value from the previous paginated call',
578
- ),
579
- limit: int = Field(
580
- default=None,
581
- description='Max number of table names to return',
582
- ),
583
- region_name: str = Field(default=None, description='The aws region to run the tool'),
584
- ) -> dict:
585
- """Returns a paginated list of table names in your account."""
586
- client = get_dynamodb_client(region_name)
587
- params = {}
588
- if exclusive_start_table_name:
589
- params['ExclusiveStartTableName'] = exclusive_start_table_name
590
- if limit:
591
- params['Limit'] = limit
592
- response = client.list_tables(**params)
593
- return {
594
- 'TableNames': response['TableNames'],
595
- 'LastEvaluatedTableName': response.get('LastEvaluatedTableName'),
596
- }
597
-
598
-
599
- @app.tool()
600
- @handle_exceptions
601
- @mutation_check
602
- async def create_table(
603
- table_name: str = Field(
604
- description='The name of the table to create.',
605
- ),
606
- attribute_definitions: List[AttributeDefinition] = Field(
607
- description='Describe the key schema for the table and indexes.'
608
- ),
609
- key_schema: List[KeySchemaElement] = Field(
610
- description='Specifies primary key attributes of the table.'
611
- ),
612
- billing_mode: Literal['PROVISIONED', 'PAY_PER_REQUEST'] = billing_mode,
613
- global_secondary_indexes: List[GlobalSecondaryIndex] = Field(
614
- default=None, description='GSIs to be created on the table.'
615
- ),
616
- provisioned_throughput: ProvisionedThroughput = Field(
617
- default=None,
618
- description='Provisioned throughput settings. Required if BillingMode is PROVISIONED.',
619
- ),
620
- region_name: str = Field(default=None, description='The aws region to run the tool'),
621
- ) -> dict:
622
- """Creates a new DynamoDB table with optional secondary indexes. This is an asynchronous operation."""
623
- client = get_dynamodb_client(region_name)
624
- params: CreateTableInput = {
625
- 'TableName': table_name,
626
- 'AttributeDefinitions': attribute_definitions,
627
- 'KeySchema': key_schema,
628
- }
629
-
630
- if billing_mode:
631
- params['BillingMode'] = billing_mode
632
- if global_secondary_indexes:
633
- params['GlobalSecondaryIndexes'] = global_secondary_indexes
634
- if provisioned_throughput:
635
- params['ProvisionedThroughput'] = provisioned_throughput
636
-
637
- response = client.create_table(**params)
638
- return response['TableDescription']
639
-
640
-
641
- @app.tool()
642
- @handle_exceptions
643
- async def describe_table(
644
- table_name: str = table_name,
645
- region_name: str = Field(default=None, description='The aws region to run the tool'),
646
- ) -> dict:
647
- """Returns table information including status, creation time, key schema and indexes."""
648
- client = get_dynamodb_client(region_name)
649
- response = client.describe_table(TableName=table_name)
650
- return response['Table']
651
-
652
-
653
- @app.tool()
654
- @handle_exceptions
655
- @mutation_check
656
- async def create_backup(
657
- table_name: str = table_name,
658
- backup_name: str = Field(
659
- description='Specified name for the backup.',
660
- ),
661
- region_name: str = Field(default=None, description='The aws region to run the tool'),
662
- ) -> dict:
663
- """Creates a backup of a DynamoDB table."""
664
- client = get_dynamodb_client(region_name)
665
- response = client.create_backup(TableName=table_name, BackupName=backup_name)
666
- return response['BackupDetails']
667
-
668
-
669
- @app.tool()
670
- @handle_exceptions
671
- async def describe_backup(
672
- backup_arn: str = Field(
673
- description='The Amazon Resource Name (ARN) associated with the backup.',
674
- ),
675
- region_name: str = Field(default=None, description='The aws region to run the tool'),
676
- ) -> dict:
677
- """Describes an existing backup of a table."""
678
- client = get_dynamodb_client(region_name)
679
- response = client.describe_backup(BackupArn=backup_arn)
680
- return response['BackupDescription']
681
-
682
-
683
- @app.tool()
684
- @handle_exceptions
685
- async def list_backups(
686
- table_name: str = table_name,
687
- backup_type: str = Field(
688
- default=None,
689
- description='Filter by backup type: USER (on-demand backup created by you), SYSTEM (automatically created by DynamoDB), AWS_BACKUP (created by AWS Backup), or ALL (all types).',
690
- pattern='^(USER|SYSTEM|AWS_BACKUP|ALL)$',
691
- ),
692
- exclusive_start_backup_arn: str = Field(
693
- default=None,
694
- description='LastEvaluatedBackupArn from a previous paginated call.',
695
- ),
696
- limit: int = Field(
697
- default=None, description='Maximum number of backups to return.', ge=1, le=100
698
- ),
699
- region_name: str = Field(default=None, description='The aws region to run the tool'),
700
- ) -> dict:
701
- """Returns a list of table backups."""
702
- client = get_dynamodb_client(region_name)
703
- params = {}
704
- if backup_type:
705
- params['BackupType'] = backup_type
706
- if exclusive_start_backup_arn:
707
- params['ExclusiveStartBackupArn'] = exclusive_start_backup_arn
708
- if limit:
709
- params['Limit'] = limit
710
- if table_name:
711
- params['TableName'] = table_name
712
-
713
- response = client.list_backups(**params)
714
- return {
715
- 'BackupSummaries': response.get('BackupSummaries', []),
716
- 'LastEvaluatedBackupArn': response.get('LastEvaluatedBackupArn'),
717
- }
718
-
719
-
720
- @app.tool()
721
- @handle_exceptions
722
- @mutation_check
723
- async def restore_table_from_backup(
724
- backup_arn: str = Field(
725
- description='The Amazon Resource Name (ARN) associated with the backup.',
726
- ),
727
- target_table_name: str = Field(
728
- description='The name of the new table.',
729
- ),
730
- region_name: str = Field(default=None, description='The aws region to run the tool'),
731
- ) -> dict:
732
- """Creates a new table from a backup."""
733
- client = get_dynamodb_client(region_name)
734
- params = {'BackupArn': backup_arn, 'TargetTableName': target_table_name}
735
-
736
- response = client.restore_table_from_backup(**params)
737
- return response['TableDescription']
738
-
739
-
740
- @app.tool()
741
- @handle_exceptions
742
- async def describe_limits(
743
- region_name: str = Field(default=None, description='The aws region to run the tool'),
744
- ) -> dict:
745
- """Returns the current provisioned-capacity quotas for your AWS account and tables in a Region."""
746
- client = get_dynamodb_client(region_name)
747
- response = client.describe_limits()
748
- return {
749
- 'AccountMaxReadCapacityUnits': response['AccountMaxReadCapacityUnits'],
750
- 'AccountMaxWriteCapacityUnits': response['AccountMaxWriteCapacityUnits'],
751
- 'TableMaxReadCapacityUnits': response['TableMaxReadCapacityUnits'],
752
- 'TableMaxWriteCapacityUnits': response['TableMaxWriteCapacityUnits'],
753
- }
754
-
755
-
756
- @app.tool()
757
- @handle_exceptions
758
- async def describe_time_to_live(
759
- table_name: str = table_name,
760
- region_name: str = Field(default=None, description='The aws region to run the tool'),
761
- ) -> dict:
762
- """Returns the Time to Live (TTL) settings for a table."""
763
- client = get_dynamodb_client(region_name)
764
- response = client.describe_time_to_live(TableName=table_name)
765
- return response['TimeToLiveDescription']
766
-
767
-
768
- @app.tool()
769
- @handle_exceptions
770
- async def describe_endpoints(
771
- region_name: str = Field(default=None, description='The aws region to run the tool'),
772
- ) -> dict:
773
- """Returns DynamoDB endpoints for the current region."""
774
- client = get_dynamodb_client(region_name)
775
- response = client.describe_endpoints()
776
- return {'Endpoints': response['Endpoints']}
777
-
778
-
779
- @app.tool()
780
- @handle_exceptions
781
- async def describe_export(
782
- export_arn: str = Field(
783
- description='The Amazon Resource Name (ARN) associated with the export.',
784
- ),
785
- region_name: str = Field(default=None, description='The aws region to run the tool'),
786
- ) -> dict:
787
- """Returns information about a table export."""
788
- client = get_dynamodb_client(region_name)
789
- response = client.describe_export(ExportArn=export_arn)
790
- return response['ExportDescription']
791
-
792
-
793
- @app.tool()
794
- @handle_exceptions
795
- async def list_exports(
796
- max_results: int = Field(
797
- default=None,
798
- description='Maximum number of results to return per page.',
799
- ),
800
- next_token: str = Field(default=None, description='Token to fetch the next page of results.'),
801
- table_arn: str = Field(
802
- default=None,
803
- description='The Amazon Resource Name (ARN) associated with the exported table.',
804
- ),
805
- region_name: str = Field(default=None, description='The aws region to run the tool'),
806
- ) -> dict:
807
- """Returns a list of table exports."""
808
- client = get_dynamodb_client(region_name)
809
- params = {}
810
- if max_results:
811
- params['MaxResults'] = max_results
812
- if next_token:
813
- params['NextToken'] = next_token
814
- if table_arn:
815
- params['TableArn'] = table_arn
816
-
817
- response = client.list_exports(**params)
818
- return {
819
- 'ExportSummaries': response.get('ExportSummaries', []),
820
- 'NextToken': response.get('NextToken'),
821
- }
822
-
823
-
824
- @app.tool()
825
- @handle_exceptions
826
- async def describe_continuous_backups(
827
- table_name: str = table_name,
828
- region_name: str = Field(default=None, description='The aws region to run the tool'),
829
- ) -> dict:
830
- """Returns continuous backup and point in time recovery status for a table."""
831
- client = get_dynamodb_client(region_name)
832
- response = client.describe_continuous_backups(TableName=table_name)
833
- return response['ContinuousBackupsDescription']
834
-
835
-
836
- @app.tool()
837
- @handle_exceptions
838
- @mutation_check
839
- async def untag_resource(
840
- resource_arn: str = resource_arn,
841
- tag_keys: List[str] = Field(description='List of tags to remove.', min_length=1),
842
- region_name: str = Field(default=None, description='The aws region to run the tool'),
843
- ) -> dict:
844
- """Removes tags from a DynamoDB resource."""
845
- client = get_dynamodb_client(region_name)
846
- response = client.untag_resource(ResourceArn=resource_arn, TagKeys=tag_keys)
847
- return response
848
-
849
-
850
- @app.tool()
851
- @handle_exceptions
852
- @mutation_check
853
- async def tag_resource(
854
- resource_arn: str = resource_arn,
855
- tags: List[Tag] = Field(description='Tags to be assigned.'),
856
- region_name: str = Field(default=None, description='The aws region to run the tool'),
857
- ) -> dict:
858
- """Adds tags to a DynamoDB resource."""
859
- client = get_dynamodb_client(region_name)
860
- response = client.tag_resource(ResourceArn=resource_arn, Tags=tags)
861
- return response
862
-
863
-
864
- @app.tool()
865
- @handle_exceptions
866
- async def list_tags_of_resource(
867
- resource_arn: str = resource_arn,
868
- next_token: str = Field(
869
- default=None, description='The NextToken from the previous paginated call'
870
- ),
871
- region_name: str = Field(default=None, description='The aws region to run the tool'),
872
- ) -> dict:
873
- """Returns tags for a DynamoDB resource."""
874
- client = get_dynamodb_client(region_name)
875
- params = {'ResourceArn': resource_arn}
876
- if next_token:
877
- params['NextToken'] = next_token
878
-
879
- response = client.list_tags_of_resource(**params)
880
- return {'Tags': response.get('Tags', []), 'NextToken': response.get('NextToken')}
881
-
882
-
883
- @app.tool()
884
- @handle_exceptions
885
- @mutation_check
886
- async def delete_table(
887
- table_name: str = table_name,
888
- region_name: str = Field(default=None, description='The aws region to run the tool'),
889
- ) -> dict:
890
- """The DeleteTable operation deletes a table and all of its items. This is an asynchronous operation that puts the table into DELETING state until DynamoDB completes the deletion."""
891
- client = get_dynamodb_client(region_name)
892
- response = client.delete_table(TableName=table_name)
893
- return response['TableDescription']
894
-
895
-
896
- @app.tool()
897
- @handle_exceptions
898
- async def update_continuous_backups(
899
- table_name: str = table_name,
900
- point_in_time_recovery_enabled: bool = Field(
901
- description='Enable or disable point in time recovery.'
902
- ),
903
- recovery_period_in_days: int = Field(
904
- default=None,
905
- description='Number of days to retain point in time recovery backups.',
906
- ),
907
- region_name: str = Field(default=None, description='The aws region to run the tool'),
908
- ) -> dict:
909
- """Enables or disables point in time recovery for the specified table."""
910
- client = get_dynamodb_client(region_name)
911
- params = {
912
- 'TableName': table_name,
913
- 'PointInTimeRecoverySpecification': {
914
- 'PointInTimeRecoveryEnabled': point_in_time_recovery_enabled
915
- },
916
- }
917
- if recovery_period_in_days:
918
- params['PointInTimeRecoverySpecification']['RecoveryPeriodInDays'] = (
919
- recovery_period_in_days
920
- )
921
-
922
- response = client.update_continuous_backups(**params)
923
- return response['ContinuousBackupsDescription']
924
-
925
-
926
- @app.tool()
927
- @handle_exceptions
928
- async def list_imports(
929
- next_token: str = Field(default=None, description='Token to fetch the next page of results.'),
930
- region_name: str = Field(default=None, description='The aws region to run the tool'),
931
- ) -> dict:
932
- """Lists imports completed within the past 90 days."""
933
- client = get_dynamodb_client(region_name)
934
- params = {}
935
- if next_token:
936
- params['NextToken'] = next_token
937
- params['PageSize'] = 25
938
- response = client.list_imports(**params)
939
- return {
940
- 'ImportSummaryList': response.get('ImportSummaryList', []),
941
- 'NextToken': response.get('NextToken'),
942
- }
943
-
944
-
945
75
  def main():
946
76
  """Main entry point for the MCP server application."""
947
77
  app.run()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: awslabs.dynamodb-mcp-server
3
- Version: 1.0.9
3
+ Version: 2.0.1
4
4
  Summary: The official MCP Server for interacting with AWS DynamoDB
5
5
  Project-URL: homepage, https://awslabs.github.io/mcp/
6
6
  Project-URL: docs, https://awslabs.github.io/mcp/servers/dynamodb-mcp-server/
@@ -34,64 +34,48 @@ Description-Content-Type: text/markdown
34
34
 
35
35
  The official MCP Server for interacting with AWS DynamoDB
36
36
 
37
- This comprehensive server provides both operational DynamoDB management and expert design guidance, featuring 30+ operational tools for managing DynamoDB tables, items, indexes, backups, and more, expert data modeling guidance.
37
+ This server provides expert DynamoDB design guidance and data modeling assistance.
38
38
 
39
39
  ## Available MCP Tools
40
40
 
41
41
  ### Design & Modeling
42
42
  - `dynamodb_data_modeling` - Retrieves the complete DynamoDB Data Modeling Expert prompt
43
43
 
44
- ### Table Operations
45
- - `create_table` - Creates a new DynamoDB table with optional secondary indexes
46
- - `delete_table` - Deletes a table and all of its items
47
- - `describe_table` - Returns table information including status, creation time, key schema and indexes
48
- - `list_tables` - Returns a paginated list of table names in your account
49
- - `update_table` - Modifies table settings including provisioned throughput, global secondary indexes, and DynamoDB Streams configuration
50
-
51
- ### Item Operations
52
- - `get_item` - Returns attributes for an item with the given primary key
53
- - `put_item` - Creates a new item or replaces an existing item in a table
54
- - `update_item` - Edits an existing item's attributes, or adds a new item if it does not already exist
55
- - `delete_item` - Deletes a single item in a table by primary key
56
-
57
- ### Query and Scan Operations
58
- - `query` - Returns items from a table or index matching a partition key value, with optional sort key filtering
59
- - `scan` - Returns items and attributes by scanning a table or secondary index
60
-
61
- ### Backup and Recovery
62
- - `create_backup` - Creates a backup of a DynamoDB table
63
- - `describe_backup` - Describes an existing backup of a table
64
- - `list_backups` - Returns a list of table backups
65
- - `restore_table_from_backup` - Creates a new table from a backup
66
- - `describe_continuous_backups` - Returns continuous backup and point in time recovery status
67
- - `update_continuous_backups` - Enables or disables point in time recovery
68
-
69
- ### Time to Live (TTL)
70
- - `update_time_to_live` - Enables or disables Time to Live (TTL) for the specified table
71
- - `describe_time_to_live` - Returns the Time to Live (TTL) settings for a table
72
-
73
- ### Export Operations
74
- - `describe_export` - Returns information about a table export
75
- - `list_exports` - Returns a list of table exports
76
-
77
- ### Tags and Resource Policies
78
- - `put_resource_policy` - Attaches a resource-based policy document to a table or stream
79
- - `get_resource_policy` - Returns the resource-based policy document attached to a table or stream
80
- - `tag_resource` - Adds tags to a DynamoDB resource
81
- - `untag_resource` - Removes tags from a DynamoDB resource
82
- - `list_tags_of_resource` - Returns tags for a DynamoDB resource
83
-
84
- ### Misc
85
- - `describe_limits` - Returns the current provisioned-capacity quotas for your AWS account
86
- - `describe_endpoints` - Returns DynamoDB endpoints for the current region
44
+ ## Migration Notice
87
45
 
88
- ## Instructions
46
+ Starting with version 2.0.0, this server focuses exclusively on DynamoDB design and modeling guidance. All operational DynamoDB management tools (table operations, item operations, queries, backups, etc.) have been removed in favour of the [AWS API MCP Server](https://github.com/awslabs/mcp/tree/main/src/aws-api-mcp-server) which provides the same capability and more.
47
+
48
+ ### Recommended: AWS API MCP Server
49
+
50
+ For operational DynamoDB management, use the [AWS API MCP Server](https://github.com/awslabs/mcp/tree/main/src/aws-api-mcp-server) which provides comprehensive AWS service management including all DynamoDB operations. [Migration guide available here](https://github.com/awslabs/mcp/tree/main/src/aws-api-mcp-server).
51
+
52
+ ### Not Recommended: Legacy Version
53
+
54
+ If you must use the previous operational tools, you can pin to version 1.0.9, though this is not recommended:
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "awslabs.dynamodb-mcp-server": {
60
+ "command": "uvx",
61
+ "args": ["awslabs.dynamodb-mcp-server@1.0.9"],
62
+ "env": {
63
+ "DDB-MCP-READONLY": "true",
64
+ "AWS_PROFILE": "default",
65
+ "AWS_REGION": "us-west-2",
66
+ "FASTMCP_LOG_LEVEL": "ERROR"
67
+ },
68
+ "disabled": false,
69
+ "autoApprove": []
70
+ }
71
+ }
72
+ }
73
+ ```
89
74
 
90
- The official MCP Server for interacting with AWS DynamoDB provides a comprehensive set of tools for both designing and managing DynamoDB resources.
75
+ ## Instructions
91
76
 
92
- To use these tools, ensure you have proper AWS credentials configured with appropriate permissions for DynamoDB operations. The server will automatically use credentials from environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) or other standard AWS credential sources.
77
+ This MCP Server provides DynamoDB design and modeling guidance only. For operational DynamoDB management (retrieving data, managing tables, etc.), use the [AWS API MCP Server](https://github.com/awslabs/mcp/tree/main/src/aws-api-mcp-server) which provides comprehensive DynamoDB operations. [Migration guide available here](https://github.com/awslabs/mcp/tree/main/src/aws-api-mcp-server).
93
78
 
94
- All tools support an optional `region_name` parameter to specify which AWS region to operate in. If not provided, it will use the AWS_REGION environment variable or default to 'us-west-2'.
95
79
 
96
80
  ## Prerequisites
97
81
 
@@ -0,0 +1,11 @@
1
+ awslabs/__init__.py,sha256=WuqxdDgUZylWNmVoPKiK7qGsTB_G4UmuXIrJ-VBwDew,731
2
+ awslabs/dynamodb_mcp_server/__init__.py,sha256=hJ7kw5_k2dM1Oyf4t2H4FTU6MFmdqfhbdtGgoodLci4,673
3
+ awslabs/dynamodb_mcp_server/common.py,sha256=--RWFURrGYjRjAnOuIbyX-DDrfZy1EeQXXRg4lASFB4,1677
4
+ awslabs/dynamodb_mcp_server/server.py,sha256=-g3MIL7wYG7LnOUV47mAb2lrJTvOGipTbWbBA-jvGFs,2919
5
+ awslabs/dynamodb_mcp_server/prompts/dynamodb_architect.md,sha256=gaWjHmTu2oFiFnEKCs20Xe2JbClr6q4kP9e4_MK1Shw,39866
6
+ awslabs_dynamodb_mcp_server-2.0.1.dist-info/METADATA,sha256=lMeU3euDvfmGDzSKS_vimIw-c-3ErSA4WoJ1b-iNvOs,6459
7
+ awslabs_dynamodb_mcp_server-2.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
+ awslabs_dynamodb_mcp_server-2.0.1.dist-info/entry_points.txt,sha256=Vn6TvAN9d67Lsbkcs0UcIiOBI5xDpNBm_MOOzc1h-YU,88
9
+ awslabs_dynamodb_mcp_server-2.0.1.dist-info/licenses/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
10
+ awslabs_dynamodb_mcp_server-2.0.1.dist-info/licenses/NOTICE,sha256=47UMmTFkf8rUc_JaJfdWe6NsAJQOcZNPZIL6JzU_k5U,95
11
+ awslabs_dynamodb_mcp_server-2.0.1.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- awslabs/__init__.py,sha256=WuqxdDgUZylWNmVoPKiK7qGsTB_G4UmuXIrJ-VBwDew,731
2
- awslabs/dynamodb_mcp_server/__init__.py,sha256=2OrpgBMsFZ4x0QsiH0kfk8b1KT461uSqvbYG9ib_14Q,673
3
- awslabs/dynamodb_mcp_server/common.py,sha256=aj1uOGa63TQdM3r75Zht74y1OGgUblDEQ-0h1RZHfn0,11422
4
- awslabs/dynamodb_mcp_server/server.py,sha256=rJhbetBZ0jxu4GyQNvuU5W8FtGKfo9iM1-YNYfZaQWE,36698
5
- awslabs/dynamodb_mcp_server/prompts/dynamodb_architect.md,sha256=gaWjHmTu2oFiFnEKCs20Xe2JbClr6q4kP9e4_MK1Shw,39866
6
- awslabs_dynamodb_mcp_server-1.0.9.dist-info/METADATA,sha256=5_7oACxc8P8y7oxoB3O5umsSdOdpEHGETY1hIcCxfuM,7948
7
- awslabs_dynamodb_mcp_server-1.0.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
- awslabs_dynamodb_mcp_server-1.0.9.dist-info/entry_points.txt,sha256=Vn6TvAN9d67Lsbkcs0UcIiOBI5xDpNBm_MOOzc1h-YU,88
9
- awslabs_dynamodb_mcp_server-1.0.9.dist-info/licenses/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
10
- awslabs_dynamodb_mcp_server-1.0.9.dist-info/licenses/NOTICE,sha256=47UMmTFkf8rUc_JaJfdWe6NsAJQOcZNPZIL6JzU_k5U,95
11
- awslabs_dynamodb_mcp_server-1.0.9.dist-info/RECORD,,