@kavo/mcp 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/discovery.d.ts +36 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +37 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/tools.d.ts +35 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +189 -0
- package/dist/tools.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ClassRef, EntityId } from "@kavo/core";
|
|
2
|
+
import type { BoundKavoService, KavoMcpToolBinding } from "./tools.js";
|
|
3
|
+
/** The minimum a host framework needs to hand this package about one `@Kavo` entity. */
|
|
4
|
+
export interface KavoEntityRef {
|
|
5
|
+
readonly entity: ClassRef;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The host-agnostic half of "collect every entity's standard toolset into
|
|
9
|
+
* one process-wide MCP toolset." One thing stays deliberately outside this
|
|
10
|
+
* package, supplied by the caller instead — the same split
|
|
11
|
+
* `@kavo/graphql`'s `resolveKavoGraphQLSchema` uses for its own "how to
|
|
12
|
+
* resolve a service" half:
|
|
13
|
+
*
|
|
14
|
+
* - **How to resolve a bound service for one entity** — `@kavo/nest`'s
|
|
15
|
+
* `ModuleRef` + `getKavoServiceToken`, a plain `Map`, or whatever DI
|
|
16
|
+
* container that host uses.
|
|
17
|
+
*
|
|
18
|
+
* Every entity in `entities` gets the full standard toolset unconditionally
|
|
19
|
+
* (`crudTools`, no per-entity opt-in) — the list of entities to expose is
|
|
20
|
+
* controlled entirely by what the caller passes in (e.g. `@kavo/nest`'s
|
|
21
|
+
* `getKavoEntities()`, every `@Kavo`-decorated class), not by a second,
|
|
22
|
+
* MCP-specific registry.
|
|
23
|
+
*
|
|
24
|
+
* This function only ever touches `@kavo/core` shapes — never a host
|
|
25
|
+
* framework — so the same call works from a Nest MCP controller today and
|
|
26
|
+
* from a future `@kavo/express`/`@kavo/fastify`/`@kavo/nextjs` binding
|
|
27
|
+
* without either package importing the other (ADR-0016's `protocols/*`
|
|
28
|
+
* shape).
|
|
29
|
+
*
|
|
30
|
+
* Unlike `mergeKavoGraphQLSchemas` (which must fail fast on an empty
|
|
31
|
+
* `Query` type — GraphQL has no such thing as a schema with zero fields),
|
|
32
|
+
* an empty tool list is a perfectly valid MCP `ListToolsResult`, so an
|
|
33
|
+
* empty `entities` list is not treated as an error here.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveKavoMcpTools(entities: readonly KavoEntityRef[], resolveService: (entity: ClassRef) => BoundKavoService<object, EntityId, unknown, unknown, unknown>): readonly KavoMcpToolBinding[];
|
|
36
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGvE,wFAAwF;AACxF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,SAAS,aAAa,EAAE,EAClC,cAAc,EAAE,CAAC,MAAM,EAAE,QAAQ,KAAK,gBAAgB,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,GAClG,SAAS,kBAAkB,EAAE,CAQ/B"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { crudTools } from "./tools.js";
|
|
2
|
+
/**
|
|
3
|
+
* The host-agnostic half of "collect every entity's standard toolset into
|
|
4
|
+
* one process-wide MCP toolset." One thing stays deliberately outside this
|
|
5
|
+
* package, supplied by the caller instead — the same split
|
|
6
|
+
* `@kavo/graphql`'s `resolveKavoGraphQLSchema` uses for its own "how to
|
|
7
|
+
* resolve a service" half:
|
|
8
|
+
*
|
|
9
|
+
* - **How to resolve a bound service for one entity** — `@kavo/nest`'s
|
|
10
|
+
* `ModuleRef` + `getKavoServiceToken`, a plain `Map`, or whatever DI
|
|
11
|
+
* container that host uses.
|
|
12
|
+
*
|
|
13
|
+
* Every entity in `entities` gets the full standard toolset unconditionally
|
|
14
|
+
* (`crudTools`, no per-entity opt-in) — the list of entities to expose is
|
|
15
|
+
* controlled entirely by what the caller passes in (e.g. `@kavo/nest`'s
|
|
16
|
+
* `getKavoEntities()`, every `@Kavo`-decorated class), not by a second,
|
|
17
|
+
* MCP-specific registry.
|
|
18
|
+
*
|
|
19
|
+
* This function only ever touches `@kavo/core` shapes — never a host
|
|
20
|
+
* framework — so the same call works from a Nest MCP controller today and
|
|
21
|
+
* from a future `@kavo/express`/`@kavo/fastify`/`@kavo/nextjs` binding
|
|
22
|
+
* without either package importing the other (ADR-0016's `protocols/*`
|
|
23
|
+
* shape).
|
|
24
|
+
*
|
|
25
|
+
* Unlike `mergeKavoGraphQLSchemas` (which must fail fast on an empty
|
|
26
|
+
* `Query` type — GraphQL has no such thing as a schema with zero fields),
|
|
27
|
+
* an empty tool list is a perfectly valid MCP `ListToolsResult`, so an
|
|
28
|
+
* empty `entities` list is not treated as an error here.
|
|
29
|
+
*/
|
|
30
|
+
export function resolveKavoMcpTools(entities, resolveService) {
|
|
31
|
+
const bindings = [];
|
|
32
|
+
for (const { entity } of entities) {
|
|
33
|
+
bindings.push(...crudTools({ name: entity.name, service: resolveService(entity) }));
|
|
34
|
+
}
|
|
35
|
+
return bindings;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAOvC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAkC,EAClC,cAAmG;IAEnG,MAAM,QAAQ,GAAyB,EAAE,CAAC;IAE1C,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QAClC,QAAQ,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACjH,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAA4E,MAAM,YAAY,CAAC;AACjH,OAAO,EAAE,mBAAmB,EAAsB,MAAM,gBAAgB,CAAC"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CallToolResult, Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import type { DefaultKavoService, EntityId } from "@kavo/core";
|
|
3
|
+
/**
|
|
4
|
+
* What a tool handler in this binding actually calls — the same
|
|
5
|
+
* transport-agnostic programmatic surface `createCrud` returns that
|
|
6
|
+
* `@kavo/graphql`'s `BoundKavoService` binds to. Kept as its own structural
|
|
7
|
+
* type for the same reason: a caller only has to satisfy the operations a
|
|
8
|
+
* toolset actually wires up.
|
|
9
|
+
*/
|
|
10
|
+
export type BoundKavoService<Entity extends object, Id extends EntityId, CreateDto, UpdateDto, PatchDto> = Pick<DefaultKavoService<Entity, Id, CreateDto, UpdateDto, PatchDto, unknown, unknown, unknown>, "findOne" | "findMany" | "createOne" | "updateOne" | "patchOne" | "deleteOne" | "restoreOne" | "purgeOne">;
|
|
11
|
+
/** One entity's MCP tool binding: a `Tool` definition plus the handler that runs it — `crudTools`'s unit of work. */
|
|
12
|
+
export interface KavoMcpToolBinding {
|
|
13
|
+
readonly tool: Tool;
|
|
14
|
+
readonly handler: (args: Record<string, unknown>) => Promise<CallToolResult>;
|
|
15
|
+
}
|
|
16
|
+
/** One entity's MCP binding options. */
|
|
17
|
+
export interface KavoMcpToolsOptions<Entity extends object, Id extends EntityId, CreateDto, UpdateDto, PatchDto> {
|
|
18
|
+
/** Singular, capitalized entity name — becomes the `<lowerName>.<operation>` tool name prefix. */
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly service: BoundKavoService<Entity, Id, CreateDto, UpdateDto, PatchDto>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Every standard operation, for one entity — unconditional. There is no
|
|
24
|
+
* per-entity opt-in or hand-authored input schema (there used to be; see
|
|
25
|
+
* git history / the issue this simplified) — every `@Kavo` entity handed
|
|
26
|
+
* to `resolveKavoMcpTools` gets the full 8-tool set, the same way `@Kavo`
|
|
27
|
+
* itself enables every standard operation by default. An operation that
|
|
28
|
+
* doesn't actually apply — `restoreOne` on a non-soft-deletable entity, or
|
|
29
|
+
* any operation an entity's own `@Kavo` config disabled — still produces a
|
|
30
|
+
* tool, and calling it surfaces `OperationDisabledException` as a normal
|
|
31
|
+
* `isError` result (`guarded`), exactly like calling the disabled REST
|
|
32
|
+
* route would.
|
|
33
|
+
*/
|
|
34
|
+
export declare function crudTools<Entity extends object, Id extends EntityId, CreateDto, UpdateDto, PatchDto>(options: KavoMcpToolsOptions<Entity, Id, CreateDto, UpdateDto, PatchDto>): readonly KavoMcpToolBinding[];
|
|
35
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAiB/D;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,CAAC,MAAM,SAAS,MAAM,EAAE,EAAE,SAAS,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,CAC7G,kBAAkB,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EACzF,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,YAAY,GAAG,UAAU,CAC1G,CAAC;AAyCF,qHAAqH;AACrH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;CAC9E;AAED,wCAAwC;AACxC,MAAM,WAAW,mBAAmB,CAAC,MAAM,SAAS,MAAM,EAAE,EAAE,SAAS,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ;IAC7G,kGAAkG;IAClG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;CAChF;AAyDD;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,MAAM,SAAS,MAAM,EAAE,EAAE,SAAS,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAClG,OAAO,EAAE,mBAAmB,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,GACvE,SAAS,kBAAkB,EAAE,CAyF/B"}
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { ConfigurationException, KavoException } from "@kavo/core";
|
|
2
|
+
/**
|
|
3
|
+
* `sort: ["-createdAt", "name"]` → `[{ field: "createdAt", direction: "desc" }, { field: "name", direction: "asc" }]`
|
|
4
|
+
* — same convention (and same reasoning) as `@kavo/graphql`'s `parseSortArg`: this binding calls the programmatic
|
|
5
|
+
* `QueryContext` surface directly, never REST's wire-string parser.
|
|
6
|
+
*/
|
|
7
|
+
function parseSortArg(tokens) {
|
|
8
|
+
if (tokens === undefined)
|
|
9
|
+
return [];
|
|
10
|
+
return tokens.map((token) => token.startsWith("-")
|
|
11
|
+
? { field: token.slice(1), direction: "desc" }
|
|
12
|
+
: { field: token, direction: "asc" });
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Refuse to bind an entity this protocol cannot page (ADR-0021 §7, extended
|
|
16
|
+
* to `since` by ADR-0022).
|
|
17
|
+
*
|
|
18
|
+
* `<name>.findMany` accepts `limit`/`offset` only, and `QueryNormalizer`
|
|
19
|
+
* ignores `offset` under both keyset strategies — so a model calling
|
|
20
|
+
* `todo.findMany({ limit: 20, offset: 40 })` against a cursor- or
|
|
21
|
+
* since-configured entity gets rows 1–20 (or everything from the beginning)
|
|
22
|
+
* back with no error and no way to tell, and the `nextCursor`/`nextSince` it
|
|
23
|
+
* would need is not in the tool's result shape. Name-gated on
|
|
24
|
+
* `"cursor"`/`"since"` rather than structural, the same limitation
|
|
25
|
+
* ADR-0021 §7 already records. Failing at bootstrap beats answering wrongly.
|
|
26
|
+
* `@kavo/graphql` carries the identical guard; the two packages may not
|
|
27
|
+
* import each other, so it is duplicated rather than shared.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* The bound entity's configured `pagination.strategy`, read structurally —
|
|
31
|
+
* for the same reason `@kavo/graphql` reads it that way: putting `engine` in
|
|
32
|
+
* `BoundKavoService`'s `Pick` would drag the entity-typed
|
|
33
|
+
* `ResolvedEntityConfig` into an invariant position and break every erased
|
|
34
|
+
* `BoundKavoService<object, …>` call site.
|
|
35
|
+
*/
|
|
36
|
+
function paginationStrategyOf(service) {
|
|
37
|
+
const engine = service.engine;
|
|
38
|
+
return engine?.config?.settings?.pagination?.strategy;
|
|
39
|
+
}
|
|
40
|
+
function requireOffsetPageable(entityName, strategy) {
|
|
41
|
+
if (strategy !== "cursor" && strategy !== "since")
|
|
42
|
+
return;
|
|
43
|
+
throw new ConfigurationException(entityName, "pagination.strategy", `'${strategy}' is not supported by the MCP binding: '<entity>.findMany' exposes 'limit'/'offset' only, ` +
|
|
44
|
+
`and a keyset page ignores 'offset' — a paged call would silently return the first page (or everything ` +
|
|
45
|
+
`from the beginning) every time. Either page this entity over REST, or give it an entity-scope ` +
|
|
46
|
+
`'pagination.strategy' of 'offset'/'page'`);
|
|
47
|
+
}
|
|
48
|
+
function lowerFirst(value) {
|
|
49
|
+
return value.charAt(0).toLowerCase() + value.slice(1);
|
|
50
|
+
}
|
|
51
|
+
function textResult(value) {
|
|
52
|
+
return { content: [{ type: "text", text: JSON.stringify(value) }] };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Runs a handler and turns a `KavoException` into a normal (`isError:
|
|
56
|
+
* true`) tool result instead of letting it propagate — the MCP protocol's
|
|
57
|
+
* own convention for an expected domain failure (bad id, disabled
|
|
58
|
+
* operation, conflict): the *call* succeeded, the *operation* didn't. An
|
|
59
|
+
* error the engine did not itself raise (a bug, an unmapped adapter
|
|
60
|
+
* failure) still propagates, so it surfaces as a protocol-level error
|
|
61
|
+
* rather than being silently reframed as routine tool output.
|
|
62
|
+
*
|
|
63
|
+
* This is also how a mutation tool that doesn't apply to a given entity —
|
|
64
|
+
* `restoreOne`/`purgeOne` on one that never declared soft delete —
|
|
65
|
+
* degrades: every entity gets the full standard toolset unconditionally
|
|
66
|
+
* (§ below), and the engine's own `OperationDisabledException` for a
|
|
67
|
+
* disabled operation lands here as a normal `isError` result, exactly the
|
|
68
|
+
* way calling the equivalent disabled REST route would.
|
|
69
|
+
*/
|
|
70
|
+
async function guarded(fn) {
|
|
71
|
+
try {
|
|
72
|
+
return textResult(await fn());
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (error instanceof KavoException) {
|
|
76
|
+
return { isError: true, content: [{ type: "text", text: `${error.code}: ${error.detail}` }] };
|
|
77
|
+
}
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const idSchema = { type: ["string", "number"] };
|
|
82
|
+
function objectSchema(properties, required) {
|
|
83
|
+
return { type: "object", properties, required: [...required] };
|
|
84
|
+
}
|
|
85
|
+
const idOnlySchema = objectSchema({ id: idSchema }, ["id"]);
|
|
86
|
+
/**
|
|
87
|
+
* `{ id }` required, with any other property left unconstrained — JSON
|
|
88
|
+
* Schema permits additional properties by default (no `additionalProperties:
|
|
89
|
+
* false` here), so this doubles as `updateOne`/`patchOne`'s input schema: a
|
|
90
|
+
* caller fills in `id` plus whatever DTO fields it wants, with no
|
|
91
|
+
* per-entity schema to author or keep in sync.
|
|
92
|
+
*/
|
|
93
|
+
const idAndFreeformSchema = objectSchema({ id: idSchema }, ["id"]);
|
|
94
|
+
/** No constraints at all — every field an entity's `create` DTO accepts, forwarded straight through. */
|
|
95
|
+
const freeformObjectSchema = { type: "object" };
|
|
96
|
+
/**
|
|
97
|
+
* Every standard operation, for one entity — unconditional. There is no
|
|
98
|
+
* per-entity opt-in or hand-authored input schema (there used to be; see
|
|
99
|
+
* git history / the issue this simplified) — every `@Kavo` entity handed
|
|
100
|
+
* to `resolveKavoMcpTools` gets the full 8-tool set, the same way `@Kavo`
|
|
101
|
+
* itself enables every standard operation by default. An operation that
|
|
102
|
+
* doesn't actually apply — `restoreOne` on a non-soft-deletable entity, or
|
|
103
|
+
* any operation an entity's own `@Kavo` config disabled — still produces a
|
|
104
|
+
* tool, and calling it surfaces `OperationDisabledException` as a normal
|
|
105
|
+
* `isError` result (`guarded`), exactly like calling the disabled REST
|
|
106
|
+
* route would.
|
|
107
|
+
*/
|
|
108
|
+
export function crudTools(options) {
|
|
109
|
+
const { name, service } = options;
|
|
110
|
+
requireOffsetPageable(name, paginationStrategyOf(service));
|
|
111
|
+
const prefix = lowerFirst(name);
|
|
112
|
+
return [
|
|
113
|
+
{
|
|
114
|
+
tool: { name: `${prefix}.findOne`, description: `Find one ${name} by id.`, inputSchema: idOnlySchema },
|
|
115
|
+
handler: (args) => guarded(() => service.findOne(args["id"])),
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
tool: {
|
|
119
|
+
name: `${prefix}.findMany`,
|
|
120
|
+
description: `List ${name} records, with optional pagination, sort, and filter.`,
|
|
121
|
+
inputSchema: objectSchema({
|
|
122
|
+
limit: { type: "integer" },
|
|
123
|
+
offset: { type: "integer" },
|
|
124
|
+
sort: { type: "array", items: { type: "string" } },
|
|
125
|
+
filter: { type: "object" },
|
|
126
|
+
}, []),
|
|
127
|
+
},
|
|
128
|
+
handler: (args) => guarded(() => service.findMany({
|
|
129
|
+
limit: args["limit"],
|
|
130
|
+
offset: args["offset"],
|
|
131
|
+
sort: parseSortArg(args["sort"]),
|
|
132
|
+
filter: args["filter"] ?? null,
|
|
133
|
+
})),
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
tool: { name: `${prefix}.createOne`, description: `Create a new ${name}.`, inputSchema: freeformObjectSchema },
|
|
137
|
+
handler: (args) => guarded(() => service.createOne(args)),
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
tool: {
|
|
141
|
+
name: `${prefix}.updateOne`,
|
|
142
|
+
description: `Replace an existing ${name} by id.`,
|
|
143
|
+
inputSchema: idAndFreeformSchema,
|
|
144
|
+
},
|
|
145
|
+
handler: (args) => {
|
|
146
|
+
const { id, ...input } = args;
|
|
147
|
+
return guarded(() => service.updateOne(id, input));
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
tool: {
|
|
152
|
+
name: `${prefix}.patchOne`,
|
|
153
|
+
description: `Partially update an existing ${name} by id.`,
|
|
154
|
+
inputSchema: idAndFreeformSchema,
|
|
155
|
+
},
|
|
156
|
+
handler: (args) => {
|
|
157
|
+
const { id, ...input } = args;
|
|
158
|
+
return guarded(() => service.patchOne(id, input));
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
tool: { name: `${prefix}.deleteOne`, description: `Delete a ${name} by id.`, inputSchema: idOnlySchema },
|
|
163
|
+
handler: (args) => guarded(async () => {
|
|
164
|
+
await service.deleteOne(args["id"]);
|
|
165
|
+
return { deleted: true };
|
|
166
|
+
}),
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
tool: {
|
|
170
|
+
name: `${prefix}.restoreOne`,
|
|
171
|
+
description: `Restore a soft-deleted ${name} by id.`,
|
|
172
|
+
inputSchema: idOnlySchema,
|
|
173
|
+
},
|
|
174
|
+
handler: (args) => guarded(() => service.restoreOne(args["id"])),
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
tool: {
|
|
178
|
+
name: `${prefix}.purgeOne`,
|
|
179
|
+
description: `Permanently delete a soft-deleted ${name} by id.`,
|
|
180
|
+
inputSchema: idOnlySchema,
|
|
181
|
+
},
|
|
182
|
+
handler: (args) => guarded(async () => {
|
|
183
|
+
await service.purgeOne(args["id"]);
|
|
184
|
+
return { purged: true };
|
|
185
|
+
}),
|
|
186
|
+
},
|
|
187
|
+
];
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kavo/mcp",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Kavo MCP binding — exposes a createCrud service's standard operations as MCP tools, delegating every call to the same engine REST uses.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/kavo-labs/kavo.git",
|
|
9
|
+
"directory": "packages/protocols/mcp"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/kavo-labs/kavo/tree/main/packages/protocols/mcp#readme",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"sideEffects": false,
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc -b"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@kavo/core": "workspace:^"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|