mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-15 20:17:22 +00:00
optimized performance
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { describe, test, expect, beforeEach, beforeAll, afterAll } from "bun:test";
|
import { describe, test, expect, beforeEach, beforeAll, afterAll } from "bun:test";
|
||||||
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
||||||
import { getSystemMcp } from "modules/mcp/system-mcp";
|
|
||||||
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||||
|
import type { McpServer } from "bknd/utils";
|
||||||
|
|
||||||
beforeAll(disableConsoleLog);
|
beforeAll(disableConsoleLog);
|
||||||
afterAll(enableConsoleLog);
|
afterAll(enableConsoleLog);
|
||||||
@@ -26,7 +26,7 @@ afterAll(enableConsoleLog);
|
|||||||
*/
|
*/
|
||||||
describe("mcp auth", async () => {
|
describe("mcp auth", async () => {
|
||||||
let app: App;
|
let app: App;
|
||||||
let server: ReturnType<typeof getSystemMcp>;
|
let server: McpServer;
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
app = createApp({
|
app = createApp({
|
||||||
initialConfig: {
|
initialConfig: {
|
||||||
@@ -44,7 +44,7 @@ describe("mcp auth", async () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
await app.build();
|
await app.build();
|
||||||
server = getSystemMcp(app);
|
server = app.mcp!;
|
||||||
server.setLogLevel("error");
|
server.setLogLevel("error");
|
||||||
server.onNotification((message) => {
|
server.onNotification((message) => {
|
||||||
console.dir(message, { depth: null });
|
console.dir(message, { depth: null });
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { describe, it, expect } from "bun:test";
|
import { describe, it, expect } from "bun:test";
|
||||||
import { createApp } from "core/test/utils";
|
import { createApp } from "core/test/utils";
|
||||||
import { getSystemMcp } from "modules/mcp/system-mcp";
|
|
||||||
import { registries } from "index";
|
import { registries } from "index";
|
||||||
import { StorageLocalAdapter } from "adapter/node/storage/StorageLocalAdapter";
|
import { StorageLocalAdapter } from "adapter/node/storage/StorageLocalAdapter";
|
||||||
|
|
||||||
@@ -22,11 +21,15 @@ describe("mcp", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
server: {
|
||||||
|
mcp: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await app.build();
|
await app.build();
|
||||||
|
|
||||||
const server = getSystemMcp(app);
|
expect(app.mcp?.tools.length).toBeGreaterThan(0);
|
||||||
expect(server.tools.length).toBeGreaterThan(0);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { describe, test, expect, beforeEach, beforeAll, afterAll } from "bun:test";
|
import { describe, test, expect, beforeEach, beforeAll, afterAll } from "bun:test";
|
||||||
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
||||||
import { getSystemMcp } from "modules/mcp/system-mcp";
|
import { getSystemMcp } from "modules/mcp/system-mcp";
|
||||||
import { pickKeys } from "bknd/utils";
|
import { pickKeys, type McpServer } from "bknd/utils";
|
||||||
import { entity, text } from "bknd";
|
import { entity, text } from "bknd";
|
||||||
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||||
|
|
||||||
@@ -37,8 +37,9 @@ afterAll(enableConsoleLog);
|
|||||||
*/
|
*/
|
||||||
describe("mcp data", async () => {
|
describe("mcp data", async () => {
|
||||||
let app: App;
|
let app: App;
|
||||||
let server: ReturnType<typeof getSystemMcp>;
|
let server: McpServer;
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const time = performance.now();
|
||||||
app = createApp({
|
app = createApp({
|
||||||
initialConfig: {
|
initialConfig: {
|
||||||
server: {
|
server: {
|
||||||
@@ -49,7 +50,7 @@ describe("mcp data", async () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
await app.build();
|
await app.build();
|
||||||
server = getSystemMcp(app);
|
server = app.mcp!;
|
||||||
server.setLogLevel("error");
|
server.setLogLevel("error");
|
||||||
server.onNotification((message) => {
|
server.onNotification((message) => {
|
||||||
console.dir(message, { depth: null });
|
console.dir(message, { depth: null });
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { getSystemMcp } from "modules/mcp/system-mcp";
|
|||||||
import { registries } from "index";
|
import { registries } from "index";
|
||||||
import { StorageLocalAdapter } from "adapter/node/storage/StorageLocalAdapter";
|
import { StorageLocalAdapter } from "adapter/node/storage/StorageLocalAdapter";
|
||||||
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||||
|
import type { McpServer } from "bknd/utils";
|
||||||
|
|
||||||
beforeAll(disableConsoleLog);
|
beforeAll(disableConsoleLog);
|
||||||
afterAll(enableConsoleLog);
|
afterAll(enableConsoleLog);
|
||||||
@@ -16,7 +17,7 @@ afterAll(enableConsoleLog);
|
|||||||
*/
|
*/
|
||||||
describe("mcp media", async () => {
|
describe("mcp media", async () => {
|
||||||
let app: App;
|
let app: App;
|
||||||
let server: ReturnType<typeof getSystemMcp>;
|
let server: McpServer;
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
registries.media.register("local", StorageLocalAdapter);
|
registries.media.register("local", StorageLocalAdapter);
|
||||||
app = createApp({
|
app = createApp({
|
||||||
@@ -38,7 +39,7 @@ describe("mcp media", async () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
await app.build();
|
await app.build();
|
||||||
server = getSystemMcp(app);
|
server = app.mcp!;
|
||||||
server.setLogLevel("error");
|
server.setLogLevel("error");
|
||||||
server.onNotification((message) => {
|
server.onNotification((message) => {
|
||||||
console.dir(message, { depth: null });
|
console.dir(message, { depth: null });
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { describe, test, expect, beforeAll, mock } from "bun:test";
|
import { describe, test, expect, beforeAll, mock, beforeEach, afterAll } from "bun:test";
|
||||||
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
||||||
import { getSystemMcp } from "modules/mcp/system-mcp";
|
import type { McpServer } from "bknd/utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* - [x] config_server_get
|
* - [x] config_server_get
|
||||||
@@ -8,7 +8,7 @@ import { getSystemMcp } from "modules/mcp/system-mcp";
|
|||||||
*/
|
*/
|
||||||
describe("mcp system", async () => {
|
describe("mcp system", async () => {
|
||||||
let app: App;
|
let app: App;
|
||||||
let server: ReturnType<typeof getSystemMcp>;
|
let server: McpServer;
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = createApp({
|
app = createApp({
|
||||||
initialConfig: {
|
initialConfig: {
|
||||||
@@ -20,23 +20,33 @@ describe("mcp system", async () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
await app.build();
|
await app.build();
|
||||||
server = getSystemMcp(app);
|
server = app.mcp!;
|
||||||
});
|
});
|
||||||
|
|
||||||
const tool = createMcpToolCaller();
|
const tool = createMcpToolCaller();
|
||||||
|
|
||||||
test("config_server_get", async () => {
|
test("config_server_get", async () => {
|
||||||
const result = await tool(server, "config_server_get", {});
|
const result = await tool(server, "config_server_get", {});
|
||||||
expect(result).toEqual({
|
expect(JSON.parse(JSON.stringify(result))).toEqual({
|
||||||
path: "",
|
path: "",
|
||||||
secrets: false,
|
secrets: false,
|
||||||
partial: false,
|
partial: false,
|
||||||
value: app.toJSON().server,
|
value: JSON.parse(JSON.stringify(app.toJSON().server)),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("config_server_get2", async () => {
|
||||||
|
const result = await tool(server, "config_server_get", {});
|
||||||
|
expect(JSON.parse(JSON.stringify(result))).toEqual({
|
||||||
|
path: "",
|
||||||
|
secrets: false,
|
||||||
|
partial: false,
|
||||||
|
value: JSON.parse(JSON.stringify(app.toJSON().server)),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("config_server_update", async () => {
|
test("config_server_update", async () => {
|
||||||
const original = app.toJSON().server;
|
const original = JSON.parse(JSON.stringify(app.toJSON().server));
|
||||||
const result = await tool(server, "config_server_update", {
|
const result = await tool(server, "config_server_update", {
|
||||||
value: {
|
value: {
|
||||||
cors: {
|
cors: {
|
||||||
@@ -46,7 +56,7 @@ describe("mcp system", async () => {
|
|||||||
return_config: true,
|
return_config: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(JSON.parse(JSON.stringify(result))).toEqual({
|
||||||
success: true,
|
success: true,
|
||||||
module: "server",
|
module: "server",
|
||||||
config: {
|
config: {
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import { AppEvents } from "App";
|
import { AppEvents } from "App";
|
||||||
import { describe, test, expect, beforeAll, mock } from "bun:test";
|
import { describe, test, expect, beforeAll, mock } from "bun:test";
|
||||||
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
||||||
import { getSystemMcp } from "modules/mcp/system-mcp";
|
import type { McpServer } from "bknd/utils";
|
||||||
import { inspect } from "node:util";
|
|
||||||
inspect.defaultOptions.depth = 10;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* - [x] system_config
|
* - [x] system_config
|
||||||
@@ -13,7 +11,7 @@ inspect.defaultOptions.depth = 10;
|
|||||||
*/
|
*/
|
||||||
describe("mcp system", async () => {
|
describe("mcp system", async () => {
|
||||||
let app: App;
|
let app: App;
|
||||||
let server: ReturnType<typeof getSystemMcp>;
|
let server: McpServer;
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = createApp({
|
app = createApp({
|
||||||
initialConfig: {
|
initialConfig: {
|
||||||
@@ -25,7 +23,7 @@ describe("mcp system", async () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
await app.build();
|
await app.build();
|
||||||
server = getSystemMcp(app);
|
server = app.mcp!;
|
||||||
});
|
});
|
||||||
|
|
||||||
const tool = createMcpToolCaller();
|
const tool = createMcpToolCaller();
|
||||||
|
|||||||
@@ -47,8 +47,4 @@ describe("[data] Entity", async () => {
|
|||||||
entity.addField(field);
|
entity.addField(field);
|
||||||
expect(entity.getField("new_field")).toBe(field);
|
expect(entity.getField("new_field")).toBe(field);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.only("types", async () => {
|
|
||||||
console.log(entity.toTypes());
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
24
app/__test__/debug/jsonv-resolution.test.ts
Normal file
24
app/__test__/debug/jsonv-resolution.test.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { describe, it, expect } from "bun:test";
|
||||||
|
import * as sDirect from "jsonv-ts";
|
||||||
|
import { s as sFromBknd } from "bknd/utils";
|
||||||
|
|
||||||
|
describe("jsonv-ts resolution", () => {
|
||||||
|
it("should resolve to a single instance", () => {
|
||||||
|
const sameNamespace = sDirect === (sFromBknd as unknown as typeof sDirect);
|
||||||
|
// If this fails, two instances are being loaded via different specifiers/paths
|
||||||
|
expect(sameNamespace).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should resolve specifiers to a single package path", async () => {
|
||||||
|
const base = await import.meta.resolve("jsonv-ts");
|
||||||
|
const hono = await import.meta.resolve("jsonv-ts/hono");
|
||||||
|
const mcp = await import.meta.resolve("jsonv-ts/mcp");
|
||||||
|
expect(typeof base).toBe("string");
|
||||||
|
expect(typeof hono).toBe("string");
|
||||||
|
expect(typeof mcp).toBe("string");
|
||||||
|
// They can be different files (subpath exports), but they should share the same package root
|
||||||
|
const pkgRoot = (p: string) => p.slice(0, p.lastIndexOf("jsonv-ts") + "jsonv-ts".length);
|
||||||
|
expect(pkgRoot(base)).toBe(pkgRoot(hono));
|
||||||
|
expect(pkgRoot(base)).toBe(pkgRoot(mcp));
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -5,7 +5,7 @@ import { format as sqlFormat } from "sql-formatter";
|
|||||||
import type { em as protoEm } from "../src/data/prototype";
|
import type { em as protoEm } from "../src/data/prototype";
|
||||||
import { writeFile } from "node:fs/promises";
|
import { writeFile } from "node:fs/promises";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { slugify } from "core/utils/strings";
|
import { slugify } from "bknd/utils";
|
||||||
import { type Connection, SqliteLocalConnection } from "data/connection";
|
import { type Connection, SqliteLocalConnection } from "data/connection";
|
||||||
import { EntityManager } from "data/entities/EntityManager";
|
import { EntityManager } from "data/entities/EntityManager";
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ import { beforeEach, describe, expect, it } from "bun:test";
|
|||||||
|
|
||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { Guard } from "auth/authorize/Guard";
|
import { Guard } from "auth/authorize/Guard";
|
||||||
import { DebugLogger } from "core/utils/DebugLogger";
|
|
||||||
import { EventManager } from "core/events";
|
import { EventManager } from "core/events";
|
||||||
import { EntityManager } from "data/entities/EntityManager";
|
import { EntityManager } from "data/entities/EntityManager";
|
||||||
import { Module, type ModuleBuildContext } from "modules/Module";
|
import { Module, type ModuleBuildContext } from "modules/Module";
|
||||||
import { getDummyConnection } from "../helper";
|
import { getDummyConnection } from "../helper";
|
||||||
import { ModuleHelper } from "modules/ModuleHelper";
|
import { ModuleHelper } from "modules/ModuleHelper";
|
||||||
import { McpServer } from "bknd/utils";
|
import { DebugLogger, McpServer } from "bknd/utils";
|
||||||
|
|
||||||
export function makeCtx(overrides?: Partial<ModuleBuildContext>): ModuleBuildContext {
|
export function makeCtx(overrides?: Partial<ModuleBuildContext>): ModuleBuildContext {
|
||||||
const { dummyConnection } = getDummyConnection();
|
const { dummyConnection } = getDummyConnection();
|
||||||
|
|||||||
@@ -1,13 +1,32 @@
|
|||||||
import pkg from "./package.json" with { type: "json" };
|
import pkg from "./package.json" with { type: "json" };
|
||||||
import c from "picocolors";
|
import c from "picocolors";
|
||||||
import { formatNumber } from "core/utils";
|
import { formatNumber } from "bknd/utils";
|
||||||
|
import * as esbuild from "esbuild";
|
||||||
|
|
||||||
|
if (process.env.DEBUG) {
|
||||||
|
await esbuild.build({
|
||||||
|
entryPoints: ["./src/cli/index.ts"],
|
||||||
|
outdir: "./dist/cli",
|
||||||
|
platform: "node",
|
||||||
|
minify: false,
|
||||||
|
format: "esm",
|
||||||
|
bundle: true,
|
||||||
|
external: ["jsonv-ts", "jsonv-ts/*"],
|
||||||
|
define: {
|
||||||
|
__isDev: "0",
|
||||||
|
__version: JSON.stringify(pkg.version),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
const result = await Bun.build({
|
const result = await Bun.build({
|
||||||
entrypoints: ["./src/cli/index.ts"],
|
entrypoints: ["./src/cli/index.ts"],
|
||||||
target: "node",
|
target: "node",
|
||||||
outdir: "./dist/cli",
|
outdir: "./dist/cli",
|
||||||
env: "PUBLIC_*",
|
env: "PUBLIC_*",
|
||||||
minify: true,
|
minify: false,
|
||||||
|
external: ["jsonv-ts", "jsonv-ts/*"],
|
||||||
define: {
|
define: {
|
||||||
__isDev: "0",
|
__isDev: "0",
|
||||||
__version: JSON.stringify(pkg.version),
|
__version: JSON.stringify(pkg.version),
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ const external = [
|
|||||||
"@libsql/client",
|
"@libsql/client",
|
||||||
"bknd",
|
"bknd",
|
||||||
/^bknd\/.*/,
|
/^bknd\/.*/,
|
||||||
|
"jsonv-ts",
|
||||||
|
/^jsonv-ts\/.*/,
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
"hono": "4.8.3",
|
"hono": "4.8.3",
|
||||||
"json-schema-library": "10.0.0-rc7",
|
"json-schema-library": "10.0.0-rc7",
|
||||||
"json-schema-to-ts": "^3.1.1",
|
"json-schema-to-ts": "^3.1.1",
|
||||||
"jsonv-ts": "^0.7.5",
|
"jsonv-ts": "^0.8.0",
|
||||||
"kysely": "0.27.6",
|
"kysely": "0.27.6",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"oauth4webapi": "^2.11.1",
|
"oauth4webapi": "^2.11.1",
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ export class App<C extends Connection = Connection, Options extends AppOptions =
|
|||||||
|
|
||||||
private trigger_first_boot = false;
|
private trigger_first_boot = false;
|
||||||
private _building: boolean = false;
|
private _building: boolean = false;
|
||||||
|
private _systemController: SystemController | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public connection: C,
|
public connection: C,
|
||||||
@@ -172,8 +173,8 @@ export class App<C extends Connection = Connection, Options extends AppOptions =
|
|||||||
|
|
||||||
// load system controller
|
// load system controller
|
||||||
guard.registerPermissions(Object.values(SystemPermissions));
|
guard.registerPermissions(Object.values(SystemPermissions));
|
||||||
const systemController = new SystemController(this);
|
this._systemController = new SystemController(this);
|
||||||
systemController.register(this);
|
this._systemController.register(this);
|
||||||
|
|
||||||
// emit built event
|
// emit built event
|
||||||
$console.log("App built");
|
$console.log("App built");
|
||||||
@@ -205,6 +206,10 @@ export class App<C extends Connection = Connection, Options extends AppOptions =
|
|||||||
return this.modules.ctx().em;
|
return this.modules.ctx().em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get mcp() {
|
||||||
|
return this._systemController?._mcpServer;
|
||||||
|
}
|
||||||
|
|
||||||
get fetch(): Hono["fetch"] {
|
get fetch(): Hono["fetch"] {
|
||||||
return this.server.fetch as any;
|
return this.server.fetch as any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import type { CliCommand } from "cli/types";
|
import type { CliCommand } from "cli/types";
|
||||||
import { makeAppFromEnv } from "../run";
|
import { makeAppFromEnv } from "../run";
|
||||||
import { getSystemMcp } from "modules/mcp/system-mcp";
|
import { getSystemMcp } from "modules/mcp/system-mcp";
|
||||||
import { $console } from "bknd/utils";
|
import { $console, stdioTransport } from "bknd/utils";
|
||||||
import { stdioTransport } from "jsonv-ts/mcp";
|
|
||||||
|
|
||||||
export const mcp: CliCommand = (program) =>
|
export const mcp: CliCommand = (program) =>
|
||||||
program
|
program
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export class SchemaObject<Schema extends TSchema = TSchema> {
|
|||||||
) {
|
) {
|
||||||
this._default = deepFreeze(_schema.template({}, { withOptional: true }) as any);
|
this._default = deepFreeze(_schema.template({}, { withOptional: true }) as any);
|
||||||
this._value = deepFreeze(
|
this._value = deepFreeze(
|
||||||
parse(_schema, structuredClone(initial ?? {}), {
|
parse(_schema, initial ?? {}, {
|
||||||
withDefaults: true,
|
withDefaults: true,
|
||||||
//withExtendedDefaults: true,
|
//withExtendedDefaults: true,
|
||||||
forceParse: this.isForceParse(),
|
forceParse: this.isForceParse(),
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
import { createApp as createAppInternal, type CreateAppConfig } from "App";
|
import { Connection, createApp as createAppInternal, type CreateAppConfig } from "bknd";
|
||||||
import { bunSqlite } from "adapter/bun/connection/BunSqliteConnection";
|
import { bunSqlite } from "bknd/adapter/bun";
|
||||||
import { Connection } from "data/connection/Connection";
|
import type { McpServer } from "bknd/utils";
|
||||||
import type { getSystemMcp } from "modules/mcp/system-mcp";
|
|
||||||
|
|
||||||
export { App } from "App";
|
export { App } from "bknd";
|
||||||
|
|
||||||
export function createApp({ connection, ...config }: CreateAppConfig = {}) {
|
export function createApp({ connection, ...config }: CreateAppConfig = {}) {
|
||||||
return createAppInternal({
|
return createAppInternal({
|
||||||
...config,
|
...config,
|
||||||
connection: Connection.isConnection(connection) ? connection : bunSqlite(connection as any),
|
connection: Connection.isConnection(connection)
|
||||||
|
? connection
|
||||||
|
: (bunSqlite(connection as any) as any),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createMcpToolCaller() {
|
export function createMcpToolCaller() {
|
||||||
return async (server: ReturnType<typeof getSystemMcp>, name: string, args: any, raw?: any) => {
|
return async (server: McpServer, name: string, args: any, raw?: any) => {
|
||||||
const res = await server.handle(
|
const res = await server.handle(
|
||||||
{
|
{
|
||||||
jsonrpc: "2.0",
|
jsonrpc: "2.0",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { extension, guess, isMimeType } from "media/storage/mime-types-tiny";
|
import { extension, guess, isMimeType } from "media/storage/mime-types-tiny";
|
||||||
import { randomString } from "core/utils/strings";
|
import { randomString } from "./strings";
|
||||||
import type { Context } from "hono";
|
import type { Context } from "hono";
|
||||||
import { invariant } from "core/utils/runtime";
|
import { invariant } from "./runtime";
|
||||||
import { $console } from "./console";
|
import { $console } from "./console";
|
||||||
|
|
||||||
export function getContentName(request: Request): string | undefined;
|
export function getContentName(request: Request): string | undefined;
|
||||||
|
|||||||
@@ -14,3 +14,4 @@ export * from "./test";
|
|||||||
export * from "./runtime";
|
export * from "./runtime";
|
||||||
export * from "./numbers";
|
export * from "./numbers";
|
||||||
export * from "./schema";
|
export * from "./schema";
|
||||||
|
export { DebugLogger } from "./DebugLogger";
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export {
|
|||||||
mcpTool,
|
mcpTool,
|
||||||
mcpResource,
|
mcpResource,
|
||||||
getMcpServer,
|
getMcpServer,
|
||||||
|
stdioTransport,
|
||||||
type ToolAnnotation,
|
type ToolAnnotation,
|
||||||
type ToolHandlerCtx,
|
type ToolHandlerCtx,
|
||||||
} from "jsonv-ts/mcp";
|
} from "jsonv-ts/mcp";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { StringSchema, type IStringOptions } from "jsonv-ts";
|
import { s } from "bknd/utils";
|
||||||
|
|
||||||
export class SecretSchema<O extends IStringOptions> extends StringSchema<O> {}
|
export class SecretSchema<O extends s.IStringOptions> extends s.StringSchema<O> {}
|
||||||
|
|
||||||
export const secret = <O extends IStringOptions>(o?: O): SecretSchema<O> & O =>
|
export const secret = <O extends s.IStringOptions>(o?: O): SecretSchema<O> & O =>
|
||||||
new SecretSchema(o) as any;
|
new SecretSchema(o) as any;
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export type { BkndConfig } from "bknd/adapter";
|
|||||||
|
|
||||||
export * as middlewares from "modules/middlewares";
|
export * as middlewares from "modules/middlewares";
|
||||||
export { registries } from "modules/registries";
|
export { registries } from "modules/registries";
|
||||||
|
export { getSystemMcp } from "modules/mcp/system-mcp";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Core
|
* Core
|
||||||
|
|||||||
@@ -6,9 +6,8 @@ import type { Hono } from "hono";
|
|||||||
import type { ServerEnv } from "modules/Controller";
|
import type { ServerEnv } from "modules/Controller";
|
||||||
import type { ModuleHelper } from "./ModuleHelper";
|
import type { ModuleHelper } from "./ModuleHelper";
|
||||||
import { SchemaObject } from "core/object/SchemaObject";
|
import { SchemaObject } from "core/object/SchemaObject";
|
||||||
import type { DebugLogger } from "core/utils/DebugLogger";
|
|
||||||
import type { Guard } from "auth/authorize/Guard";
|
import type { Guard } from "auth/authorize/Guard";
|
||||||
import type { McpServer } from "bknd/utils";
|
import type { McpServer, DebugLogger } from "bknd/utils";
|
||||||
|
|
||||||
type PartialRec<T> = { [P in keyof T]?: PartialRec<T[P]> };
|
type PartialRec<T> = { [P in keyof T]?: PartialRec<T[P]> };
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
import { mark, stripMark, $console, s, objectEach, transformObject, McpServer } from "bknd/utils";
|
import {
|
||||||
|
mark,
|
||||||
|
stripMark,
|
||||||
|
$console,
|
||||||
|
s,
|
||||||
|
objectEach,
|
||||||
|
transformObject,
|
||||||
|
McpServer,
|
||||||
|
DebugLogger,
|
||||||
|
} from "bknd/utils";
|
||||||
import { Guard } from "auth/authorize/Guard";
|
import { Guard } from "auth/authorize/Guard";
|
||||||
import { env } from "core/env";
|
import { env } from "core/env";
|
||||||
import { BkndError } from "core/errors";
|
import { BkndError } from "core/errors";
|
||||||
import { DebugLogger } from "core/utils/DebugLogger";
|
|
||||||
import { EventManager, Event } from "core/events";
|
import { EventManager, Event } from "core/events";
|
||||||
import * as $diff from "core/object/diff";
|
import * as $diff from "core/object/diff";
|
||||||
import type { Connection } from "data/connection";
|
import type { Connection } from "data/connection";
|
||||||
|
|||||||
@@ -8,12 +8,9 @@ export function getSystemMcp(app: App) {
|
|||||||
|
|
||||||
const appConfig = app.modules.configs();
|
const appConfig = app.modules.configs();
|
||||||
const { version, ...appSchema } = app.getSchema();
|
const { version, ...appSchema } = app.getSchema();
|
||||||
|
|
||||||
const schema = s.strictObject(appSchema);
|
const schema = s.strictObject(appSchema);
|
||||||
|
const result = [...schema.walk({ maxDepth: 3 })];
|
||||||
const nodes = [...schema.walk({ data: appConfig })].filter(
|
const nodes = result.filter((n) => mcpSchemaSymbol in n.schema) as s.Node<McpSchema>[];
|
||||||
(n) => isObject(n.schema) && mcpSchemaSymbol in n.schema,
|
|
||||||
) as s.Node<McpSchema>[];
|
|
||||||
const tools = [
|
const tools = [
|
||||||
// tools from hono routes
|
// tools from hono routes
|
||||||
...middlewareServer.tools,
|
...middlewareServer.tools,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
mcpTool,
|
mcpTool,
|
||||||
mcp as mcpMiddleware,
|
mcp as mcpMiddleware,
|
||||||
isNode,
|
isNode,
|
||||||
|
type McpServer,
|
||||||
} from "bknd/utils";
|
} from "bknd/utils";
|
||||||
import type { Context, Hono } from "hono";
|
import type { Context, Hono } from "hono";
|
||||||
import { Controller } from "modules/Controller";
|
import { Controller } from "modules/Controller";
|
||||||
@@ -47,6 +48,8 @@ export type SchemaResponse = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export class SystemController extends Controller {
|
export class SystemController extends Controller {
|
||||||
|
_mcpServer: McpServer | null = null;
|
||||||
|
|
||||||
constructor(private readonly app: App) {
|
constructor(private readonly app: App) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@@ -64,8 +67,8 @@ export class SystemController extends Controller {
|
|||||||
|
|
||||||
this.registerMcp();
|
this.registerMcp();
|
||||||
|
|
||||||
const mcpServer = getSystemMcp(app);
|
this._mcpServer = getSystemMcp(app);
|
||||||
mcpServer.onNotification((message) => {
|
this._mcpServer.onNotification((message) => {
|
||||||
if (message.method === "notification/message") {
|
if (message.method === "notification/message") {
|
||||||
const consoleMap = {
|
const consoleMap = {
|
||||||
emergency: "error",
|
emergency: "error",
|
||||||
@@ -87,7 +90,7 @@ export class SystemController extends Controller {
|
|||||||
|
|
||||||
app.server.use(
|
app.server.use(
|
||||||
mcpMiddleware({
|
mcpMiddleware({
|
||||||
server: mcpServer,
|
server: this._mcpServer,
|
||||||
sessionsEnabled: true,
|
sessionsEnabled: true,
|
||||||
debug: {
|
debug: {
|
||||||
logLevel: "debug",
|
logLevel: "debug",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import type { Connection } from "./src/data/connection/Connection";
|
|||||||
import { __bknd } from "modules/ModuleManager";
|
import { __bknd } from "modules/ModuleManager";
|
||||||
import { nodeSqlite } from "./src/adapter/node/connection/NodeSqliteConnection";
|
import { nodeSqlite } from "./src/adapter/node/connection/NodeSqliteConnection";
|
||||||
import { libsql } from "./src/data/connection/sqlite/libsql/LibsqlConnection";
|
import { libsql } from "./src/data/connection/sqlite/libsql/LibsqlConnection";
|
||||||
import { $console } from "core/utils";
|
import { $console } from "bknd/utils";
|
||||||
import { createClient } from "@libsql/client";
|
import { createClient } from "@libsql/client";
|
||||||
|
|
||||||
registries.media.register("local", StorageLocalAdapter);
|
registries.media.register("local", StorageLocalAdapter);
|
||||||
|
|||||||
4
bun.lock
4
bun.lock
@@ -35,7 +35,7 @@
|
|||||||
"hono": "4.8.3",
|
"hono": "4.8.3",
|
||||||
"json-schema-library": "10.0.0-rc7",
|
"json-schema-library": "10.0.0-rc7",
|
||||||
"json-schema-to-ts": "^3.1.1",
|
"json-schema-to-ts": "^3.1.1",
|
||||||
"jsonv-ts": "^0.7.5",
|
"jsonv-ts": "^0.8.0",
|
||||||
"kysely": "0.27.6",
|
"kysely": "0.27.6",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"oauth4webapi": "^2.11.1",
|
"oauth4webapi": "^2.11.1",
|
||||||
@@ -2516,7 +2516,7 @@
|
|||||||
|
|
||||||
"jsonpointer": ["jsonpointer@5.0.1", "", {}, "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ=="],
|
"jsonpointer": ["jsonpointer@5.0.1", "", {}, "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ=="],
|
||||||
|
|
||||||
"jsonv-ts": ["jsonv-ts@0.7.5", "", { "optionalDependencies": { "hono": "*" }, "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-/FXLINo/mbMLVFD4zjNRFfWe5D9oBsc2H9Fy/KLgmdGdhgUo9T/xbVteGWBVQSPg+P2hPdbVgaKFWgvDPk4qVw=="],
|
"jsonv-ts": ["jsonv-ts@0.8.0", "", { "optionalDependencies": { "hono": "*" }, "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-OS0QnkpmyqoFbK+qh7Rk+XAc+TCpWnOW1j9hJWJ1e0Lz1yGOExpa7ghokI4gUjKOwUXNq1eN7vUs+WUTzX2+gA=="],
|
||||||
|
|
||||||
"jsonwebtoken": ["jsonwebtoken@9.0.2", "", { "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ=="],
|
"jsonwebtoken": ["jsonwebtoken@9.0.2", "", { "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ=="],
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user