Let the coordinator manage skills, MCP servers and tools, behind a confirm card

- Coordinator tools in its own chat (super admin only): list_extensions,
  set_extension_access, delete_extension, and update_skill /
  update_mcp_server / update_custom_tool for what can't change where
  anything is sent (on/off, names, arguments, left-out tools)
- Adding a skill, MCP server or tool, or changing a skill's words, a
  server's URL or headers or a tool's kind or config, goes through
  propose_skill / propose_mcp_server / propose_custom_tool: stored in
  extension_proposals with the bot's background check, shown as a
  [proposal:ID] chip that opens a card with Confirm and Reject
- The card's facts are worked out by the app from what Confirm saves: the
  host, every {{env.KEY}} and whether it's saved, the config; for a skill
  its links, hosts, tool names, mentions of secrets and a diff against
  the saved runbook
- Confirming decides once and checks again; a server or tool missing a key
  is saved switched off, and the outcome is posted to the bot in chat
- Never from a bot: stdio servers, a URL whose host a template decides,
  envs in a prompt tool, a key's value

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-25 06:08:09 +01:00
co-authored by Claude Opus 5.5
parent e6c278198b
commit fefc295d15
77 changed files with 3307 additions and 12 deletions
+82
View File
@@ -2216,6 +2216,88 @@ const schema: BUN_SQLITE_DatabaseSchemaType = {
},
],
},
{
tableName: "extension_proposals",
tableDescription: `An MCP server, custom tool or skill the coordinator proposed adding or changing, waiting for the super admin to confirm or reject it from the chat. Nothing is saved, connected or run until they confirm: the card shows where it sends, which envs it reads (saved or missing), for a skill what its runbook tells bots to do and what changed, and the bot's background check`,
fields: [
{
fieldName: "kind",
fieldDescription: `mcp (a remote MCP server), tool (a custom tool) or skill (a runbook)`,
dataType: "TEXT",
options: ["mcp", "tool", "skill"],
},
{
fieldName: "extension_id",
fieldDescription: `The server or tool it changes, null for a new one. Not a foreign key: a deleted one makes the proposal fail on confirm`,
dataType: "INTEGER",
},
{
fieldName: "name",
fieldDescription: `The server's or tool's name, for the chip`,
dataType: "TEXT",
},
{
fieldName: "data",
fieldDescription: `JSON: the whole server, tool or skill as it would be saved (SaveMcpServerRequest, SaveCustomToolRequest or SaveSkillRequest)`,
dataType: "TEXT",
},
{
fieldName: "research",
fieldDescription: `The bot's background check, markdown: who publishes it, whether it's official, what it needs`,
dataType: "TEXT",
},
{
fieldName: "sources",
fieldDescription: `JSON array of the URLs the background check read`,
dataType: "TEXT",
},
{
fieldName: "status",
dataType: "TEXT",
options: ["pending", "confirmed", "rejected", "replaced", "failed"],
defaultValue: "pending",
},
{
fieldName: "outcome",
fieldDescription: `What happened on confirm (saved, connected, keys missing) or why it failed`,
dataType: "TEXT",
},
{
fieldName: "result_id",
fieldDescription: `The server or tool it saved, once confirmed`,
dataType: "INTEGER",
},
{
fieldName: "expires_at",
fieldDescription: `A pending proposal can't be confirmed after this (Unix ms)`,
dataType: "INTEGER",
},
{
fieldName: "decided_at",
dataType: "INTEGER",
},
{
fieldName: "user_id",
fieldDescription: `The super admin whose conversation it was proposed in`,
dataType: "INTEGER",
},
{
fieldName: "bot_id",
fieldDescription: `The bot that proposed it (the coordinator). Not a foreign key`,
dataType: "INTEGER",
},
{
fieldName: "session_id",
fieldDescription: `The conversation it was proposed in, where the outcome is reported. Not a foreign key`,
dataType: "INTEGER",
},
{
fieldName: "workspace_id",
fieldDescription: `The session's workspace, null for the bot's own chat. Not a foreign key`,
dataType: "INTEGER",
},
],
},
{
tableName: "bot_mcp_servers",
tableDescription: `A bot that gets an MCP server's tools everywhere it works`,