awslabs.timestream-for-influxdb-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 +17 -0
- awslabs/timestream_for_influxdb_mcp_server/__init__.py +18 -0
- awslabs/timestream_for_influxdb_mcp_server/server.py +1239 -0
- awslabs_timestream_for_influxdb_mcp_server-0.0.1.dist-info/METADATA +114 -0
- awslabs_timestream_for_influxdb_mcp_server-0.0.1.dist-info/RECORD +9 -0
- awslabs_timestream_for_influxdb_mcp_server-0.0.1.dist-info/WHEEL +4 -0
- awslabs_timestream_for_influxdb_mcp_server-0.0.1.dist-info/entry_points.txt +2 -0
- awslabs_timestream_for_influxdb_mcp_server-0.0.1.dist-info/licenses/LICENSE +175 -0
- awslabs_timestream_for_influxdb_mcp_server-0.0.1.dist-info/licenses/NOTICE +2 -0
|
@@ -0,0 +1,1239 @@
|
|
|
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
|
+
|
|
16
|
+
"""awslabs Timestream for InfluxDB MCP Server implementation."""
|
|
17
|
+
|
|
18
|
+
import boto3
|
|
19
|
+
import os
|
|
20
|
+
from influxdb_client.client.influxdb_client import InfluxDBClient
|
|
21
|
+
from influxdb_client.client.write.point import Point
|
|
22
|
+
from influxdb_client.client.write_api import ASYNCHRONOUS, SYNCHRONOUS
|
|
23
|
+
from influxdb_client.domain.write_precision import WritePrecision
|
|
24
|
+
from loguru import logger
|
|
25
|
+
from mcp.server.fastmcp import FastMCP
|
|
26
|
+
from pydantic import Field
|
|
27
|
+
from typing import Any, Dict, List, Optional
|
|
28
|
+
from urllib.parse import urlparse
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Define Field parameters as global variables to avoid duplication
|
|
32
|
+
# Common fields
|
|
33
|
+
REQUIRED_FIELD_DB_CLUSTER_ID = Field(
|
|
34
|
+
..., description='Service-generated unique identifier of the DB cluster.'
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
REQUIRED_FIELD_DB_INSTANCE_NAME = Field(
|
|
38
|
+
...,
|
|
39
|
+
description='The name that uniquely identifies the DB instance. '
|
|
40
|
+
'This name will also be a prefix included in the endpoint. '
|
|
41
|
+
'DB instance names must be unique per customer and per region.',
|
|
42
|
+
)
|
|
43
|
+
REQUIRED_FIELD_DB_INSTANCE_TYPE = Field(
|
|
44
|
+
..., description='The Timestream for InfluxDB DB instance type to run InfluxDB on.'
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
OPTIONAL_FIELD_DB_INSTANCE_TYPE_CLUSTER_UPDATE = Field(
|
|
48
|
+
None, description='Update the DB cluster to use the specified DB instance Type.'
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
REQUIRED_FIELD_PASSWORD = Field(
|
|
52
|
+
...,
|
|
53
|
+
description='The password of the initial admin user created in InfluxDB. '
|
|
54
|
+
'This password will allow you to access the InfluxDB UI to perform various administrative task '
|
|
55
|
+
'and also use the InfluxDB CLI to create an operator token.',
|
|
56
|
+
)
|
|
57
|
+
REQUIRED_FIELD_ALLOCATED_STORAGE_GB = Field(
|
|
58
|
+
...,
|
|
59
|
+
description='The amount of storage to allocate for your DB storage type in GiB (gibibytes).',
|
|
60
|
+
)
|
|
61
|
+
OPTIONAL_FIELD_ALLOCATED_STORAGE_GB_OPTIONAL = Field(
|
|
62
|
+
None, description='The amount of storage to allocate for your DB storage type (in gibibytes).'
|
|
63
|
+
)
|
|
64
|
+
REQUIRED_FIELD_VPC_SECURITY_GROUP_IDS = Field(
|
|
65
|
+
..., description='A list of VPC security group IDs to associate with the DB.'
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
REQUIRED_FIELD_VPC_SUBNET_IDS = Field(
|
|
69
|
+
...,
|
|
70
|
+
description='A list of VPC subnet IDs to associate with the DB. '
|
|
71
|
+
'Provide at least two VPC subnet IDs in different Availability Zones when deploying with a Multi-AZ standby.',
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
OPTIONAL_FIELD_PUBLICLY_ACCESSIBLE = Field(
|
|
75
|
+
True,
|
|
76
|
+
description='Configures the DB with a public IP to facilitate access from outside the VPC.',
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
OPTIONAL_FIELD_TOOL_WRITE_MODE = Field(
|
|
80
|
+
False,
|
|
81
|
+
description='Tool is run in write mode and will be able to perform any create/update/delete operations. '
|
|
82
|
+
'Default is read-only mode (False)',
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
OPTIONAL_FIELD_USERNAME = Field(
|
|
86
|
+
None, description='The username of the initial admin user created in InfluxDB.'
|
|
87
|
+
)
|
|
88
|
+
OPTIONAL_FIELD_ORGANIZATION = Field(
|
|
89
|
+
None,
|
|
90
|
+
description='The name of the initial organization for the initial admin user in InfluxDB.'
|
|
91
|
+
'An InfluxDB organization is a workspace for a group of users',
|
|
92
|
+
)
|
|
93
|
+
REQUIRED_FIELD_BUCKET = Field(..., description='The name of the initial InfluxDB bucket.')
|
|
94
|
+
OPTIONAL_FIELD_BUCKET = Field(None, description='The name of the initial InfluxDB bucket.')
|
|
95
|
+
OPTIONAL_FIELD_DB_STORAGE_TYPE = Field(
|
|
96
|
+
None,
|
|
97
|
+
description='The Timestream for InfluxDB DB storage type to read and write InfluxDB data.',
|
|
98
|
+
)
|
|
99
|
+
OPTIONAL_FIELD_DEPLOYMENT_TYPE_INSTANCE = Field(
|
|
100
|
+
None,
|
|
101
|
+
description='Specifies whether the DB instance will be deployed as a standalone instance or with a Multi-AZ standby for high availability.',
|
|
102
|
+
)
|
|
103
|
+
OPTIONAL_FIELD_NETWORK_TYPE = Field(
|
|
104
|
+
None,
|
|
105
|
+
description='Specifies whether the network type of the Timestream for InfluxDB cluster is IPv4 or DUAL.',
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
OPTIONAL_FIELD_PORT = Field(
|
|
109
|
+
None, description='The port number on which InfluxDB accepts connections. Default: 8086'
|
|
110
|
+
)
|
|
111
|
+
OPTIONAL_FIELD_PORT_UPDATE = Field(
|
|
112
|
+
None, description='Update the DB cluster to use the specified port.'
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
OPTIONAL_FIELD_FAILOVER_MODE = Field(
|
|
116
|
+
None,
|
|
117
|
+
description='Specifies the behavior of failure recovery when the primary node of the cluster fails.',
|
|
118
|
+
)
|
|
119
|
+
OPTIONAL_FIELD_FAILOVER_MODE_UPDATE = Field(
|
|
120
|
+
None, description="Update the DB cluster's failover behavior."
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
OPTIONAL_FIELD_TAGS = Field(None, description='A list of tags to assign to the DB.')
|
|
124
|
+
OPTIONAL_FIELD_TAGS_PARAM_GROUP = Field(
|
|
125
|
+
None, description='A list of key-value pairs to associate with the DB parameter group.'
|
|
126
|
+
)
|
|
127
|
+
OPTIONAL_FIELD_LOG_DELIVERY_CONFIGURATION = Field(
|
|
128
|
+
None, description='Configuration for sending InfluxDB engine logs to a specified S3 bucket.'
|
|
129
|
+
)
|
|
130
|
+
OPTIONAL_FIELD_LOG_DELIVERY_CONFIGURATION_UPDATE = Field(
|
|
131
|
+
None, description='The log delivery configuration to apply to the DB cluster.'
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Pagination fields
|
|
135
|
+
OPTIONAL_FIELD_NEXT_TOKEN = Field(
|
|
136
|
+
None,
|
|
137
|
+
description='The pagination token. To resume pagination, provide the next-token value as an argument of a subsequent API invocation.',
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
OPTIONAL_FIELD_MAX_RESULTS = Field(
|
|
141
|
+
None,
|
|
142
|
+
description='The maximum number of items to return in the output. If the total number of items available is more than the value specified, a nextToken is provided in the output.',
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Resource fields
|
|
146
|
+
REQUIRED_FIELD_RESOURCE_ARN = Field(
|
|
147
|
+
..., description='The Amazon Resource Name (ARN) of the tagged resource.'
|
|
148
|
+
)
|
|
149
|
+
REQUIRED_FIELD_TAG_KEYS = Field(..., description='The keys used to identify the tags to remove.')
|
|
150
|
+
REQUIRED_FIELD_TAGS_RESOURCE = Field(..., description='A list of key-value pairs as tags.')
|
|
151
|
+
|
|
152
|
+
# DB Parameter Group fiels
|
|
153
|
+
REQUIRED_FIELD_PARAMETER_GROUP_ID = Field(..., description='The id of the DB parameter group.')
|
|
154
|
+
REQUIRED_FIELD_PARAM_GROUP_NAME = Field(
|
|
155
|
+
...,
|
|
156
|
+
description='The name of the DB parameter group. The name must be unique per customer and per region.',
|
|
157
|
+
)
|
|
158
|
+
OPTIONAL_FIELD_PARAM_GROUP_DESCRIPTION = Field(
|
|
159
|
+
None, description='A description of the DB parameter group.'
|
|
160
|
+
)
|
|
161
|
+
OPTIONAL_FIELD_PARAMETERS = Field(
|
|
162
|
+
None, description='A list of the parameters that comprise the DB parameter group.'
|
|
163
|
+
)
|
|
164
|
+
OPTIONAL_FIELD_DB_PARAMETER_GROUP_ID = Field(
|
|
165
|
+
None, description='The id of the DB parameter group to assign to your DB.'
|
|
166
|
+
)
|
|
167
|
+
OPTIONAL_FIELD_DB_PARAMETER_GROUP_IDENTIFIER_UPDATE = Field(
|
|
168
|
+
None, description='Update the DB cluster to use the specified DB parameter group.'
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# DB Instance fields
|
|
172
|
+
REQUIRED_FIELD_DB_INSTANCE_IDENTIFIER = Field(..., description='The id of the DB instance.')
|
|
173
|
+
|
|
174
|
+
# Status fields
|
|
175
|
+
REQUIRED_FIELD_STATUS = Field(
|
|
176
|
+
..., description='The status to filter DB instances by (case-insensitive).'
|
|
177
|
+
)
|
|
178
|
+
REQUIRED_FIELD_STATUS_CLUSTER = Field(
|
|
179
|
+
..., description='The status to filter DB clusters by (case-insensitive).'
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# InfluxDB fields
|
|
183
|
+
REQUIRED_FIELD_URL = Field(..., description='The URL of the InfluxDB server.')
|
|
184
|
+
REQUIRED_FIELD_TOKEN = Field(..., description='The authentication token.')
|
|
185
|
+
REQUIRED_FIELD_BUCKET_INFLUX = Field(..., description='The destination bucket for writes.')
|
|
186
|
+
REQUIRED_FIELD_ORG = Field(..., description='The organization name.')
|
|
187
|
+
REQUIRED_FIELD_POINTS = Field(
|
|
188
|
+
...,
|
|
189
|
+
description='List of data points to write. Each point should be a dictionary with measurement, tags, fields, and optional time.',
|
|
190
|
+
)
|
|
191
|
+
REQUIRED_FIELD_DATA_LINE_PROTOCOL = Field(
|
|
192
|
+
..., description='Data in InfluxDB Line Protocol format.'
|
|
193
|
+
)
|
|
194
|
+
OPTIONAL_FIELD_WRITE_PRECISION = Field(
|
|
195
|
+
default='ns',
|
|
196
|
+
description='The precision for the unix timestamps within the body line-protocol. One of: ns, us, ms, s (default is ns).',
|
|
197
|
+
)
|
|
198
|
+
OPTIONAL_FIELD_SYNC_MODE = Field(
|
|
199
|
+
default='synchronous',
|
|
200
|
+
description="The synchronization mode, either 'synchronous' or 'asynchronous'.",
|
|
201
|
+
)
|
|
202
|
+
OPTIONAL_FIELD_VERIFY_SSL = Field(
|
|
203
|
+
True, description='Whether to verify SSL with https connections.'
|
|
204
|
+
)
|
|
205
|
+
REQUIRED_FIELD_QUERY = Field(..., description='The Flux query string.')
|
|
206
|
+
|
|
207
|
+
# Cluster name field
|
|
208
|
+
REQUIRED_FIELD_CLUSTER_NAME = Field(
|
|
209
|
+
...,
|
|
210
|
+
description='The name that uniquely identifies the DB cluster when interacting with '
|
|
211
|
+
'the Amazon Timestream for InfluxDB API and CLI commands. '
|
|
212
|
+
'This name will also be a prefix included in the endpoint.',
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
mcp = FastMCP(
|
|
216
|
+
'awslabs.timestream-for-influxdb-mcp-server',
|
|
217
|
+
instructions="""
|
|
218
|
+
This MCP server provides tools to interact with AWS Timestream for InfluxDB APIs.
|
|
219
|
+
It allows you to create and manage databases, users, and perform other operations
|
|
220
|
+
related to Timestream for InfluxDB service.
|
|
221
|
+
""",
|
|
222
|
+
dependencies=['loguru', 'boto3', 'influxdb-client'],
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def get_timestream_influxdb_client():
|
|
227
|
+
"""Get the AWS Timestream for InfluxDB client."""
|
|
228
|
+
aws_region: str = os.environ.get('AWS_REGION', 'us-east-1')
|
|
229
|
+
aws_profile = os.environ.get('AWS_PROFILE')
|
|
230
|
+
try:
|
|
231
|
+
if aws_profile:
|
|
232
|
+
logger.info(f'Using AWS profile for AWS Timestream Influx Client: {aws_profile}')
|
|
233
|
+
client = boto3.Session(profile_name=aws_profile, region_name=aws_region).client(
|
|
234
|
+
'timestream-influxdb'
|
|
235
|
+
)
|
|
236
|
+
else:
|
|
237
|
+
client = boto3.Session(region_name=aws_region).client('timestream-influxdb')
|
|
238
|
+
except Exception as e:
|
|
239
|
+
logger.error(f'Error creating AWS Timestream for InfluxDB client: {str(e)}')
|
|
240
|
+
raise
|
|
241
|
+
|
|
242
|
+
return client
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def get_influxdb_client(url, token, org=None, timeout=10000, verify_ssl: bool = True):
|
|
246
|
+
"""Get an InfluxDB client.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
url: The URL of the InfluxDB server e.g. https://<host-name>:8086.
|
|
250
|
+
token: The authentication token.
|
|
251
|
+
org: The organization name.
|
|
252
|
+
timeout: The timeout in milliseconds.
|
|
253
|
+
verify_ssl: whether to verify SSL with https connections
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
An InfluxDB client.
|
|
257
|
+
|
|
258
|
+
Raises:
|
|
259
|
+
ValueError: If the URL does not use HTTPS protocol or is not properly formatted.
|
|
260
|
+
"""
|
|
261
|
+
try:
|
|
262
|
+
parsed_url = urlparse(url)
|
|
263
|
+
url_scheme = parsed_url.scheme
|
|
264
|
+
if url_scheme != 'https' and url_scheme != 'http':
|
|
265
|
+
raise ValueError('URL must use HTTP(S) protocol')
|
|
266
|
+
except Exception as e:
|
|
267
|
+
logger.error(f'Error parsing URL: {str(e)}')
|
|
268
|
+
raise
|
|
269
|
+
|
|
270
|
+
if not token:
|
|
271
|
+
raise ValueError('Token must be provided')
|
|
272
|
+
|
|
273
|
+
# Ensure org is not None when passed to InfluxDBClient
|
|
274
|
+
org_param = org if org is not None else ''
|
|
275
|
+
|
|
276
|
+
return InfluxDBClient(
|
|
277
|
+
url=url, token=token, org=org_param, timeout=timeout, verify_ssl=verify_ssl
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
@mcp.tool(
|
|
282
|
+
name='CreateDbCluster', description='Create a new Timestream for InfluxDB database cluster.'
|
|
283
|
+
)
|
|
284
|
+
async def create_db_cluster(
|
|
285
|
+
name: str = REQUIRED_FIELD_CLUSTER_NAME,
|
|
286
|
+
db_instance_type: str = REQUIRED_FIELD_DB_INSTANCE_TYPE,
|
|
287
|
+
password: str = REQUIRED_FIELD_PASSWORD,
|
|
288
|
+
allocated_storage_gb: int = REQUIRED_FIELD_ALLOCATED_STORAGE_GB,
|
|
289
|
+
vpc_security_group_ids: List[str] = REQUIRED_FIELD_VPC_SECURITY_GROUP_IDS,
|
|
290
|
+
vpc_subnet_ids: List[str] = REQUIRED_FIELD_VPC_SUBNET_IDS,
|
|
291
|
+
publicly_accessible: bool = OPTIONAL_FIELD_PUBLICLY_ACCESSIBLE,
|
|
292
|
+
username: Optional[str] = OPTIONAL_FIELD_USERNAME,
|
|
293
|
+
organization: Optional[str] = OPTIONAL_FIELD_ORGANIZATION,
|
|
294
|
+
bucket: Optional[str] = OPTIONAL_FIELD_BUCKET,
|
|
295
|
+
db_storage_type: Optional[str] = OPTIONAL_FIELD_DB_STORAGE_TYPE,
|
|
296
|
+
deployment_type: Optional[str] = OPTIONAL_FIELD_DEPLOYMENT_TYPE_INSTANCE,
|
|
297
|
+
networkType: Optional[str] = OPTIONAL_FIELD_NETWORK_TYPE,
|
|
298
|
+
port: Optional[int] = OPTIONAL_FIELD_PORT,
|
|
299
|
+
db_parameter_group_identifier: Optional[str] = OPTIONAL_FIELD_DB_PARAMETER_GROUP_ID,
|
|
300
|
+
failover_mode: Optional[str] = OPTIONAL_FIELD_FAILOVER_MODE,
|
|
301
|
+
tags: Optional[Dict[str, str]] = OPTIONAL_FIELD_TAGS,
|
|
302
|
+
log_delivery_configuration: Optional[
|
|
303
|
+
Dict[str, Any]
|
|
304
|
+
] = OPTIONAL_FIELD_LOG_DELIVERY_CONFIGURATION,
|
|
305
|
+
tool_write_mode: bool = OPTIONAL_FIELD_TOOL_WRITE_MODE,
|
|
306
|
+
) -> Dict[str, Any]:
|
|
307
|
+
"""Create a new Timestream for InfluxDB database cluster.
|
|
308
|
+
|
|
309
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_CreateDbCluster.html
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
Details of the created DB cluster.
|
|
313
|
+
"""
|
|
314
|
+
if not tool_write_mode:
|
|
315
|
+
raise Exception(
|
|
316
|
+
'CreateDbCluster tool invocation not allowed when tool-write-mode is set to False'
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
320
|
+
|
|
321
|
+
# Required parameters
|
|
322
|
+
params = {
|
|
323
|
+
'name': name,
|
|
324
|
+
'dbInstanceType': db_instance_type,
|
|
325
|
+
'password': password,
|
|
326
|
+
'vpcSecurityGroupIds': vpc_security_group_ids,
|
|
327
|
+
'vpcSubnetIds': vpc_subnet_ids,
|
|
328
|
+
'allocatedStorage': allocated_storage_gb,
|
|
329
|
+
'publiclyAccessible': publicly_accessible,
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
# Add optional parameters if provided
|
|
333
|
+
if db_parameter_group_identifier:
|
|
334
|
+
params['dbParameterGroupIdentifier'] = db_parameter_group_identifier
|
|
335
|
+
if username:
|
|
336
|
+
params['username'] = username
|
|
337
|
+
if organization:
|
|
338
|
+
params['organization'] = organization
|
|
339
|
+
if bucket:
|
|
340
|
+
params['bucket'] = bucket
|
|
341
|
+
if port:
|
|
342
|
+
params['port'] = port
|
|
343
|
+
if db_storage_type:
|
|
344
|
+
params['dbStorageType'] = db_storage_type
|
|
345
|
+
if deployment_type:
|
|
346
|
+
params['deploymentType'] = deployment_type
|
|
347
|
+
if networkType:
|
|
348
|
+
params['networkType'] = networkType
|
|
349
|
+
if failover_mode:
|
|
350
|
+
params['failoverMode'] = failover_mode
|
|
351
|
+
if log_delivery_configuration:
|
|
352
|
+
params['logDeliveryConfiguration'] = str(log_delivery_configuration)
|
|
353
|
+
|
|
354
|
+
if tags:
|
|
355
|
+
tag_list = [{'Key': k, 'Value': v} for k, v in tags.items()]
|
|
356
|
+
params['tags'] = str(tag_list)
|
|
357
|
+
|
|
358
|
+
try:
|
|
359
|
+
response = ts_influx_client.create_db_cluster(**params)
|
|
360
|
+
return response
|
|
361
|
+
except Exception as e:
|
|
362
|
+
logger.error(f'Error creating DB cluster: {str(e)}')
|
|
363
|
+
raise e
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
@mcp.tool(
|
|
367
|
+
name='CreateDbInstance', description='Create a new Timestream for InfluxDB database instance'
|
|
368
|
+
)
|
|
369
|
+
async def create_db_instance(
|
|
370
|
+
db_instance_name: str = REQUIRED_FIELD_DB_INSTANCE_NAME,
|
|
371
|
+
db_instance_type: str = REQUIRED_FIELD_DB_INSTANCE_TYPE,
|
|
372
|
+
password: str = REQUIRED_FIELD_PASSWORD,
|
|
373
|
+
allocated_storage_gb: int = REQUIRED_FIELD_ALLOCATED_STORAGE_GB,
|
|
374
|
+
vpc_security_group_ids: List[str] = REQUIRED_FIELD_VPC_SECURITY_GROUP_IDS,
|
|
375
|
+
vpc_subnet_ids: List[str] = REQUIRED_FIELD_VPC_SUBNET_IDS,
|
|
376
|
+
publicly_accessible: bool = OPTIONAL_FIELD_PUBLICLY_ACCESSIBLE,
|
|
377
|
+
username: Optional[str] = OPTIONAL_FIELD_USERNAME,
|
|
378
|
+
organization: Optional[str] = OPTIONAL_FIELD_ORGANIZATION,
|
|
379
|
+
bucket: Optional[str] = OPTIONAL_FIELD_BUCKET,
|
|
380
|
+
db_storage_type: Optional[str] = OPTIONAL_FIELD_DB_STORAGE_TYPE,
|
|
381
|
+
deployment_type: Optional[str] = OPTIONAL_FIELD_DEPLOYMENT_TYPE_INSTANCE,
|
|
382
|
+
networkType: Optional[str] = OPTIONAL_FIELD_NETWORK_TYPE,
|
|
383
|
+
port: Optional[int] = OPTIONAL_FIELD_PORT,
|
|
384
|
+
db_parameter_group_id: Optional[str] = OPTIONAL_FIELD_DB_PARAMETER_GROUP_ID,
|
|
385
|
+
tags: Optional[Dict[str, str]] = OPTIONAL_FIELD_TAGS,
|
|
386
|
+
tool_write_mode: bool = OPTIONAL_FIELD_TOOL_WRITE_MODE,
|
|
387
|
+
) -> Dict[str, Any]:
|
|
388
|
+
"""Create a new Timestream for InfluxDB database instance.
|
|
389
|
+
|
|
390
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_CreateDbInstance.html#tsinfluxdb-CreateDbInstance-request-dbStorageType
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
Details of the created DB instance.
|
|
394
|
+
"""
|
|
395
|
+
if not tool_write_mode:
|
|
396
|
+
raise Exception(
|
|
397
|
+
'CreateDbInstance tool invocation not allowed when tool-write-mode is set to False'
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
401
|
+
|
|
402
|
+
# Required parameters
|
|
403
|
+
params = {
|
|
404
|
+
'name': db_instance_name,
|
|
405
|
+
'dbInstanceType': db_instance_type,
|
|
406
|
+
'password': password,
|
|
407
|
+
'vpcSecurityGroupIds': vpc_security_group_ids,
|
|
408
|
+
'vpcSubnetIds': vpc_subnet_ids,
|
|
409
|
+
'allocatedStorage': allocated_storage_gb,
|
|
410
|
+
'publiclyAccessible': publicly_accessible,
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
# Add optional parameters if provided
|
|
414
|
+
if db_parameter_group_id:
|
|
415
|
+
params['dbParameterGroupIdentifier'] = db_parameter_group_id
|
|
416
|
+
if username:
|
|
417
|
+
params['username'] = username
|
|
418
|
+
if organization:
|
|
419
|
+
params['organization'] = organization
|
|
420
|
+
if bucket:
|
|
421
|
+
params['bucket'] = bucket
|
|
422
|
+
if port:
|
|
423
|
+
params['port'] = str(port)
|
|
424
|
+
if username:
|
|
425
|
+
params['username'] = username
|
|
426
|
+
if db_storage_type:
|
|
427
|
+
params['db_storage_type'] = db_storage_type
|
|
428
|
+
if deployment_type:
|
|
429
|
+
params['deployment_type'] = deployment_type
|
|
430
|
+
if networkType:
|
|
431
|
+
params['networkType'] = networkType
|
|
432
|
+
|
|
433
|
+
if tags:
|
|
434
|
+
tag_list = [{'Key': k, 'Value': v} for k, v in tags.items()]
|
|
435
|
+
params['tags'] = str(tag_list)
|
|
436
|
+
|
|
437
|
+
try:
|
|
438
|
+
response = ts_influx_client.create_db_instance(**params)
|
|
439
|
+
return response
|
|
440
|
+
except Exception as e:
|
|
441
|
+
logger.error(f'Error creating DB instance: {str(e)}')
|
|
442
|
+
raise e
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
@mcp.tool(
|
|
446
|
+
name='LsInstancesOfCluster',
|
|
447
|
+
description='List all Timestream for InfluxDB instances belonging to a specific DB cluster.',
|
|
448
|
+
)
|
|
449
|
+
async def list_db_instances_for_cluster(
|
|
450
|
+
db_cluster_id: str = REQUIRED_FIELD_DB_CLUSTER_ID,
|
|
451
|
+
next_token: Optional[str] = OPTIONAL_FIELD_NEXT_TOKEN,
|
|
452
|
+
max_results: Optional[int] = OPTIONAL_FIELD_MAX_RESULTS,
|
|
453
|
+
) -> Dict[str, Any]:
|
|
454
|
+
"""Returns a list of Timestream for InfluxDB DB instances belonging to a specific cluster.
|
|
455
|
+
|
|
456
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_ListDbInstancesForCluster.html
|
|
457
|
+
|
|
458
|
+
Returns:
|
|
459
|
+
A list of Timestream for InfluxDB instance summaries belonging to the cluster.
|
|
460
|
+
"""
|
|
461
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
462
|
+
|
|
463
|
+
params = {'dbClusterId': db_cluster_id}
|
|
464
|
+
|
|
465
|
+
if next_token:
|
|
466
|
+
params['nextToken'] = next_token
|
|
467
|
+
if max_results:
|
|
468
|
+
params['maxResults'] = str(max_results)
|
|
469
|
+
|
|
470
|
+
try:
|
|
471
|
+
response = ts_influx_client.list_db_instances_for_cluster(**params)
|
|
472
|
+
return response
|
|
473
|
+
except Exception as e:
|
|
474
|
+
logger.error(f'Error listing DB instances for cluster: {str(e)}')
|
|
475
|
+
raise e
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
@mcp.tool(name='ListDbInstances', description='List all Timestream for InfluxDB DB instances')
|
|
479
|
+
async def list_db_instances(
|
|
480
|
+
next_token: Optional[str] = OPTIONAL_FIELD_NEXT_TOKEN,
|
|
481
|
+
max_results: Optional[int] = OPTIONAL_FIELD_MAX_RESULTS,
|
|
482
|
+
) -> Dict[str, Any]:
|
|
483
|
+
"""Returns a list of Timestream for InfluxDB DB instances.
|
|
484
|
+
|
|
485
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_ListDbInstances.html
|
|
486
|
+
|
|
487
|
+
Returns:
|
|
488
|
+
A list of Timestream for InfluxDB DB instance summaries.
|
|
489
|
+
"""
|
|
490
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
491
|
+
|
|
492
|
+
params = {}
|
|
493
|
+
if next_token:
|
|
494
|
+
params['nextToken'] = next_token
|
|
495
|
+
if max_results:
|
|
496
|
+
params['maxResults'] = str(max_results)
|
|
497
|
+
|
|
498
|
+
try:
|
|
499
|
+
response = ts_influx_client.list_db_instances(**params)
|
|
500
|
+
return response
|
|
501
|
+
except Exception as e:
|
|
502
|
+
logger.error(f'Error listing DB instances: {str(e)}')
|
|
503
|
+
raise e
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
@mcp.tool(name='ListDbClusters', description='List all Timestream for InfluxDB DB clusters.')
|
|
507
|
+
async def list_db_clusters(
|
|
508
|
+
next_token: Optional[str] = OPTIONAL_FIELD_NEXT_TOKEN,
|
|
509
|
+
max_results: Optional[int] = OPTIONAL_FIELD_MAX_RESULTS,
|
|
510
|
+
) -> Dict[str, Any]:
|
|
511
|
+
"""Returns a list of Timestream for InfluxDB DB clusters.
|
|
512
|
+
|
|
513
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_ListDbClusters.html
|
|
514
|
+
|
|
515
|
+
Returns:
|
|
516
|
+
A list of Timestream for InfluxDB cluster summaries.
|
|
517
|
+
"""
|
|
518
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
519
|
+
|
|
520
|
+
params = {}
|
|
521
|
+
if next_token:
|
|
522
|
+
params['nextToken'] = next_token
|
|
523
|
+
if max_results:
|
|
524
|
+
params['maxResults'] = str(max_results)
|
|
525
|
+
|
|
526
|
+
try:
|
|
527
|
+
response = ts_influx_client.list_db_clusters(**params)
|
|
528
|
+
return response
|
|
529
|
+
except Exception as e:
|
|
530
|
+
logger.error(f'Error listing DB clusters: {str(e)}')
|
|
531
|
+
raise e
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
@mcp.tool(
|
|
535
|
+
name='GetDbParameterGroup',
|
|
536
|
+
description='Get a Timestream for InfluxDB DB parameter group details for a db_parameter_group_id',
|
|
537
|
+
)
|
|
538
|
+
async def get_db_parameter_group(
|
|
539
|
+
identifier: str = REQUIRED_FIELD_PARAMETER_GROUP_ID,
|
|
540
|
+
) -> Dict[str, Any]:
|
|
541
|
+
"""Returns a Timestream for InfluxDB DB parameter group.
|
|
542
|
+
|
|
543
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_GetDbParameterGroup.html
|
|
544
|
+
|
|
545
|
+
Returns:
|
|
546
|
+
Details of the DB parameter group.
|
|
547
|
+
"""
|
|
548
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
549
|
+
|
|
550
|
+
try:
|
|
551
|
+
response = ts_influx_client.get_db_parameter_group(identifier=identifier)
|
|
552
|
+
return response
|
|
553
|
+
except Exception as e:
|
|
554
|
+
logger.error(f'Error getting DB parameter group: {str(e)}')
|
|
555
|
+
raise e
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
@mcp.tool(
|
|
559
|
+
name='GetDbInstance',
|
|
560
|
+
description='Returns a Timestream for InfluxDB DB instance details by the instance-identifier',
|
|
561
|
+
)
|
|
562
|
+
async def get_db_instance(
|
|
563
|
+
identifier: str = REQUIRED_FIELD_DB_INSTANCE_IDENTIFIER,
|
|
564
|
+
) -> Dict[str, Any]:
|
|
565
|
+
"""Returns a Timestream for InfluxDB DB instance.
|
|
566
|
+
|
|
567
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_GetDbInstance.html
|
|
568
|
+
|
|
569
|
+
Returns:
|
|
570
|
+
Details of the DB instance.
|
|
571
|
+
"""
|
|
572
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
573
|
+
|
|
574
|
+
try:
|
|
575
|
+
response = ts_influx_client.get_db_instance(identifier=identifier)
|
|
576
|
+
return response
|
|
577
|
+
except Exception as e:
|
|
578
|
+
logger.error(f'Error getting DB instance: {str(e)}')
|
|
579
|
+
raise e
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
@mcp.tool(
|
|
583
|
+
name='GetDbCluster',
|
|
584
|
+
description='Returns a Timestream for InfluxDB DB cluster details by the db_cluster_id',
|
|
585
|
+
)
|
|
586
|
+
async def get_db_cluster(
|
|
587
|
+
db_cluster_id: str = REQUIRED_FIELD_DB_CLUSTER_ID,
|
|
588
|
+
) -> Dict[str, Any]:
|
|
589
|
+
"""Retrieves information about a Timestream for InfluxDB cluster.
|
|
590
|
+
|
|
591
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_GetDbCluster.html
|
|
592
|
+
|
|
593
|
+
Returns:
|
|
594
|
+
Details of the DB cluster.
|
|
595
|
+
"""
|
|
596
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
597
|
+
|
|
598
|
+
try:
|
|
599
|
+
response = ts_influx_client.get_db_cluster(dbClusterId=db_cluster_id)
|
|
600
|
+
return response
|
|
601
|
+
except Exception as e:
|
|
602
|
+
logger.error(f'Error getting DB cluster: {str(e)}')
|
|
603
|
+
raise e
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
@mcp.tool(
|
|
607
|
+
name='DeleteDbInstance',
|
|
608
|
+
description='Deletes a Timestream for InfluxDB DB instance by the instance-identifier',
|
|
609
|
+
)
|
|
610
|
+
async def delete_db_instance(
|
|
611
|
+
identifier: str = REQUIRED_FIELD_DB_INSTANCE_IDENTIFIER,
|
|
612
|
+
tool_write_mode: bool = OPTIONAL_FIELD_TOOL_WRITE_MODE,
|
|
613
|
+
) -> Dict[str, Any]:
|
|
614
|
+
"""Deletes a Timestream for InfluxDB DB instance.
|
|
615
|
+
|
|
616
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_DeleteDbInstance.html
|
|
617
|
+
|
|
618
|
+
Returns:
|
|
619
|
+
Details of the deleted DB instance.
|
|
620
|
+
"""
|
|
621
|
+
if not tool_write_mode:
|
|
622
|
+
raise Exception(
|
|
623
|
+
'DeleteDbInstance tool invocation not allowed when tool-write-mode is set to False'
|
|
624
|
+
)
|
|
625
|
+
|
|
626
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
627
|
+
|
|
628
|
+
try:
|
|
629
|
+
response = ts_influx_client.delete_db_instance(identifier=identifier)
|
|
630
|
+
return response
|
|
631
|
+
except Exception as e:
|
|
632
|
+
logger.error(f'Error deleting DB instance: {str(e)}')
|
|
633
|
+
raise e
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
@mcp.tool(
|
|
637
|
+
name='DeleteDbCluster',
|
|
638
|
+
description='Deletes a Timestream for InfluxDB cluster by the db_cluster_id',
|
|
639
|
+
)
|
|
640
|
+
async def delete_db_cluster(
|
|
641
|
+
db_cluster_id: str = REQUIRED_FIELD_DB_CLUSTER_ID,
|
|
642
|
+
tool_write_mode: bool = OPTIONAL_FIELD_TOOL_WRITE_MODE,
|
|
643
|
+
) -> Dict[str, Any]:
|
|
644
|
+
"""Deletes a Timestream for InfluxDB cluster.
|
|
645
|
+
|
|
646
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_DeleteDbCluster.html
|
|
647
|
+
|
|
648
|
+
Returns:
|
|
649
|
+
Details of the deleted DB cluster.
|
|
650
|
+
"""
|
|
651
|
+
if not tool_write_mode:
|
|
652
|
+
raise Exception(
|
|
653
|
+
'DeleteDbCluster tool invocation not allowed when tool-write-mode is set to False'
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
657
|
+
|
|
658
|
+
try:
|
|
659
|
+
response = ts_influx_client.delete_db_cluster(dbClusterId=db_cluster_id)
|
|
660
|
+
return response
|
|
661
|
+
except Exception as e:
|
|
662
|
+
logger.error(f'Error deleting DB cluster: {str(e)}')
|
|
663
|
+
raise e
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
@mcp.tool(
|
|
667
|
+
name='ListDbParamGroups', description='List all Timestream for InfluxDB DB parameter groups.'
|
|
668
|
+
)
|
|
669
|
+
async def list_db_parameter_groups(
|
|
670
|
+
next_token: Optional[str] = OPTIONAL_FIELD_NEXT_TOKEN,
|
|
671
|
+
max_results: Optional[int] = OPTIONAL_FIELD_MAX_RESULTS,
|
|
672
|
+
) -> Dict[str, Any]:
|
|
673
|
+
"""Returns a list of Timestream for InfluxDB DB parameter groups.
|
|
674
|
+
|
|
675
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_ListDbParameterGroups.html
|
|
676
|
+
|
|
677
|
+
Returns:
|
|
678
|
+
A list of Timestream for InfluxDB DB parameter group summaries.
|
|
679
|
+
"""
|
|
680
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
681
|
+
|
|
682
|
+
params = {}
|
|
683
|
+
if next_token:
|
|
684
|
+
params['nextToken'] = next_token
|
|
685
|
+
if max_results:
|
|
686
|
+
params['maxResults'] = str(max_results)
|
|
687
|
+
|
|
688
|
+
try:
|
|
689
|
+
response = ts_influx_client.list_db_parameter_groups(**params)
|
|
690
|
+
return response
|
|
691
|
+
except Exception as e:
|
|
692
|
+
logger.error(f'Error listing DB parameter groups: {str(e)}')
|
|
693
|
+
raise e
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
@mcp.tool(name='ListTagsForResource', description='A list of tags applied to the resource.')
|
|
697
|
+
async def list_tags_for_resource(
|
|
698
|
+
resource_arn: str = REQUIRED_FIELD_RESOURCE_ARN,
|
|
699
|
+
) -> Dict[str, Any]:
|
|
700
|
+
"""A list of tags applied to the resource.
|
|
701
|
+
|
|
702
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_ListTagsForResource.html
|
|
703
|
+
|
|
704
|
+
Returns:
|
|
705
|
+
A list of tags used to categorize and track resources.
|
|
706
|
+
"""
|
|
707
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
708
|
+
|
|
709
|
+
try:
|
|
710
|
+
response = ts_influx_client.list_tags_for_resource(resourceArn=resource_arn)
|
|
711
|
+
return response
|
|
712
|
+
except Exception as e:
|
|
713
|
+
logger.error(f'Error listing tags for resource: {str(e)}')
|
|
714
|
+
raise e
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
@mcp.tool(
|
|
718
|
+
name='TagResource',
|
|
719
|
+
description='Tags are composed of a Key/Value pairs. Apply them to Timestream for InfluxDB resource.',
|
|
720
|
+
)
|
|
721
|
+
async def tag_resource(
|
|
722
|
+
resource_arn: str = REQUIRED_FIELD_RESOURCE_ARN,
|
|
723
|
+
tags: Dict[str, str] = REQUIRED_FIELD_TAGS_RESOURCE,
|
|
724
|
+
tool_write_mode: bool = OPTIONAL_FIELD_TOOL_WRITE_MODE,
|
|
725
|
+
) -> Dict[str, Any]:
|
|
726
|
+
"""Tags are composed of a Key/Value pairs. You can use tags to categorize and track your Timestream for InfluxDB resources.
|
|
727
|
+
|
|
728
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_TagResource.html
|
|
729
|
+
|
|
730
|
+
Returns:
|
|
731
|
+
Status of the tag operation.
|
|
732
|
+
"""
|
|
733
|
+
if not tool_write_mode:
|
|
734
|
+
raise Exception(
|
|
735
|
+
'TagResource tool invocation not allowed when tool-write-mode is set to False'
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
739
|
+
|
|
740
|
+
# Convert tags dictionary to list of Key/Value pairs
|
|
741
|
+
tag_list = [{'Key': k, 'Value': v} for k, v in tags.items()]
|
|
742
|
+
|
|
743
|
+
try:
|
|
744
|
+
response = ts_influx_client.tag_resource(resourceArn=resource_arn, tags=tag_list)
|
|
745
|
+
return response
|
|
746
|
+
except Exception as e:
|
|
747
|
+
logger.error(f'Error tagging resource: {str(e)}')
|
|
748
|
+
raise e
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
@mcp.tool(
|
|
752
|
+
name='UntagResource',
|
|
753
|
+
description='Removes the tags, identified by the keys, from the specified resource.',
|
|
754
|
+
)
|
|
755
|
+
async def untag_resource(
|
|
756
|
+
resource_arn: str = REQUIRED_FIELD_RESOURCE_ARN,
|
|
757
|
+
tag_keys: List[str] = REQUIRED_FIELD_TAG_KEYS,
|
|
758
|
+
tool_write_mode: bool = OPTIONAL_FIELD_TOOL_WRITE_MODE,
|
|
759
|
+
) -> Dict[str, Any]:
|
|
760
|
+
"""Removes the tag from the specified resource.
|
|
761
|
+
|
|
762
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_UntagResource.html
|
|
763
|
+
|
|
764
|
+
Returns:
|
|
765
|
+
Status of the untag operation.
|
|
766
|
+
"""
|
|
767
|
+
if not tool_write_mode:
|
|
768
|
+
raise Exception(
|
|
769
|
+
'UntagResource tool invocation not allowed when tool-write-mode is set to False'
|
|
770
|
+
)
|
|
771
|
+
|
|
772
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
773
|
+
|
|
774
|
+
try:
|
|
775
|
+
response = ts_influx_client.untag_resource(resourceArn=resource_arn, tagKeys=tag_keys)
|
|
776
|
+
return response
|
|
777
|
+
except Exception as e:
|
|
778
|
+
logger.error(f'Error untagging resource: {str(e)}')
|
|
779
|
+
raise e
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
@mcp.tool(name='UpdateDbCluster', description='Updates a Timestream for InfluxDB cluster.')
|
|
783
|
+
async def update_db_cluster(
|
|
784
|
+
db_cluster_id: str = REQUIRED_FIELD_DB_CLUSTER_ID,
|
|
785
|
+
db_instance_type: Optional[str] = OPTIONAL_FIELD_DB_INSTANCE_TYPE_CLUSTER_UPDATE,
|
|
786
|
+
db_parameter_group_identifier: Optional[
|
|
787
|
+
str
|
|
788
|
+
] = OPTIONAL_FIELD_DB_PARAMETER_GROUP_IDENTIFIER_UPDATE,
|
|
789
|
+
port: Optional[int] = OPTIONAL_FIELD_PORT_UPDATE,
|
|
790
|
+
failover_mode: Optional[str] = OPTIONAL_FIELD_FAILOVER_MODE_UPDATE,
|
|
791
|
+
log_delivery_configuration: Optional[
|
|
792
|
+
Dict[str, Any]
|
|
793
|
+
] = OPTIONAL_FIELD_LOG_DELIVERY_CONFIGURATION_UPDATE,
|
|
794
|
+
tool_write_mode: bool = OPTIONAL_FIELD_TOOL_WRITE_MODE,
|
|
795
|
+
) -> Dict[str, Any]:
|
|
796
|
+
"""Updates a Timestream for InfluxDB cluster.
|
|
797
|
+
|
|
798
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_UpdateDbCluster.html
|
|
799
|
+
|
|
800
|
+
Returns:
|
|
801
|
+
Details of the updated DB cluster.
|
|
802
|
+
"""
|
|
803
|
+
if not tool_write_mode:
|
|
804
|
+
raise Exception(
|
|
805
|
+
'UpdateDbCluster tool invocation not allowed when tool-write-mode is set to False'
|
|
806
|
+
)
|
|
807
|
+
|
|
808
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
809
|
+
|
|
810
|
+
# Required parameters
|
|
811
|
+
params = {'dbClusterId': db_cluster_id}
|
|
812
|
+
|
|
813
|
+
# Add optional parameters if provided
|
|
814
|
+
if db_instance_type:
|
|
815
|
+
params['dbInstanceType'] = db_instance_type
|
|
816
|
+
if db_parameter_group_identifier:
|
|
817
|
+
params['dbParameterGroupIdentifier'] = db_parameter_group_identifier
|
|
818
|
+
if port:
|
|
819
|
+
params['port'] = str(port)
|
|
820
|
+
if failover_mode:
|
|
821
|
+
params['failoverMode'] = failover_mode
|
|
822
|
+
if log_delivery_configuration:
|
|
823
|
+
params['logDeliveryConfiguration'] = str(log_delivery_configuration)
|
|
824
|
+
|
|
825
|
+
try:
|
|
826
|
+
response = ts_influx_client.update_db_cluster(**params)
|
|
827
|
+
return response
|
|
828
|
+
except Exception as e:
|
|
829
|
+
logger.error(f'Error updating DB cluster: {str(e)}')
|
|
830
|
+
raise e
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
@mcp.tool(name='UpdateDbInstance', description='Updates a Timestream for InfluxDB DB instance.')
|
|
834
|
+
async def update_db_instance(
|
|
835
|
+
identifier: str = REQUIRED_FIELD_DB_INSTANCE_IDENTIFIER,
|
|
836
|
+
db_instance_type: Optional[str] = OPTIONAL_FIELD_DB_INSTANCE_TYPE_CLUSTER_UPDATE,
|
|
837
|
+
db_parameter_group_identifier: Optional[str] = OPTIONAL_FIELD_DB_PARAMETER_GROUP_ID,
|
|
838
|
+
port: Optional[int] = OPTIONAL_FIELD_PORT,
|
|
839
|
+
allocated_storage_gb: Optional[int] = OPTIONAL_FIELD_ALLOCATED_STORAGE_GB_OPTIONAL,
|
|
840
|
+
db_storage_type: Optional[str] = OPTIONAL_FIELD_DB_STORAGE_TYPE,
|
|
841
|
+
deployment_type: Optional[str] = OPTIONAL_FIELD_DEPLOYMENT_TYPE_INSTANCE,
|
|
842
|
+
log_delivery_configuration: Optional[
|
|
843
|
+
Dict[str, Any]
|
|
844
|
+
] = OPTIONAL_FIELD_LOG_DELIVERY_CONFIGURATION,
|
|
845
|
+
tool_write_mode: bool = OPTIONAL_FIELD_TOOL_WRITE_MODE,
|
|
846
|
+
) -> Dict[str, Any]:
|
|
847
|
+
"""Updates a Timestream for InfluxDB DB instance.
|
|
848
|
+
|
|
849
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_UpdateDbInstance.html
|
|
850
|
+
|
|
851
|
+
Returns:
|
|
852
|
+
Details of the updated DB instance.
|
|
853
|
+
"""
|
|
854
|
+
if not tool_write_mode:
|
|
855
|
+
raise Exception(
|
|
856
|
+
'UpdateDbInstance tool invocation not allowed when tool-write-mode is set to False'
|
|
857
|
+
)
|
|
858
|
+
|
|
859
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
860
|
+
|
|
861
|
+
# Required parameters
|
|
862
|
+
params = {'identifier': identifier}
|
|
863
|
+
|
|
864
|
+
# Add optional parameters if provided
|
|
865
|
+
if db_instance_type:
|
|
866
|
+
params['dbInstanceType'] = db_instance_type
|
|
867
|
+
if db_parameter_group_identifier:
|
|
868
|
+
params['dbParameterGroupIdentifier'] = db_parameter_group_identifier
|
|
869
|
+
if port:
|
|
870
|
+
params['port'] = str(port)
|
|
871
|
+
if allocated_storage_gb:
|
|
872
|
+
params['allocatedStorage'] = str(allocated_storage_gb)
|
|
873
|
+
if db_storage_type:
|
|
874
|
+
params['dbStorageType'] = db_storage_type
|
|
875
|
+
if deployment_type:
|
|
876
|
+
params['deploymentType'] = deployment_type
|
|
877
|
+
if log_delivery_configuration:
|
|
878
|
+
params['logDeliveryConfiguration'] = str(log_delivery_configuration)
|
|
879
|
+
|
|
880
|
+
try:
|
|
881
|
+
response = ts_influx_client.update_db_instance(**params)
|
|
882
|
+
return response
|
|
883
|
+
except Exception as e:
|
|
884
|
+
logger.error(f'Error updating DB instance: {str(e)}')
|
|
885
|
+
raise e
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
@mcp.tool(
|
|
889
|
+
name='LsInstancesByStatus',
|
|
890
|
+
description='Returns a list of Timestream for InfluxDB DB instances filtered by status (case-insensitive).',
|
|
891
|
+
)
|
|
892
|
+
async def list_db_instances_by_status(
|
|
893
|
+
status: str = REQUIRED_FIELD_STATUS,
|
|
894
|
+
) -> Dict[str, Any]:
|
|
895
|
+
"""Returns a list of Timestream for InfluxDB DB instances filtered by status (case-insensitive).
|
|
896
|
+
|
|
897
|
+
This tool paginates through all DB instances and filters them by the provided status
|
|
898
|
+
in a case-insensitive manner.
|
|
899
|
+
|
|
900
|
+
Returns:
|
|
901
|
+
A list of Timestream for InfluxDB DB instance summaries matching the specified status.
|
|
902
|
+
"""
|
|
903
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
904
|
+
|
|
905
|
+
# Convert status to lowercase for case-insensitive comparison
|
|
906
|
+
status_lower = status.lower()
|
|
907
|
+
|
|
908
|
+
# Initialize variables for pagination
|
|
909
|
+
next_token = None
|
|
910
|
+
filtered_instances = []
|
|
911
|
+
|
|
912
|
+
try:
|
|
913
|
+
# Paginate through all instances
|
|
914
|
+
while True:
|
|
915
|
+
# Prepare parameters for the API call
|
|
916
|
+
params = {}
|
|
917
|
+
if next_token:
|
|
918
|
+
params['nextToken'] = next_token
|
|
919
|
+
|
|
920
|
+
# Call the ListDbInstances API
|
|
921
|
+
response = ts_influx_client.list_db_instances(**params)
|
|
922
|
+
|
|
923
|
+
# Filter instances by status (case-insensitive)
|
|
924
|
+
if 'items' in response:
|
|
925
|
+
for instance in response['items']:
|
|
926
|
+
if (
|
|
927
|
+
'status' in instance
|
|
928
|
+
and instance['status'] is not None
|
|
929
|
+
and instance['status'].lower() == status_lower
|
|
930
|
+
):
|
|
931
|
+
filtered_instances.append(instance)
|
|
932
|
+
|
|
933
|
+
# Check if there are more results to fetch
|
|
934
|
+
if 'nextToken' in response and response['nextToken']:
|
|
935
|
+
next_token = response['nextToken']
|
|
936
|
+
else:
|
|
937
|
+
# No more results to fetch
|
|
938
|
+
break
|
|
939
|
+
|
|
940
|
+
# Prepare the response
|
|
941
|
+
result = {'items': filtered_instances, 'count': len(filtered_instances)}
|
|
942
|
+
|
|
943
|
+
return result
|
|
944
|
+
except Exception as e:
|
|
945
|
+
logger.error(f'Error listing DB instances by status: {str(e)}')
|
|
946
|
+
raise e
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
@mcp.tool(
|
|
950
|
+
name='ListClustersByStatus',
|
|
951
|
+
description='Returns a list of Timestream for InfluxDB DB clusters filtered by status (case-insensitive).',
|
|
952
|
+
)
|
|
953
|
+
async def list_db_clusters_by_status(
|
|
954
|
+
status: str = REQUIRED_FIELD_STATUS_CLUSTER,
|
|
955
|
+
) -> Dict[str, Any]:
|
|
956
|
+
"""Returns a list of Timestream for InfluxDB DB clusters filtered by status (case-insensitive).
|
|
957
|
+
|
|
958
|
+
This tool paginates through all DB clusters and filters them by the provided status
|
|
959
|
+
in a case-insensitive manner.
|
|
960
|
+
|
|
961
|
+
Returns:
|
|
962
|
+
A list of Timestream for InfluxDB DB cluster summaries matching the specified status.
|
|
963
|
+
"""
|
|
964
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
965
|
+
|
|
966
|
+
# Convert status to lowercase for case-insensitive comparison
|
|
967
|
+
status_lower = status.lower()
|
|
968
|
+
|
|
969
|
+
# Initialize variables for pagination
|
|
970
|
+
next_token = None
|
|
971
|
+
filtered_clusters = []
|
|
972
|
+
|
|
973
|
+
try:
|
|
974
|
+
# Paginate through all clusters
|
|
975
|
+
while True:
|
|
976
|
+
# Prepare parameters for the API call
|
|
977
|
+
params = {}
|
|
978
|
+
if next_token:
|
|
979
|
+
params['nextToken'] = next_token
|
|
980
|
+
|
|
981
|
+
# Call the ListDbClusters API
|
|
982
|
+
response = ts_influx_client.list_db_clusters(**params)
|
|
983
|
+
|
|
984
|
+
# Filter clusters by status (case-insensitive)
|
|
985
|
+
if 'items' in response:
|
|
986
|
+
for cluster in response['items']:
|
|
987
|
+
if (
|
|
988
|
+
'status' in cluster
|
|
989
|
+
and cluster['status'] is not None
|
|
990
|
+
and cluster['status'].lower() == status_lower
|
|
991
|
+
):
|
|
992
|
+
filtered_clusters.append(cluster)
|
|
993
|
+
|
|
994
|
+
# Check if there are more results to fetch
|
|
995
|
+
if 'nextToken' in response and response['nextToken']:
|
|
996
|
+
next_token = response['nextToken']
|
|
997
|
+
else:
|
|
998
|
+
# No more results to fetch
|
|
999
|
+
break
|
|
1000
|
+
|
|
1001
|
+
# Prepare the response
|
|
1002
|
+
result = {'items': filtered_clusters, 'count': len(filtered_clusters)}
|
|
1003
|
+
|
|
1004
|
+
return result
|
|
1005
|
+
except Exception as e:
|
|
1006
|
+
logger.error(f'Error listing DB clusters by status: {str(e)}')
|
|
1007
|
+
raise e
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
@mcp.tool(
|
|
1011
|
+
name='CreateDbParamGroup',
|
|
1012
|
+
description='Creates a new Timestream for InfluxDB DB parameter group to associate with DB instances.',
|
|
1013
|
+
)
|
|
1014
|
+
async def create_db_parameter_group(
|
|
1015
|
+
name: str = REQUIRED_FIELD_PARAM_GROUP_NAME,
|
|
1016
|
+
tool_write_mode: bool = OPTIONAL_FIELD_TOOL_WRITE_MODE,
|
|
1017
|
+
description: Optional[str] = OPTIONAL_FIELD_PARAM_GROUP_DESCRIPTION,
|
|
1018
|
+
parameters: Optional[Dict[str, Any]] = OPTIONAL_FIELD_PARAMETERS,
|
|
1019
|
+
tags: Optional[Dict[str, str]] = OPTIONAL_FIELD_TAGS,
|
|
1020
|
+
) -> Dict[str, Any]:
|
|
1021
|
+
"""Creates a new Timestream for InfluxDB DB parameter group to associate with DB instances.
|
|
1022
|
+
|
|
1023
|
+
API reference: https://docs.aws.amazon.com/ts-influxdb/latest/ts-influxdb-api/API_CreateDbParameterGroup.html
|
|
1024
|
+
|
|
1025
|
+
Returns:
|
|
1026
|
+
Details of the created DB parameter group.
|
|
1027
|
+
"""
|
|
1028
|
+
if not tool_write_mode:
|
|
1029
|
+
raise Exception(
|
|
1030
|
+
'CreateDbParamGroup tool invocation not allowed when tool-write-mode is set to False'
|
|
1031
|
+
)
|
|
1032
|
+
|
|
1033
|
+
ts_influx_client = get_timestream_influxdb_client()
|
|
1034
|
+
|
|
1035
|
+
# Required parameters
|
|
1036
|
+
params = {'name': name}
|
|
1037
|
+
|
|
1038
|
+
# Add optional parameters if provided
|
|
1039
|
+
if description:
|
|
1040
|
+
params['description'] = description
|
|
1041
|
+
if parameters:
|
|
1042
|
+
params['parameters'] = str(parameters)
|
|
1043
|
+
if tags:
|
|
1044
|
+
tag_list = [{'Key': k, 'Value': v} for k, v in tags.items()]
|
|
1045
|
+
params['tags'] = str(tag_list)
|
|
1046
|
+
|
|
1047
|
+
try:
|
|
1048
|
+
response = ts_influx_client.create_db_parameter_group(**params)
|
|
1049
|
+
return response
|
|
1050
|
+
except Exception as e:
|
|
1051
|
+
logger.error(f'Error creating DB parameter group: {str(e)}')
|
|
1052
|
+
raise e
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
@mcp.tool(name='InfluxDBWritePoints', description='Write data points to InfluxDB endpoint.')
|
|
1056
|
+
async def influxdb_write_points(
|
|
1057
|
+
url: str = REQUIRED_FIELD_URL,
|
|
1058
|
+
token: str = REQUIRED_FIELD_TOKEN,
|
|
1059
|
+
bucket: str = REQUIRED_FIELD_BUCKET,
|
|
1060
|
+
org: str = REQUIRED_FIELD_ORG,
|
|
1061
|
+
points: List[Dict[str, Any]] = REQUIRED_FIELD_POINTS,
|
|
1062
|
+
time_precision: str = OPTIONAL_FIELD_WRITE_PRECISION,
|
|
1063
|
+
sync_mode: Optional[str] = OPTIONAL_FIELD_SYNC_MODE,
|
|
1064
|
+
verify_ssl: bool = OPTIONAL_FIELD_VERIFY_SSL,
|
|
1065
|
+
tool_write_mode: bool = OPTIONAL_FIELD_TOOL_WRITE_MODE,
|
|
1066
|
+
) -> Dict[str, Any]:
|
|
1067
|
+
"""Write data points to InfluxDB.
|
|
1068
|
+
|
|
1069
|
+
Example of points:
|
|
1070
|
+
[
|
|
1071
|
+
{
|
|
1072
|
+
"measurement": "my_measurement",
|
|
1073
|
+
"tags": {"location": "Prague"},
|
|
1074
|
+
"fields": {"temperature": 25.3}
|
|
1075
|
+
"time": "2025-06-06T19:00:00Z"
|
|
1076
|
+
}
|
|
1077
|
+
]
|
|
1078
|
+
|
|
1079
|
+
Returns:
|
|
1080
|
+
Status of the write operation.
|
|
1081
|
+
"""
|
|
1082
|
+
if not tool_write_mode:
|
|
1083
|
+
raise Exception(
|
|
1084
|
+
'InfluxDBWritePoints tool invocation not allowed when tool-write-mode is set to False'
|
|
1085
|
+
)
|
|
1086
|
+
|
|
1087
|
+
try:
|
|
1088
|
+
client = get_influxdb_client(url, token, org, verify_ssl)
|
|
1089
|
+
|
|
1090
|
+
# Set write mode
|
|
1091
|
+
if sync_mode and sync_mode.lower() == 'synchronous':
|
|
1092
|
+
write_api = client.write_api(write_options=SYNCHRONOUS)
|
|
1093
|
+
else:
|
|
1094
|
+
write_api = client.write_api(write_options=ASYNCHRONOUS)
|
|
1095
|
+
|
|
1096
|
+
# Convert dictionary points to Point objects
|
|
1097
|
+
influx_points = []
|
|
1098
|
+
for p in points:
|
|
1099
|
+
point = Point(p['measurement'])
|
|
1100
|
+
|
|
1101
|
+
# Add tags
|
|
1102
|
+
if 'tags' in p:
|
|
1103
|
+
for tag_key, tag_value in p['tags'].items():
|
|
1104
|
+
point = point.tag(tag_key, tag_value)
|
|
1105
|
+
|
|
1106
|
+
# Add fields
|
|
1107
|
+
if 'fields' in p:
|
|
1108
|
+
for field_key, field_value in p['fields'].items():
|
|
1109
|
+
point = point.field(field_key, field_value)
|
|
1110
|
+
|
|
1111
|
+
# Add time if provided
|
|
1112
|
+
if 'time' in p:
|
|
1113
|
+
point = point.time(p['time'])
|
|
1114
|
+
|
|
1115
|
+
influx_points.append(point)
|
|
1116
|
+
|
|
1117
|
+
# Write points
|
|
1118
|
+
write_api.write(
|
|
1119
|
+
bucket=bucket,
|
|
1120
|
+
org=org,
|
|
1121
|
+
record=influx_points,
|
|
1122
|
+
write_precision=getattr(WritePrecision, time_precision.upper()),
|
|
1123
|
+
verify_ssl=verify_ssl,
|
|
1124
|
+
)
|
|
1125
|
+
|
|
1126
|
+
# Close client
|
|
1127
|
+
client.close()
|
|
1128
|
+
|
|
1129
|
+
return {
|
|
1130
|
+
'status': 'success',
|
|
1131
|
+
'message': f'Successfully wrote {len(points)} points to InfluxDB',
|
|
1132
|
+
}
|
|
1133
|
+
except Exception as e:
|
|
1134
|
+
logger.error(f'Error writing points to InfluxDB: {str(e)}')
|
|
1135
|
+
return {'status': 'error', 'message': str(e)}
|
|
1136
|
+
|
|
1137
|
+
|
|
1138
|
+
@mcp.tool(name='InfluxDBWriteLP', description='Write data in Line Protocol format to InfluxDB.')
|
|
1139
|
+
async def influxdb_write_line_protocol(
|
|
1140
|
+
url: str = REQUIRED_FIELD_URL,
|
|
1141
|
+
token: str = REQUIRED_FIELD_TOKEN,
|
|
1142
|
+
bucket: str = REQUIRED_FIELD_BUCKET,
|
|
1143
|
+
org: str = REQUIRED_FIELD_ORG,
|
|
1144
|
+
data_line_protocol: str = REQUIRED_FIELD_DATA_LINE_PROTOCOL,
|
|
1145
|
+
time_precision: str = OPTIONAL_FIELD_WRITE_PRECISION,
|
|
1146
|
+
sync_mode: str = OPTIONAL_FIELD_SYNC_MODE,
|
|
1147
|
+
verify_ssl: bool = OPTIONAL_FIELD_VERIFY_SSL,
|
|
1148
|
+
tool_write_mode: bool = OPTIONAL_FIELD_TOOL_WRITE_MODE,
|
|
1149
|
+
) -> Dict[str, Any]:
|
|
1150
|
+
"""Write data in Line Protocol format to InfluxDB.
|
|
1151
|
+
|
|
1152
|
+
Returns:
|
|
1153
|
+
Status of the write operation.
|
|
1154
|
+
"""
|
|
1155
|
+
if not tool_write_mode:
|
|
1156
|
+
raise Exception(
|
|
1157
|
+
'InfluxDBWriteLineProtocol tool invocation not allowed when tool-write-mode is set to False'
|
|
1158
|
+
)
|
|
1159
|
+
|
|
1160
|
+
try:
|
|
1161
|
+
client = get_influxdb_client(url, token, org)
|
|
1162
|
+
|
|
1163
|
+
# Set write mode
|
|
1164
|
+
if sync_mode and sync_mode.lower() == 'synchronous':
|
|
1165
|
+
write_api = client.write_api(write_options=SYNCHRONOUS)
|
|
1166
|
+
else:
|
|
1167
|
+
write_api = client.write_api(write_options=ASYNCHRONOUS)
|
|
1168
|
+
|
|
1169
|
+
# Write line protocol
|
|
1170
|
+
write_api.write(
|
|
1171
|
+
bucket=bucket,
|
|
1172
|
+
org=org,
|
|
1173
|
+
record=data_line_protocol,
|
|
1174
|
+
write_precision=getattr(WritePrecision, time_precision.upper()),
|
|
1175
|
+
verify_ssl=verify_ssl,
|
|
1176
|
+
)
|
|
1177
|
+
|
|
1178
|
+
# Close client
|
|
1179
|
+
client.close()
|
|
1180
|
+
|
|
1181
|
+
return {
|
|
1182
|
+
'status': 'success',
|
|
1183
|
+
'message': 'Successfully wrote line protocol data to InfluxDB',
|
|
1184
|
+
}
|
|
1185
|
+
except Exception as e:
|
|
1186
|
+
logger.error(f'Error writing line protocol to InfluxDB: {str(e)}')
|
|
1187
|
+
return {'status': 'error', 'message': str(e)}
|
|
1188
|
+
|
|
1189
|
+
|
|
1190
|
+
@mcp.tool(name='InfluxDBQuery', description='Query data from InfluxDB using Flux query language.')
|
|
1191
|
+
async def influxdb_query(
|
|
1192
|
+
url: str = REQUIRED_FIELD_URL,
|
|
1193
|
+
token: str = REQUIRED_FIELD_TOKEN,
|
|
1194
|
+
org: str = REQUIRED_FIELD_ORG,
|
|
1195
|
+
query: str = REQUIRED_FIELD_QUERY,
|
|
1196
|
+
verify_ssl: bool = OPTIONAL_FIELD_VERIFY_SSL,
|
|
1197
|
+
) -> Dict[str, Any]:
|
|
1198
|
+
"""Query data from InfluxDB using Flux query language.
|
|
1199
|
+
|
|
1200
|
+
Returns:
|
|
1201
|
+
Query results in the specified format.
|
|
1202
|
+
"""
|
|
1203
|
+
try:
|
|
1204
|
+
client = get_influxdb_client(url, token, org, verify_ssl)
|
|
1205
|
+
query_api = client.query_api()
|
|
1206
|
+
|
|
1207
|
+
# Return as JSON
|
|
1208
|
+
tables = query_api.query(org=org, query=query)
|
|
1209
|
+
|
|
1210
|
+
# Process the tables into a more usable format
|
|
1211
|
+
result = []
|
|
1212
|
+
for table in tables:
|
|
1213
|
+
for record in table.records:
|
|
1214
|
+
result.append(
|
|
1215
|
+
{
|
|
1216
|
+
'measurement': record.get_measurement(),
|
|
1217
|
+
'field': record.get_field(),
|
|
1218
|
+
'value': record.get_value(),
|
|
1219
|
+
'time': record.get_time().isoformat() if record.get_time() else None,
|
|
1220
|
+
'tags': record.values.get('tags', {}),
|
|
1221
|
+
}
|
|
1222
|
+
)
|
|
1223
|
+
|
|
1224
|
+
client.close()
|
|
1225
|
+
return {'status': 'success', 'result': result, 'format': 'json'}
|
|
1226
|
+
|
|
1227
|
+
except Exception as e:
|
|
1228
|
+
logger.error(f'Error querying InfluxDB: {str(e)}')
|
|
1229
|
+
return {'status': 'error', 'message': str(e)}
|
|
1230
|
+
|
|
1231
|
+
|
|
1232
|
+
def main():
|
|
1233
|
+
"""Main entry point for the MCP server application."""
|
|
1234
|
+
logger.info('Starting Timestream for InfluxDB MCP Server')
|
|
1235
|
+
mcp.run()
|
|
1236
|
+
|
|
1237
|
+
|
|
1238
|
+
if __name__ == '__main__':
|
|
1239
|
+
main()
|