Skip to content

Commit 544358b

Browse files
committed
refactor: Remove app_config.yaml file and update env vars
1 parent 3653d48 commit 544358b

File tree

9 files changed

+89
-176
lines changed

9 files changed

+89
-176
lines changed

README.md

Lines changed: 13 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
- [Requirements](#requirements)
1818
- [UV Setup](#uv-setup)
1919
- [Configuration](#configuration)
20-
- [`app_config.yaml`](#app_configyaml)
2120
- [Environment Variables](#environment-variables)
2221
- [Running the Server](#running-the-server)
2322
- [Docker](#docker)
@@ -85,21 +84,6 @@ Get up and running with the Sysdig MCP Server quickly using our pre-built Docker
8584

8685
## Available Tools
8786

88-
You can select what group of tools to add when running the server by adding/removing them from the `mcp.allowed_tools` list in the app_config.yaml file
89-
90-
```yaml
91-
...
92-
mcp:
93-
transport: stdio
94-
...
95-
allowed_tools:
96-
- "events-feed"
97-
- "inventory"
98-
- "vulnerability-management"
99-
- "sysdig-sage"
100-
- "sysdig-cli-scanner" # Only available in stdio local transport mode
101-
```
102-
10387
<details>
10488
<summary><strong>Events Feed</strong></summary>
10589

@@ -168,13 +152,9 @@ mcp:
168152

169153
You can use [uv](https://github.com/astral-sh/uv) as a drop-in replacement for pip to create the virtual environment and install dependencies.
170154

171-
If you don't have `uv` installed, you can install it via (Linux and MacOS users):
155+
If you don't have `uv` installed, you can install it following the instructions that you can find on the `README` of the project.
172156
173-
```bash
174-
curl -Ls https://astral.sh/uv/install.sh | sh
175-
```
176-
177-
To set up the environment:
157+
If you want to develop, set up the environment using:
178158
179159
```bash
180160
uv venv
@@ -185,36 +165,26 @@ This will create a virtual environment using `uv` and install the required depen
185165
186166
## Configuration
187167
188-
The application can be configured via the `app_config.yaml` file and environment variables.
189-
190-
### `app_config.yaml`
191-
192-
This file contains the main configuration for the application, including:
193-
194-
- **app**: Host, port, and log level for the MCP server.
195-
- **sysdig**: The Sysdig Secure host to connect to.
196-
- **mcp**: Transport protocol (stdio, sse, streamable-http), URL, host, and port for the MCP server.
197-
198-
> You can set the path for the app_config.yaml using the `APP_CONFIG_FILE=/path/to/app_config.yaml` env var. By default the app will search the file in the root of the app.
199-
200-
### Environment Variables
201-
202-
The following environment variables are required for configuring the Sysdig SDK:
168+
The following environment variables are **required** for configuring the Sysdig SDK:
203169
204170
- `SYSDIG_HOST`: The URL of your Sysdig Secure instance (e.g., `https://us2.app.sysdig.com`).
205171
- `SYSDIG_SECURE_TOKEN`: Your Sysdig Secure API token.
206172
173+
You can also set the following variables to override the default configuration:
174+
175+
- `SYSDIG_MCP_TRANSPORT`: The transport protocol for the MCP Server (`stdio`, `streamable-http`, `sse`). Defaults to: `stdio`.
176+
- `SYSDIG_MCP_MOUNT_PATH`: The URL prefix for the Streamable-http/sse deployment. Defaults to: `/sysdig-mcp-server`
177+
- `LOGLEVEL`: Log Level of the application (`DEBUG`, `INFO`, `WARNING`, `ERROR`). Defaults to: `INFO`
178+
- `SYSDIG_MCP_LISTENING_PORT`: The port for the server when it is deployed using remote protocols (`steamable-http`, `sse`). Defaults to: `8080`
179+
- `SYSDIG_MCP_LISTENING_HOST`: The host for the server when it is deployed using remote protocols (`steamable-http`, `sse`). Defaults to: `localhost`
180+
207181
You can find your API token in the Sysdig Secure UI under **Settings > Sysdig Secure API**. Make sure to copy the token as it will not be shown again.
208182
209183
![API_TOKEN_CONFIG](./docs/assets/settings-config-token.png)
210184
![API_TOKEN_SETTINGS](./docs/assets/api-token-copy.png)
211185
212186
You can set these variables in your shell or in a `.env` file.
213187
214-
You can also use `MCP_TRANSPORT` to override the transport protocol set in `app_config.yaml`.
215-
216-
> All of this env variables have precedence over the fields configured in the app_config.yaml.
217-
218188
## Running the Server
219189
220190
You can run the MCP server using either Docker, `uv` or install it in your K8s cluster with helm.
@@ -255,7 +225,6 @@ sysdig:
255225
secureAPIToken: "<your_sysdig_secure_api_token>"
256226
mcp:
257227
transport: "streamable-http"
258-
# You can set the Sysdig Tenant URL at this level or below in the app_config configmap
259228
host: "https://us2.app.sysdig.com" # <your_sysdig_host> "https://eu1.app.sysdig.com"
260229
261230
configMap:
@@ -312,7 +281,7 @@ To use the MCP server with a client like Claude or Cursor, you need to provide t
312281

313282
When using the `sse` or `streamable-http` transport, the server requires a Bearer token for authentication. The token is passed in the `Authorization` header of the HTTP request.
314283

315-
Additionally, you can specify the Sysdig Secure host by providing the `X-Sysdig-Host` header. If this header is not present, the server will use the value from `app_config.yaml`.
284+
Additionally, you can specify the Sysdig Secure host by providing the `X-Sysdig-Host` header. If this header is not present, the server will use the value from the env variable.
316285

317286
Example headers:
318287

@@ -323,7 +292,7 @@ X-Sysdig-Host: <your_sysdig_host>
323292

324293
### URL
325294

326-
If you are running the server with the `sse` or `streamable-http` transport, the URL will be `http://<host>:<port>/sysdig-mcp-server/mcp`, where `<host>` and `<port>` are the values configured in `app_config.yaml` or the Docker run command.
295+
If you are running the server with the `sse` or `streamable-http` transport, the URL will be `http://<host>:<port>/sysdig-mcp-server/mcp`.
327296

328297
For example, if you are running the server locally on port 8080, the URL will be `http://localhost:8080/sysdig-mcp-server/mcp`.
329298

app_config.yaml

Lines changed: 0 additions & 20 deletions
This file was deleted.

main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def signal_handler(sig, frame):
4242
def main():
4343
# Choose transport: "stdio" or "sse" (HTTP/SSE)
4444
handle_signals()
45-
transport = os.environ.get("MCP_TRANSPORT", app_config.transport())
45+
transport = app_config.transport()
4646
log.info("""
4747
▄▖ ▌▘ ▖ ▖▄▖▄▖ ▄▖
4848
▚ ▌▌▛▘▛▌▌▛▌ ▛▖▞▌▌ ▙▌ ▚ █▌▛▘▌▌█▌▛▘

tools/cli_scanner/tool.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111

1212
from utils.app_config import AppConfig
1313

14-
15-
16-
1714
class CLIScannerTool:
1815
"""
1916
A class to encapsulate the tools for interacting with the Sysdig CLI Scanner.
@@ -62,8 +59,8 @@ def check_env_credentials(self) -> None:
6259
Raises:
6360
EnvironmentError: If the SYSDIG_SECURE_TOKEN or SYSDIG_HOST environment variables are not set.
6461
"""
65-
sysdig_secure_token = os.environ.get("SYSDIG_SECURE_TOKEN")
66-
sysdig_host = os.environ.get("SYSDIG_HOST", self.app_config.sysdig_endpoint())
62+
sysdig_secure_token = self.app_config.sysdig_secure_token()
63+
sysdig_host = self.app_config.sysdig_endpoint()
6764
if not sysdig_secure_token:
6865
self.log.error("SYSDIG_SECURE_TOKEN environment variable is not set.")
6966
raise EnvironmentError("SYSDIG_SECURE_TOKEN environment variable is not set.")
@@ -158,7 +155,7 @@ def run_sysdig_cli_scanner(
158155
"output": output_result + result.stderr.strip(),
159156
"exit_codes_explained": self.exit_code_explained,
160157
}
161-
# Handle non-zero exit codes speically exit code 1
158+
# Handle non-zero exit codes specially exit code 1
162159
except subprocess.CalledProcessError as e:
163160
self.log.warning(f"Sysdig CLI Scanner returned non-zero exit code: {e.returncode}")
164161
if e.returncode in [2, 3]:

tools/events_feed/tool.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,6 @@ def tool_list_runtime_events(
138138
Args:
139139
cursor (Optional[str]): Cursor for pagination.
140140
scope_hours (int): Number of hours back from now to include events. Defaults to 1.
141-
severity_level (Optional[str]): One of "info", "low", "medium", "high". If provided, filters by that severity.
142-
If None, includes all severities.
143-
cluster_name (Optional[str]): Name of the Kubernetes cluster to filter events. If None, includes all clusters.
144141
limit (int): Maximum number of events to return. Defaults to 50.
145142
filter_expr (Optional[str]): An optional filter expression to further narrow down events.
146143

utils/app_config.py

Lines changed: 56 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,110 +3,107 @@
33
It will load a singleton configuration object that can be accessed throughout the application.
44
"""
55

6-
import yaml
7-
import logging
86
import os
97
from typing import Optional
108

11-
# Set up logging
12-
logging.basicConfig(format="%(asctime)s-%(process)d-%(levelname)s- %(message)s", level=os.environ.get("LOGLEVEL", "ERROR"))
13-
log = logging.getLogger(__name__)
14-
159
# app_config singleton
1610
_app_config: Optional[dict] = None
17-
APP_CONFIG_FILE: str = os.getenv("APP_CONFIG_FILE", "./app_config.yaml")
18-
1911

2012
class AppConfig:
2113
"""
2214
A class to encapsulate the application configuration.
2315
"""
2416

25-
def __init__(self, config: dict):
26-
self.app_config = config
27-
2817
def sysdig_endpoint(self) -> str:
2918
"""
30-
Get the Sysdig endpoint from the app config
19+
Get the Sysdig endpoint.
3120
21+
Raises:
22+
RuntimeError: If no SYSDIG_HOST environment variable is set.
3223
Returns:
3324
str: The Sysdig API host (e.g., "https://us2.app.sysdig.com").
3425
"""
35-
return os.environ.get("SYSDIG_HOST", self.app_config["sysdig"]["host"])
26+
if "SYSDIG_HOST" not in os.environ:
27+
raise RuntimeError("Variable `SYSDIG_HOST` must be defined.")
28+
29+
return os.environ.get("SYSDIG_HOST")
30+
31+
def sysdig_secure_token(self) -> str:
32+
"""
33+
Get the Sysdig secure token.
34+
35+
Raises:
36+
RuntimeError: If no SYSDIG_SECURE_TOKEN environment variable is set.
37+
Returns:
38+
str: The Sysdig secure token.
39+
"""
40+
if "SYSDIG_SECURE_TOKEN" not in os.environ:
41+
raise RuntimeError("Variable `SYSDIG_SECURE_TOKEN` must be defined.")
3642

43+
return os.environ.get("SYSDIG_SECURE_TOKEN")
44+
45+
# MCP Config Vars
3746
def transport(self) -> str:
3847
"""
39-
Get the transport protocol (lower case) from the app config
48+
Get the transport protocol (lower case).
49+
Valid values are: "stdio", "streamable-http", or "sse".
50+
Defaults to "stdio".
4051
52+
Raises:
53+
ValueError: If no transport protocol environment variable is set.
4154
Returns:
4255
str: The transport protocol (e.g., "stdio", "streamable-http", or "sse").
4356
"""
44-
return os.environ.get("MCP_TRANSPORT", self.app_config["mcp"]["transport"]).lower()
57+
transport = os.environ.get("SYSDIG_TRANSPORT", "stdio").lower()
58+
59+
if transport not in ("stdio", "streamable-http", "sse"):
60+
raise ValueError("Invalid transport protocol. Valid values are: stdio, streamable-http, sse.")
61+
62+
return transport
4563

4664
def log_level(self) -> str:
4765
"""
48-
Get the log level from the environment or defaults.
66+
Get the log level from the environment or defaults to INFO.
4967
5068
Returns:
5169
str: The log level string (e.g., "DEBUG", "INFO", "WARNING", "ERROR").
5270
"""
53-
return os.environ.get("LOGLEVEL", "ERROR")
71+
return os.environ.get("LOGLEVEL", "INFO")
5472

5573
def port(self) -> int:
5674
"""
57-
Get the port from the app config
75+
Get the port for the remote MCP Server Deployment ("streamable-http", or "sse" transports).
76+
Defaults to `8080`.
5877
5978
Returns:
6079
int: The MCP server port.
6180
"""
62-
return os.environ.get("SYSDIG_MCP_PORT", self.app_config["mcp"]["port"])
63-
64-
65-
def env_constructor(loader, node):
66-
return os.environ[node.value[0:]]
81+
return os.environ.get("SYSDIG_MCP_LISTENING_PORT", "8080")
6782

83+
#
84+
def host(self) -> str:
85+
"""
86+
Get the host for the remote MCP Server deployment ("streamable-http", or "sse" transports).
87+
Defaults to "localhost".
6888
69-
def check_config_file_exists() -> bool:
70-
"""
71-
Check if the config file exists
72-
73-
Returns:
74-
bool: True if the config file exists, False otherwise
75-
"""
76-
if os.path.exists(APP_CONFIG_FILE):
77-
log.debug("Config file exists")
78-
return True
79-
else:
80-
log.error("Config file does not exist")
81-
return False
82-
89+
Returns:
90+
str: The host string (e.g., "localhost").
91+
"""
92+
return os.environ.get("SYSDIG_MCP_LISTENING_HOST", "localhost")
8393

84-
def load_app_config() -> AppConfig:
85-
"""
86-
Load the app config from the YAML file
94+
def mcp_mount_path(self) -> str:
95+
"""
96+
Get the string value for the remote MCP Mount Path.
8797
88-
Returns:
89-
AppConfig: The loaded application configuration wrapper.
90-
"""
91-
if not check_config_file_exists():
92-
log.error("Config file does not exist")
93-
return {}
94-
# Load the config file
95-
app_config: dict = {}
96-
log.debug(f"Loading app config from YAML file: {APP_CONFIG_FILE}")
97-
with open(APP_CONFIG_FILE, "r", encoding="utf8") as file:
98-
try:
99-
yaml.add_constructor("!env", env_constructor, Loader=yaml.SafeLoader)
100-
app_config: dict = yaml.safe_load(file)
101-
except Exception as exc:
102-
logging.error(exc)
103-
104-
return AppConfig(app_config)
98+
Returns:
99+
str: The MCP mount path.
100+
"""
101+
return os.environ.get("MCP_MOUNT_PATH", "/sysdig-mcp-server")
105102

106103

107104
def get_app_config() -> AppConfig:
108105
"""
109-
Get the the overall app config
106+
Get the overall app config
110107
This function uses a singleton pattern to ensure the config is loaded only once.
111108
If the config is already loaded, it returns the existing config.
112109
@@ -115,5 +112,5 @@ def get_app_config() -> AppConfig:
115112
"""
116113
global _app_config
117114
if _app_config is None:
118-
_app_config = load_app_config()
115+
_app_config = AppConfig()
119116
return _app_config

0 commit comments

Comments
 (0)