Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions dashboard/directory.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
(() => {
const hero = document.querySelector("section.hero");
if (hero) {
const eyebrow = hero.querySelector(".eyebrow");
const title = hero.querySelector("h1");
const subtitle = hero.querySelector(".subtitle");
const actions = hero.querySelector(".hero-actions");
if (eyebrow) eyebrow.textContent = "AGENT WORKFLOW SAFETY";
if (title) title.innerHTML = 'Is this agent <span>safe to ship?</span>';
if (subtitle) {
subtitle.textContent = "Your agents can call tools \u2014 GitHub, Slack, files, sometimes production. Those tools are small servers your team pasted into a config. MCP is just the name of the plug. Observatory checks them before the agent is allowed to connect.";
}
if (actions) {
actions.innerHTML = '<a class="button primary" href="/safety-index/">See a scored tool \u2197</a><a class="button" href="https://www.npmjs.com/package/@kryptosai/mcp-observatory">Run a free scan \u2197</a>';
}
document.title = "MCP Observatory \u2014 Check the tools your agents can use";
}

const cards = [...document.querySelectorAll(".server-card")];
const search = document.querySelector("#server-search");
const category = document.querySelector("#category-filter");
const status = document.querySelector("#directory-status");
const showMore = document.querySelector("#show-more");
if (!search || !category || !status || !showMore) return;
let limit = 12;

const render = () => {
Expand Down
53 changes: 53 additions & 0 deletions docs/homepage-plain-language.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Homepage copy

Replace the current hero and first sections with this. The SDM test: they can retell it in one breath without knowing what MCP is.

## Browser tab / social

- Title: MCP Observatory — Check the tools your agents can use
- Description: Your agents can call tools like GitHub, Slack, and files. Observatory checks those tools before the agent is allowed to use them.

## Hero

Eyebrow: AGENT WORKFLOW SAFETY

Headline: Is this agent safe to ship?

Subhead: Your agents can call tools — GitHub, Slack, files, sometimes production. Those tools are small servers your team pasted into a config. MCP is just the name of the plug. Observatory checks them before the agent is allowed to connect.

Primary button: See a scored tool ↗ → `/safety-index/`
Secondary button: Run a free scan ↗ → npm package

Keep the two `npx` command rows (local scan, then `cloud upload`).

Hero card: Kubernetes tool, 72, BLOCK. Checks in English: What can this tool do? Are the permissions too broad? Should an agent be allowed to use it?

## Example

Eyebrow: A REAL EXAMPLE

Headline: Here is a tool. We said block.

Body: This Kubernetes tool scored 72/100. Security was 0. An agent that can talk to your cluster should not get it until those findings are fixed. Click through to see the report — no install required.

## How it works

Headline: Check the tools. Then decide.

Body: Point Observatory at the tools in your agent setup. It starts them, looks at what they can do, and gives a written call: allow, review, or block.

1. Find the tools — read the agent config, list every tool the agent can reach.
2. Check them — permissions, hidden instructions, tools that changed.
3. Get a call — allow, review, or block, plus a report. Keep it in CI.
4. Optionally stop the call — runtime blocking when you want it. Local scan stays free.

## Teams

Headline: Don’t learn what the agent can do from an incident.

Allow / Review / Block — not approve / gate / defer.
Pilot is a secondary link, not the first CTA.

## Do not claim on this page

Do not say the whole agentic workflow is already enforced and taped. That loop is not one CLI yet. This page sells the tool check, in English.
8 changes: 5 additions & 3 deletions scripts/validate-dashboard.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ if (/body::before\s*\{[^}]*display:none/.test(css) === false) failures.push("dec

const homepage = await readFile(path.join(root, "index.html"), "utf8");
const homepageTop = homepage.slice(0, homepage.indexOf('<div class="section-title" id="index">'));
if (count(homepage, /Trust is a <span>production decision\.<\/span>/g) !== 1) failures.push("homepage: expected exactly one trust-led hero headline");
if (count(homepage, /THE MOMENT BEFORE TRUST/g) !== 1) failures.push("homepage: expected exactly one trust-led eyebrow");
if (count(homepage, /Is this agent <span>safe to ship\?<\/span>/g) !== 1) failures.push("homepage: expected exactly one plain-language hero headline");
if (count(homepage, /AGENT WORKFLOW SAFETY/g) !== 1) failures.push("homepage: expected exactly one workflow-safety eyebrow");
if (!homepage.includes("MCP is just the name of the plug.")) failures.push("homepage: missing plain-language MCP definition");
if (!homepage.includes("See a scored tool")) failures.push("homepage: missing non-CLI primary CTA");
if (!homepage.includes('class="logo-strip"')) failures.push("homepage: missing full-width company logo strip");
if (!homepage.includes("Evaluated technologies, not MCP Observatory customers, endorsements, or partnerships.")) failures.push("homepage: missing evaluated-technologies disclaimer");
if (!homepage.includes('class="hero-product"')) failures.push("homepage: missing product decision visual");
Expand Down Expand Up @@ -65,7 +67,7 @@ for (const file of await htmlFiles(root)) {
const source = await readFile(file, "utf8");
const rel = path.relative(process.cwd(), file);
if (!/href="\/m3\.css(?:\?[^"]*)?"/.test(source)) failures.push(`${rel}: missing shared m3.css`);
if (count(source, /<main\b/gi) !== 1) failures.push(`${rel}: expected exactly one main landmark`);
if (count(source, /<main\b/gi) !== 1) failures.push(`${rel}: expected exactly one main landmark");
if (count(source, /<h1\b/gi) !== 1) failures.push(`${rel}: expected exactly one h1`);
const headingLevels = [...source.matchAll(/<h([1-6])\b/gi)].map(match => Number(match[1]));
if (headingLevels[0] !== 1) failures.push(`${rel}: h1 is not the first heading`);
Expand Down
Loading