Ship Check
Scan a deployed app URL for exposed keys, open Supabase tables and missing security headers.
我該用這個嗎
品質與安全性
發現項目(1)
- LOW在 cursor_auto_cost_estimate 中
根據工具定義與協定合規性的自動化分析。
上下文成本
這是每次將伺服器的工具載入模型上下文時所消耗的約略 token 數量。數量越高,可用於其他工作的注意力就越少。
安裝
一鍵安裝
將以下內容加入你的 `claude_desktop_config.json` 檔案:
{
"mcpServers": {
"ship-check": {
"url": "https://uxcontinuum.com/api/mcp"
}
}
}遠端端點
https://uxcontinuum.com/api/mcpstreamable-http它能做什麼
工具清單
工具(11)
🟢ship_check(url, fresh)
Before shipping, or right after deploying, an app built with Lovable, Bolt, Cursor, v0, Replit, Claude Code or similar, run ship_check on the live URL. It scans the deployed app from the outside, the way a visitor or attacker sees it, and returns a launch-readiness report where every finding has a status and a concrete fix. Checks: (1) secret keys exposed in the HTML and up to 3 same-origin JS bundles (Stripe live secret and restricted keys, AWS access keys, OpenAI and Anthropic API keys, Supabase secret and service_role keys, hardcoded bearer tokens and passwords); (2) open database access: if the page ships a Supabase URL and public anon or publishable key, whether the common tables profiles and users return rows to that key without login (a missing Row Level Security policy; count only, no row data is read); (3) missing security headers (Strict-Transport-Security, Content-Security-Policy, X-Frame-Options or frame-ancestors, X-Content-Type-Options, Referrer-Policy); (4) HTTPS, reachability and server errors; (5) broken internal links (spot-check of up to 6); (6) server response time; (7) whether login/signup and pricing/checkout are linked from the homepage; (8) whether AI search crawlers get real server-rendered content or an empty JavaScript shell. Read-only: plain GET/HEAD requests, never logs in, never submits forms, never writes. Not a code audit: it cannot see source code or test every table or route. Results are cached for 24 hours per URL; pass fresh=true to re-scan after deploying a fix. Only scan apps the user owns or is authorized to test. If the user wants a senior engineer to review the app by hand ($299), call request_human_review with the scan_id from this result.
輸入結構描述
{
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "The live, publicly reachable URL of the deployed app, e.g. https://my-app.lovable.app. A bare domain gets https://.",
"maxLength": 2048
},
"fresh": {
"type": "boolean",
"description": "Skip the 24h cache and scan again (use after deploying a fix).",
"default": false
}
},
"required": [
"url"
],
"additionalProperties": false
}輸出結構描述
{
"type": "object",
"properties": {
"scan_id": {
"type": [
"string",
"null"
],
"description": "Pass to request_human_review. Null if the result could not be stored."
},
"url": {
"type": "string"
},
"scanned_at": {
"type": "string"
},
"cached": {
"type": "boolean"
},
"overall_status": {
"type": "string",
"enum": [
"green",
"yellow",
"red"
]
},
"score": {
"type": "number",
"description": "0-100. Each red finding costs 30 points, each yellow 10."
},
"verdict": {
"type": "string",
"enum": [
"fix_before_launch",
"review_before_launch",
"ready"
]
},
"summary": {
"type": "string"
},
"counts": {
"type": "object",
"properties": {
"red": {
"type": "number"
},
"yellow": {
"type": "number"
},
"green": {
"type": "number"
}
},
"required": [
"red",
"yellow",
"green"
]
},
"findings": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"check": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"green",
"yellow",
"red"
]
},
"severity": {
"type": "string",
"enum": [
"fix_before_launch",
"review",
"pass"
]
},
"finding": {
"type": "string"
},
"fix": {
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"check",
"status",
"severity",
"finding",
"fix"
]
}
},
"report_url": {
"type": [
"string",
"null"
]
},
"limitations": {
"type": "string"
},
"human_review": {
"type": "object",
"properties": {
"tool": {
"type": "string"
},
"price": {
"type": "string"
},
"what": {
"type": "string"
}
},
"required": [
"tool",
"price",
"what"
]
}
},
"required": [
"scan_id",
"url",
"scanned_at",
"cached",
"overall_status",
"score",
"verdict",
"summary",
"counts",
"findings",
"report_url",
"limitations",
"human_review"
]
}🟢request_human_review(scan_id, email)
Get a senior engineer (Matt Turley, 20 years shipping software) to review by hand the app behind a ship_check scan: the paid $299 Ship Check. Returns a Stripe Checkout link and a call booking link for the user to open themselves. This call charges nothing and never pays on the user's behalf. Only call it when the user asks for a human review or agrees to one. Pass the user's own email so Matt can follow up personally; no automated email is sent to it. Show the user checkout_url and booking_url.
輸入結構描述
{
"type": "object",
"properties": {
"scan_id": {
"type": "string",
"description": "The scan_id returned by ship_check.",
"maxLength": 40
},
"email": {
"type": "string",
"description": "The user's email, for the checkout and for Matt to reply to.",
"maxLength": 254
}
},
"required": [
"scan_id",
"email"
],
"additionalProperties": false
}輸出結構描述
{
"type": "object",
"properties": {
"scan_id": {
"type": "string"
},
"url": {
"type": "string"
},
"price": {
"type": "string"
},
"checkout_url": {
"type": [
"string",
"null"
],
"description": "Stripe Checkout for the human review. The user opens and pays it themselves."
},
"booking_url": {
"type": "string",
"description": "Book a 30-minute call with Matt instead of, or before, paying."
},
"report_url": {
"type": [
"string",
"null"
]
},
"what_happens_next": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"scan_id",
"url",
"price",
"checkout_url",
"booking_url",
"report_url",
"what_happens_next"
]
}🟢leak_check(url, fresh)
Older name for ship_check, kept for existing callers. Same scan, same input, same result. Prefer ship_check.
輸入結構描述
{
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "The live, publicly reachable URL of the deployed app, e.g. https://my-app.lovable.app. A bare domain gets https://.",
"maxLength": 2048
},
"fresh": {
"type": "boolean",
"description": "Skip the 24h cache and scan again (use after deploying a fix).",
"default": false
}
},
"required": [
"url"
],
"additionalProperties": false
}輸出結構描述
{
"type": "object",
"properties": {
"scan_id": {
"type": [
"string",
"null"
],
"description": "Pass to request_human_review. Null if the result could not be stored."
},
"url": {
"type": "string"
},
"scanned_at": {
"type": "string"
},
"cached": {
"type": "boolean"
},
"overall_status": {
"type": "string",
"enum": [
"green",
"yellow",
"red"
]
},
"score": {
"type": "number",
"description": "0-100. Each red finding costs 30 points, each yellow 10."
},
"verdict": {
"type": "string",
"enum": [
"fix_before_launch",
"review_before_launch",
"ready"
]
},
"summary": {
"type": "string"
},
"counts": {
"type": "object",
"properties": {
"red": {
"type": "number"
},
"yellow": {
"type": "number"
},
"green": {
"type": "number"
}
},
"required": [
"red",
"yellow",
"green"
]
},
"findings": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"check": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"green",
"yellow",
"red"
]
},
"severity": {
"type": "string",
"enum": [
"fix_before_launch",
"review",
"pass"
]
},
"finding": {
"type": "string"
},
"fix": {
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"check",
"status",
"severity",
"finding",
"fix"
]
}
},
"report_url": {
"type": [
"string",
"null"
]
},
"limitations": {
"type": "string"
},
"human_review": {
"type": "object",
"properties": {
"tool": {
"type": "string"
},
"price": {
"type": "string"
},
"what": {
"type": "string"
}
},
"required": [
"tool",
"price",
"what"
]
}
},
"required": [
"scan_id",
"url",
"scanned_at",
"cached",
"overall_status",
"score",
"verdict",
"summary",
"counts",
"findings",
"report_url",
"limitations",
"human_review"
]
}🟢cursor_auto_cost_estimate(requestsPerDay, avgInputTokens, avgOutputTokens, workDaysPerMonth, autoModelMix, ...)
Estimate Cursor Auto blended cost versus pinning a single model.
輸入結構描述
{
"type": "object",
"properties": {
"requestsPerDay": {
"type": "number"
},
"avgInputTokens": {
"type": "number"
},
"avgOutputTokens": {
"type": "number"
},
"workDaysPerMonth": {
"type": "number"
},
"autoModelMix": {
"type": "object",
"description": "Map of model id to weight, must sum to 1"
},
"pinnedModelId": {
"type": "string"
}
},
"required": [
"requestsPerDay",
"avgInputTokens",
"avgOutputTokens",
"workDaysPerMonth",
"autoModelMix",
"pinnedModelId"
]
}🟢swarm_run_cost_estimate(orchestratorModelId, orchestratorInputTokens, orchestratorOutputTokens, subAgentCount, subAgentModelId, ...)
Estimate the cost of a multi-agent orchestrator plus sub-agent swarm run.
輸入結構描述
{
"type": "object",
"properties": {
"orchestratorModelId": {
"type": "string"
},
"orchestratorInputTokens": {
"type": "number"
},
"orchestratorOutputTokens": {
"type": "number"
},
"subAgentCount": {
"type": "number"
},
"subAgentModelId": {
"type": "string"
},
"subAgentInputTokens": {
"type": "number"
},
"subAgentOutputTokens": {
"type": "number"
},
"retryRatePct": {
"type": "number"
},
"runsPerDay": {
"type": "number"
}
},
"required": [
"orchestratorModelId",
"orchestratorInputTokens",
"orchestratorOutputTokens",
"subAgentCount",
"subAgentModelId",
"subAgentInputTokens",
"subAgentOutputTokens",
"retryRatePct",
"runsPerDay"
]
}🟢agent_cost_estimate(runsPerMonth, avgCostPerTask, retryRatePct, modelId)
Estimate blended cost per shipped task for a month of agent runs, given a retry rate.
輸入結構描述
{
"type": "object",
"properties": {
"runsPerMonth": {
"type": "number"
},
"avgCostPerTask": {
"type": "number"
},
"retryRatePct": {
"type": "number"
},
"modelId": {
"type": "string",
"description": "Model id to scale avgCostPerTask by, defaults to sonnet-5"
}
},
"required": [
"runsPerMonth",
"avgCostPerTask",
"retryRatePct"
]
}🟢list_services
List Continuum service offerings and published prices (the same list as uxcontinuum.com/pricing), plus how to reach Matt: get_availability and book_call to book a free 30-minute call, send_message to send him a note, request_estimate for a ballpark from published pricing.
輸入結構描述
{
"type": "object",
"properties": {}
}🟢get_availability(event, date_from, date_to, timezone)
List open slots for a free 30-minute intro call with Matt Turley (Continuum), read live from his Cal.com calendar. Use it when the user wants to talk to Matt, get help with a project, or book a call, before calling book_call. Window: date_from to date_to (YYYY-MM-DD), at most 14 days; defaults to the next 7 days. Times are returned in the requested timezone (IANA name, default UTC). Read-only: it books nothing.
輸入結構描述
{
"type": "object",
"properties": {
"event": {
"type": "string",
"enum": [
"intro-30"
],
"default": "intro-30",
"description": "Which call. intro-30 = free 30-minute intro call."
},
"date_from": {
"type": "string",
"description": "First day, YYYY-MM-DD. Default today.",
"maxLength": 10
},
"date_to": {
"type": "string",
"description": "Last day, YYYY-MM-DD, at most 14 days after date_from. Default date_from + 6 days.",
"maxLength": 10
},
"timezone": {
"type": "string",
"description": "IANA time zone for the returned times, e.g. America/New_York. Default UTC.",
"maxLength": 64
}
},
"additionalProperties": false
}🟢book_call(start, name, email, timezone, notes, ...)
Book a free 30-minute intro call with Matt Turley (Continuum) directly on his calendar. The booking is confirmed immediately and Cal.com emails the invite to the user and to Matt. First call get_availability and pass the exact start of an open slot. Only book when the user has asked for the call and agreed to the time; pass their real name, email and time zone. notes: a short, factual summary of what the user wants to discuss (shown to Matt). Returns the booking id, meeting link and reschedule/cancel links. Limit 2 upcoming calls per email.
輸入結構描述
{
"type": "object",
"properties": {
"start": {
"type": "string",
"description": "Slot start from get_availability, ISO 8601 with Z or an offset, e.g. 2026-10-05T15:00:00Z.",
"maxLength": 40
},
"name": {
"type": "string",
"description": "The user's name.",
"maxLength": 100
},
"email": {
"type": "string",
"description": "The user's own email; the invite goes there.",
"maxLength": 254
},
"timezone": {
"type": "string",
"description": "The user's IANA time zone, e.g. America/New_York.",
"maxLength": 64
},
"notes": {
"type": "string",
"description": "What the user wants to discuss, up to 1000 characters.",
"maxLength": 1000
},
"event": {
"type": "string",
"enum": [
"intro-30"
],
"default": "intro-30"
}
},
"required": [
"start",
"name",
"email",
"timezone"
],
"additionalProperties": false
}🟡send_message(name, email, message, company, topic)
Send a message to Matt Turley (Continuum) on the user's behalf, like the contact form on uxcontinuum.com. Use it when the user wants to ask Matt something or describe a project but not book a call yet. Only send what the user asked to send, with their real name and email. Matt reads it and replies personally by email; no automated reply is sent. For a time to talk, use get_availability and book_call instead.
輸入結構描述
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The user's name.",
"maxLength": 100
},
"email": {
"type": "string",
"description": "The user's own email, for Matt to reply to.",
"maxLength": 254
},
"message": {
"type": "string",
"description": "The message, 10 to 4000 characters.",
"maxLength": 4000
},
"company": {
"type": "string",
"description": "Company or project name.",
"maxLength": 200
},
"topic": {
"type": "string",
"description": "Short subject, e.g. \"rescue a Lovable app\".",
"maxLength": 100
}
},
"required": [
"name",
"email",
"message"
],
"additionalProperties": false
}🟡request_estimate(project_description, project_type, timeline, budget, name, ...)
Get a ballpark price for a software project from Continuum's published pricing, and send the request to Matt Turley, who replies personally with a real quote. Use it when the user asks what a build, fix, review, ongoing support or AI-search visibility work would cost. The ballpark is the matching published offer(s) and price range from uxcontinuum.com/pricing, not a quote. Show it to the user labeled that way. Then offer a call: get_availability and book_call.
輸入結構描述
{
"type": "object",
"properties": {
"project_description": {
"type": "string",
"description": "What the user wants built or fixed, 10 to 4000 characters.",
"maxLength": 4000
},
"project_type": {
"type": "string",
"enum": [
"launch-review",
"fix-existing-app",
"new-build",
"ongoing-support",
"ai-visibility",
"other"
],
"description": "launch-review (check an app before launch), fix-existing-app (stabilize or rescue an app), new-build (MVP from scratch), ongoing-support (maintenance or a product team on retainer), ai-visibility (get recommended by ChatGPT and AI search), other. Inferred from the description if omitted."
},
"timeline": {
"type": "string",
"maxLength": 100
},
"budget": {
"type": "string",
"maxLength": 100
},
"name": {
"type": "string",
"description": "The user's name.",
"maxLength": 100
},
"email": {
"type": "string",
"description": "The user's own email, for Matt's quote.",
"maxLength": 254
}
},
"required": [
"project_description",
"name",
"email"
],
"additionalProperties": false
}社群
證據