From 67f09116bacc4c6aa6580f809848fa667dce57ed Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 18 Jul 2026 16:21:30 +0000 Subject: [PATCH] feat(cli): surface the MCP endpoint in the server-ready banner (#3167) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MCP server (/api/v1/mcp) is a default-on core capability, but nothing in the os dev / os serve boot output pointed to it — a developer had to already know it was there to connect an AI client. This is the dev-loop discoverability gap #3167 set out to close: the platform's "let an AI operate the running app" channel was live but invisible. printServerReady now prints the MCP URL and the SKILL.md pointer whenever the surface is enabled — gated on isMcpServerEnabled(), the SAME switch that auto-loads the plugin and gates the route, so the banner can never advertise an endpoint that isn't served. Hidden when OS_MCP_SERVER_ENABLED=false. Runtime-verified: the line renders with the URL + skill pointer when enabled and is absent when disabled. CLI builds clean; lint clean. Closes the last (optional, DX) item on #3167 — the admission story itself landed in #3202/#3225. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Pbmw3pMqNJfPbkvwh9Fkjs --- .changeset/mcp-dev-connect-hint.md | 13 +++++++++++++ packages/cli/src/commands/serve.ts | 5 +++++ packages/cli/src/utils/format.ts | 12 ++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 .changeset/mcp-dev-connect-hint.md diff --git a/.changeset/mcp-dev-connect-hint.md b/.changeset/mcp-dev-connect-hint.md new file mode 100644 index 0000000000..348a2cb110 --- /dev/null +++ b/.changeset/mcp-dev-connect-hint.md @@ -0,0 +1,13 @@ +--- +'@objectstack/cli': patch +--- + +feat(cli): surface the MCP endpoint in the server-ready banner (#3167) + +The MCP server (`/api/v1/mcp`) is a default-on core capability, but nothing in +the `os dev` / `os serve` boot output pointed to it — a developer had to already +know it was there to connect an AI client. The server-ready banner now prints +the MCP URL and the `SKILL.md` pointer whenever the surface is enabled +(`isMcpServerEnabled()`, the same switch that auto-loads the plugin and gates +the route), so an agent can operate the running app straight from the dev loop. +Hidden when `OS_MCP_SERVER_ENABLED=false`. diff --git a/packages/cli/src/commands/serve.ts b/packages/cli/src/commands/serve.ts index 041236cf26..aa676c08e7 100644 --- a/packages/cli/src/commands/serve.ts +++ b/packages/cli/src/commands/serve.ts @@ -2455,6 +2455,11 @@ export default class Serve extends Command { multiTenant: resolveMultiOrgEnabled(), seededAdmin, automation: automationSummary, + // #3167 — surface the default-on MCP endpoint in the dev loop, where an + // AI client can connect to operate the running app. Same decision point + // that auto-loads the plugin + gates the route, so the banner never + // advertises an endpoint that isn't served. + mcpEnabled: isMcpServerEnabled(), }); // ── Publish the actually-bound port ──────────────────────────── diff --git a/packages/cli/src/utils/format.ts b/packages/cli/src/utils/format.ts index fa35ba938f..c261b68860 100644 --- a/packages/cli/src/utils/format.ts +++ b/packages/cli/src/utils/format.ts @@ -203,6 +203,14 @@ export interface ServerReadyOptions { * armed. Collected from the live engine after runtime.start(). */ automation?: AutomationReadySummary; + /** + * Whether the MCP server surface (`/api/v1/mcp`) is on (#3167). Default-on + * core capability, but nothing in the dev loop surfaces it — an AI client + * (Claude Code, Cursor, …) can operate the running app the instant a + * developer knows the endpoint is there. The banner is where they look, so + * print the URL + the SKILL.md pointer when it's live. + */ + mcpEnabled?: boolean; } export interface AutomationReadySummary { @@ -233,6 +241,10 @@ export function printServerReady(opts: ServerReadyOptions) { if (opts.uiEnabled && opts.consolePath) { console.log(chalk.cyan(' ➜') + chalk.bold(' Console: ') + chalk.cyan(base + opts.consolePath + '/')); } + if (opts.mcpEnabled) { + console.log(chalk.cyan(' ➜') + chalk.bold(' MCP: ') + chalk.cyan(base + '/api/v1/mcp')); + console.log(chalk.dim(` connect an AI client (Claude Code, Cursor, …) · skill: ${base}/api/v1/mcp/skill`)); + } if (opts.seededAdmin) { console.log(''); console.log(