Skip to content

Ship Check

by uxcontinuum.com · remote · no sign-in to list tools · v0.2.0 · published by com.uxcontinuum

Scan a deployed app URL for exposed keys, open Supabase tables and missing security headers.

Final · 1Changes · 8

11 tools: 1 do something that can't be undone, 8 change things and 2 only read.

Scanned Oct 21, 2026

1 check matched something in the tool definitions. No finding is not a safety guarantee. How the checks work.

claude mcp add --transport http ship-check https://uxcontinuum.com/api/mcp

Findings

Matches of fixed checks, with the text they matched.

1 warn
  • The server marks "swarm_run_cost_estimate" read-only (readOnlyHint: true), and its own name, description or input give the class "write".

    Matched text

    annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The name "swarm_run_cost_estimate" says "run": a word for a change.

    What this check looks for

Tools

Open a tool for its reasons and full description. Descriptions are the publisher's own words, shown as they are.

11 tools

Can't be undone 1Claude Code: ask
  • send_messageSend a message to Matt Turley (Continuum) on the user's behalf, like the contact form on uxcontinuum.com.Reads text others writeCan send data outNo findings

    Why it is in this group

    • The name "send_message" says "send": a word for sending, and what is sent cannot be taken back.

    What it can reach

    • untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
    • outboundThe name "send_message" says "send": it sends or publishes something to other people.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Send Matt a message
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: true
Changes things 8Claude Code: ask
  • agent_cost_estimateEstimate blended cost per shipped task for a month of agent runs, given a retry rate.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    Estimate blended cost per shipped task for a month of agent runs, given a retry rate.

    Annotations the server declares

    • title: Agent cost per shipped task
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • book_callBook a free 30-minute intro call with Matt Turley (Continuum) directly on his calendar.Reads text others writeNo findings

    Why it is in this group

    • The name "book_call" says "call": a word for a change.

    What it can reach

    • untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Book a call with Matt
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: true
  • cursor_auto_cost_estimateEstimate Cursor Auto blended cost versus pinning a single model.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    Estimate Cursor Auto blended cost versus pinning a single model.

    Annotations the server declares

    • title: Cursor Auto vs pinned model cost
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • leak_checkOlder name for ship_check, kept for existing callers.Reads text others writeCan send data outNo findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.

    What it can reach

    • untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
    • outboundThe input takes a URL (input.url): a request to a URL can carry data to whoever runs it.
    Description, as the server wrote it
    Older name for ship_check, kept for existing callers. Same scan, same input, same result. Prefer ship_check.

    Annotations the server declares

    • title: Leak Check (older name for ship_check)
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: true
  • request_estimateGet 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.Reads text others writeNo findings

    Why it is in this group

    • The name "request_estimate" says "request": a word for a change.

    What it can reach

    • untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Request a project estimate
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: true
  • request_human_reviewGet 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.Reads text others writeNo findings

    Why it is in this group

    • The name "request_human_review" says "request": a word for a change.

    What it can reach

    • untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Request a human review ($299)
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: true
  • ship_checkBefore 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.Reads text others writeCan send data outNo findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.

    What it can reach

    • untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
    • outboundThe input takes a URL (input.url): a request to a URL can carry data to whoever runs it.
    Description, as the server wrote it
    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 the same-origin JS bundles it ships (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.

    Annotations the server declares

    • title: Ship Check: scan a deployed app
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: true
  • swarm_run_cost_estimateEstimate the cost of a multi-agent orchestrator plus sub-agent swarm run.1 finding

    Why it is in this group

    • The name "swarm_run_cost_estimate" says "run": a word for a change.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.

    Findings

    • Warn

      The server marks "swarm_run_cost_estimate" read-only (readOnlyHint: true), and its own name, description or input give the class "write".

      Matched text

      annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The name "swarm_run_cost_estimate" says "run": a word for a change.

      What this check looks for
    Description, as the server wrote it
    Estimate the cost of a multi-agent orchestrator plus sub-agent swarm run.

    Annotations the server declares

    • title: Multi-agent swarm run cost
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
Only reads 2Claude Code: allow
  • get_availabilityList open slots for a free 30-minute intro call with Matt Turley (Continuum), read live from his Cal.com calendar.Reads private dataReads text others writeNo findings

    Why it is in this group

    • The name "get_availability" says "get": a word for reading.

    What it can reach

    • private-dataThe description's first sentence says "list" and "calendar": it reads calendars.
    • untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Get open call times with Matt
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: true
  • list_servicesList 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 ca…Reads private dataReads text others writeNo findings

    Why it is in this group

    • The name "list_services" says "list": a word for reading.

    What it can reach

    • private-dataThe description's first sentence says "list" and "message": it reads messages.
    • untrusted-inputThe description's first sentence says "list" and "message": it reads messages, which other people can write.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Continuum services and prices
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false

This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.

Exfil surface

Which tools read private data, which read text someone else can write, and which can send data out. One of each is a path a prompt injection can use.

48 paths in this server alone from private data, through text someone else wrote, to a way out. Denying 2 private-data tools breaks every one.

Reads private data2
Reads files, mail, messages, databases, secrets, calendars or repositories.
Reads text others write8
Brings in text someone else can write: web pages, inbound email, messages, issues and comments.
Can send data out3
Can carry data to people or systems: it sends, posts or publishes, or takes a recipient, channel or URL.
deny to break every path
{
  "permissions": {
    "deny": [
      "mcp__ship-check__get_availability",
      "mcp__ship-check__list_services"
    ]
  }
}

Other servers in the same agent add their own tools to these paths. Audit your whole setup to see them together.

Remote posture

What anyone on the internet sees at the remote endpoint: an anonymous initialize and tools/list, and the public OAuth metadata.

Looked at Oct 22, 2026, 14:43 UTC, unchanged since Oct 22, 2026. No credentials were sent and no tool was called. What is looked at.

Reachable
yes
HTTP status of an anonymous initialize
200
tools/list served without credentials
yes
Tools that change things, listed without credentials
9
Protocol version
2025-06-18
WWW-Authenticate on 401
not observed
resource_metadata in WWW-Authenticate
none
RFC 9728 protected resource metadata
none
Authorization servers
none
Legacy HTTP+SSE transport
no
Dynamic client registration
not observed
Client ID metadata documents
not observed
  • HighThe whole server

    The endpoint served tools/list without credentials, and the list has 9 tools that change things (1 irreversible, 8 write). Whether a call also works without credentials was not tested: tools are never called.

    Matched text

    https://uxcontinuum.com/api/mcp: tools/list returned 11 tools to an anonymous client, including send_message (irreversible), ship_check (write), request_human_review (write), leak_check (write), cursor_auto_cost_estimate (write) and 4 more

    What this check looks for

Install

Pinned to version 0.2.0. Values in angle brackets are yours to fill in.

claude mcp add --transport http ship-check https://uxcontinuum.com/api/mcp

Run in a terminal.

Claude Code permissions

Allow the reads, ask before a change or a way out, deny the deletes. Paste into .claude/settings.json.

.claude/settings.json
{
  "permissions": {
    "allow": [
      "mcp__ship-check__list_services",
      "mcp__ship-check__get_availability"
    ],
    "ask": [
      "mcp__ship-check__ship_check",
      "mcp__ship-check__request_human_review",
      "mcp__ship-check__leak_check",
      "mcp__ship-check__cursor_auto_cost_estimate",
      "mcp__ship-check__swarm_run_cost_estimate",
      "mcp__ship-check__agent_cost_estimate",
      "mcp__ship-check__book_call",
      "mcp__ship-check__send_message",
      "mcp__ship-check__request_estimate"
    ],
    "deny": []
  }
}

Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. A read that can send data out (it takes a URL, say) asks first too. It assumes the server is installed as ship-check. Review it before you use it.

Capability tags behind 8 rules
  • mcp__ship-check__ship_check untrusted-input, outbound
  • mcp__ship-check__request_human_review untrusted-input
  • mcp__ship-check__leak_check untrusted-input, outbound
  • mcp__ship-check__list_services private-data, untrusted-input
  • mcp__ship-check__get_availability private-data, untrusted-input
  • mcp__ship-check__book_call untrusted-input
  • mcp__ship-check__send_message untrusted-input, outbound
  • mcp__ship-check__request_estimate untrusted-input