diff --git a/.cursor/mcp.json b/.cursor/mcp.json index 064ec5c..8cd1d99 100644 --- a/.cursor/mcp.json +++ b/.cursor/mcp.json @@ -1,10 +1,7 @@ { "mcpServers": { "bknd": { - "url": "http://localhost:3000/mcp", - "headers": { - "API_KEY": "value" - } + "url": "http://localhost:28623/api/system/mcp" } } } diff --git a/app/src/auth/api/AuthController.ts b/app/src/auth/api/AuthController.ts index 33c0df6..ba12d4a 100644 --- a/app/src/auth/api/AuthController.ts +++ b/app/src/auth/api/AuthController.ts @@ -221,6 +221,7 @@ export class AuthController extends Controller { return user; }; + const roles = Object.keys(this.auth.config.roles ?? {}); mcp.tool( // @todo: needs permission "auth_user_create", @@ -231,7 +232,7 @@ export class AuthController extends Controller { password: s.string({ minLength: 8 }), role: s .string({ - enum: Object.keys(this.auth.config.roles ?? {}), + enum: roles.length > 0 ? roles : undefined, }) .optional(), }), diff --git a/app/src/core/utils/objects.ts b/app/src/core/utils/objects.ts index 4a5e129..6f6a985 100644 --- a/app/src/core/utils/objects.ts +++ b/app/src/core/utils/objects.ts @@ -473,3 +473,10 @@ export function deepFreeze(object: T): T { return Object.freeze(object); } + +export function convertNumberedObjectToArray(obj: object): any[] | object { + if (Object.keys(obj).every((key) => Number.isInteger(Number(key)))) { + return Object.values(obj); + } + return obj; +} diff --git a/app/src/data/api/DataController.ts b/app/src/data/api/DataController.ts index a0d7f02..055033c 100644 --- a/app/src/data/api/DataController.ts +++ b/app/src/data/api/DataController.ts @@ -1,6 +1,15 @@ import type { ModuleBuildContext } from "modules"; import { Controller } from "modules/Controller"; -import { jsc, s, describeRoute, schemaToSpec, omitKeys, pickKeys, mcpTool } from "bknd/utils"; +import { + jsc, + s, + describeRoute, + schemaToSpec, + omitKeys, + pickKeys, + mcpTool, + convertNumberedObjectToArray, +} from "bknd/utils"; import * as SystemPermissions from "modules/permissions"; import type { AppDataConfig } from "../data-schema"; import type { EntityManager, EntityData } from "data/entities"; @@ -420,7 +429,13 @@ export class DataController extends Controller { if (!this.entityExists(entity)) { return this.notFound(c); } - const body = (await c.req.json()) as EntityData | EntityData[]; + + const _body = (await c.req.json()) as EntityData | EntityData[]; + // @todo: check on jsonv-ts how to handle this better + // temporary fix for numbered object to array + // this happens when the MCP tool uses the allOf function + // to transform all validation targets into a single object + const body = convertNumberedObjectToArray(_body); if (Array.isArray(body)) { const result = await this.em.mutator(entity).insertMany(body); diff --git a/app/vite.dev.ts b/app/vite.dev.ts index bee9219..1bc2309 100644 --- a/app/vite.dev.ts +++ b/app/vite.dev.ts @@ -9,6 +9,9 @@ import { nodeSqlite } from "./src/adapter/node/connection/NodeSqliteConnection"; import { libsql } from "./src/data/connection/sqlite/libsql/LibsqlConnection"; import { $console } from "core/utils/console"; import { createClient } from "@libsql/client"; +import util from "node:util"; + +util.inspect.defaultOptions.depth = 5; registries.media.register("local", StorageLocalAdapter);