mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-15 20:17:22 +00:00
added data mcp tests
This commit is contained in:
@@ -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";
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|||||||
@@ -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>[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
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.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=="],
|
||||||
|
|
||||||
|
|||||||
155
docs/mcp.json
155
docs/mcp.json
@@ -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": [
|
||||||
|
|||||||
Reference in New Issue
Block a user