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

Potentially problematic release.


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

awslabs/__init__.py CHANGED
@@ -14,3 +14,23 @@
14
14
 
15
15
  # This file is part of the awslabs namespace.
16
16
  # It is intentionally minimal to support PEP 420 namespace packages.
17
+
18
+ # Namespace Package Configuration
19
+ #
20
+ # This line resolves namespace conflicts when multiple packages share the 'awslabs' namespace prefix.
21
+ # Without this configuration, test suites fail and build issues occur because Python cannot properly
22
+ # resolve which package owns the 'awslabs' namespace when both 'awslabs.dynamodb-mcp-server' and
23
+ # 'awslabs.mysql-mcp-server' are installed in the same environment.
24
+ #
25
+ # The extend_path() function implements PEP 420 namespace packages, allowing multiple distributions
26
+ # to contribute modules to the same namespace. This ensures that:
27
+ # 1. Both DynamoDB and MySQL MCP servers can coexist in the same Python environment
28
+ # 2. Import statements like 'from awslabs.dynamodb_mcp_server import ...' work correctly
29
+ # 3. Test discovery and execution functions properly across both packages
30
+ # 4. Build processes complete successfully without namespace collision errors
31
+ #
32
+ # This is the standard solution for namespace packages in Python and is required for proper
33
+ # multi-package namespace support in the awslabs ecosystem.
34
+
35
+ # Extend namespace to include installed packages
36
+ __path__ = __import__('pkgutil').extend_path(__path__, __name__)
@@ -14,4 +14,4 @@
14
14
 
15
15
  """awslabs.dynamodb-mcp-server"""
16
16
 
17
- __version__ = '1.0.9'
17
+ __version__ = '2.0.2'
@@ -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
@@ -0,0 +1,210 @@
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
+ """Source Database Analysis SQL Query Resources for DynamoDB Data Modeling."""
16
+
17
+ from typing import Any, Dict
18
+
19
+
20
+ # SQL Query Templates for MySQL
21
+ mysql_analysis_queries = {
22
+ 'performance_schema_check': {
23
+ 'name': 'Performance Schema Status Check',
24
+ 'description': 'Returns the status of the performance_schema system variable (ON/OFF)',
25
+ 'sql': 'SELECT @@performance_schema;',
26
+ 'parameters': [],
27
+ },
28
+ 'query_pattern_analysis': {
29
+ 'name': 'Query Pattern Analysis',
30
+ 'description': 'Returns query patterns from Performance Schema with execution counts, calculated RPS, average execution time, average rows examined per execution, scan counts, execution timeframes, and SQL complexity classification',
31
+ 'sql': """SELECT
32
+ -- Basic pattern information
33
+ DIGEST_TEXT as query_pattern,
34
+ COUNT_STAR as frequency,
35
+ -- Timing information
36
+ FIRST_SEEN as first_seen,
37
+ LAST_SEEN as last_seen
38
+ FROM performance_schema.events_statements_summary_by_digest
39
+ WHERE SCHEMA_NAME = '{target_database}'
40
+ AND COUNT_STAR > 0
41
+ AND LAST_SEEN >= DATE_SUB(NOW(), INTERVAL {pattern_analysis_days} DAY)
42
+ -- Exclude system and administrative queries
43
+ AND DIGEST_TEXT NOT LIKE 'SET%'
44
+ AND DIGEST_TEXT NOT LIKE 'USE %'
45
+ AND DIGEST_TEXT NOT LIKE 'SHOW%'
46
+ AND DIGEST_TEXT NOT LIKE '/* RDS Data API */%'
47
+ AND DIGEST_TEXT NOT LIKE '%information_schema%'
48
+ AND DIGEST_TEXT NOT LIKE '%performance_schema%'
49
+ AND DIGEST_TEXT NOT LIKE '%mysql.%'
50
+ AND DIGEST_TEXT NOT LIKE 'SELECT @@%'
51
+ AND DIGEST_TEXT NOT LIKE '%sys.%'
52
+ AND DIGEST_TEXT NOT LIKE 'select ?'
53
+ AND DIGEST_TEXT NOT LIKE '%mysql.general_log%'
54
+ AND DIGEST_TEXT NOT LIKE 'DESCRIBE %'
55
+ AND DIGEST_TEXT NOT LIKE 'EXPLAIN %'
56
+ AND DIGEST_TEXT NOT LIKE '%configured_database%'
57
+ AND DIGEST_TEXT NOT LIKE 'FLUSH %'
58
+ AND DIGEST_TEXT NOT LIKE 'RESET %'
59
+ AND DIGEST_TEXT NOT LIKE 'OPTIMIZE %'
60
+ AND DIGEST_TEXT NOT LIKE 'ANALYZE %'
61
+ AND DIGEST_TEXT NOT LIKE 'CHECK %'
62
+ AND DIGEST_TEXT NOT LIKE 'REPAIR %'
63
+ AND DIGEST_TEXT NOT LIKE '%@@default_storage_engine%'
64
+ AND DIGEST_TEXT NOT LIKE '%@%:=%'
65
+ AND DIGEST_TEXT NOT LIKE '%MD5%'
66
+ AND DIGEST_TEXT NOT LIKE '%SHA%'
67
+ AND DIGEST_TEXT NOT LIKE '%CONCAT_WS%'
68
+ ORDER BY frequency DESC;""",
69
+ 'parameters': ['target_database', 'pattern_analysis_days'],
70
+ },
71
+ 'table_analysis': {
72
+ 'name': 'Table Structure Analysis',
73
+ 'description': 'Returns table statistics including row counts, data size in MB, index size in MB, column counts, foreign key counts, and creation/modification timestamps',
74
+ 'sql': """SELECT
75
+ TABLE_NAME,
76
+ TABLE_ROWS,
77
+ -- Storage sizes in MB
78
+ ROUND(DATA_LENGTH/1024/1024, 2) as datamb,
79
+ ROUND(INDEX_LENGTH/1024/1024, 2) as indexmb,
80
+ -- Count columns in this table
81
+ (SELECT COUNT(*) FROM information_schema.COLUMNS c
82
+ WHERE c.TABLE_SCHEMA = t.TABLE_SCHEMA AND c.TABLE_NAME = t.TABLE_NAME) as columncount,
83
+ -- Count foreign keys in this table
84
+ (SELECT COUNT(*) FROM information_schema.KEY_COLUMN_USAGE k
85
+ WHERE k.TABLE_SCHEMA = t.TABLE_SCHEMA AND k.TABLE_NAME = t.TABLE_NAME
86
+ AND k.REFERENCED_TABLE_NAME IS NOT NULL) as fkcount,
87
+ CREATE_TIME,
88
+ UPDATE_TIME
89
+ FROM information_schema.TABLES t
90
+ WHERE TABLE_SCHEMA = '{target_database}'
91
+ ORDER BY TABLE_ROWS DESC;""",
92
+ 'parameters': ['target_database'],
93
+ },
94
+ 'column_analysis': {
95
+ 'name': 'Column Information Analysis',
96
+ 'description': 'Returns all column definitions including table name, column name, data type, nullability, key type, default value, and extra attributes',
97
+ 'sql': """SELECT
98
+ TABLE_NAME,
99
+ COLUMN_NAME,
100
+ COLUMN_TYPE,
101
+ IS_NULLABLE,
102
+ COLUMN_KEY,
103
+ COLUMN_DEFAULT,
104
+ EXTRA
105
+ FROM information_schema.COLUMNS
106
+ WHERE TABLE_SCHEMA = '{target_database}'
107
+ ORDER BY TABLE_NAME, ORDINAL_POSITION;""",
108
+ 'parameters': ['target_database'],
109
+ },
110
+ 'index_analysis': {
111
+ 'name': 'Index Statistics Analysis',
112
+ 'description': 'Returns index structure details including table name, index name, column name, uniqueness flag, and column position within each index',
113
+ 'sql': """SELECT
114
+ TABLE_NAME,
115
+ INDEX_NAME,
116
+ COLUMN_NAME,
117
+ NON_UNIQUE,
118
+ SEQ_IN_INDEX
119
+ FROM information_schema.STATISTICS
120
+ WHERE TABLE_SCHEMA = '{target_database}'
121
+ ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX;""",
122
+ 'parameters': ['target_database'],
123
+ },
124
+ 'foreign_key_analysis': {
125
+ 'name': 'Foreign Key Relationship Analysis',
126
+ 'description': 'Returns foreign key relationships including constraint names, child/parent table and column mappings, referential action rules, and estimated relationship cardinality',
127
+ 'sql': """SELECT
128
+ kcu.CONSTRAINT_NAME,
129
+ kcu.TABLE_NAME as child_table,
130
+ kcu.COLUMN_NAME as child_column,
131
+ kcu.REFERENCED_TABLE_NAME as parent_table,
132
+ kcu.REFERENCED_COLUMN_NAME as parent_column,
133
+ rc.UPDATE_RULE,
134
+ rc.DELETE_RULE,
135
+ -- Estimate relationship cardinality based on unique constraints
136
+ CASE
137
+ WHEN EXISTS (
138
+ SELECT 1 FROM information_schema.STATISTICS s
139
+ WHERE s.TABLE_SCHEMA = '{target_database}'
140
+ AND s.TABLE_NAME = kcu.TABLE_NAME
141
+ AND s.COLUMN_NAME = kcu.COLUMN_NAME
142
+ AND s.NON_UNIQUE = 0 -- Unique constraint exists
143
+ AND (SELECT COUNT(*) FROM information_schema.KEY_COLUMN_USAGE kcu2
144
+ WHERE kcu2.CONSTRAINT_NAME = s.INDEX_NAME
145
+ AND kcu2.TABLE_SCHEMA = s.TABLE_SCHEMA) = 1 -- Single column constraint
146
+ ) THEN '1:1 or 1:0..1'
147
+ ELSE '1:Many'
148
+ END as estimated_cardinality
149
+ FROM information_schema.KEY_COLUMN_USAGE kcu
150
+ LEFT JOIN information_schema.REFERENTIAL_CONSTRAINTS rc
151
+ ON kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
152
+ AND kcu.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA
153
+ WHERE kcu.TABLE_SCHEMA = '{target_database}'
154
+ AND kcu.REFERENCED_TABLE_NAME IS NOT NULL -- Only foreign key constraints
155
+ ORDER BY kcu.TABLE_NAME, kcu.COLUMN_NAME;""",
156
+ 'parameters': ['target_database'],
157
+ },
158
+ 'database_objects': {
159
+ 'name': 'Database Objects Summary',
160
+ 'description': 'Returns object counts and concatenated names grouped by object type: tables, triggers, stored procedures, and functions',
161
+ 'sql': """SELECT
162
+ 'Tables' as object_type,
163
+ COUNT(*) as count,
164
+ GROUP_CONCAT(TABLE_NAME) as names
165
+ FROM information_schema.TABLES
166
+ WHERE TABLE_SCHEMA = '{target_database}'
167
+ UNION ALL
168
+ SELECT
169
+ 'Triggers' as object_type,
170
+ COUNT(*) as count,
171
+ COALESCE(GROUP_CONCAT(TRIGGER_NAME), 'None') as names
172
+ FROM information_schema.TRIGGERS
173
+ WHERE TRIGGER_SCHEMA = '{target_database}'
174
+ UNION ALL
175
+ SELECT
176
+ 'Stored Procedures' as object_type,
177
+ COUNT(*) as count,
178
+ COALESCE(GROUP_CONCAT(ROUTINE_NAME), 'None') as names
179
+ FROM information_schema.ROUTINES
180
+ WHERE ROUTINE_SCHEMA = '{target_database}'
181
+ AND ROUTINE_TYPE = 'PROCEDURE'
182
+ UNION ALL
183
+ SELECT
184
+ 'Functions' as object_type,
185
+ COUNT(*) as count,
186
+ COALESCE(GROUP_CONCAT(ROUTINE_NAME), 'None') as names
187
+ FROM information_schema.ROUTINES
188
+ WHERE ROUTINE_SCHEMA = '{target_database}'
189
+ AND ROUTINE_TYPE = 'FUNCTION';""",
190
+ 'parameters': ['target_database'],
191
+ },
192
+ }
193
+
194
+
195
+ def get_query_resource(query_name: str, max_query_results: int, **params) -> Dict[str, Any]:
196
+ """Get a SQL query resource with parameters substituted."""
197
+ if query_name not in mysql_analysis_queries:
198
+ raise ValueError(f"Query '{query_name}' not found")
199
+
200
+ query_info = mysql_analysis_queries[query_name].copy()
201
+
202
+ # Substitute parameters in SQL
203
+ if params:
204
+ query_info['sql'] = query_info['sql'].format(**params)
205
+
206
+ # Apply LIMIT to all queries
207
+ sql = query_info['sql'].rstrip(';')
208
+ query_info['sql'] = f'{sql} LIMIT {max_query_results};'
209
+
210
+ return query_info