From ebb996cd4a439ad712a4b1236556a3dee57347a5 Mon Sep 17 00:00:00 2001
From: jonnyparris <6400000+jonnyparris@users.noreply.github.com>
Date: Tue, 26 May 2026 12:46:18 +0100
Subject: [PATCH] fix(mcp): seed new catalog entries on every onStart +
integrations-first UI layout
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Two follow-ups to PR #83:
1. **Catalog seed was first-run-only.** The cf-portal entry I added to
`mcp-catalog.ts` never appeared in `/api/mcp-catalog` because the
endpoint reads from UserControl's `approved_mcps` table, which is
seeded once when the table is empty. Existing DOs (i.e. mine, and
everyone else's) had been seeded back when the catalog was just
browser-rendering + github, so the new entry never propagated.
Fix: use `INSERT OR IGNORE` on every onStart, keyed by `mcp_url`
(PRIMARY KEY). New catalog entries flow through; admin edits and
soft-deletes on existing rows are preserved.
2. **Integrations buried below Skills + Tools.** Settings panel order
was Skills (~50 entries) → Tools (~30 entries) → Integrations.
Moved Integrations above both. Skills and Tools are now wrapped in
collapsed `` so they don't dominate the scroll.
No tests added — the seed behaviour is exercised implicitly by every
test that hits `/api/mcp-catalog` (which seeds via onStart). The UI
move is markup-only.
beep-boop-🤖
---
public/index.html | 24 ++++++++++++++----------
src/user-control.ts | 42 +++++++++++++++++++++++-------------------
2 files changed, 37 insertions(+), 29 deletions(-)
diff --git a/public/index.html b/public/index.html
index 3cfca44..4fd0ef8 100644
--- a/public/index.html
+++ b/public/index.html
@@ -910,16 +910,6 @@
Browser Rendering
-
-
Skills
-
Skills are SKILL.md files the agent loads on demand. Built-in skills ship with Dodo; personal skills you author here. Workspace skills (per-session, from .dodo/skills/ etc.) are not shown here.
-
-
-
-
Tools
-
Tools available to the agent. Dimmed entries are gated on session config (codemode, browser) or reachable only inside a codemode block (most git ops). Configure MCP integrations below to add more.
-
-
Integrations
@@ -934,6 +924,20 @@
Integrations
+
+
+
Skills
+
Skills are SKILL.md files the agent loads on demand. Built-in skills ship with Dodo; personal skills you author here. Workspace skills (per-session, from .dodo/skills/ etc.) are not shown here.
+
+
+
+
+
+
Tools
+
Tools available to the agent. Dimmed entries are gated on session config (codemode, browser) or reachable only inside a codemode block (most git ops). Configure MCP integrations above to add more.
+
+
+
Secrets
diff --git a/src/user-control.ts b/src/user-control.ts
index fb8ca3d..567ed9a 100644
--- a/src/user-control.ts
+++ b/src/user-control.ts
@@ -1468,25 +1468,29 @@ export class UserControl extends DurableObject {
this.ctx.storage.sql.exec("INSERT OR IGNORE INTO user_config (key, value, updated_at) VALUES (?, ?, ?)", key, String(value), now);
}
- const existingCount = (Array.from(this.ctx.storage.sql.exec("SELECT COUNT(*) AS n FROM approved_mcps WHERE is_deleted = 0"))[0] as SqlRow | null);
- if (Number(existingCount?.n ?? 0) === 0) {
- const { getDeployMcpCatalog } = await import("./mcp-catalog");
- const seedNow = Date.now();
- for (const entry of getDeployMcpCatalog(this.env)) {
- this.ctx.storage.sql.exec(
- `INSERT INTO approved_mcps (mcp_url, id, display_name, description, setup_guide, known_hosts, auth_type, status, is_deleted, created_at, updated_at)
- VALUES (?, ?, ?, ?, ?, ?, ?, 'enabled', 0, ?, ?)`,
- entry.url,
- entry.id,
- entry.name,
- entry.description ?? null,
- entry.setupGuide ?? null,
- JSON.stringify(entry.knownHosts ?? []),
- entry.auth_type ?? "static_headers",
- seedNow,
- seedNow,
- );
- }
+ // Seed `approved_mcps` from the code-level catalog. We use `INSERT OR IGNORE`
+ // keyed by `mcp_url` so:
+ // - On first run, every catalog entry is inserted.
+ // - On subsequent runs, only NEW entries (not yet in the table) are
+ // inserted; admin-edited rows and soft-deleted rows are preserved.
+ // This is how adding a new entry to `mcp-catalog.ts` propagates to all
+ // existing UserControl DOs without an explicit migration.
+ const { getDeployMcpCatalog } = await import("./mcp-catalog");
+ const seedNow = Date.now();
+ for (const entry of getDeployMcpCatalog(this.env)) {
+ this.ctx.storage.sql.exec(
+ `INSERT OR IGNORE INTO approved_mcps (mcp_url, id, display_name, description, setup_guide, known_hosts, auth_type, status, is_deleted, created_at, updated_at)
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'enabled', 0, ?, ?)`,
+ entry.url,
+ entry.id,
+ entry.name,
+ entry.description ?? null,
+ entry.setupGuide ?? null,
+ JSON.stringify(entry.knownHosts ?? []),
+ entry.auth_type ?? "static_headers",
+ seedNow,
+ seedNow,
+ );
}
}