fix(cli): stateful MCP HTTP transport for display_image (#944)

* fix(cli): stateful MCP HTTP transport for display_image

MCP SDK 1.29+ rejects stateless StreamableHTTP reuse across separate POSTs
(initialize, notifications/initialized, tools/call), so display_image 500'd
on the second request. Generate per-session IDs instead.

Add hapi-display-image.mjs to call the live session CLI's MCP via hostPid so
generated-image bytes stay in the owning process.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli): multi-session MCP transport + hapiMcpUrl metadata

Route streamable HTTP by mcp-session-id so agent bridge and
hapi-display-image can each initialize without "already initialized".
Publish metadata.hapiMcpUrl at MCP start; helper uses that instead of
guessing loopback ports (hook server collision).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(scripts): preserve namespaced CLI_API_TOKEN in display-image helper

Do not append :default; namespace is already encoded in the stored token.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(scripts): read settings only when CLI_API_TOKEN unset

Env-only auth must not require ~/.hapi/settings.json to exist.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
HeavyGee
2026-06-18 10:11:18 +08:00
committed by GitHub
co-authored by Cursor
parent b3add07ad7
commit 4bc3393904
3 changed files with 152 additions and 36 deletions
+1
View File
@@ -56,6 +56,7 @@ export const MetadataSchema = z.object({
happyToolsDir: z.string().optional(),
startedFromRunner: z.boolean().optional(),
hostPid: z.number().optional(),
hapiMcpUrl: z.string().url().optional(),
startedBy: z.enum(['runner', 'terminal']).optional(),
lifecycleState: z.string().optional(),
lifecycleStateSince: z.number().optional(),