Atlas / MCP servers / phillips-jon / cronwatch

cronwatchBLOCK

mcp/phillips-jon/cronwatch

CronWatch records every run of your scheduled jobs in your own database, and speaks up when one is missed, fails, gets stuck, runs slow or costs too much.

Verdict
BLOCK
Grade
F
Trust score
40 /100
Exposed tools
9 8r · 1w · 0d
Transport
stdio
License
MIT
Stars
4
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

Cron and scheduled-job monitoring that lives inside your app. Wrap a job once; CronWatch records every run in a database you already have and tells you when a run is missed, fails, gets stuck, runs slow, goes over budget, or quietly does nothing. No server to run, no account to make. MIT.

Site and docs: cronwatch.dev

// lib/cronwatch.ts
import { cronwatch } from "@cronwatch/sdk";
import { sqlite } from "@cronwatch/sdk/sqlite";
import { slack } from "@cronwatch/sdk/slack";

export const cw = cronwatch({
store: sqlite({ path: "./data/cronwatch.db" }),
alerts: [slack({ webhookUrl: process.env.SLACK_WEBHOOK_URL! })],
});

export const nightlyReport = cw.job("nightly-report", {
schedule: "0 2 * * *", timezone: "UTC", grace: "15m", expect: "Report written",
});
// app/api/cron/nightly-report/route.ts: checks Authorization: Bearer CRON_SECRET
import { nightlyReport } from "@/lib/cronwatch";

export const GET = nightlyReport.handler(async (job) => {
const report = await buildReport();
job.log("Report written:", report.path);
job.metric("cost", report.usdCost);
});
// app/cronwatch/[[...path]]/route.ts: a dashboard and JSON API behind CRONWATCH_TOKEN
import { cw } from "@/lib/cronwatch";

export const { GET, POST, DELETE } = cw.routes();

Packages

Read from source at commit ae2b8530078cOBSERVED · 2026-10-11
Advertisement
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code
claude mcp add cronwatch-site --env CRONWATCH_TOKEN=${CRONWATCH_TOKEN} --env CRON_SECRET=${CRON_SECRET} --env RESEND_API_KEY=${RESEND_API_KEY} --env TWILIO_AUTH_TOKEN=${TWILIO_AUTH_TOKEN} -- npx -y cronwatch-site
claude-desktop
{
  "mcpServers": {
    "cronwatch-site": {
      "command": "npx",
      "args": [
        "-y",
        "cronwatch-site"
      ],
      "env": {
        "CRONWATCH_TOKEN": "${CRONWATCH_TOKEN}",
        "CRON_SECRET": "${CRON_SECRET}",
        "RESEND_API_KEY": "${RESEND_API_KEY}",
        "TWILIO_AUTH_TOKEN": "${TWILIO_AUTH_TOKEN}"
      }
    }
  }
}
03

Exposed tools (9)

8 read · 1 write · 0 destructive.

ToolRiskDescription
CronWatchreadThe scheduled jobs of this app: their health, their last day, and their runs.
forget_jobread
get_jobread
get_setup_guideread
list_jobsread
nul2readab
run_checkwrite
silence_jobread
unsilence_jobread
04

Trust audit

BLOCKgrade F · trust 40/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (5 observation(s))
Network
declared (3 observation(s))
Shell
declared (14 observation(s))
Dependencies
not all pinned
Secrets in source
found

Findings (25)

CRITICALHard-coded secrets · secret.anthropic · CWE-798, CWE-321
conformance/output.json:650
"input": "sk-ant-api03-Ab_-Ab_-Ab_-Ab_-Ab_-Ab_-Ab_-Ab_-Ab_-Ab_-",
CRITICALHard-coded secrets · secret.github · CWE-798, CWE-321
conformance/output.json:284
"input": "export GITHUB_TOKEN=ghp_a1B2a1B2a1B2a1B2a1B2a1B2a1B2a1B2a1B2",
CRITICALHard-coded secrets · secret.github · CWE-798, CWE-321
conformance/output.json:859
"text": "ghp_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
CRITICALHard-coded secrets · secret.private_key · CWE-798, CWE-321
conformance/output.json:1082
"input": "-----BEGIN RSA PRIVATE KEY-----\nMIIEow\nIBAAK==\n-----END RSA PRIVATE KEY-----\nafter",
CRITICALHard-coded secrets · secret.private_key · CWE-798, CWE-321
conformance/output.json:1088
"input": "key:\n-----BEGIN PRIVATE KEY-----\nMIIE\nabc",
CRITICALHard-coded secrets · secret.private_key · CWE-798, CWE-321
conformance/output.json:1106
"input": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3Blbn\n-----END OPENSSH PRIVATE KEY-----",
CRITICALHard-coded secrets · secret.private_key · CWE-798, CWE-321
conformance/output.json:1112
"input": "-----BEGIN EC PRIVATE KEY-----\nMHc\n-----END RSA PRIVATE KEY----- x",
CRITICALHard-coded secrets · secret.private_key · CWE-798, CWE-321
conformance/output.json:1118
"input": "a -----BEGIN PRIVATE KEY-----\nk1\n-----END PRIVATE KEY----- b -----BEGIN PRIVATE KEY-----\nk2\n-----END PRIVATE KEY----- c",
CRITICALHard-coded secrets · secret.slack · CWE-798, CWE-321
conformance/output.json:608
"input": "xoxb-1234567890-abc",
CRITICALHard-coded secrets · secret.slack · CWE-798, CWE-321
scripts/conformance.mjs:1344
"xoxb-1234567890-abc", "xoxp-12345", "xoxq-1234567890", "sk_live_abcdefghij12", "rk_test_abcdefghij", "pk_live_abcdefghi",
HIGHCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
packages/ruby/lib/cronwatch/types.rb:319
@written_details = [Marshal.load(Marshal.dump(details)), Alert.string_keys(written)] if written.is_a?(Hash)
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
packages/go/internal/jsre/match.go:560
func (re *Regexp) exec(m *matcher, from int) bool {
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
packages/go/sqlstore/store.go:170
err = retryBusy(ctx, func() error { return exec(ctx, conn, "PRAGMA journal_mode = WAL") })
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
packages/go/sqlstore/store.go:172
err = exec(ctx, conn, "PRAGMA busy_timeout = 5000")
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
packages/go/sqlstore/store.go:175
err = exec(ctx, conn, "PRAGMA synchronous = NORMAL")
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
packages/go/sqlstore/store.go:193
func exec(ctx context.Context, q querier, text string, args ...any) error {
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
MEDIUMCode injection · code.dynamic_import · CWE-78, CWE-94, CWE-95
packages/python/src/cronwatch/__init__.py:92
return importlib.import_module(f"{__name__}.{name}")
MEDIUMCode injection · code.dynamic_import · CWE-78, CWE-94, CWE-95
packages/python/src/cronwatch/_deprecated.py:23
return getattr(importlib.import_module(new), name)
MEDIUMCode injection · code.dynamic_import · CWE-78, CWE-94, CWE-95
packages/python/src/cronwatch/_deprecated.py:26
return sorted(vars(importlib.import_module(new)))
MEDIUMInformation disclosure · disclose.log_secret · CWE-209, CWE-532
scripts/dev-dashboard.mjs:157
console.log(`Sign in: http://localhost:${PORT}${BASE}/?token=${TOKEN}`);
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
deploy/nginx.conf:122
proxy_pass http://127.0.0.1:3790;
MEDIUMObfuscation / stealth · obf.base64_blob · CWE-506, CWE-94
conformance/channels.json:65
"triage": "<b>Likely</b> cause & fix: tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
MEDIUMObfuscation / stealth · obf.base64_blob · CWE-506, CWE-94
conformance/channels.json:80
"output": "````\nzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
MEDIUMObfuscation / stealth · obf.base64_blob · CWE-506, CWE-94
conformance/channels.json:95
"message": "Started 2026-01-05 09:30:00 UTC (now), ran 2s.\nError: long\nOutput (tail):\n````\nzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
MEDIUMObfuscation / stealth · obf.base64_blob · CWE-506, CWE-94
conformance/channels.json:2356
"body": "{\"schema\":1,\"type\":\"failed\",\"run\":{\"id\":\"r1\",\"job\":\"nightly\",\"status\":\"failed\",\"startedAt\":1767605400000,\"finishedAt\":1767605401500,\"durationMs\":1500,\"error\":\"Err

Gates applied: critical_finding, no_behavioural_pass.

Audited 2026-10-11 · audit v0.4.1 · source sha ae2b8530078cfull audit observations/trust-audit/mcp-server/phillips-jon__cronwatch.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-11ae2b8530078cBLOCKF40first audit
06

Questions

What is the cronwatch MCP server?

CronWatch records every run of your scheduled jobs in your own database, and speaks up when one is missed, fails, gets stuck, runs slow or costs too much.

What tools does cronwatch expose?

9 in total: 8 read-only, 1 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.

Is cronwatch safe to connect to an agent?

No — not without reading the findings first. The audit graded it F (40/100) and found 16 critical or high issues in the source. Each one is listed on this page with the file and line it is on.

What credentials does cronwatch need?

It reads CRONWATCH_TOKEN, CRON_SECRET, RESEND_API_KEY and TWILIO_AUTH_TOKEN from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does cronwatch run?

It speaks stdio, so it runs as a local process your client starts. It is published on npm as cronwatch-site.

How current is this page?

The grade is for one exact copy of the source (ae2b8530078c), read on 2026-10-11. The repository is watched and re-audited when it changes.

Advertisement