MCP, MCP server
nable
nable prices what your coding agents are about to do, before they do it.
Compatibility: Not stated.
Grade C
One Medium finding. Read the report before installing.
Not a guarantee. A hygiene check of the source at the commit shown, not a security audit.
SECRETS_PATH_CREDENTIAL
Why this grade
- SECRETS_PATH_CREDENTIAL Medium
Mentions a credential store path (~/.ssh, id_rsa, .npmrc, .aws/credentials, credentials.json, .netrc).
src/finops/ambient.py, line 4
which resolves the whole default chain: env vars, ~/.aws/credentials, named
Any High, or two or more Medium findings, give D. One Medium gives C. Low findings or a security Note give B. Each code names a finding behind the letter.
Grades are a hygiene check of the source at the commit shown, on the date checked, not a security audit or a guarantee. The free directory grades are automated. Before release, a PlugVet engineer reviews every paid report and any grade we hold back, including all F grades, against the source code and the evidence we quote.
What was checked
Plain notes from the hygiene checks.
Permissions
Concern
can delete files.
PERMISSION_DELETE_FILES
scripts/bump_version.py, line 107
subprocess.run([sys.executable, str(ROOT / "scripts" / "generate_sbom.py")], check=True)
scripts/check_release.py, line 131
out = subprocess.run( # nosec B603 B607
scripts/launch_funnel.py, line 168
r = subprocess.run(["gh", "api", path], capture_output=True, text=True, timeout=30)
Show more
scripts/weekly-read.py, line 81
out = subprocess.run(cmd, capture_output=True, text=True, timeout=35)
shim/nable_shim.py, line 97
return subprocess.run(_reexec_argv(uv, argv), env=env).returncode
src/finops/ai_budget.py, line 1078
r = subprocess.run([git, "config", "--get", "user.email"], # nosec B603
src/finops/background_refresh.py, line 162
subprocess.Popen([sys.executable, "-m", "finops.background_refresh", job],
src/finops/guard_release.py, line 76
r = subprocess.run(argv, capture_output=True, text=True, timeout=timeout, # nosec B603
src/finops/packs/broker.py, line 897
shutil.rmtree(dest, ignore_errors=True)
src/finops/packs/broker.py, line 978
shutil.rmtree(home, ignore_errors=True)
src/finops/packs/broker.py, line 980
shutil.rmtree(code_root, ignore_errors=True)
src/finops/packs/install.py, line 273
shutil.rmtree(dest / ".git")
src/finops/packs/install.py, line 560
shutil.rmtree(work, ignore_errors=True)
src/finops/packs/install.py, line 658
shutil.rmtree(dest) # a leftover no index entry points at
src/finops/packs/install.py, line 680
shutil.rmtree(old, ignore_errors=True)
src/finops/packs/install.py, line 712
shutil.rmtree(dest, ignore_errors=True)
Install and update
Note
README documents an installer that pipes a download into a shell.
INSTALL_DOCUMENTED_INSTALLER
README.md, line 189
Requires Python 3.11+. Need `uv`? `curl -LsSf https://astral.sh/uv/install.sh | sh` (or `brew install uv`).
Network
Concern
can reach a host that is not written as a fixed address. can reach api.github.com. The description does not name that host. can reach evil. The description does not name that host.
NETWORK_NO_FIXED_HOST NETWORK_UNNAMED_HOST
examples/packs/example-csv-connector/example_csv_connector/costs.py, line 32
def fetch(ctx, start: str, end: str):
scripts/build_rds_price_tables.py, line 168
with urllib.request.urlopen(req, timeout=_TIMEOUT_S) as resp: # nosec B310 - https, one host
scripts/check_release.py, line 120
with urllib.request.urlopen(req, timeout=timeout) as r: # nosec B310
Show more
scripts/launch_funnel.py, line 70
with urllib.request.urlopen(req, timeout=90) as r:
scripts/weekly-read.py, line 83
raise RuntimeError(out.stderr.strip() or f"curl exit {out.returncode}")
scripts/weekly-read.py, line 245
print(f" downloads: could not fetch ({e})")
src/finops/ambient.py, line 212
resp = httpx.get(
src/finops/doctor.py, line 325
r = httpx.get(
src/finops/update_check.py, line 48
r = httpx.get("https://pypi.org/pypi/finops-mcp/json", timeout=timeout)
Secrets
Concern
reads a credential or environment file.
SECRETS_ENV_READ SECRETS_PATH_CREDENTIAL SECRETS_PATH_DOTENV
scripts/launch_funnel.py, line 5
step it is stalling. Reads PostHog creds from .env.local.
scripts/launch_funnel.py, line 50
env = Path(__file__).resolve().parent.parent / ".env.local"
src/finops/ambient.py, line 4
which resolves the whole default chain: env vars, ~/.aws/credentials, named
Show more
scripts/launch_funnel.py, line 60
sys.exit("POSTHOG_PROJECT_ID / POSTHOG_PERSONAL_API_KEY not found in .env.local")
scripts/weekly-read.py, line 33
"""Read KEY=VALUE lines from the repo's .env.local into the environment so
scripts/weekly-read.py, line 37
env_path = Path(__file__).resolve().parent.parent / ".env.local"
scripts/weekly-read.py, line 55
POSTHOG_API_KEY = os.environ.get("POSTHOG_PERSONAL_API_KEY", "")
src/finops/ambient.py, line 11
An AWS user with ~/.aws/credentials connected in three seconds; an Azure user in
src/finops/ambient.py, line 261
return (cfg / "application_default_credentials.json").exists() or cfg.is_dir()
src/finops/ambient.py, line 290
source = "env" if os.getenv("GOOGLE_APPLICATION_CREDENTIALS") else "adc"
src/finops/cli_scan.py, line 1078
env_keys = bool(os.environ.get("AWS_ACCESS_KEY_ID")) and not flag_profile and not demo
src/finops/demo_data.py, line 39
os.environ.get("FINOPS_CONTROL_PLANE_SECRET", "").strip()
src/finops/doctor.py, line 97
if os.environ.get("FINOPS_VAULT_KEY"):
src/finops/doctor.py, line 101
elif os.environ.get("FINOPS_NO_KEYRING") == "1" or _env_flag_set("FINOPS_AIRGAP"):
src/finops/doctor.py, line 166
if os.environ.get("AWS_ACCESS_KEY_ID"):
src/finops/guard_outcome.py, line 156
and os.getenv("CURSOR_ADMIN_API_KEY", "").strip() else _NO_SESSION)
Agent instructions
Pass
No instruction to ignore earlier instructions or to hide a step.
Obfuscation
Note
a file was over the read cap and was not fully read. the file cap was reached before every file was read.
OBFUSCATION_FILE_OVER_READ_CAP OBFUSCATION_FILE_CAP_REACHED
CHANGELOG.md, line 1
# Changelog
src/finops/guard.py, line 1
"""Seamless agent cost guardrail: a PreToolUse hook for AI coding agents.
src/finops/setup_wizard.py, line 1
#!/usr/bin/env python3
Show more
src/finops/price_data/rds_on_demand.json, line 1
{
src/finops/remediation/rightsizing_pr.py, line 1
"""
Licence
Pass
A licence file is present (LICENSE).
Maintainer activity
Pass
The latest commit is within the last 365 days.
Note
Hygiene check of commit 90737bc53580. can delete files. README documents an installer that pipes a download into a shell. can reach a host that is not written as a fixed address. can reach api.github.com. The description does not name that host. can reach evil. The description does not name that host. reads a credential or environment file. a file was over the read cap and was not fully read. the file cap was reached before every file was read.
Date and source
Date checked:
github.com
Commit graded: 90737bc535808da23e7515c1d2147363c65ab83d
This link goes to the original host. PlugVet does not host or check what you download from there, and installing it is your own decision and risk.