Nicholai 3f8d273986 feat(agent): MCP-based tool architecture
Extract agent-core as shared package with agentic loop,
tool definitions, and MCP integration. Compass tools
wrapped as MCP server using low-level Server API. Client
manager connects multiple MCP servers (in-memory, stdio,
HTTP) with unified tool routing. External MCP server
configs stored in DB with CRUD actions. Both Workers and
Bun runtimes use the new MCP client manager.
2026-02-16 20:14:57 -07:00

111 lines
3.1 KiB
TypeScript

import { z } from "zod"
import type { DataSource } from "../types"
import type { ToolDef } from "./data"
import { zodToJsonSchema } from "./data"
const saveSchema = z.object({
name: z.string().describe("Dashboard display name"),
description: z
.string()
.optional()
.describe("Brief description of the dashboard"),
dashboardId: z
.string()
.optional()
.describe("Existing dashboard ID to update (for edits)"),
})
const listSchema = z.object({})
const editSchema = z.object({
dashboardId: z
.string()
.describe("ID of the dashboard to edit"),
editPrompt: z
.string()
.optional()
.describe("Description of changes to make"),
})
const deleteSchema = z.object({
dashboardId: z
.string()
.describe("ID of the dashboard to delete"),
})
export function dashboardTools(
dataSource: DataSource
): ToolDef[] {
return [
{
name: "saveDashboard",
description:
"Save the currently rendered UI as a named dashboard. " +
"The client captures the current spec and data context " +
"automatically. Returns an action for the client to " +
"handle the save.",
input_schema: zodToJsonSchema(saveSchema),
run: async (input: unknown): Promise<string> => {
const args = saveSchema.parse(input)
return JSON.stringify({
action: "save_dashboard",
name: args.name,
description: args.description ?? "",
dashboardId: args.dashboardId,
})
},
},
{
name: "listDashboards",
description: "List the user's saved custom dashboards.",
input_schema: zodToJsonSchema(listSchema),
run: async (): Promise<string> => {
const result = await dataSource.fetch(
"/api/compass/dashboards/list"
)
return JSON.stringify(result)
},
},
{
name: "editDashboard",
description:
"Load a saved dashboard for editing. The client " +
"injects the spec into the render context and " +
"navigates to /dashboard. Optionally pass an " +
"editPrompt to trigger immediate re-generation.",
input_schema: zodToJsonSchema(editSchema),
run: async (input: unknown): Promise<string> => {
const args = editSchema.parse(input)
const result = await dataSource.fetch(
"/api/compass/dashboards/get",
{ dashboardId: args.dashboardId }
)
return JSON.stringify({
action: "load_dashboard",
dashboardId: args.dashboardId,
spec: result,
editPrompt: args.editPrompt,
})
},
},
{
name: "deleteDashboard",
description:
"Delete a saved dashboard. Always confirm with the " +
"user before deleting.",
input_schema: zodToJsonSchema(deleteSchema),
run: async (input: unknown): Promise<string> => {
const args = deleteSchema.parse(input)
const result = await dataSource.fetch(
"/api/compass/dashboards/delete",
args
)
return JSON.stringify(result)
},
},
]
}