From 94b3fe9166c877a985c69a8113ecf03696237a10 Mon Sep 17 00:00:00 2001 From: robertjamesprior <83608739+robertjamesprior@users.noreply.github.com> Date: Wed, 16 Sep 2026 23:20:42 +0000 Subject: [PATCH 1/3] Describe the server by what an agent can accomplish The registry description spent its 100-character budget on transport and auth, so a host agent picking among installed integrations had nothing to match a task against. Rewrite it around the job, and add server instructions on initialize for the framing that does not fit in 100 characters, including the order to try WebMCP, Playwright and computer use. Also point repository.url at the current org, replace the onkernel.com links that now redirect, add websiteUrl, and move $schema to the version the registry stores entries under. Co-Authored-By: Claude Opus 5 --- server.json | 11 ++++++----- src/app/[transport]/route.ts | 6 +++++- src/lib/mcp/instructions.test.ts | 22 ++++++++++++++++++++++ src/lib/mcp/instructions.ts | 21 +++++++++++++++++++++ 4 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 src/lib/mcp/instructions.test.ts create mode 100644 src/lib/mcp/instructions.ts diff --git a/server.json b/server.json index 14176435..b02b613e 100644 --- a/server.json +++ b/server.json @@ -1,13 +1,14 @@ { - "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json", + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json", "name": "com.onkernel/kernel-mcp-server", "title": "Kernel MCP Server", - "description": "Access Kernel's cloud-based browsers and app actions via MCP (remote HTTP + OAuth).", + "description": "Use websites and web apps on a user's behalf when no API or direct integration can do the job.", "status": "active", - "homepage_url": "https://onkernel.com", - "documentation_url": "https://onkernel.com/docs/reference/mcp-server", + "websiteUrl": "https://www.kernel.sh/docs/reference/mcp-server", + "homepage_url": "https://www.kernel.sh", + "documentation_url": "https://www.kernel.sh/docs/reference/mcp-server", "repository": { - "url": "https://github.com/onkernel/kernel-mcp-server", + "url": "https://github.com/kernel/kernel-mcp-server", "source": "github" }, "license": "MIT", diff --git a/src/app/[transport]/route.ts b/src/app/[transport]/route.ts index 5bfea6ce..29f8e3a3 100644 --- a/src/app/[transport]/route.ts +++ b/src/app/[transport]/route.ts @@ -23,6 +23,7 @@ import { createMcpTransportSession, verifyMcpTransportSession, } from "@/lib/mcp-transport-session"; +import { MCP_SERVER_INSTRUCTIONS } from "@/lib/mcp/instructions"; import { registerMcpCapabilities } from "@/lib/mcp/register"; import { resolveMcpVaultAccess } from "@/lib/mcp/entitlements"; import { name, version } from "../../../server.json"; @@ -105,7 +106,10 @@ export function connectionScopeFailureResponse( // Handler variants keep per-connection capabilities out of tools/list unless // the authenticated connection can use them. -const serverInfo = { serverInfo: { name, version } }; +const serverInfo = { + serverInfo: { name, version }, + instructions: MCP_SERVER_INSTRUCTIONS, +}; function createHandler({ mcpApps = false, vaults = false, diff --git a/src/lib/mcp/instructions.test.ts b/src/lib/mcp/instructions.test.ts new file mode 100644 index 00000000..3740a4c6 --- /dev/null +++ b/src/lib/mcp/instructions.test.ts @@ -0,0 +1,22 @@ +import { describe, expect, test } from "bun:test"; +import { description } from "../../../server.json"; +import { MCP_SERVER_INSTRUCTIONS } from "./instructions"; + +describe("MCP server metadata", () => { + // Exceeding the schema's 100-character cap fails registry publication, not CI. + test("registry description fits the schema limit", () => { + expect(description.length).toBeLessThanOrEqual(100); + }); + + test("instructions list the execution layers in escalation order", () => { + const webmcp = MCP_SERVER_INSTRUCTIONS.indexOf("webmcp"); + const playwright = MCP_SERVER_INSTRUCTIONS.indexOf( + "execute_playwright_code", + ); + const computerUse = MCP_SERVER_INSTRUCTIONS.indexOf("computer_action"); + + expect(webmcp).toBeGreaterThanOrEqual(0); + expect(playwright).toBeGreaterThan(webmcp); + expect(computerUse).toBeGreaterThan(playwright); + }); +}); diff --git a/src/lib/mcp/instructions.ts b/src/lib/mcp/instructions.ts new file mode 100644 index 00000000..1372a39f --- /dev/null +++ b/src/lib/mcp/instructions.ts @@ -0,0 +1,21 @@ +import { description } from "../../../server.json"; + +/** + * Returned on `initialize` as the server's `instructions`. Hosts surface this + * to the model, so it answers what an agent can accomplish here and when to + * reach for it, rather than describing the infrastructure underneath. + * + * The registry `description` in server.json is capped at 100 characters by the + * MCP server schema, so the longer framing has to live here. + */ +export const MCP_SERVER_INSTRUCTIONS = `${description} + +Kernel runs real Chrome browsers in the cloud. Reach for it when the task is on a website: navigating a site, acting inside an authenticated account, filling and submitting forms, uploading or downloading files, or driving a page that offers no other interface. When a purpose-built integration covers the same task, use that instead. + +Once a session exists, try these in order and stop at the first one that works: + +1. webmcp: tools the site itself exposes to agents. Fastest and least brittle where a site provides them. +2. execute_playwright_code: structured DOM interaction. +3. computer_action: visual control, for pages the DOM cannot drive. + +Create sessions with manage_browsers and delete them when finished. Set timeout_seconds so an abandoned session cleans itself up.`; From 19a112562094008fd758e16a02ae2f98a148974f Mon Sep 17 00:00:00 2001 From: robertjamesprior <83608739+robertjamesprior@users.noreply.github.com> Date: Thu, 17 Sep 2026 00:13:15 +0000 Subject: [PATCH 2/3] Use the full description budget and keep a searchable noun The MCP registry only matches the server name when searching, so the description is read by humans scanning a catalog and by third-party catalogs that index text. Spend all 100 characters on the job and the verbs rather than leaving 6 unused, and keep "cloud browser" in for the catalogs that do index descriptions. Co-Authored-By: Claude Opus 5 --- server.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.json b/server.json index b02b613e..dac4c114 100644 --- a/server.json +++ b/server.json @@ -2,7 +2,7 @@ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json", "name": "com.onkernel/kernel-mcp-server", "title": "Kernel MCP Server", - "description": "Use websites and web apps on a user's behalf when no API or direct integration can do the job.", + "description": "Use any website on a user's behalf in a cloud browser: navigate, sign in, fill forms, buy, download.", "status": "active", "websiteUrl": "https://www.kernel.sh/docs/reference/mcp-server", "homepage_url": "https://www.kernel.sh", From a8940a54ebc3927f6777bed8d3b61f6127c32187 Mon Sep 17 00:00:00 2001 From: robertjamesprior <83608739+robertjamesprior@users.noreply.github.com> Date: Fri, 18 Sep 2026 19:40:49 +0000 Subject: [PATCH 3/3] Frame the layer order per step and apply KERNEL brand rules Review feedback: a task can use webmcp for one step and still need playwright or computer control for another, which awaiting_submission already forces, so a one-time choice was the wrong framing. Also lowercase the model-facing prose per KERNEL brand rules, keep KERNEL uppercase, and replace "fastest and least brittle" with the mechanism that earns the preference: the site defines the action contract rather than the caller inferring it from the dom. Co-Authored-By: Claude Opus 5 --- server.json | 2 +- src/lib/mcp/instructions.ts | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/server.json b/server.json index dac4c114..e333d40b 100644 --- a/server.json +++ b/server.json @@ -2,7 +2,7 @@ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json", "name": "com.onkernel/kernel-mcp-server", "title": "Kernel MCP Server", - "description": "Use any website on a user's behalf in a cloud browser: navigate, sign in, fill forms, buy, download.", + "description": "use any website on a user's behalf in a cloud browser: navigate, sign in, fill forms, buy, download.", "status": "active", "websiteUrl": "https://www.kernel.sh/docs/reference/mcp-server", "homepage_url": "https://www.kernel.sh", diff --git a/src/lib/mcp/instructions.ts b/src/lib/mcp/instructions.ts index 1372a39f..aede424f 100644 --- a/src/lib/mcp/instructions.ts +++ b/src/lib/mcp/instructions.ts @@ -10,12 +10,14 @@ import { description } from "../../../server.json"; */ export const MCP_SERVER_INSTRUCTIONS = `${description} -Kernel runs real Chrome browsers in the cloud. Reach for it when the task is on a website: navigating a site, acting inside an authenticated account, filling and submitting forms, uploading or downloading files, or driving a page that offers no other interface. When a purpose-built integration covers the same task, use that instead. +KERNEL runs real chromium browsers in the cloud. reach for it when the task is on a website: navigating a site, acting inside an authenticated account, filling and submitting forms, uploading or downloading files, or driving a page that offers no other interface. when a purpose-built integration covers the same task, use that instead. -Once a session exists, try these in order and stop at the first one that works: +for each step, prefer these layers in order. move to the next when the current one is unavailable or insufficient: -1. webmcp: tools the site itself exposes to agents. Fastest and least brittle where a site provides them. -2. execute_playwright_code: structured DOM interaction. -3. computer_action: visual control, for pages the DOM cannot drive. +1. webmcp: tools the site itself exposes to agents. prefer this where available, because the site defines the action contract rather than you inferring it from the dom. +2. execute_playwright_code: structured dom interaction. +3. computer_action: visual control, for pages the dom cannot drive. -Create sessions with manage_browsers and delete them when finished. Set timeout_seconds so an abandoned session cleans itself up.`; +a single task can mix layers. an \`awaiting_submission\` result from webmcp, for example, populates a form and then needs one of the other two to submit it. + +create sessions with manage_browsers and delete them when finished. set timeout_seconds so an abandoned session cleans itself up.`;