Is Keboola MCP server safe?
- Python network egress
- Python filesystem read
- Python filesystem write/delete
x is an AI python_package analyzed by SkillTotal's deterministic static scanner. The scan found no malicious indicators, though 4 risky constructs are reported for review. It can: delegated authentication, filesystem read, filesystem write and network egress — capabilities are what the code can do, not a verdict on intent. Risk score 0/100 (low).
x 1.74.6
Automated static-analysis result. It can contain false positives and false negatives, and is not a claim about the intent of Keboola MCP server's authors. Report a false positive.
Behavioral traits
How this component maps to the CSA agentic threat model. Descriptive — it never affects the risk score.
Findings (4)
The component reads files from disk.
jwt = Path(kubernetes_token_path).read_text().strip()
return resources.files(__package__).joinpath(name).read_text(encoding='utf-8')
_QUERY_SERVICE_QUERY_DATA_FUNCTION_CODE = _DATA_APP_RESOURCES.joinpath('qsapi_query_data_code.py').read_text(
encoding='utf-8'
)_STORAGE_QUERY_DATA_FUNCTION_CODE = _DATA_APP_RESOURCES.joinpath('sapi_query_data_code.py').read_text(encoding='utf-8')Why it matters: Usually legitimate, but worth confirming it can't be steered into reading sensitive files.
Fix: Confirm which files are read and that paths cannot be influenced by untrusted input to reach sensitive locations.
The component writes or deletes files on disk.
with open(self._output_path, mode='w', encoding='utf-8') as f:
Why it matters: Usually legitimate, but worth confirming the paths can't be controlled by untrusted input.
Fix: Confirm which files are written/deleted and that paths cannot be influenced by untrusted input.
The component makes outbound network requests.
import httpx
self.timeout = timeout or httpx.Timeout(connect=5.0, read=60.0, write=10.0, pool=5.0)
raise httpx.HTTPStatusError('\n'.join(message_parts), request=response.request, response=response) from easync with httpx.AsyncClient(timeout=self.timeout, transport=self._create_transport()) as client:
async with httpx.AsyncClient(timeout=self.timeout, transport=self._create_transport()) as client:
async with httpx.AsyncClient(timeout=timeout or self.timeout, transport=self._create_transport()) as client:
async with httpx.AsyncClient(timeout=self.timeout, transport=self._create_transport()) as client:
async with httpx.AsyncClient(timeout=self.timeout, transport=self._create_transport()) as client:
async with httpx.AsyncClient(timeout=self.timeout, transport=self._create_transport()) as client:
from urllib.parse import urlparse, urlunparse
import httpx
raise httpx.HTTPStatusError(message, request=exc.request, response=exc.response) from exc
sapi_url_parsed = urlparse(storage_api_url)
self._storage_api_url = urlunparse(('https', f'connection.{self._hostname_suffix}', '', '', '', ''))metastore_api_url = urlunparse(('https', f'metastore.{self._hostname_suffix}', '', '', '', ''))queue_api_url = urlunparse(('https', f'queue.{self._hostname_suffix}', '', '', '', ''))ai_service_api_url = urlunparse(('https', f'ai.{self._hostname_suffix}', '', '', '', ''))data_science_api_url = urlunparse(('https', f'data-science.{self._hostname_suffix}', '', '', '', ''))encryption_api_url = urlunparse(('https', f'encryption.{self._hostname_suffix}', '', '', '', ''))scheduler_api_url = urlunparse(('https', f'scheduler.{self._hostname_suffix}', '', '', '', ''))sync_actions_api_url = urlunparse(('https', f'sync-actions.{self._hostname_suffix}', '', '', '', ''))import httpx
_QS_TIMEOUT = httpx.Timeout(connect=5.0, read=120.0, write=10.0, pool=5.0)
from urllib.parse import urlparse, urlunparse
url_value = urlparse(value)
Why it matters: Usually legitimate, but confirm the destinations are expected and no sensitive data leaves.
Fix: Confirm the destination hosts are expected and that no sensitive data is sent off-host.
An OAuth 2.0 / OpenID Connect delegated-authentication flow was detected (authorization-code / refresh-token / token-exchange grant, an OIDC authorize/discovery endpoint or id_token, or a delegation library). Tools authenticate with the end user's delegated, scoped credentials rather than a long-lived embedded service credential. (3 occurrence(s) shown as evidence).
self._oauth_server_auth_url = urljoin(server_url, '/oauth/authorize')
'grant_type': 'authorization_code',
'grant_type': 'refresh_token',
Fix: Delegated auth is a lower-blast-radius execution context than an embedded static credential. Confirm the requested scopes are minimal and that tokens are never logged or forwarded off-host.
Check your own component
Run the same evidence-backed scan on any MCP server, agent skill, or package.
Scan your own componentHow we determine this: deterministic static analysis (regex + AST), evidence-anchored, no code execution. Methodology →