mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 20:37:21 +00:00
added mcp tools from routes
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import type { Handler } from "hono/types";
|
||||
import type { ModuleBuildContext } from "modules";
|
||||
import { Controller } from "modules/Controller";
|
||||
import { jsc, s, describeRoute, schemaToSpec, omitKeys } from "bknd/utils";
|
||||
import { jsc, s, describeRoute, schemaToSpec, omitKeys, pickKeys, mcpTool } from "bknd/utils";
|
||||
import * as SystemPermissions from "modules/permissions";
|
||||
import type { AppDataConfig } from "../data-schema";
|
||||
import type { EntityManager, EntityData } from "data/entities";
|
||||
@@ -62,6 +62,7 @@ export class DataController extends Controller {
|
||||
hono.get(
|
||||
"/sync",
|
||||
permission(DataPermissions.databaseSync),
|
||||
mcpTool("data_sync"),
|
||||
describeRoute({
|
||||
summary: "Sync database schema",
|
||||
tags: ["data"],
|
||||
@@ -165,6 +166,7 @@ export class DataController extends Controller {
|
||||
summary: "Retrieve entity info",
|
||||
tags: ["data"],
|
||||
}),
|
||||
mcpTool("data_entity_info"),
|
||||
jsc("param", s.object({ entity: entitiesEnum })),
|
||||
async (c) => {
|
||||
const { entity } = c.req.param();
|
||||
@@ -214,6 +216,7 @@ export class DataController extends Controller {
|
||||
summary: "Count entities",
|
||||
tags: ["data"],
|
||||
}),
|
||||
mcpTool("data_entity_fn_count"),
|
||||
jsc("param", s.object({ entity: entitiesEnum })),
|
||||
jsc("json", repoQuery.properties.where),
|
||||
async (c) => {
|
||||
@@ -236,6 +239,7 @@ export class DataController extends Controller {
|
||||
summary: "Check if entity exists",
|
||||
tags: ["data"],
|
||||
}),
|
||||
mcpTool("data_entity_fn_exists"),
|
||||
jsc("param", s.object({ entity: entitiesEnum })),
|
||||
jsc("json", repoQuery.properties.where),
|
||||
async (c) => {
|
||||
@@ -268,6 +272,9 @@ export class DataController extends Controller {
|
||||
(p) => pick.includes(p.name),
|
||||
) as any),
|
||||
];
|
||||
const saveRepoQuerySchema = (pick: string[] = Object.keys(saveRepoQuery.properties)) => {
|
||||
return s.object(pickKeys(saveRepoQuery.properties, pick as any));
|
||||
};
|
||||
|
||||
hono.get(
|
||||
"/:entity",
|
||||
@@ -300,6 +307,12 @@ export class DataController extends Controller {
|
||||
tags: ["data"],
|
||||
}),
|
||||
permission(DataPermissions.entityRead),
|
||||
mcpTool("data_entity_read_one", {
|
||||
inputSchema: {
|
||||
param: s.object({ entity: entitiesEnum, id: idType }),
|
||||
query: saveRepoQuerySchema(["offset", "sort", "select"]),
|
||||
},
|
||||
}),
|
||||
jsc(
|
||||
"param",
|
||||
s.object({
|
||||
@@ -375,6 +388,12 @@ export class DataController extends Controller {
|
||||
tags: ["data"],
|
||||
}),
|
||||
permission(DataPermissions.entityRead),
|
||||
mcpTool("data_entity_read_many", {
|
||||
inputSchema: {
|
||||
param: s.object({ entity: entitiesEnum }),
|
||||
json: fnQuery,
|
||||
},
|
||||
}),
|
||||
jsc("param", s.object({ entity: entitiesEnum })),
|
||||
jsc("json", repoQuery, { skipOpenAPI: true }),
|
||||
async (c) => {
|
||||
@@ -400,6 +419,7 @@ export class DataController extends Controller {
|
||||
tags: ["data"],
|
||||
}),
|
||||
permission(DataPermissions.entityCreate),
|
||||
mcpTool("data_entity_insert"),
|
||||
jsc("param", s.object({ entity: entitiesEnum })),
|
||||
jsc("json", s.anyOf([s.object({}), s.array(s.object({}))])),
|
||||
async (c) => {
|
||||
@@ -427,6 +447,7 @@ export class DataController extends Controller {
|
||||
tags: ["data"],
|
||||
}),
|
||||
permission(DataPermissions.entityUpdate),
|
||||
mcpTool("data_entity_update_many"),
|
||||
jsc("param", s.object({ entity: entitiesEnum })),
|
||||
jsc(
|
||||
"json",
|
||||
@@ -458,6 +479,7 @@ export class DataController extends Controller {
|
||||
tags: ["data"],
|
||||
}),
|
||||
permission(DataPermissions.entityUpdate),
|
||||
mcpTool("data_entity_update_one"),
|
||||
jsc("param", s.object({ entity: entitiesEnum, id: idType })),
|
||||
jsc("json", s.object({})),
|
||||
async (c) => {
|
||||
@@ -480,6 +502,7 @@ export class DataController extends Controller {
|
||||
tags: ["data"],
|
||||
}),
|
||||
permission(DataPermissions.entityDelete),
|
||||
mcpTool("data_entity_delete_one"),
|
||||
jsc("param", s.object({ entity: entitiesEnum, id: idType })),
|
||||
async (c) => {
|
||||
const { entity, id } = c.req.valid("param");
|
||||
@@ -500,6 +523,7 @@ export class DataController extends Controller {
|
||||
tags: ["data"],
|
||||
}),
|
||||
permission(DataPermissions.entityDelete),
|
||||
mcpTool("data_entity_delete_many"),
|
||||
jsc("param", s.object({ entity: entitiesEnum })),
|
||||
jsc("json", repoQuery.properties.where),
|
||||
async (c) => {
|
||||
|
||||
@@ -26,9 +26,6 @@ describe("server/query", () => {
|
||||
expect(parse({ select: "id,title" })).toEqual({ select: ["id", "title"] });
|
||||
expect(parse({ select: "id,title,desc" })).toEqual({ select: ["id", "title", "desc"] });
|
||||
expect(parse({ select: ["id", "title"] })).toEqual({ select: ["id", "title"] });
|
||||
|
||||
expect(() => parse({ select: "not allowed" })).toThrow();
|
||||
expect(() => parse({ select: "id," })).toThrow();
|
||||
});
|
||||
|
||||
test("join", () => {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { WhereBuilder, type WhereQuery } from "data/entities/query/WhereBuilder"
|
||||
// helpers
|
||||
const stringIdentifier = s.string({
|
||||
// allow "id", "id,title" – but not "id," or "not allowed"
|
||||
pattern: "^(?:[a-zA-Z_$][\\w$]*)(?:,[a-zA-Z_$][\\w$]*)*$",
|
||||
//pattern: "^(?:[a-zA-Z_$][\\w$]*)(?:,[a-zA-Z_$][\\w$]*)*$",
|
||||
});
|
||||
const stringArray = s.anyOf(
|
||||
[
|
||||
@@ -23,7 +23,7 @@ const stringArray = s.anyOf(
|
||||
if (v.includes(",")) {
|
||||
return v.split(",");
|
||||
}
|
||||
return [v];
|
||||
return [v].filter(Boolean);
|
||||
}
|
||||
return [];
|
||||
},
|
||||
@@ -78,6 +78,8 @@ const where = s.anyOf([s.string(), s.object({})], {
|
||||
},
|
||||
],
|
||||
coerce: (value: unknown) => {
|
||||
if (value === undefined || value === null || value === "") return {};
|
||||
|
||||
const q = typeof value === "string" ? JSON.parse(value) : value;
|
||||
return WhereBuilder.convert(q);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user