added data mcp tests

This commit is contained in:
dswbx
2025-08-12 20:22:38 +02:00
parent 871cec9251
commit bd3d2ea900
9 changed files with 425 additions and 105 deletions

View File

@@ -1,4 +1,4 @@
import { describe, it, expect, beforeAll } from "bun:test"; import { describe, beforeAll } from "bun:test";
import { type App, createApp } from "core/test/utils"; import { type App, createApp } from "core/test/utils";
import { getSystemMcp } from "modules/mcp/system-mcp"; import { getSystemMcp } from "modules/mcp/system-mcp";

View File

@@ -1,38 +1,44 @@
import { describe, test, expect, beforeAll } 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 { entity, text } from "bknd";
import { disableConsoleLog, enableConsoleLog } from "core/utils";
beforeAll(disableConsoleLog);
afterAll(enableConsoleLog);
/** /**
* - [ ] data_sync * - [ ] data_sync
* - [ ] data_entity_fn_count * - [x] data_entity_fn_count
* - [ ] data_entity_fn_exists * - [x] data_entity_fn_exists
* - [ ] data_entity_read_one * - [x] data_entity_read_one
* - [ ] data_entity_read_many * - [x] data_entity_read_many
* - [ ] data_entity_insert * - [x] data_entity_insert
* - [ ] data_entity_update_many * - [x] data_entity_update_many
* - [ ] data_entity_update_one * - [x] data_entity_update_one
* - [ ] data_entity_delete_one * - [x] data_entity_delete_one
* - [ ] data_entity_delete_many * - [x] data_entity_delete_many
* - [ ] data_entity_info * - [x] data_entity_info
* - [ ] config_data_get * - [ ] config_data_get
* - [ ] config_data_update * - [ ] config_data_update
* - [x] config_data_entities_get * - [x] config_data_entities_get
* - [x] config_data_entities_add * - [x] config_data_entities_add
* - [x] config_data_entities_update * - [x] config_data_entities_update
* - [x] config_data_entities_remove * - [x] config_data_entities_remove
* - [ ] config_data_relations_get * - [x] config_data_relations_add
* - [ ] config_data_relations_add * - [x] config_data_relations_get
* - [ ] config_data_relations_update * - [x] config_data_relations_update
* - [ ] config_data_relations_remove * - [x] config_data_relations_remove
* - [ ] config_data_indices_get * - [x] config_data_indices_get
* - [ ] config_data_indices_add * - [x] config_data_indices_add
* - [ ] config_data_indices_update * - [x] config_data_indices_update
* - [ ] config_data_indices_remove * - [x] config_data_indices_remove
*/ */
describe("mcp data", async () => { describe("mcp data", async () => {
let app: App; let app: App;
let server: ReturnType<typeof getSystemMcp>; let server: ReturnType<typeof getSystemMcp>;
beforeAll(async () => { beforeEach(async () => {
app = createApp({ app = createApp({
initialConfig: { initialConfig: {
server: { server: {
@@ -55,6 +61,7 @@ describe("mcp data", async () => {
test("config_data_entities_{add,get,update,remove}", async () => { test("config_data_entities_{add,get,update,remove}", async () => {
const result = await tool(server, "config_data_entities_add", { const result = await tool(server, "config_data_entities_add", {
key: "test", key: "test",
return_config: true,
value: {}, value: {},
}); });
expect(result.success).toBe(true); expect(result.success).toBe(true);
@@ -78,6 +85,7 @@ describe("mcp data", async () => {
// update // update
const result = await tool(server, "config_data_entities_update", { const result = await tool(server, "config_data_entities_update", {
key: "test", key: "test",
return_config: true,
value: { value: {
config: { config: {
name: "Test", name: "Test",
@@ -100,4 +108,238 @@ describe("mcp data", async () => {
expect(app.toJSON().data.entities?.test).toBeUndefined(); expect(app.toJSON().data.entities?.test).toBeUndefined();
} }
}); });
test("config_data_relations_{add,get,update,remove}", async () => {
// create posts and comments
await tool(server, "config_data_entities_add", {
key: "posts",
value: {},
});
await tool(server, "config_data_entities_add", {
key: "comments",
value: {},
});
expect(Object.keys(app.toJSON().data.entities ?? {})).toEqual(["posts", "comments"]);
// create relation
await tool(server, "config_data_relations_add", {
key: "", // doesn't matter
value: {
type: "n:1",
source: "comments",
target: "posts",
},
});
const config = app.toJSON().data;
expect(
pickKeys((config.relations?.n1_comments_posts as any) ?? {}, ["type", "source", "target"]),
).toEqual({
type: "n:1",
source: "comments",
target: "posts",
});
expect(config.entities?.comments?.fields?.posts_id?.type).toBe("relation");
{
// info
const postsInfo = await tool(server, "data_entity_info", {
entity: "posts",
});
expect(postsInfo.fields).toEqual(["id"]);
expect(postsInfo.relations.all.length).toBe(1);
const commentsInfo = await tool(server, "data_entity_info", {
entity: "comments",
});
expect(commentsInfo.fields).toEqual(["id", "posts_id"]);
expect(commentsInfo.relations.all.length).toBe(1);
}
// update
await tool(server, "config_data_relations_update", {
key: "n1_comments_posts",
value: {
config: {
with_limit: 10,
},
},
});
expect((app.toJSON().data.relations?.n1_comments_posts?.config as any)?.with_limit).toBe(10);
// delete
await tool(server, "config_data_relations_remove", {
key: "n1_comments_posts",
});
expect(app.toJSON().data.relations?.n1_comments_posts).toBeUndefined();
});
test("config_data_indices_update", async () => {
expect(server.tools.map((t) => t.name).includes("config_data_indices_update")).toBe(false);
});
test("config_data_indices_{add,get,remove}", async () => {
// create posts and comments
await tool(server, "config_data_entities_add", {
key: "posts",
value: entity("posts", {
title: text(),
content: text(),
}).toJSON(),
});
// add index on title
await tool(server, "config_data_indices_add", {
key: "", // auto generated
value: {
entity: "posts",
fields: ["title"],
},
});
expect(app.toJSON().data.indices?.idx_posts_title).toEqual({
entity: "posts",
fields: ["title"],
unique: false,
});
// delete
await tool(server, "config_data_indices_remove", {
key: "idx_posts_title",
});
expect(app.toJSON().data.indices?.idx_posts_title).toBeUndefined();
});
test("data_entity_*", async () => {
// create posts and comments
await tool(server, "config_data_entities_add", {
key: "posts",
value: entity("posts", {
title: text(),
content: text(),
}).toJSON(),
});
await tool(server, "config_data_entities_add", {
key: "comments",
value: entity("comments", {
content: text(),
}).toJSON(),
});
// insert a few posts
for (let i = 0; i < 10; i++) {
await tool(server, "data_entity_insert", {
entity: "posts",
json: {
title: `Post ${i}`,
},
});
}
// insert a few comments
for (let i = 0; i < 5; i++) {
await tool(server, "data_entity_insert", {
entity: "comments",
json: {
content: `Comment ${i}`,
},
});
}
const result = await tool(server, "data_entity_read_many", {
entity: "posts",
limit: 5,
});
expect(result.data.length).toBe(5);
expect(result.meta.items).toBe(5);
expect(result.meta.total).toBe(10);
expect(result.data[0].title).toBe("Post 0");
{
// count
const result = await tool(server, "data_entity_fn_count", {
entity: "posts",
});
expect(result.count).toBe(10);
}
{
// exists
const res = await tool(server, "data_entity_fn_exists", {
entity: "posts",
json: {
id: result.data[0].id,
},
});
expect(res.exists).toBe(true);
const res2 = await tool(server, "data_entity_fn_exists", {
entity: "posts",
json: {
id: "123",
},
});
expect(res2.exists).toBe(false);
}
// update
await tool(server, "data_entity_update_one", {
entity: "posts",
id: result.data[0].id,
json: {
title: "Post 0 updated",
},
});
const result2 = await tool(server, "data_entity_read_one", {
entity: "posts",
id: result.data[0].id,
});
expect(result2.data.title).toBe("Post 0 updated");
// delete the second post
await tool(server, "data_entity_delete_one", {
entity: "posts",
id: result.data[1].id,
});
const result3 = await tool(server, "data_entity_read_many", {
entity: "posts",
limit: 2,
});
expect(result3.data.map((p) => p.id)).toEqual([1, 3]);
// update many
await tool(server, "data_entity_update_many", {
entity: "posts",
update: {
title: "Post updated",
},
where: {
title: { $isnull: 0 },
},
});
const result4 = await tool(server, "data_entity_read_many", {
entity: "posts",
limit: 10,
});
expect(result4.data.length).toBe(9);
expect(result4.data.map((p) => p.title)).toEqual(
Array.from({ length: 9 }, () => "Post updated"),
);
// delete many
await tool(server, "data_entity_delete_many", {
entity: "posts",
json: {
title: { $isnull: 0 },
},
});
const result5 = await tool(server, "data_entity_read_many", {
entity: "posts",
limit: 10,
});
expect(result5.data.length).toBe(0);
expect(result5.meta.items).toBe(0);
expect(result5.meta.total).toBe(0);
});
}); });

View File

@@ -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.3", "jsonv-ts": "^0.7.4",
"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",

View File

@@ -445,7 +445,15 @@ export class DataController extends Controller {
tags: ["data"], tags: ["data"],
}), }),
permission(DataPermissions.entityUpdate), permission(DataPermissions.entityUpdate),
mcpTool("data_entity_update_many"), mcpTool("data_entity_update_many", {
inputSchema: {
param: s.object({ entity: entitiesEnum }),
json: s.object({
update: s.object({}),
where: s.object({}),
}),
},
}),
jsc("param", s.object({ entity: entitiesEnum })), jsc("param", s.object({ entity: entitiesEnum })),
jsc( jsc(
"json", "json",
@@ -521,7 +529,12 @@ export class DataController extends Controller {
tags: ["data"], tags: ["data"],
}), }),
permission(DataPermissions.entityDelete), permission(DataPermissions.entityDelete),
mcpTool("data_entity_delete_many"), mcpTool("data_entity_delete_many", {
inputSchema: {
param: s.object({ entity: entitiesEnum }),
json: s.object({}),
},
}),
jsc("param", s.object({ entity: entitiesEnum })), jsc("param", s.object({ entity: entitiesEnum })),
jsc("json", repoQuery.properties.where), jsc("json", repoQuery.properties.where),
async (c) => { async (c) => {

View File

@@ -83,7 +83,10 @@ export const dataConfigSchema = $object("config_data", {
relations: $record("config_data_relations", s.anyOf(relationsSchema), { relations: $record("config_data_relations", s.anyOf(relationsSchema), {
default: {}, default: {},
}).optional(), }).optional(),
indices: $record("config_data_indices", indicesSchema, { default: {} }).optional(), indices: $record("config_data_indices", indicesSchema, {
default: {},
mcp: { update: false },
}).optional(),
}).strict(); }).strict();
export type AppDataConfig = s.Static<typeof dataConfigSchema>; export type AppDataConfig = s.Static<typeof dataConfigSchema>;

View File

@@ -7,7 +7,16 @@ import {
type SchemaWithMcpOptions, type SchemaWithMcpOptions,
} from "./McpSchemaHelper"; } from "./McpSchemaHelper";
export interface RecordToolSchemaOptions extends s.IRecordOptions, SchemaWithMcpOptions {} type RecordToolAdditionalOptions = {
get?: boolean;
add?: boolean;
update?: boolean;
remove?: boolean;
};
export interface RecordToolSchemaOptions
extends s.IRecordOptions,
SchemaWithMcpOptions<RecordToolAdditionalOptions> {}
const opts = Symbol.for("bknd-mcp-record-opts"); const opts = Symbol.for("bknd-mcp-record-opts");
@@ -28,7 +37,7 @@ export class RecordToolSchema<
}; };
} }
get mcp(): McpSchemaHelper { get mcp(): McpSchemaHelper<RecordToolAdditionalOptions> {
return this[mcpSchemaSymbol]; return this[mcpSchemaSymbol];
} }
@@ -104,6 +113,12 @@ export class RecordToolSchema<
description: "key to add", description: "key to add",
}), }),
value: this.getNewSchema(), value: this.getNewSchema(),
return_config: s
.boolean({
default: false,
description: "If the new configuration should be returned",
})
.optional(),
}), }),
}, },
async (params, ctx: AppToolHandlerCtx) => { async (params, ctx: AppToolHandlerCtx) => {
@@ -122,7 +137,9 @@ export class RecordToolSchema<
return ctx.json({ return ctx.json({
success: true, success: true,
module: module_name, module: module_name,
config: ctx.context.app.module[module_name as any].config, config: params.return_config
? ctx.context.app.module[module_name as any].config
: undefined,
}); });
}, },
); );
@@ -138,6 +155,12 @@ export class RecordToolSchema<
description: "key to update", description: "key to update",
}), }),
value: this.getNewSchema(s.object({})), value: this.getNewSchema(s.object({})),
return_config: s
.boolean({
default: false,
description: "If the new configuration should be returned",
})
.optional(),
}), }),
}, },
async (params, ctx: AppToolHandlerCtx) => { async (params, ctx: AppToolHandlerCtx) => {
@@ -156,7 +179,9 @@ export class RecordToolSchema<
return ctx.json({ return ctx.json({
success: true, success: true,
module: module_name, module: module_name,
config: ctx.context.app.module[module_name as any].config, config: params.return_config
? ctx.context.app.module[module_name as any].config
: undefined,
}); });
}, },
); );
@@ -171,6 +196,12 @@ export class RecordToolSchema<
key: s.string({ key: s.string({
description: "key to remove", description: "key to remove",
}), }),
return_config: s
.boolean({
default: false,
description: "If the new configuration should be returned",
})
.optional(),
}), }),
}, },
async (params, ctx: AppToolHandlerCtx) => { async (params, ctx: AppToolHandlerCtx) => {
@@ -189,20 +220,22 @@ export class RecordToolSchema<
return ctx.json({ return ctx.json({
success: true, success: true,
module: module_name, module: module_name,
config: ctx.context.app.module[module_name as any].config, config: params.return_config
? ctx.context.app.module[module_name as any].config
: undefined,
}); });
}, },
); );
} }
getTools(node: s.Node<RecordToolSchema<AP, O>>): Tool<any, any, any>[] { getTools(node: s.Node<RecordToolSchema<AP, O>>): Tool<any, any, any>[] {
const { tools = [] } = this.mcp.options; const { tools = [], get = true, add = true, update = true, remove = true } = this.mcp.options;
return [ return [
this.toolGet(node), get && this.toolGet(node),
this.toolAdd(node), add && this.toolAdd(node),
this.toolUpdate(node), update && this.toolUpdate(node),
this.toolRemove(node), remove && this.toolRemove(node),
...tools, ...tools,
].filter(Boolean) as Tool<any, any, any>[]; ].filter(Boolean) as Tool<any, any, any>[];
} }

View File

@@ -21,9 +21,9 @@ export interface McpToolOptions {
resources?: Resource<any, any, any, any>[]; resources?: Resource<any, any, any, any>[];
} }
export interface SchemaWithMcpOptions { export type SchemaWithMcpOptions<AdditionalOptions = {}> = {
mcp?: McpToolOptions; mcp?: McpToolOptions & AdditionalOptions;
} };
export type AppToolContext = { export type AppToolContext = {
app: App; app: App;
@@ -35,13 +35,13 @@ export interface McpSchema extends s.Schema {
getTools(node: s.Node<any>): Tool<any, any, any>[]; getTools(node: s.Node<any>): Tool<any, any, any>[];
} }
export class McpSchemaHelper { export class McpSchemaHelper<AdditionalOptions = {}> {
cleanSchema: s.ObjectSchema<any, any>; cleanSchema: s.ObjectSchema<any, any>;
constructor( constructor(
public schema: s.Schema, public schema: s.Schema,
public name: string, public name: string,
public options: McpToolOptions, public options: McpToolOptions & AdditionalOptions,
) { ) {
this.cleanSchema = this.getCleanSchema(); this.cleanSchema = this.getCleanSchema();
} }

View File

@@ -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.3", "jsonv-ts": "^0.7.4",
"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.3", "", { "optionalDependencies": { "hono": "*" }, "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-1P/ouF/a84Rc7NCXfSGPmkttyBFqemHE+5tZjb7hyaTs8MxmVUkuUO+d80/uu8sguzTnd3MmAuyuLAM0HQT4cA=="], "jsonv-ts": ["jsonv-ts@0.7.4", "", { "optionalDependencies": { "hono": "*" }, "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-SDx7Nt1kku6mAefrMffIdA9INqJnRLDJVooQOlstDmn0SvmTEHNAPifB+S14RR3f+Lep1T+WUeUdrHADrZsnYA=="],
"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=="],

View File

@@ -52,6 +52,7 @@
"properties": {} "properties": {}
} }
], ],
"$synthetic": true,
"$target": "json" "$target": "json"
} }
} }
@@ -92,6 +93,7 @@
"properties": {} "properties": {}
} }
], ],
"$synthetic": true,
"$target": "json" "$target": "json"
} }
} }
@@ -196,6 +198,7 @@
"properties": {} "properties": {}
} }
], ],
"$synthetic": true,
"$target": "json" "$target": "json"
}, },
"select": { "select": {
@@ -252,6 +255,7 @@
} }
} }
], ],
"$synthetic": true,
"$target": "json" "$target": "json"
} }
} }
@@ -264,7 +268,8 @@
"type": "object", "type": "object",
"required": [ "required": [
"entity", "entity",
"update" "update",
"where"
], ],
"properties": { "properties": {
"entity": { "entity": {
@@ -281,24 +286,9 @@
"properties": {} "properties": {}
}, },
"where": { "where": {
"examples": [ "type": "object",
{ "$target": "json",
"attribute": { "properties": {}
"$eq": 1
}
}
],
"default": {},
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {}
}
],
"$target": "json"
} }
} }
} }
@@ -310,7 +300,8 @@
"type": "object", "type": "object",
"required": [ "required": [
"entity", "entity",
"id" "id",
"json"
], ],
"properties": { "properties": {
"entity": { "entity": {
@@ -331,6 +322,12 @@
} }
], ],
"$target": "param" "$target": "param"
},
"json": {
"type": "object",
"$synthetic": true,
"$target": "json",
"properties": {}
} }
} }
} }
@@ -373,7 +370,8 @@
"inputSchema": { "inputSchema": {
"type": "object", "type": "object",
"required": [ "required": [
"entity" "entity",
"json"
], ],
"properties": { "properties": {
"entity": { "entity": {
@@ -385,24 +383,10 @@
"$target": "param" "$target": "param"
}, },
"json": { "json": {
"examples": [ "type": "object",
{ "$synthetic": true,
"attribute": { "$target": "json",
"$eq": 1 "properties": {}
}
}
],
"default": {},
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {}
}
],
"$target": "json"
} }
} }
} }
@@ -1907,6 +1891,11 @@
} }
} }
} }
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -1932,6 +1921,11 @@
"value": { "value": {
"type": "object", "type": "object",
"properties": {} "properties": {}
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -1953,6 +1947,11 @@
"key": { "key": {
"type": "string", "type": "string",
"description": "key to remove" "description": "key to remove"
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -2193,6 +2192,11 @@
] ]
} }
] ]
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -2218,6 +2222,11 @@
"value": { "value": {
"type": "object", "type": "object",
"properties": {} "properties": {}
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -2239,6 +2248,11 @@
"key": { "key": {
"type": "string", "type": "string",
"description": "key to remove" "description": "key to remove"
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -2310,31 +2324,11 @@
"entity", "entity",
"fields" "fields"
] ]
}
},
"required": [
"key",
"value"
]
},
"annotations": {
"destructiveHint": true,
"idempotentHint": true
}
},
{
"name": "config_data_indices_update",
"inputSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"key": {
"type": "string",
"description": "key to update"
}, },
"value": { "return_config": {
"type": "object", "type": "boolean",
"properties": {} "description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -2356,6 +2350,11 @@
"key": { "key": {
"type": "string", "type": "string",
"description": "key to remove" "description": "key to remove"
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -2592,6 +2591,11 @@
"type", "type",
"config" "config"
] ]
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -2631,6 +2635,11 @@
"type", "type",
"config" "config"
] ]
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -2653,6 +2662,11 @@
"key": { "key": {
"type": "string", "type": "string",
"description": "key to remove" "description": "key to remove"
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -2718,6 +2732,11 @@
"type": "boolean" "type": "boolean"
} }
} }
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -2743,6 +2762,11 @@
"value": { "value": {
"type": "object", "type": "object",
"properties": {} "properties": {}
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [
@@ -2764,6 +2788,11 @@
"key": { "key": {
"type": "string", "type": "string",
"description": "key to remove" "description": "key to remove"
},
"return_config": {
"type": "boolean",
"description": "If the new configuration should be returned",
"default": false
} }
}, },
"required": [ "required": [