import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; interface ActionLogSlots { org_namespace?: string; action_type?: string; payload?: string; occurred_at?: string; } interface ActionLogRecord { id: string; slots?: ActionLogSlots; } export function registerGetGuiContext(server: McpServer, env: Env, orgNamespace: string) { server.tool( "u6u_get_gui_context", "查詢用戶在 GUI 上的最近操作記錄,了解用戶的當前意圖與操作上下文。" + "回傳最近 N 條操作記錄(從新到舊),以及用戶當前所在頁面和正在編輯的 Workflow ID。", { limit: z.number().int().min(1).max(100).default(20) .describe("要取回的最近操作數量(預設 20,最大 100)"), }, async ({ limit }) => { try { if (!env.KBDB) { return { content: [{ type: "text", text: "Error: KBDB service binding unavailable" }], isError: true, }; } const resp = await kbdbFetch( env, `/records/search?template_id=tpl-action-log&user_id=${encodeURIComponent(orgNamespace)}&limit=${limit ?? 20}` ); if (!resp.ok) { return { content: [{ type: "text", text: `Error querying action log: ${await resp.text()}` }], isError: true, }; } const data = await resp.json<{ records: ActionLogRecord[] }>(); const records = data.records ?? []; // 按 occurred_at 降序排列(最新在前) const sorted = records .map(r => ({ action_type: r.slots?.action_type ?? '', payload: (() => { try { return JSON.parse(r.slots?.payload ?? '{}'); } catch { return {}; } })(), occurred_at: r.slots?.occurred_at ?? '', })) .sort((a, b) => b.occurred_at.localeCompare(a.occurred_at)) .slice(0, limit ?? 20); // 提取當前頁面和正在操作的 Workflow const lastNavigate = sorted.find(a => a.action_type === 'NAVIGATE'); const lastOpenWorkflow = sorted.find(a => a.action_type === 'OPEN_WORKFLOW'); const context = { recent_actions: sorted, current_page: (lastNavigate?.payload as { page?: string })?.page ?? null, open_workflow_id: (lastOpenWorkflow?.payload as { workflow_id?: string })?.workflow_id ?? null, }; return { content: [{ type: "text", text: JSON.stringify(context, null, 2) }], }; } catch (error) { return { content: [{ type: "text", text: `Internal Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true, }; } } ); }