diff --git a/bun.lock b/bun.lock index 8d0e7aa..cb24d63 100644 --- a/bun.lock +++ b/bun.lock @@ -10,7 +10,7 @@ "@clerk/themes": "^2.4.19", "@mcp-ui/server": "^5.10.0", "@modelcontextprotocol/sdk": "1.26.0", - "@onkernel/sdk": "^0.60.0", + "@onkernel/sdk": "^0.78.0", "@types/jsonwebtoken": "^9.0.10", "@types/redis": "^4.0.11", "builtin-modules": "^5.0.0", @@ -20,7 +20,7 @@ "jszip": "^3.10.1", "lucide-react": "^0.534.0", "mcp-handler": "^1.1.0", - "next": "16.2.6", + "next": "^16.2.6", "next-themes": "^0.4.4", "playwright": "^1.49.1", "prettier": "^3.6.2", @@ -145,7 +145,7 @@ "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.2.6", "", { "os": "win32", "cpu": "x64" }, "sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA=="], - "@onkernel/sdk": ["@onkernel/sdk@0.60.0", "", {}, "sha512-z9POhDK6uanj9FJ5GS/ff7MaqYjCOWP5605pbuUYEH9EuX5bthD89y/XPqwcC9xpgr9RLjlFVJ73ORAiAXfuPw=="], + "@onkernel/sdk": ["@onkernel/sdk@0.78.0", "", {}, "sha512-VrGEDcuSwO6AKe6oYTNaQsAHnOAVeqehmStDTM0EFd3u8+WhITYxhU+jNFq+9yEt0N/nrn2COsk/ThQ+dxWBlw=="], "@redis/bloom": ["@redis/bloom@5.6.0", "", { "peerDependencies": { "@redis/client": "^5.6.0" } }, "sha512-l13/d6BaZDJzogzZJEphIeZ8J0hpQpjkMiozomTm6nJiMNYkoPsNOBOOQua4QsG0fFjyPmLMDJFPAp5FBQtTXg=="], diff --git a/package.json b/package.json index beb5d8d..46f6178 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@clerk/themes": "^2.4.19", "@mcp-ui/server": "^5.10.0", "@modelcontextprotocol/sdk": "1.26.0", - "@onkernel/sdk": "^0.60.0", + "@onkernel/sdk": "^0.78.0", "@types/jsonwebtoken": "^9.0.10", "@types/redis": "^4.0.11", "builtin-modules": "^5.0.0", diff --git a/src/lib/mcp/responses.ts b/src/lib/mcp/responses.ts index eafb72f..c97f76c 100644 --- a/src/lib/mcp/responses.ts +++ b/src/lib/mcp/responses.ts @@ -9,7 +9,9 @@ type JsonItemsResponseOptions = { note?: string; }; -type PaginatedJsonResponseOptions = JsonItemsResponseOptions; +type PaginatedJsonResponseOptions = JsonItemsResponseOptions & { + emptyText?: string; +}; type ItemsJsonResponseOptions = JsonItemsResponseOptions & { emptyText?: string; @@ -47,10 +49,8 @@ export function paginatedJsonResponse( page: PaginatedPage, options: PaginatedJsonResponseOptions = {}, ) { - const { mapItem, note } = options; return itemsJsonResponse(page.getPaginatedItems(), { - mapItem, - note, + ...options, has_more: page.has_more, next_offset: page.next_offset, }); diff --git a/src/lib/mcp/tools/browser-pools.ts b/src/lib/mcp/tools/browser-pools.ts index c72b204..20ced89 100644 --- a/src/lib/mcp/tools/browser-pools.ts +++ b/src/lib/mcp/tools/browser-pools.ts @@ -10,9 +10,11 @@ import { registerJsonResourceTemplate } from "@/lib/mcp/resource-templates"; import { jsonResponse, errorResponse, + paginatedJsonResponse, textResponse, toolErrorResponse, } from "@/lib/mcp/responses"; +import { paginationParams } from "@/lib/mcp/schemas"; type BrowserPoolCreateParams = Parameters< KernelClient["browserPools"]["create"] @@ -27,7 +29,10 @@ type BrowserPoolAcquireResponse = Awaited< ReturnType >; -type PoolConfigParams = BrowserCreateConfigParams & { +type PoolConfigParams = Omit< + BrowserCreateConfigParams, + "save_profile_changes" +> & { size?: number; name?: string; headless?: boolean; @@ -159,14 +164,17 @@ export function registerBrowserPoolCapabilities(server: McpServer) { } const client = createKernelClient(extra.authInfo.token); - const pools = await client.browserPools.list(); + const pools = []; + for await (const pool of client.browserPools.list()) { + pools.push(pool); + } return { contents: [ { uri: uri.toString(), mimeType: "application/json", text: - pools && pools.length > 0 + pools.length > 0 ? JSON.stringify(pools.map(summarizeBrowserPool), null, 2) : "No browser pools found", }, @@ -245,12 +253,6 @@ export function registerBrowserPoolCapabilities(server: McpServer) { "(create, update) Profile ID to load into pool browsers. Cannot use with profile_name.", ) .optional(), - save_profile_changes: z - .boolean() - .describe( - "(create, update) Save browser changes back to the selected profile when sessions end.", - ) - .optional(), proxy_id: z .string() .describe("(create, update) Proxy for pool browsers.") @@ -335,6 +337,7 @@ export function registerBrowserPoolCapabilities(server: McpServer) { .boolean() .describe("(release) Reuse browser instance or recreate. Default true.") .optional(), + ...paginationParams, }, { title: "Manage Kernel browser pools", @@ -391,13 +394,15 @@ export function registerBrowserPoolCapabilities(server: McpServer) { }); } case "list": { - const pools = (await client.browserPools.list()) ?? []; - return pools.length > 0 - ? jsonResponse({ - items: pools.map(summarizeBrowserPool), - note: 'Use action "get" with id_or_name for full pool details.', - }) - : textResponse("No browser pools found"); + const page = await client.browserPools.list({ + ...(params.limit !== undefined && { limit: params.limit }), + ...(params.offset !== undefined && { offset: params.offset }), + }); + return paginatedJsonResponse(page, { + mapItem: summarizeBrowserPool, + note: 'Use action "get" with id_or_name for full pool details.', + emptyText: "No browser pools found", + }); } case "get": { if (!params.id_or_name) diff --git a/src/lib/mcp/tools/credential-providers.ts b/src/lib/mcp/tools/credential-providers.ts index c29d478..e13f05e 100644 --- a/src/lib/mcp/tools/credential-providers.ts +++ b/src/lib/mcp/tools/credential-providers.ts @@ -4,9 +4,11 @@ import { createKernelClient } from "@/lib/mcp/kernel-client"; import { errorResponse, jsonResponse, + paginatedJsonResponse, textResponse, toolErrorResponse, } from "@/lib/mcp/responses"; +import { paginationParams } from "@/lib/mcp/schemas"; export function registerCredentialProviderTools(server: McpServer) { // manage_credential_providers -- Manage external credential providers @@ -31,6 +33,7 @@ export function registerCredentialProviderTools(server: McpServer) { "(get, update, delete, list_items, test) Credential provider ID.", ) .optional(), + ...paginationParams, name: z .string() .describe("(create, update) Human-readable name (unique per org).") @@ -80,8 +83,11 @@ export function registerCredentialProviderTools(server: McpServer) { try { switch (params.action) { case "list": { - const providers = await client.credentialProviders.list(); - return jsonResponse(providers); + const page = await client.credentialProviders.list({ + ...(params.limit !== undefined && { limit: params.limit }), + ...(params.offset !== undefined && { offset: params.offset }), + }); + return paginatedJsonResponse(page); } case "get": { if (!params.id) diff --git a/src/lib/mcp/tools/credentials.ts b/src/lib/mcp/tools/credentials.ts index 933634e..cb7f2c3 100644 --- a/src/lib/mcp/tools/credentials.ts +++ b/src/lib/mcp/tools/credentials.ts @@ -37,7 +37,7 @@ export function registerCredentialTools(server: McpServer) { ) .optional(), values: z - .record(z.string()) + .record(z.string(), z.string()) .describe( "(create, update) Field name to value mapping (e.g. username, password). On update, merged with existing values.", ) diff --git a/src/lib/mcp/tools/extensions.ts b/src/lib/mcp/tools/extensions.ts index 5928607..f20d831 100644 --- a/src/lib/mcp/tools/extensions.ts +++ b/src/lib/mcp/tools/extensions.ts @@ -3,10 +3,11 @@ import { z } from "zod"; import { createKernelClient } from "@/lib/mcp/kernel-client"; import { errorResponse, - itemsJsonResponse, + paginatedJsonResponse, textResponse, toolErrorResponse, } from "@/lib/mcp/responses"; +import { paginationParams } from "@/lib/mcp/schemas"; export function registerExtensionTools(server: McpServer) { // manage_extensions -- List and delete browser extensions @@ -19,6 +20,7 @@ export function registerExtensionTools(server: McpServer) { .string() .describe("(delete) Extension ID or name to delete.") .optional(), + ...paginationParams, }, { title: "Manage Kernel browser extensions", @@ -34,10 +36,11 @@ export function registerExtensionTools(server: McpServer) { try { switch (params.action) { case "list": { - const extensions = await client.extensions.list(); - return itemsJsonResponse(extensions ?? [], { - has_more: false, - next_offset: null, + const page = await client.extensions.list({ + ...(params.limit !== undefined && { limit: params.limit }), + ...(params.offset !== undefined && { offset: params.offset }), + }); + return paginatedJsonResponse(page, { emptyText: "No extensions found", }); } diff --git a/src/lib/mcp/tools/proxies.ts b/src/lib/mcp/tools/proxies.ts index e2b4b74..632ed10 100644 --- a/src/lib/mcp/tools/proxies.ts +++ b/src/lib/mcp/tools/proxies.ts @@ -3,11 +3,12 @@ import { z } from "zod"; import { createKernelClient } from "@/lib/mcp/kernel-client"; import { errorResponse, - itemsJsonResponse, jsonResponse, + paginatedJsonResponse, textResponse, toolErrorResponse, } from "@/lib/mcp/responses"; +import { paginationParams } from "@/lib/mcp/schemas"; const httpUrlSchema = z .string() @@ -77,6 +78,7 @@ export function registerProxyTools(server: McpServer) { .string() .describe("(create, custom type) Auth password.") .optional(), + ...paginationParams, }, { title: "Manage Kernel proxy configurations", @@ -134,10 +136,11 @@ export function registerProxyTools(server: McpServer) { return jsonResponse(proxy); } case "list": { - const proxies = await client.proxies.list(); - return itemsJsonResponse(proxies ?? [], { - has_more: false, - next_offset: null, + const page = await client.proxies.list({ + ...(params.limit !== undefined && { limit: params.limit }), + ...(params.offset !== undefined && { offset: params.offset }), + }); + return paginatedJsonResponse(page, { emptyText: "No proxies found", }); }