mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-15 20:17:22 +00:00
feat: lazy load mcp server
This commit is contained in:
@@ -16,6 +16,7 @@ describe("AppServer", () => {
|
||||
mcp: {
|
||||
enabled: false,
|
||||
path: "/api/system/mcp",
|
||||
logLevel: "warning",
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -38,6 +39,7 @@ describe("AppServer", () => {
|
||||
mcp: {
|
||||
enabled: false,
|
||||
path: "/api/system/mcp",
|
||||
logLevel: "warning",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ describe("mcp auth", async () => {
|
||||
},
|
||||
});
|
||||
await app.build();
|
||||
await app.getMcpClient().ping();
|
||||
server = app.mcp!;
|
||||
server.setLogLevel("error");
|
||||
server.onNotification((message) => {
|
||||
|
||||
@@ -34,6 +34,11 @@ describe("mcp", () => {
|
||||
});
|
||||
await app.build();
|
||||
|
||||
// expect mcp to not be loaded yet
|
||||
expect(app.mcp).toBeNull();
|
||||
|
||||
// after first request, mcp should be loaded
|
||||
await app.getMcpClient().listTools();
|
||||
expect(app.mcp?.tools.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -50,6 +50,7 @@ describe("mcp data", async () => {
|
||||
},
|
||||
});
|
||||
await app.build();
|
||||
await app.getMcpClient().ping();
|
||||
server = app.mcp!;
|
||||
server.setLogLevel("error");
|
||||
server.onNotification((message) => {
|
||||
|
||||
@@ -39,6 +39,7 @@ describe("mcp media", async () => {
|
||||
},
|
||||
});
|
||||
await app.build();
|
||||
await app.getMcpClient().ping();
|
||||
server = app.mcp!;
|
||||
server.setLogLevel("error");
|
||||
server.onNotification((message) => {
|
||||
|
||||
@@ -24,6 +24,7 @@ describe("mcp system", async () => {
|
||||
},
|
||||
});
|
||||
await app.build();
|
||||
await app.getMcpClient().ping();
|
||||
server = app.mcp!;
|
||||
});
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ describe("mcp system", async () => {
|
||||
},
|
||||
});
|
||||
await app.build();
|
||||
await app.getMcpClient().ping();
|
||||
server = app.mcp!;
|
||||
});
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"hono": "4.8.3",
|
||||
"json-schema-library": "10.0.0-rc7",
|
||||
"json-schema-to-ts": "^3.1.1",
|
||||
"jsonv-ts": "0.8.2",
|
||||
"jsonv-ts": "0.8.4",
|
||||
"kysely": "0.27.6",
|
||||
"lodash-es": "^4.17.21",
|
||||
"oauth4webapi": "^2.11.1",
|
||||
|
||||
@@ -302,13 +302,13 @@ export class App<
|
||||
}
|
||||
|
||||
getMcpClient() {
|
||||
if (!this.mcp) {
|
||||
const config = this.modules.get("server").config.mcp;
|
||||
if (!config.enabled) {
|
||||
throw new Error("MCP is not enabled");
|
||||
}
|
||||
const mcpPath = this.modules.get("server").config.mcp.path;
|
||||
|
||||
return new McpClient({
|
||||
url: "http://localhost" + mcpPath,
|
||||
url: "http://localhost" + config.path,
|
||||
fetch: this.server.request,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { getVersion } from "core/env";
|
||||
export function getSystemMcp(app: App) {
|
||||
const middlewareServer = getMcpServer(app.server);
|
||||
|
||||
const appConfig = app.modules.configs();
|
||||
//const appConfig = app.modules.configs();
|
||||
const { version, ...appSchema } = app.getSchema();
|
||||
const schema = s.strictObject(appSchema);
|
||||
const result = [...schema.walk({ maxDepth: 3 })];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Exception } from "core/errors";
|
||||
import { isDebug } from "core/env";
|
||||
import { $console, s } from "bknd/utils";
|
||||
import { $console, mcpLogLevels, s } from "bknd/utils";
|
||||
import { $object } from "modules/mcp";
|
||||
import { cors } from "hono/cors";
|
||||
import { Module } from "modules/Module";
|
||||
@@ -25,6 +25,10 @@ export const serverConfigSchema = $object(
|
||||
mcp: s.strictObject({
|
||||
enabled: s.boolean({ default: false }),
|
||||
path: s.string({ default: "/api/system/mcp" }),
|
||||
logLevel: s.string({
|
||||
enum: mcpLogLevels,
|
||||
default: "warning",
|
||||
}),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -70,33 +70,41 @@ export class SystemController extends Controller {
|
||||
|
||||
this.registerMcp();
|
||||
|
||||
this._mcpServer = getSystemMcp(app);
|
||||
this._mcpServer.onNotification((message) => {
|
||||
if (message.method === "notification/message") {
|
||||
const consoleMap = {
|
||||
emergency: "error",
|
||||
alert: "error",
|
||||
critical: "error",
|
||||
error: "error",
|
||||
warning: "warn",
|
||||
notice: "log",
|
||||
info: "info",
|
||||
debug: "debug",
|
||||
};
|
||||
|
||||
const level = consoleMap[message.params.level];
|
||||
if (!level) return;
|
||||
|
||||
$console[level]("MCP notification", message.params.message ?? message.params);
|
||||
}
|
||||
});
|
||||
|
||||
app.server.use(
|
||||
mcpMiddleware({
|
||||
server: this._mcpServer,
|
||||
setup: async () => {
|
||||
if (!this._mcpServer) {
|
||||
this._mcpServer = getSystemMcp(app);
|
||||
this._mcpServer.onNotification((message) => {
|
||||
if (message.method === "notification/message") {
|
||||
const consoleMap = {
|
||||
emergency: "error",
|
||||
alert: "error",
|
||||
critical: "error",
|
||||
error: "error",
|
||||
warning: "warn",
|
||||
notice: "log",
|
||||
info: "info",
|
||||
debug: "debug",
|
||||
};
|
||||
|
||||
const level = consoleMap[message.params.level];
|
||||
if (!level) return;
|
||||
|
||||
$console[level](
|
||||
"MCP notification",
|
||||
message.params.message ?? message.params,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
return {
|
||||
server: this._mcpServer,
|
||||
};
|
||||
},
|
||||
sessionsEnabled: true,
|
||||
debug: {
|
||||
logLevel: "debug",
|
||||
logLevel: config.mcp.logLevel as any,
|
||||
explainEndpoint: true,
|
||||
},
|
||||
endpoint: {
|
||||
|
||||
6
bun.lock
6
bun.lock
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"app": {
|
||||
"name": "bknd",
|
||||
"version": "0.18.0-rc.4",
|
||||
"version": "0.18.0-rc.6",
|
||||
"bin": "./dist/cli/index.js",
|
||||
"dependencies": {
|
||||
"@cfworker/json-schema": "^4.1.1",
|
||||
@@ -35,7 +35,7 @@
|
||||
"hono": "4.8.3",
|
||||
"json-schema-library": "10.0.0-rc7",
|
||||
"json-schema-to-ts": "^3.1.1",
|
||||
"jsonv-ts": "0.8.2",
|
||||
"jsonv-ts": "0.8.4",
|
||||
"kysely": "0.27.6",
|
||||
"lodash-es": "^4.17.21",
|
||||
"oauth4webapi": "^2.11.1",
|
||||
@@ -2529,7 +2529,7 @@
|
||||
|
||||
"jsonpointer": ["jsonpointer@5.0.1", "", {}, "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ=="],
|
||||
|
||||
"jsonv-ts": ["jsonv-ts@0.8.2", "", { "optionalDependencies": { "hono": "*" }, "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-1Z7+maCfoGGqBPu5vN8rU9gIsW7OatYmn+STBTPkybbtNqeMzAoJDDrXHjsZ89x5dPH9W+OgMpNLtN0ouwiMYg=="],
|
||||
"jsonv-ts": ["jsonv-ts@0.8.4", "", { "optionalDependencies": { "hono": "*" }, "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-TZOyAVGBZxHuzk09NgJCx2dbeh0XqVWVKHU1PtIuvjT9XO7zhvAD02RcVisJoUdt2rJNt3zlyeNQ2b8MMPc+ug=="],
|
||||
|
||||
"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