init code-first mode by splitting module manager

This commit is contained in:
dswbx
2025-09-04 09:21:35 +02:00
parent c9773d49a6
commit e3888537f9
22 changed files with 768 additions and 541 deletions

View File

@@ -6,7 +6,6 @@ import {
type McpSchema,
type SchemaWithMcpOptions,
} from "./McpSchemaHelper";
import type { Module } from "modules/Module";
export interface ObjectToolSchemaOptions extends s.IObjectOptions, SchemaWithMcpOptions {}
@@ -79,6 +78,7 @@ export class ObjectToolSchema<
private toolUpdate(node: s.Node<ObjectToolSchema>) {
const schema = this.mcp.cleanSchema;
return new Tool(
[this.mcp.name, "update"].join("_"),
{
@@ -97,11 +97,12 @@ export class ObjectToolSchema<
async (params, ctx: AppToolHandlerCtx) => {
const { full, value, return_config } = params;
const [module_name] = node.instancePath;
const manager = this.mcp.getManager(ctx);
if (full) {
await ctx.context.app.mutateConfig(module_name as any).set(value);
await manager.mutateConfigSafe(module_name as any).set(value);
} else {
await ctx.context.app.mutateConfig(module_name as any).patch("", value);
await manager.mutateConfigSafe(module_name as any).patch("", value);
}
let config: any = undefined;

View File

@@ -129,13 +129,14 @@ export class RecordToolSchema<
const configs = ctx.context.app.toJSON(true);
const config = getPath(configs, node.instancePath);
const [module_name, ...rest] = node.instancePath;
const manager = this.mcp.getManager(ctx);
if (params.key in config) {
throw new Error(`Key "${params.key}" already exists in config`);
}
await ctx.context.app
.mutateConfig(module_name as any)
await manager
.mutateConfigSafe(module_name as any)
.patch([...rest, params.key], params.value);
const newConfig = getPath(ctx.context.app.toJSON(), node.instancePath);
@@ -175,13 +176,14 @@ export class RecordToolSchema<
const configs = ctx.context.app.toJSON(true);
const config = getPath(configs, node.instancePath);
const [module_name, ...rest] = node.instancePath;
const manager = this.mcp.getManager(ctx);
if (!(params.key in config)) {
throw new Error(`Key "${params.key}" not found in config`);
}
await ctx.context.app
.mutateConfig(module_name as any)
await manager
.mutateConfigSafe(module_name as any)
.patch([...rest, params.key], params.value);
const newConfig = getPath(ctx.context.app.toJSON(), node.instancePath);
@@ -220,13 +222,14 @@ export class RecordToolSchema<
const configs = ctx.context.app.toJSON(true);
const config = getPath(configs, node.instancePath);
const [module_name, ...rest] = node.instancePath;
const manager = this.mcp.getManager(ctx);
if (!(params.key in config)) {
throw new Error(`Key "${params.key}" not found in config`);
}
await ctx.context.app
.mutateConfig(module_name as any)
await manager
.mutateConfigSafe(module_name as any)
.remove([...rest, params.key].join("."));
const newConfig = getPath(ctx.context.app.toJSON(), node.instancePath);

View File

@@ -58,8 +58,9 @@ export const $schema = <
async (params, ctx: AppToolHandlerCtx) => {
const { value, return_config, secrets } = params;
const [module_name, ...rest] = node.instancePath;
const manager = mcp.getManager(ctx);
await ctx.context.app.mutateConfig(module_name as any).overwrite(rest, value);
await manager.mutateConfigSafe(module_name as any).overwrite(rest, value);
let config: any = undefined;
if (return_config) {

View File

@@ -10,6 +10,7 @@ import {
} from "bknd/utils";
import type { ModuleBuildContext } from "modules";
import { excludePropertyTypes, rescursiveClean } from "./utils";
import type { DbModuleManager } from "modules/manager/DbModuleManager";
export const mcpSchemaSymbol = Symbol.for("bknd-mcp-schema");
@@ -74,4 +75,13 @@ export class McpSchemaHelper<AdditionalOptions = {}> {
},
};
}
getManager(ctx: AppToolHandlerCtx): DbModuleManager {
const manager = ctx.context.app.modules;
if ("mutateConfigSafe" in manager) {
return manager as DbModuleManager;
}
throw new Error("Manager not found");
}
}

View File

@@ -19,9 +19,11 @@ export function getSystemMcp(app: App) {
].sort((a, b) => a.name.localeCompare(b.name));
// tools from app schema
tools.push(
...nodes.flatMap((n) => n.schema.getTools(n)).sort((a, b) => a.name.localeCompare(b.name)),
);
if (!app.isReadOnly()) {
tools.push(
...nodes.flatMap((n) => n.schema.getTools(n)).sort((a, b) => a.name.localeCompare(b.name)),
);
}
const resources = [...middlewareServer.resources, ...app.modules.ctx().mcp.resources];