mcp-instana 0.3.1__py3-none-any.whl → 0.6.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.
@@ -1,17 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-instana
3
- Version: 0.3.1
3
+ Version: 0.6.2
4
4
  Summary: MCP server for Instana
5
5
  Author-email: Elina Priyadarshinee <Elina.priyadarshinee1@ibm.com>, Guangya Liu <gyliu@ibm.com>, Isabell Sippli <ischwert@de.ibm.com>, Jay Sharma <Jay.Sharma3@ibm.com>, Madhu Tadiparthi <madhu.tadiparthi@ibm.com>, Riya Kumari <Riya.Kumari3@ibm.com>
6
6
  License: Apache-2.0
7
7
  License-File: LICENSE.md
8
8
  Requires-Python: >=3.10
9
- Requires-Dist: fastmcp==2.10.3
10
- Requires-Dist: instana-client==1.0.1
9
+ Requires-Dist: fastmcp==2.13.0
10
+ Requires-Dist: instana-client==1.0.2
11
11
  Requires-Dist: mcp
12
12
  Requires-Dist: pydantic==2.11.7
13
13
  Requires-Dist: python-dotenv==1.1.0
14
14
  Requires-Dist: requests==2.32.4
15
+ Requires-Dist: traceloop-sdk>=0.47.5
15
16
  Provides-Extra: dev
16
17
  Requires-Dist: coverage>=7.10.1; extra == 'dev'
17
18
  Requires-Dist: pytest-asyncio>=1.1.0; extra == 'dev'
@@ -25,7 +26,6 @@ Description-Content-Type: text/markdown
25
26
  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
26
27
  <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
27
28
  <!-- mcp-name: io.github.instana/mcp-instana -->
28
- **Table of Contents**
29
29
 
30
30
  - [MCP Server for IBM Instana](#mcp-server-for-ibm-instana)
31
31
  - [Architecture Overview](#architecture-overview)
@@ -72,27 +72,8 @@ Description-Content-Type: text/markdown
72
72
  - [**pyproject.toml** (Development)](#pyprojecttoml-development)
73
73
  - [**pyproject-runtime.toml** (Production)](#pyproject-runtimetoml-production)
74
74
  - [Building the Docker Image](#building-the-docker-image)
75
- - [**Prerequisites**](#prerequisites-1)
75
+ - [**Prerequisites**](#prerequisites)
76
76
  - [**Build Command**](#build-command)
77
- - [**What the Build Does**](#what-the-build-does)
78
- - [Running the Docker Container](#running-the-docker-container)
79
- - [**Basic Usage**](#basic-usage)
80
- - [**Environment Variables**](#environment-variables)
81
- - [**Docker Compose Example**](#docker-compose-example)
82
- - [Multi-Architecture Support](#multi-architecture-support)
83
- - [**Supported Architectures**](#supported-architectures)
84
- - [**Benefits of Multi-Architecture Images**](#benefits-of-multi-architecture-images)
85
- - [**How It Works**](#how-it-works)
86
- - [Docker Security Features](#docker-security-features)
87
- - [**Security Best Practices Implemented**](#security-best-practices-implemented)
88
- - [**Image Size Optimization**](#image-size-optimization)
89
- - [Testing the Docker Container](#testing-the-docker-container)
90
- - [**Health Check**](#health-check)
91
- - [**MCP Inspector Testing**](#mcp-inspector-testing)
92
- - [**Logs and Debugging**](#logs-and-debugging)
93
- - [Production Deployment](#production-deployment)
94
- - [**Recommended Production Setup**](#recommended-production-setup)
95
- - [**Kubernetes Example**](#kubernetes-example)
96
77
  - [Troubleshooting](#troubleshooting)
97
78
  - [**Docker Issues**](#docker-issues)
98
79
  - [**Container Won't Start**](#container-wont-start)
@@ -1032,47 +1013,14 @@ The project uses a **two-file dependency management strategy**:
1032
1013
  - Docker BuildKit for multi-architecture builds (enabled by default in recent Docker versions)
1033
1014
 
1034
1015
  #### **Build Command**
1035
-
1036
- **Single Architecture Build (Default):**
1037
1016
  ```bash
1038
- # Build for your local architecture (automatic detection)
1017
+ # Build the optimized production image
1039
1018
  docker build -t mcp-instana:latest .
1040
1019
 
1041
1020
  # Build with a specific tag
1042
- docker build -t mcp-instana:v1.0.0 .
1043
- ```
1044
-
1045
- **Multi-Architecture Build:**
1046
- ```bash
1047
- # Set up Docker BuildKit builder if you haven't already
1048
- docker buildx create --name multiarch --driver docker-container --use
1049
-
1050
- # Build and push a multi-architecture image to a registry
1051
- docker buildx build --platform linux/amd64,linux/arm64 -t username/mcp-instana:latest --push .
1052
- ```
1021
+ docker build -t mcp-instana:< image_tag > .
1053
1022
 
1054
- **Using the Helper Script:**
1055
- ```bash
1056
- # Make the script executable
1057
- chmod +x build_multiarch.sh
1058
-
1059
- # Build for local architecture
1060
- ./build_multiarch.sh
1061
-
1062
- # Build and push multi-architecture image
1063
- ./build_multiarch.sh --registry username/ --push
1064
- ```
1065
-
1066
- #### **What the Build Does**
1067
- 1. **Multi-stage build** for optimal size and security
1068
- 2. **Builder stage**: Installs only runtime dependencies from `pyproject-runtime.toml`
1069
- 3. **Runtime stage**: Creates minimal production image with non-root user
1070
- 4. **Security**: No hardcoded secrets, proper user permissions
1071
- 5. **Optimization**: Only essential dependencies (20 vs 95+ in development)
1072
-
1073
- ### Running the Docker Container
1074
-
1075
- #### **Basic Usage**
1023
+ #### **Run Command**
1076
1024
  ```bash
1077
1025
  # Run the container (no credentials needed in the container)
1078
1026
  docker run -p 8080:8080 mcp-instana
@@ -1081,135 +1029,6 @@ docker run -p 8080:8080 mcp-instana
1081
1029
  docker run -p 8081:8080 mcp-instana
1082
1030
  ```
1083
1031
 
1084
-
1085
-
1086
- #### **Docker Compose Example**
1087
- ```yaml
1088
- version: '3.8'
1089
- services:
1090
- mcp-instana:
1091
- build: .
1092
- ports:
1093
- - "8080:8080"
1094
- restart: unless-stopped
1095
- healthcheck:
1096
- test: ["CMD", "python", "-c", "import requests; requests.get('http://127.0.0.1:8080/health', timeout=5)"]
1097
- interval: 30s
1098
- timeout: 10s
1099
- retries: 3
1100
- start_period: 40s
1101
- ```
1102
-
1103
- ### Multi-Architecture Support
1104
-
1105
- The Docker image supports multiple processor architectures, making it portable across different environments:
1106
-
1107
- #### **Supported Architectures**
1108
- - ✅ **amd64/x86_64**: Standard Intel/AMD processors (Windows, Linux, most cloud VMs)
1109
- - ✅ **arm64/aarch64**: Apple Silicon (M1/M2/M3), AWS Graviton, Raspberry Pi 4, etc.
1110
-
1111
- #### **Benefits of Multi-Architecture Images**
1112
- - **Cross-Platform Compatibility**: Run the same image on any supported architecture
1113
- - **Seamless Deployment**: No need to build different images for different environments
1114
- - **CI/CD Simplification**: Build once, deploy anywhere
1115
- - **Cloud Flexibility**: Switch between cloud providers and instance types without rebuilding images
1116
-
1117
- #### **How It Works**
1118
- 1. The multi-architecture image is a "manifest list" containing images for each architecture
1119
- 2. When you pull the image, Docker automatically selects the correct architecture for your system
1120
- 3. The image runs natively on your architecture without emulation, ensuring optimal performance
1121
-
1122
- ### Docker Security Features
1123
-
1124
- #### **Security Best Practices Implemented**
1125
- - ✅ **Non-root user**: Container runs as `mcpuser` (not root)
1126
- - ✅ **No secrets in container**: Credentials are passed via HTTP headers from clients, not stored in the container
1127
- - ✅ **Minimal dependencies**: Only 20 essential runtime dependencies
1128
- - ✅ **Multi-stage build**: Build tools don't make it to final image
1129
- - ✅ **Health checks**: Built-in container health monitoring
1130
- - ✅ **Optimized base image**: Uses `python:3.11-slim`
1131
- - ✅ **Multi-architecture support**: Run natively on any supported platform
1132
-
1133
- #### **Image Size Optimization**
1134
- - **Original approach**: 95+ dependencies → ~1-2GB+ image
1135
- - **Optimized approach**: 20 dependencies → ~266MB image
1136
- - **Size reduction**: ~70-80% smaller images
1137
- - **Benefits**: Faster deployments, lower storage costs, reduced attack surface
1138
-
1139
- ### Testing the Docker Container
1140
-
1141
- #### **Health Check**
1142
- ```bash
1143
- # Check if container is healthy
1144
- docker ps
1145
-
1146
- # Test the MCP endpoint
1147
- curl http://localhost:8080/mcp/
1148
- ```
1149
-
1150
- #### **MCP Inspector Testing**
1151
- ```bash
1152
- # Test with MCP Inspector
1153
- npx @modelcontextprotocol/inspector http://localhost:8080/mcp/
1154
- ```
1155
-
1156
- #### **Logs and Debugging**
1157
- ```bash
1158
- # View container logs
1159
- docker logs <container_id>
1160
-
1161
- # Follow logs in real-time
1162
- docker logs -f <container_id>
1163
-
1164
- # Execute commands in running container
1165
- docker exec -it <container_id> /bin/bash
1166
- ```
1167
-
1168
- ### Production Deployment
1169
-
1170
- #### **Recommended Production Setup**
1171
- 1. **Run container without credentials** - The container runs in Streamable HTTP mode, so no Instana credentials are needed in the container
1172
- 2. **Configure clients with credentials** - Pass Instana credentials via HTTP headers from MCP clients (Claude Desktop, GitHub Copilot, etc.)
1173
- 3. **Set up proper logging** and monitoring
1174
- 4. **Configure health checks** for container orchestration
1175
- 5. **Use container orchestration** (Kubernetes, Docker Swarm, etc.)
1176
- 6. **Implement proper backup** and disaster recovery
1177
-
1178
- #### **Kubernetes Example**
1179
- ```yaml
1180
- apiVersion: apps/v1
1181
- kind: Deployment
1182
- metadata:
1183
- name: mcp-instana
1184
- spec:
1185
- replicas: 2
1186
- selector:
1187
- matchLabels:
1188
- app: mcp-instana
1189
- template:
1190
- metadata:
1191
- labels:
1192
- app: mcp-instana
1193
- spec:
1194
- containers:
1195
- - name: mcp-instana
1196
- image: mcp-instana:latest
1197
- ports:
1198
- - containerPort: 8080
1199
- livenessProbe:
1200
- httpGet:
1201
- path: /health
1202
- port: 8080
1203
- initialDelaySeconds: 30
1204
- periodSeconds: 10
1205
- readinessProbe:
1206
- httpGet:
1207
- path: /health
1208
- port: 8080
1209
- initialDelaySeconds: 5
1210
- periodSeconds: 5
1211
- ```
1212
-
1213
1032
  ## Troubleshooting
1214
1033
 
1215
1034
  ### **Docker Issues**
@@ -1218,12 +1037,10 @@ spec:
1218
1037
  ```bash
1219
1038
  # Check container logs
1220
1039
  docker logs <container_id>
1221
-
1222
1040
  # Common issues:
1223
1041
  # 1. Port already in use
1224
1042
  # 2. Invalid container image
1225
1043
  # 3. Missing dependencies
1226
-
1227
1044
  # Credentials are passed via HTTP headers from the MCP client
1228
1045
  ```
1229
1046
 
@@ -1231,7 +1048,6 @@ docker logs <container_id>
1231
1048
  ```bash
1232
1049
  # Test container connectivity
1233
1050
  docker exec -it <container_id> curl http://127.0.0.1:8080/health
1234
-
1235
1051
  # Check port mapping
1236
1052
  docker port <container_id>
1237
1053
  ```
@@ -1240,7 +1056,6 @@ docker port <container_id>
1240
1056
  ```bash
1241
1057
  # Check container resource usage
1242
1058
  docker stats <container_id>
1243
-
1244
1059
  # Monitor container health
1245
1060
  docker inspect <container_id> | grep -A 10 Health
1246
1061
  ```
@@ -1256,3 +1071,4 @@ docker inspect <container_id> | grep -A 10 Health
1256
1071
  - If that works, your Python environment may not be able to verify the certificate and might not have access to the same certificates as your shell or system. Ensure your Python environment uses system certificates (macOS). You can do this by installing certificates to Python:
1257
1072
  `//Applications/Python\ 3.13/Install\ Certificates.command`
1258
1073
  - If you cannot reach the endpoint with SSL verification, try without it. If that works, check your system's CA certificates and ensure they are up-to-date.
1074
+ ```
@@ -1,26 +1,27 @@
1
1
  src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ src/observability.py,sha256=FQIMF4reR-UtXqnBSa3Ub0wuPvlf9VNSTeMieJmFdMM,959
2
3
  src/application/__init__.py,sha256=cfWHjA5NzAvL0jcekaIO3NTe5DRtznYRqg9_8hVwSzc,37
3
- src/application/application_alert_config.py,sha256=dbYGzUNZdfcEp_-zLLLm8_AfJZHoSPamLp4eHNYQ42I,31196
4
- src/application/application_analyze.py,sha256=EXOaGRn8wEoFUltAmAnzFRiTrkLzh7c_RHdP5Nj2-Hk,26947
4
+ src/application/application_alert_config.py,sha256=LDUgkpMBx_5tX88dzE0emr31kydzMZWDCi36JzZDyEw,31590
5
+ src/application/application_analyze.py,sha256=cb5kbt2GYntyFAHXvix9r7nFthoftCa9haWmXjxpDEM,27046
5
6
  src/application/application_catalog.py,sha256=MVjU1CyYf6NSeCt2o0aTlNDAKeMUY3vr-wDOprnt2D8,6540
6
- src/application/application_global_alert_config.py,sha256=HqBlLLhMmpwy8pJlz9SDkHJ6w1vHH0LD7_LX4YWe7uk,31684
7
- src/application/application_metrics.py,sha256=swuoMk6fWNbW-IzivxJv8C7CgJie66u9d0JvtZ2jU4Y,15476
8
- src/application/application_resources.py,sha256=USbIrPnkokUBOiack7EChOTH2vqJM2D0EF-9MjGbn5w,18279
9
- src/application/application_settings.py,sha256=UZHZwY3GNW4JMl1Q6gGtGCE4iYERR7ijK0hslCYBMTo,76210
7
+ src/application/application_global_alert_config.py,sha256=PGDPXAuSu_J6uKohMhKWh1gpPOUkk4COvQF4mXsEPZI,31474
8
+ src/application/application_metrics.py,sha256=M8OymCr2TxlckpnUtASFaLb5kZD1AbnZy2ApvfQgGbI,15466
9
+ src/application/application_resources.py,sha256=3cZEOaAppDwSMG_DItR1BTbjuz_JkxedorvbvxzDcbw,20262
10
+ src/application/application_settings.py,sha256=gwkGKeiKpXLGmRe_MYtSvGglXHsgP9JakaBkm8TeKbo,83655
10
11
  src/application/application_topology.py,sha256=WinVNHSSTF771vq5hl2GxTLm3bdpehAQJ1AMumfy7M0,4870
11
12
  src/automation/action_catalog.py,sha256=jivR73riqBt-MGDnhSoEsshG7bHk7JpxvVuRx7FCtOA,17493
12
13
  src/automation/action_history.py,sha256=aMHUd5RLMrgdDvJXv0x6dkUA7I_35O0A89RPhFUfORI,16494
13
14
  src/core/__init__.py,sha256=gZdGV4TVETqe3XV-_lzQMw0IgyTTCqYYgP3PH9YdWbU,30
14
- src/core/server.py,sha256=WvkxAWYBiKdo3mdxoc6v_9SCO8Ij6hS2vCSMSlIvbTY,25022
15
+ src/core/server.py,sha256=LSdYYO-G9g1k_2yRqZVta2e8ZaGr3hFvj0duSbc7o-Y,25107
15
16
  src/core/utils.py,sha256=vB2ArNkOy0YIHk8Xv8nYHGEeTpw79pStJz6HL2aHWK8,11527
16
17
  src/event/__init__.py,sha256=ru-xCHU9xksGf9aJslvI37-6SI2yoBOpsoaED-vbaaQ,31
17
- src/event/events_tools.py,sha256=R17EYk1jUUIQl5706idtOKzLWWNLchv2fRd-U8S1Uno,42775
18
+ src/event/events_tools.py,sha256=ajCARRjxd6tkqH_fdFC1cOg9TYRV_gJE4BBVqDmyLV0,45365
18
19
  src/infrastructure/__init__.py,sha256=xZuRO1Zb2iPyO5G3PRM90dfesaFheL7DMSSJMujtLVk,40
19
20
  src/infrastructure/infrastructure_analyze.py,sha256=eBo9Rq7DRzsIKup4LR-ar_1g4kr_IPWeKcHMb-w1hLA,29455
20
- src/infrastructure/infrastructure_catalog.py,sha256=rE_ySS-MHDwGc_msat6XsxKolgYbduZSnPp4adXFQKM,29827
21
- src/infrastructure/infrastructure_metrics.py,sha256=he_KAadNp5VAWdDM65ZuDavHOZvwOX4tEuXJYwXjm78,7081
22
- src/infrastructure/infrastructure_resources.py,sha256=gFxjzGbUdlFXVjbuWKUxC0NEuwkPsZNkrWhnZ2Zd2t0,29297
23
- src/infrastructure/infrastructure_topology.py,sha256=mVz9jrpjstDNh_iUxZfGo912Ze5I3zH3XlapFIwm_3A,14830
21
+ src/infrastructure/infrastructure_catalog.py,sha256=tXrDAJ0ZzS6cfrx-aDJ63GkYGKUbePV_NLH-opm5bsE,31254
22
+ src/infrastructure/infrastructure_metrics.py,sha256=P5uiy2uGLrmh8LuYcW1GG_DkOAvAb64nEpKD_lBeydo,7136
23
+ src/infrastructure/infrastructure_resources.py,sha256=sVnYUkeMiaMAp3ln6ujHzRLOwceHr_XLE9LB0Qmrgbg,29240
24
+ src/infrastructure/infrastructure_topology.py,sha256=rVY7QnLGANHPXlezAhbc6wJfOoUO2TRr_VlXtkifo4A,15456
24
25
  src/log/__init__.py,sha256=NwPZccMqR5aR6PrISe760gkABtpg7zpbwOK-uMPB-_Y,29
25
26
  src/log/log_alert_configuration.py,sha256=-8ORRo889n4X4GalwhTQa9uHU4JuERy2OfnhP7k6LOM,18430
26
27
  src/prompts/__init__.py,sha256=oXt7rf_EASRtgL43lKRgH8xhX6abJ3fhpHfarIlkFog,405
@@ -52,8 +53,8 @@ src/website/website_analyze.py,sha256=0VyK8f-9vW1LzZ70b7IxKzwqSL2bWw8wDFSOCx2pEr
52
53
  src/website/website_catalog.py,sha256=Z21urtdTf8sU2SZiCwGq5OyPLaswS9lw12TCD9pS__4,7127
53
54
  src/website/website_configuration.py,sha256=hBHSFgj6GXOfLvlq8p-tBU4KFQc99uS167DBz4cjjK0,35926
54
55
  src/website/website_metrics.py,sha256=6McxbVYZq5i61Ml3QcVeHS86y2rCIPzdDuUDOxNtnMM,10954
55
- mcp_instana-0.3.1.dist-info/METADATA,sha256=ihXkPTCUrBqJJ_hqtIBfi7rSfb-3xuEiQLn_-LhSwL8,48596
56
- mcp_instana-0.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
57
- mcp_instana-0.3.1.dist-info/entry_points.txt,sha256=p1aZ9Ks0aJKpoIy6Mk-08cGYAfkXMNbwYIlokm513A4,140
58
- mcp_instana-0.3.1.dist-info/licenses/LICENSE.md,sha256=Ox7lseFP2kBRXBjsLweW1jLmWiCyrKjwF8ZUvCbKd70,11310
59
- mcp_instana-0.3.1.dist-info/RECORD,,
56
+ mcp_instana-0.6.2.dist-info/METADATA,sha256=utEaEnN7t95AmdwuR4a-ODN_Q5WJEl-zeSJfRrP06bY,42334
57
+ mcp_instana-0.6.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
58
+ mcp_instana-0.6.2.dist-info/entry_points.txt,sha256=p1aZ9Ks0aJKpoIy6Mk-08cGYAfkXMNbwYIlokm513A4,140
59
+ mcp_instana-0.6.2.dist-info/licenses/LICENSE.md,sha256=Ox7lseFP2kBRXBjsLweW1jLmWiCyrKjwF8ZUvCbKd70,11310
60
+ mcp_instana-0.6.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -525,11 +525,16 @@ class ApplicationAlertMCPTools(BaseInstanaClient):
525
525
  logger.debug(f"Error importing ApplicationAlertConfig: {e}")
526
526
  return {"error": f"Failed to import ApplicationAlertConfig: {e!s}"}
527
527
 
528
- # Create an ApplicationAlertConfig object from the request body
528
+ # Create an ApplicationAlertConfig object from the request body using from_dict
529
+ # This properly handles nested objects and discriminators
529
530
  try:
530
531
  logger.debug(f"Creating ApplicationAlertConfig with params: {request_body}")
531
- config_object = ApplicationAlertConfig(**request_body)
532
+ config_object = ApplicationAlertConfig.from_dict(request_body)
532
533
  logger.debug("Successfully created config object")
534
+
535
+ # Debug: Log what will be sent to API
536
+ config_dict = config_object.to_dict()
537
+ logger.debug(f"Config object as dict (what will be sent to API): {config_dict}")
533
538
  except Exception as e:
534
539
  logger.debug(f"Error creating ApplicationAlertConfig: {e}")
535
540
  return {"error": f"Failed to create config object: {e!s}"}
@@ -655,10 +660,11 @@ class ApplicationAlertMCPTools(BaseInstanaClient):
655
660
  logger.debug(f"Error importing ApplicationAlertConfig: {e}")
656
661
  return {"error": f"Failed to import ApplicationAlertConfig: {e!s}"}
657
662
 
658
- # Create an ApplicationAlertConfig object from the request body
663
+ # Create an ApplicationAlertConfig object from the request body using from_dict
664
+ # This properly handles nested objects and discriminators
659
665
  try:
660
666
  logger.debug(f"Creating ApplicationAlertConfig with params: {request_body}")
661
- config_object = ApplicationAlertConfig(**request_body)
667
+ config_object = ApplicationAlertConfig.from_dict(request_body)
662
668
  logger.debug("Successfully created config object")
663
669
  except Exception as e:
664
670
  logger.debug(f"Error creating ApplicationAlertConfig: {e}")
@@ -84,21 +84,24 @@ class ApplicationAnalyzeMCPTools(BaseInstanaClient):
84
84
  return {"error": "Both trace_id and call_id must be provided"}
85
85
 
86
86
  logger.debug(f"Fetching call details for trace_id={trace_id}, call_id={call_id}")
87
- result = api_client.get_call_details(
87
+ result = api_client.get_call_details_without_preload_content(
88
88
  trace_id=trace_id,
89
89
  call_id=call_id
90
90
  )
91
91
 
92
- # Convert the result to a dictionary
93
- if hasattr(result, 'to_dict'):
94
- result_dict = result.to_dict()
95
- else:
96
- # If it's already a dict or another format, use it as is
97
- result_dict = result
92
+ import json
98
93
 
99
- logger.debug(f"Result from get_call_details: {result_dict}")
100
- # Ensure we return a dictionary
101
- return dict(result_dict) if not isinstance(result_dict, dict) else result_dict
94
+ try:
95
+ response_text = result.data.decode('utf-8')
96
+ result_dict = json.loads(response_text)
97
+ logger.debug("Successfully retrieved call details")
98
+ return result_dict
99
+
100
+ # Convert the result to a dictionary
101
+ except (json.JSONDecodeError, AttributeError) as json_err:
102
+ error_message = f"Failed to parse JSON response: {json_err}"
103
+ logger.error(error_message)
104
+ return {"error": error_message}
102
105
 
103
106
  except Exception as e:
104
107
  logger.error(f"Error getting call details: {e}", exc_info=True)
@@ -41,7 +41,7 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
41
41
  async def find_active_global_application_alert_configs(self,
42
42
  application_id: str,
43
43
  alert_ids: Optional[List[str]] = None,
44
- ctx=None, api_client=None) -> List[Dict[str, Any]]:
44
+ ctx=None, api_client=None) -> Dict[str, Any]:
45
45
  """
46
46
  Get All Global Smart Alert Configuration.
47
47
 
@@ -63,36 +63,37 @@ class ApplicationGlobalAlertMCPTools(BaseInstanaClient):
63
63
 
64
64
  # Validate required parameters
65
65
  if not application_id:
66
- return [{"error": "application_id is required"}]
66
+ return {"error": "application_id is required"}
67
67
 
68
68
  # Call the find_active_global_application_alert_configs method from the SDK
69
69
  logger.debug(f"Calling find_active_global_application_alert_configs with application_id={application_id}, alert_ids={alert_ids}")
70
- result = api_client.find_active_global_application_alert_configs(
70
+ response = api_client.find_active_global_application_alert_configs_without_preload_content(
71
71
  application_id=application_id,
72
72
  alert_ids=alert_ids
73
73
  )
74
74
 
75
- # Convert the result to a list format
76
- if isinstance(result, list):
77
- # If it's already a list, convert each item to dict if needed
78
- result_list = []
79
- for item in result:
80
- if hasattr(item, 'to_dict'):
81
- result_list.append(item.to_dict())
82
- else:
83
- result_list.append(item)
84
- elif hasattr(result, 'to_dict'):
85
- # If it's a single object, wrap it in a list
86
- result_list = [result.to_dict()]
87
- else:
88
- # If it's already a dict or other format, wrap it in a list
89
- result_list = [result] if result else []
75
+ import json
76
+
77
+ raw_data = response.data.decode('utf-8')
78
+ logger.debug(f"Raw data: {raw_data}")
79
+
80
+ try:
81
+ result = json.loads(raw_data)
82
+ logger.debug(f"Parsed JSON result: {result}")
83
+
84
+ if isinstance(result, list):
85
+ return {"configs": result}
86
+ else:
87
+ return {"configs": [result] if result else []}
88
+
89
+ except json.JSONDecodeError as e:
90
+ error_msg = f"Failed to parse response JSON: {e}"
91
+ logger.error(error_msg)
92
+ return {"error": error_msg}
90
93
 
91
- logger.debug(f"Result from find_active_global_application_alert_configs: {result_list}")
92
- return result_list
93
94
  except Exception as e:
94
95
  logger.error(f"Error in find_active_global_application_alert_configs: {e}", exc_info=True)
95
- return [{"error": f"Failed to get active global application alert config: {e!s}"}]
96
+ return {"error": f"Failed to get active global application alert config: {e!s}"}
96
97
 
97
98
 
98
99
  @register_as_tool(
@@ -134,18 +134,18 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
134
134
  )
135
135
  @with_header_auth(ApplicationMetricsApi)
136
136
  async def get_application_metrics(self,
137
- application_ids: Optional[List[str]] = None,
137
+ application_id: Optional[str] = None,
138
138
  metrics: Optional[List[Dict[str, str]]] = None,
139
139
  time_frame: Optional[Dict[str, int]] = None,
140
140
  fill_time_series: Optional[bool] = True,
141
141
  ctx=None, api_client=None) -> Dict[str, Any]:
142
142
  """
143
- Get metrics for specific applications.
143
+ Get metrics for a specific application.
144
144
 
145
145
  This API endpoint retrieves one or more supported aggregations of metrics for an Application Perspective.
146
146
 
147
147
  Args:
148
- application_ids: List of application IDs to get metrics for
148
+ application_id: Application ID to get metrics for (single application)
149
149
  metrics: List of metrics to retrieve with their aggregations
150
150
  Example: [{"metric": "latency", "aggregation": "MEAN"}]
151
151
  time_frame: Dictionary with 'from' and 'to' timestamps in milliseconds
@@ -157,7 +157,7 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
157
157
  Dictionary containing application metrics data or error information
158
158
  """
159
159
  try:
160
- logger.debug(f"get_application_metrics called with application_ids={application_ids}")
160
+ logger.debug(f"get_application_metrics called with application_id={application_id}")
161
161
 
162
162
  # Set default time range if not provided
163
163
  if not time_frame:
@@ -183,9 +183,9 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
183
183
  "timeFrame": time_frame
184
184
  }
185
185
 
186
- # Add application IDs if provided
187
- if application_ids:
188
- request_body["applicationIds"] = application_ids
186
+ # Add application ID if provided
187
+ if application_id:
188
+ request_body["applicationId"] = application_id
189
189
 
190
190
  # Create the GetApplications object
191
191
  get_applications = GetApplications(**request_body)
@@ -215,18 +215,18 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
215
215
  )
216
216
  @with_header_auth(ApplicationMetricsApi)
217
217
  async def get_endpoints_metrics(self,
218
- endpoint_ids: Optional[List[str]] = None,
218
+ endpoint_id: Optional[str] = None,
219
219
  metrics: Optional[List[Dict[str, str]]] = None,
220
220
  time_frame: Optional[Dict[str, int]] = None,
221
221
  fill_time_series: Optional[bool] = True,
222
222
  ctx=None, api_client=None) -> Dict[str, Any]:
223
223
  """
224
- Get metrics for specific endpoints.
224
+ Get metrics for a specific endpoint.
225
225
 
226
226
  This API endpoint retrieves one or more supported aggregations of metrics for an Endpoint.
227
227
 
228
228
  Args:
229
- endpoint_ids: List of endpoint IDs to get metrics for
229
+ endpoint_id: Endpoint ID to get metrics for (single endpoint)
230
230
  metrics: List of metrics to retrieve with their aggregations
231
231
  Example: [{"metric": "latency", "aggregation": "MEAN"}]
232
232
  time_frame: Dictionary with 'from' and 'to' timestamps in milliseconds
@@ -238,7 +238,7 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
238
238
  Dictionary containing endpoint metrics data or error information
239
239
  """
240
240
  try:
241
- logger.debug(f"get_endpoints_metrics called with endpoint_ids={endpoint_ids}")
241
+ logger.debug(f"get_endpoints_metrics called with endpoint_id={endpoint_id}")
242
242
 
243
243
  # Set default time range if not provided
244
244
  if not time_frame:
@@ -264,9 +264,9 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
264
264
  "timeFrame": time_frame
265
265
  }
266
266
 
267
- # Add endpoint IDs if provided
268
- if endpoint_ids:
269
- request_body["endpointIds"] = endpoint_ids
267
+ # Add endpoint ID if provided
268
+ if endpoint_id:
269
+ request_body["endpointId"] = endpoint_id
270
270
 
271
271
  # Create the GetEndpoints object
272
272
  get_endpoints = GetEndpoints(**request_body)
@@ -296,19 +296,19 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
296
296
  )
297
297
  @with_header_auth(ApplicationMetricsApi)
298
298
  async def get_services_metrics(self,
299
- service_ids: Optional[List[str]] = None,
299
+ service_id: Optional[str] = None,
300
300
  metrics: Optional[List[Dict[str, str]]] = None,
301
301
  time_frame: Optional[Dict[str, int]] = None,
302
302
  fill_time_series: Optional[bool] = True,
303
303
  include_snapshot_ids: Optional[bool] = False,
304
304
  ctx=None, api_client=None) -> Dict[str, Any]:
305
305
  """
306
- Get metrics for specific services.
306
+ Get metrics for a specific service.
307
307
 
308
308
  This API endpoint retrieves one or more supported aggregations of metrics for a Service.
309
309
 
310
310
  Args:
311
- service_ids: List of service IDs to get metrics for
311
+ service_id: Service ID to get metrics for (single service)
312
312
  metrics: List of metrics to retrieve with their aggregations
313
313
  Example: [{"metric": "latency", "aggregation": "MEAN"}]
314
314
  time_frame: Dictionary with 'from' and 'to' timestamps in milliseconds
@@ -321,7 +321,7 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
321
321
  Dictionary containing service metrics data or error information
322
322
  """
323
323
  try:
324
- logger.debug(f"get_services_metrics called with service_ids={service_ids}")
324
+ logger.debug(f"get_services_metrics called with service_id={service_id}")
325
325
 
326
326
  # Set default time range if not provided
327
327
  if not time_frame:
@@ -347,9 +347,9 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
347
347
  "timeFrame": time_frame
348
348
  }
349
349
 
350
- # Add service IDs if provided
351
- if service_ids:
352
- request_body["serviceIds"] = service_ids
350
+ # Add service ID if provided
351
+ if service_id:
352
+ request_body["serviceId"] = service_id
353
353
 
354
354
  # Create the GetServices object
355
355
  get_services = GetServices(**request_body)