awslabs.cloudwatch-mcp-server 0.0.13__tar.gz → 0.0.15__tar.gz

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.
Files changed (48) hide show
  1. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/PKG-INFO +2 -2
  2. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/__init__.py +1 -0
  3. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/__init__.py +2 -1
  4. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/cloudwatch_metrics/tools.py +12 -2
  5. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/pyproject.toml +2 -2
  6. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_metrics/test_metrics_server.py +107 -3
  7. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/uv.lock +38 -20
  8. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/.gitignore +0 -0
  9. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/.python-version +0 -0
  10. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/CHANGELOG.md +0 -0
  11. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/Dockerfile +0 -0
  12. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/LICENSE +0 -0
  13. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/NOTICE +0 -0
  14. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/README.md +0 -0
  15. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/cloudwatch_alarms/models.py +0 -0
  16. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/cloudwatch_alarms/tools.py +0 -0
  17. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/cloudwatch_logs/models.py +0 -0
  18. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/cloudwatch_logs/tools.py +0 -0
  19. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/cloudwatch_metrics/cloudformation_template_generator.py +0 -0
  20. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/cloudwatch_metrics/constants.py +0 -0
  21. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/cloudwatch_metrics/data/metric_metadata.json +0 -0
  22. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/cloudwatch_metrics/metric_analyzer.py +0 -0
  23. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/cloudwatch_metrics/metric_data_decomposer.py +0 -0
  24. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/cloudwatch_metrics/models.py +0 -0
  25. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/common.py +0 -0
  26. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/awslabs/cloudwatch_mcp_server/server.py +0 -0
  27. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/docker-healthcheck.sh +0 -0
  28. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_alarms/test_active_alarms.py +0 -0
  29. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_alarms/test_alarm_history.py +0 -0
  30. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_alarms/test_alarm_history_integration.py +0 -0
  31. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_alarms/test_alarms_error_handling.py +0 -0
  32. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_logs/test_logs_error_handling.py +0 -0
  33. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_logs/test_logs_models.py +0 -0
  34. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_logs/test_logs_server.py +0 -0
  35. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_metrics/test_analyze_metric.py +0 -0
  36. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_metrics/test_cloudformation_template_generator.py +0 -0
  37. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_metrics/test_decomposer_trend.py +0 -0
  38. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_metrics/test_metric_analyzer.py +0 -0
  39. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_metrics/test_metrics_error_handling.py +0 -0
  40. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_metrics/test_metrics_models.py +0 -0
  41. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_metrics/test_seasonal_detector.py +0 -0
  42. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_metrics/test_seasonality_enum.py +0 -0
  43. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_metrics/test_utils.py +0 -0
  44. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/cloudwatch_metrics/test_validation_error.py +0 -0
  45. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/test_common_and_server.py +0 -0
  46. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/test_init.py +0 -0
  47. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/tests/test_main.py +0 -0
  48. {awslabs_cloudwatch_mcp_server-0.0.13 → awslabs_cloudwatch_mcp_server-0.0.15}/uv-requirements.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: awslabs.cloudwatch-mcp-server
3
- Version: 0.0.13
3
+ Version: 0.0.15
4
4
  Summary: An AWS Labs Model Context Protocol (MCP) server for cloudwatch
5
5
  Project-URL: homepage, https://awslabs.github.io/mcp/
6
6
  Project-URL: docs, https://awslabs.github.io/mcp/servers/cloudwatch-mcp-server/
@@ -23,7 +23,7 @@ Classifier: Programming Language :: Python :: 3.13
23
23
  Requires-Python: >=3.10
24
24
  Requires-Dist: boto3>=1.38.22
25
25
  Requires-Dist: loguru>=0.7.0
26
- Requires-Dist: mcp[cli]>=1.11.0
26
+ Requires-Dist: mcp[cli]>=1.23.0
27
27
  Requires-Dist: numpy>=2.0.0
28
28
  Requires-Dist: pandas>=2.2.3
29
29
  Requires-Dist: pydantic>=2.10.6
@@ -14,3 +14,4 @@
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
+ __path__ = __import__('pkgutil').extend_path(__path__, __name__)
@@ -14,4 +14,5 @@
14
14
 
15
15
  """awslabs.cloudwatch-mcp-server"""
16
16
 
17
- MCP_SERVER_VERSION = '0.0.12'
17
+ __version__ = '0.0.15'
18
+ MCP_SERVER_VERSION = __version__
@@ -162,7 +162,10 @@ class CloudWatchMetricsTools:
162
162
  ctx: Context,
163
163
  namespace: str,
164
164
  metric_name: str,
165
- start_time: Union[str, datetime],
165
+ start_time: Annotated[
166
+ Union[str, datetime],
167
+ Field(description='The start time for the metric data query (ISO format or datetime)'),
168
+ ],
166
169
  dimensions: List[Dimension] = [],
167
170
  end_time: Annotated[
168
171
  Union[str, datetime] | None,
@@ -390,10 +393,17 @@ class CloudWatchMetricsTools:
390
393
  start_time = datetime.fromisoformat(start_time.replace('Z', '+00:00'))
391
394
 
392
395
  if end_time is None:
393
- end_time = datetime.utcnow()
396
+ end_time = datetime.now(timezone.utc)
394
397
  elif isinstance(end_time, str):
395
398
  end_time = datetime.fromisoformat(end_time.replace('Z', '+00:00'))
396
399
 
400
+ # Ensure both datetimes have timezone info for correct datetime arithmetic afterwards.
401
+ # This avoids issues when datetime is passed as naive values (without timezone)
402
+ if start_time.tzinfo is None:
403
+ start_time = start_time.replace(tzinfo=timezone.utc)
404
+ if end_time.tzinfo is None:
405
+ end_time = end_time.replace(tzinfo=timezone.utc)
406
+
397
407
  # Calculate period based on time window and target datapoints
398
408
  time_window_seconds = int((end_time - start_time).total_seconds())
399
409
  calculated_period = max(60, int(time_window_seconds / target_datapoints))
@@ -1,13 +1,13 @@
1
1
  [project]
2
2
  name = "awslabs.cloudwatch-mcp-server"
3
- version = "0.0.13"
3
+ version = "0.0.15"
4
4
  description = "An AWS Labs Model Context Protocol (MCP) server for cloudwatch"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
7
7
  dependencies = [
8
8
  "boto3>=1.38.22",
9
9
  "loguru>=0.7.0",
10
- "mcp[cli]>=1.11.0",
10
+ "mcp[cli]>=1.23.0",
11
11
  "pydantic>=2.10.6",
12
12
  "numpy>=2.0.0",
13
13
  "pandas>=2.2.3",
@@ -23,7 +23,7 @@ from awslabs.cloudwatch_mcp_server.cloudwatch_metrics.models import (
23
23
  StaticAlarmThreshold,
24
24
  )
25
25
  from awslabs.cloudwatch_mcp_server.cloudwatch_metrics.tools import CloudWatchMetricsTools
26
- from datetime import datetime
26
+ from datetime import datetime, timezone
27
27
  from moto import mock_aws
28
28
  from typing import Any
29
29
  from unittest.mock import AsyncMock, MagicMock, patch
@@ -116,8 +116,9 @@ class TestGetMetricData:
116
116
  == 'CPUUtilization'
117
117
  )
118
118
  assert call_args['MetricDataQueries'][0]['MetricStat']['Stat'] == 'Average'
119
- assert call_args['StartTime'] == start_time
120
- assert call_args['EndTime'] == end_time
119
+
120
+ assert call_args['StartTime'] == start_time.replace(tzinfo=timezone.utc)
121
+ assert call_args['EndTime'] == end_time.replace(tzinfo=timezone.utc)
121
122
  assert isinstance(result, GetMetricDataResponse)
122
123
  assert len(result.metricDataResults) == 1
123
124
  assert result.metricDataResults[0].label == 'CPUUtilization'
@@ -504,6 +505,109 @@ class TestGetMetricData:
504
505
  ctx.error.assert_called_once()
505
506
  assert 'Test exception' in ctx.error.call_args[0][0]
506
507
 
508
+ @pytest.mark.parametrize(
509
+ 'start_time,end_time,test_description',
510
+ [
511
+ # Timezone-aware start, no end (defaults to now)
512
+ (
513
+ '2023-01-01T00:00:00+00:00',
514
+ None,
515
+ 'timezone-aware start_time with None end_time (defaults to now)',
516
+ ),
517
+ # Both timezone-aware
518
+ (
519
+ '2023-01-01T00:00:00+00:00',
520
+ '2023-01-01T01:00:00+00:00',
521
+ 'both timezone-aware (ISO strings)',
522
+ ),
523
+ # Both naive datetime objects
524
+ (
525
+ datetime(2023, 1, 1, 0, 0, 0),
526
+ datetime(2023, 1, 1, 1, 0, 0),
527
+ 'both naive datetime objects',
528
+ ),
529
+ # Timezone-aware datetime objects
530
+ (
531
+ datetime(2023, 1, 1, 0, 0, 0, tzinfo=__import__('datetime').timezone.utc),
532
+ datetime(2023, 1, 1, 1, 0, 0, tzinfo=__import__('datetime').timezone.utc),
533
+ 'both timezone-aware datetime objects',
534
+ ),
535
+ # Mixed: naive start, timezone-aware end (ISO string)
536
+ (
537
+ datetime(2023, 1, 1, 0, 0, 0),
538
+ '2023-01-01T01:00:00+00:00',
539
+ 'naive datetime start with timezone-aware ISO string end',
540
+ ),
541
+ # Mixed: timezone-aware start (ISO string), naive end
542
+ (
543
+ '2023-01-01T00:00:00+00:00',
544
+ datetime(2023, 1, 1, 1, 0, 0),
545
+ 'timezone-aware ISO string start with naive datetime end',
546
+ ),
547
+ # Naive start, no end
548
+ (
549
+ datetime(2023, 1, 1, 0, 0, 0),
550
+ None,
551
+ 'naive datetime start with None end_time',
552
+ ),
553
+ # Different timezone offsets
554
+ (
555
+ '2023-01-01T00:00:00-05:00',
556
+ '2023-01-01T06:00:00+00:00',
557
+ 'different timezone offsets (EST and UTC)',
558
+ ),
559
+ # ISO string with Z notation
560
+ (
561
+ '2023-01-01T00:00:00Z',
562
+ '2023-01-01T01:00:00Z',
563
+ 'ISO strings with Z notation',
564
+ ),
565
+ ],
566
+ )
567
+ async def test_get_metric_data_with_various_datetime_formats(
568
+ self, ctx, cloudwatch_metrics_tools, start_time, end_time, test_description
569
+ ):
570
+ """Parametrized test for various datetime format combinations.
571
+
572
+ Tests all combinations of:
573
+ - Timezone-aware vs naive datetimes
574
+ - ISO strings vs datetime objects
575
+ - With and without end_time (None defaults to now)
576
+ - Different timezone offsets
577
+
578
+ This ensures the fix for timezone handling works correctly in all scenarios.
579
+ """
580
+ mock_client = MagicMock()
581
+ mock_client.get_metric_data.return_value = {
582
+ 'MetricDataResults': [
583
+ {
584
+ 'Id': 'm1',
585
+ 'Label': 'CPUUtilization',
586
+ 'StatusCode': 'Complete',
587
+ 'Timestamps': [datetime(2023, 1, 1, 0, 0, 0, tzinfo=timezone.utc)],
588
+ 'Values': [10.5],
589
+ }
590
+ ],
591
+ }
592
+
593
+ with patch.object(
594
+ cloudwatch_metrics_tools, '_get_cloudwatch_client', return_value=mock_client
595
+ ):
596
+ result = await cloudwatch_metrics_tools.get_metric_data(
597
+ ctx,
598
+ namespace='AWS/EC2',
599
+ metric_name='CPUUtilization',
600
+ start_time=start_time,
601
+ end_time=end_time,
602
+ dimensions=[Dimension(name='InstanceId', value='i-1234567890abcdef0')],
603
+ statistic='AVG',
604
+ target_datapoints=60,
605
+ )
606
+
607
+ # Should not raise an error and should return valid response
608
+ assert isinstance(result, GetMetricDataResponse), f'Failed for: {test_description}'
609
+ assert len(result.metricDataResults) == 1, f'Failed for: {test_description}'
610
+
507
611
  async def test_get_metric_metadata_found(self, ctx, cloudwatch_metrics_tools):
508
612
  """Test getting metric metadata for existing metric."""
509
613
  result = await cloudwatch_metrics_tools.get_metric_metadata(
@@ -51,7 +51,7 @@ wheels = [
51
51
 
52
52
  [[package]]
53
53
  name = "awslabs-cloudwatch-mcp-server"
54
- version = "0.0.13"
54
+ version = "0.0.15"
55
55
  source = { editable = "." }
56
56
  dependencies = [
57
57
  { name = "boto3" },
@@ -81,7 +81,7 @@ dev = [
81
81
  requires-dist = [
82
82
  { name = "boto3", specifier = ">=1.38.22" },
83
83
  { name = "loguru", specifier = ">=0.7.0" },
84
- { name = "mcp", extras = ["cli"], specifier = ">=1.11.0" },
84
+ { name = "mcp", extras = ["cli"], specifier = ">=1.23.0" },
85
85
  { name = "numpy", specifier = ">=2.0.0" },
86
86
  { name = "pandas", specifier = ">=2.2.3" },
87
87
  { name = "pydantic", specifier = ">=2.10.6" },
@@ -452,11 +452,11 @@ wheels = [
452
452
 
453
453
  [[package]]
454
454
  name = "filelock"
455
- version = "3.18.0"
455
+ version = "3.20.1"
456
456
  source = { registry = "https://pypi.org/simple" }
457
- sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" }
457
+ sdist = { url = "https://files.pythonhosted.org/packages/a7/23/ce7a1126827cedeb958fc043d61745754464eb56c5937c35bbf2b8e26f34/filelock-3.20.1.tar.gz", hash = "sha256:b8360948b351b80f420878d8516519a2204b07aefcdcfd24912a5d33127f188c", size = 19476, upload-time = "2025-12-15T23:54:28.027Z" }
458
458
  wheels = [
459
- { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" },
459
+ { url = "https://files.pythonhosted.org/packages/e3/7f/a1a97644e39e7316d850784c642093c99df1290a460df4ede27659056834/filelock-3.20.1-py3-none-any.whl", hash = "sha256:15d9e9a67306188a44baa72f569d2bfd803076269365fdea0934385da4dc361a", size = 16666, upload-time = "2025-12-15T23:54:26.874Z" },
460
460
  ]
461
461
 
462
462
  [[package]]
@@ -665,7 +665,7 @@ wheels = [
665
665
 
666
666
  [[package]]
667
667
  name = "mcp"
668
- version = "1.11.0"
668
+ version = "1.23.3"
669
669
  source = { registry = "https://pypi.org/simple" }
670
670
  dependencies = [
671
671
  { name = "anyio" },
@@ -674,15 +674,18 @@ dependencies = [
674
674
  { name = "jsonschema" },
675
675
  { name = "pydantic" },
676
676
  { name = "pydantic-settings" },
677
+ { name = "pyjwt", extra = ["crypto"] },
677
678
  { name = "python-multipart" },
678
679
  { name = "pywin32", marker = "sys_platform == 'win32'" },
679
680
  { name = "sse-starlette" },
680
681
  { name = "starlette" },
682
+ { name = "typing-extensions" },
683
+ { name = "typing-inspection" },
681
684
  { name = "uvicorn", marker = "sys_platform != 'emscripten'" },
682
685
  ]
683
- sdist = { url = "https://files.pythonhosted.org/packages/3a/f5/9506eb5578d5bbe9819ee8ba3198d0ad0e2fbe3bab8b257e4131ceb7dfb6/mcp-1.11.0.tar.gz", hash = "sha256:49a213df56bb9472ff83b3132a4825f5c8f5b120a90246f08b0dac6bedac44c8", size = 406907, upload-time = "2025-07-10T16:41:09.388Z" }
686
+ sdist = { url = "https://files.pythonhosted.org/packages/a7/a4/d06a303f45997e266f2c228081abe299bbcba216cb806128e2e49095d25f/mcp-1.23.3.tar.gz", hash = "sha256:b3b0da2cc949950ce1259c7bfc1b081905a51916fcd7c8182125b85e70825201", size = 600697, upload-time = "2025-12-09T16:04:37.351Z" }
684
687
  wheels = [
685
- { url = "https://files.pythonhosted.org/packages/92/9c/c9ca79f9c512e4113a5d07043013110bb3369fc7770040c61378c7fbcf70/mcp-1.11.0-py3-none-any.whl", hash = "sha256:58deac37f7483e4b338524b98bc949b7c2b7c33d978f5fafab5bde041c5e2595", size = 155880, upload-time = "2025-07-10T16:41:07.935Z" },
688
+ { url = "https://files.pythonhosted.org/packages/32/c6/13c1a26b47b3f3a3b480783001ada4268917c9f42d78a079c336da2e75e5/mcp-1.23.3-py3-none-any.whl", hash = "sha256:32768af4b46a1b4f7df34e2bfdf5c6011e7b63d7f1b0e321d0fdef4cd6082031", size = 231570, upload-time = "2025-12-09T16:04:35.56Z" },
686
689
  ]
687
690
 
688
691
  [package.optional-dependencies]
@@ -1130,6 +1133,20 @@ wheels = [
1130
1133
  { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" },
1131
1134
  ]
1132
1135
 
1136
+ [[package]]
1137
+ name = "pyjwt"
1138
+ version = "2.10.1"
1139
+ source = { registry = "https://pypi.org/simple" }
1140
+ sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" }
1141
+ wheels = [
1142
+ { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" },
1143
+ ]
1144
+
1145
+ [package.optional-dependencies]
1146
+ crypto = [
1147
+ { name = "cryptography" },
1148
+ ]
1149
+
1133
1150
  [[package]]
1134
1151
  name = "pyright"
1135
1152
  version = "1.1.401"
@@ -1330,7 +1347,7 @@ wheels = [
1330
1347
 
1331
1348
  [[package]]
1332
1349
  name = "requests"
1333
- version = "2.32.3"
1350
+ version = "2.32.5"
1334
1351
  source = { registry = "https://pypi.org/simple" }
1335
1352
  dependencies = [
1336
1353
  { name = "certifi" },
@@ -1338,9 +1355,9 @@ dependencies = [
1338
1355
  { name = "idna" },
1339
1356
  { name = "urllib3" },
1340
1357
  ]
1341
- sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" }
1358
+ sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
1342
1359
  wheels = [
1343
- { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" },
1360
+ { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
1344
1361
  ]
1345
1362
 
1346
1363
  [[package]]
@@ -1710,14 +1727,15 @@ wheels = [
1710
1727
 
1711
1728
  [[package]]
1712
1729
  name = "starlette"
1713
- version = "0.46.2"
1730
+ version = "0.50.0"
1714
1731
  source = { registry = "https://pypi.org/simple" }
1715
1732
  dependencies = [
1716
1733
  { name = "anyio" },
1734
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
1717
1735
  ]
1718
- sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" }
1736
+ sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" }
1719
1737
  wheels = [
1720
- { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" },
1738
+ { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" },
1721
1739
  ]
1722
1740
 
1723
1741
  [[package]]
@@ -1871,11 +1889,11 @@ wheels = [
1871
1889
 
1872
1890
  [[package]]
1873
1891
  name = "urllib3"
1874
- version = "2.4.0"
1892
+ version = "2.6.2"
1875
1893
  source = { registry = "https://pypi.org/simple" }
1876
- sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" }
1894
+ sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930, upload-time = "2025-12-11T15:56:40.252Z" }
1877
1895
  wheels = [
1878
- { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" },
1896
+ { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182, upload-time = "2025-12-11T15:56:38.584Z" },
1879
1897
  ]
1880
1898
 
1881
1899
  [[package]]
@@ -1917,14 +1935,14 @@ wheels = [
1917
1935
 
1918
1936
  [[package]]
1919
1937
  name = "werkzeug"
1920
- version = "3.1.3"
1938
+ version = "3.1.4"
1921
1939
  source = { registry = "https://pypi.org/simple" }
1922
1940
  dependencies = [
1923
1941
  { name = "markupsafe" },
1924
1942
  ]
1925
- sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" }
1943
+ sdist = { url = "https://files.pythonhosted.org/packages/45/ea/b0f8eeb287f8df9066e56e831c7824ac6bab645dd6c7a8f4b2d767944f9b/werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e", size = 864687, upload-time = "2025-11-29T02:15:22.841Z" }
1926
1944
  wheels = [
1927
- { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" },
1945
+ { url = "https://files.pythonhosted.org/packages/2f/f9/9e082990c2585c744734f85bec79b5dae5df9c974ffee58fe421652c8e91/werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", size = 224960, upload-time = "2025-11-29T02:15:21.13Z" },
1928
1946
  ]
1929
1947
 
1930
1948
  [[package]]