@kubun/mcp 0.10.0 → 0.11.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/lib/client.d.ts +1 -1
- package/lib/client.js +79 -1
- package/lib/config.d.ts +1 -1
- package/lib/config.js +40 -1
- package/lib/container.js +14 -1
- package/lib/index.js +2 -1
- package/lib/prompts/data-model-designer.js +2 -2
- package/lib/prompts/index.js +19 -1
- package/lib/run.js +18 -1
- package/lib/tools/cluster.js +79 -1
- package/lib/tools/connection.d.ts +1 -1
- package/lib/tools/connection.js +103 -1
- package/lib/tools/graph.js +284 -1
- package/lib/tools/index.js +3 -1
- package/package.json +15 -15
package/lib/client.d.ts
CHANGED
package/lib/client.js
CHANGED
|
@@ -1 +1,79 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { randomIdentity } from '@kokuin/token';
|
|
2
|
+
import { KubunDB } from '@kubun/db';
|
|
3
|
+
import { NodeSQLiteAdapter } from '@kubun/db-node-sqlite';
|
|
4
|
+
import { PostgresAdapter } from '@kubun/db-postgres';
|
|
5
|
+
import { KubunEngine } from '@kubun/engine';
|
|
6
|
+
import { HTTPClient } from '@kubun/http-client';
|
|
7
|
+
export function parseDatabase(database) {
|
|
8
|
+
if (database.startsWith('http://') || database.startsWith('https://')) {
|
|
9
|
+
return {
|
|
10
|
+
type: 'http',
|
|
11
|
+
url: database
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (database.startsWith('postgres://')) {
|
|
15
|
+
return {
|
|
16
|
+
type: 'postgres',
|
|
17
|
+
url: database
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (database === ':memory:') {
|
|
21
|
+
return {
|
|
22
|
+
type: 'memory'
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
type: 'sqlite',
|
|
27
|
+
path: database
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function getAddress(config) {
|
|
31
|
+
switch(config.type){
|
|
32
|
+
case 'http':
|
|
33
|
+
return config.url;
|
|
34
|
+
case 'postgres':
|
|
35
|
+
return config.url;
|
|
36
|
+
case 'sqlite':
|
|
37
|
+
return config.path;
|
|
38
|
+
case 'memory':
|
|
39
|
+
return ':memory:';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export async function createConnection(params) {
|
|
43
|
+
const identity = params.identity ?? randomIdentity();
|
|
44
|
+
const address = getAddress(params);
|
|
45
|
+
if (params.type === 'http') {
|
|
46
|
+
return {
|
|
47
|
+
provider: new HTTPClient({
|
|
48
|
+
identity,
|
|
49
|
+
serverID: params.serverID,
|
|
50
|
+
url: params.url
|
|
51
|
+
}),
|
|
52
|
+
dispose: async ()=>{},
|
|
53
|
+
type: 'http',
|
|
54
|
+
address
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const adapter = params.type === 'postgres' ? new PostgresAdapter({
|
|
58
|
+
url: params.url
|
|
59
|
+
}) : new NodeSQLiteAdapter({
|
|
60
|
+
database: params.type === 'sqlite' ? params.path : ':memory:'
|
|
61
|
+
});
|
|
62
|
+
const db = new KubunDB({
|
|
63
|
+
adapter
|
|
64
|
+
});
|
|
65
|
+
const engine = new KubunEngine({
|
|
66
|
+
db,
|
|
67
|
+
identity,
|
|
68
|
+
plugins: []
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
provider: engine,
|
|
72
|
+
dispose: async ()=>{
|
|
73
|
+
await engine.dispose();
|
|
74
|
+
await db.close();
|
|
75
|
+
},
|
|
76
|
+
type: params.type,
|
|
77
|
+
address
|
|
78
|
+
};
|
|
79
|
+
}
|
package/lib/config.d.ts
CHANGED
package/lib/config.js
CHANGED
|
@@ -1 +1,40 @@
|
|
|
1
|
-
import{createConnection
|
|
1
|
+
import { createConnection, parseDatabase } from './client.js';
|
|
2
|
+
import { prompts } from './prompts/index.js';
|
|
3
|
+
import { createClusterTools } from './tools/cluster.js';
|
|
4
|
+
import { createConnectionTools } from './tools/connection.js';
|
|
5
|
+
import { createGraphTools } from './tools/graph.js';
|
|
6
|
+
function parseConfig(config) {
|
|
7
|
+
if (config.connect != null) {
|
|
8
|
+
return {
|
|
9
|
+
type: 'http',
|
|
10
|
+
url: config.connect,
|
|
11
|
+
identity: config.identity
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (config.database != null) {
|
|
15
|
+
return {
|
|
16
|
+
...parseDatabase(config.database),
|
|
17
|
+
identity: config.identity
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
export async function createConfig(config = {}) {
|
|
23
|
+
const params = parseConfig(config);
|
|
24
|
+
const container = {
|
|
25
|
+
current: params != null ? await createConnection(params) : null
|
|
26
|
+
};
|
|
27
|
+
const connectionTools = createConnectionTools(container, config.identity);
|
|
28
|
+
const clusterTools = createClusterTools(container);
|
|
29
|
+
const graphTools = createGraphTools(container);
|
|
30
|
+
return {
|
|
31
|
+
name: 'kubun',
|
|
32
|
+
version: '0.1.0',
|
|
33
|
+
prompts,
|
|
34
|
+
tools: {
|
|
35
|
+
...connectionTools,
|
|
36
|
+
...clusterTools,
|
|
37
|
+
...graphTools
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
package/lib/container.js
CHANGED
|
@@ -1 +1,14 @@
|
|
|
1
|
-
export function getProvider(
|
|
1
|
+
export function getProvider(container) {
|
|
2
|
+
return container.current?.provider ?? null;
|
|
3
|
+
}
|
|
4
|
+
export function notConnectedError() {
|
|
5
|
+
return {
|
|
6
|
+
isError: true,
|
|
7
|
+
content: [
|
|
8
|
+
{
|
|
9
|
+
type: 'text',
|
|
10
|
+
text: 'No database connected. Use the connect tool first.'
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
};
|
|
14
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export{createConnection,parseDatabase}from
|
|
1
|
+
export { createConnection, parseDatabase } from './client.js';
|
|
2
|
+
export { createConfig } from './config.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const KUBUN_PROMPT_INSTRUCTIONS
|
|
1
|
+
export const KUBUN_PROMPT_INSTRUCTIONS = `# Kubun Protocol Data Model Generator
|
|
2
2
|
|
|
3
3
|
You are an expert at creating data models following the Kubun protocol specification. Your task is to generate valid JSON schemas for data models based on user requirements.
|
|
4
4
|
|
|
@@ -612,4 +612,4 @@ When generating a model cluster, organize models in this order:
|
|
|
612
612
|
|
|
613
613
|
## Response Format
|
|
614
614
|
|
|
615
|
-
Always generate models as a JSON array, even when a single model is needed. Validate that your output follows the specification exactly.`;
|
|
615
|
+
Always generate models as a JSON array, even when a single model is needed. Validate that your output follows the specification exactly.`;
|
package/lib/prompts/index.js
CHANGED
|
@@ -1 +1,19 @@
|
|
|
1
|
-
import{KUBUN_PROMPT_INSTRUCTIONS
|
|
1
|
+
import { KUBUN_PROMPT_INSTRUCTIONS } from './data-model-designer.js';
|
|
2
|
+
export const prompts = {
|
|
3
|
+
'data-model-designer': {
|
|
4
|
+
description: 'Instructions to help design a data model following the Kubun protocol specification',
|
|
5
|
+
handler: ()=>{
|
|
6
|
+
return {
|
|
7
|
+
messages: [
|
|
8
|
+
{
|
|
9
|
+
role: 'user',
|
|
10
|
+
content: {
|
|
11
|
+
type: 'text',
|
|
12
|
+
text: KUBUN_PROMPT_INSTRUCTIONS
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
package/lib/run.js
CHANGED
|
@@ -1,2 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import { serveProcess } from '@mokei/context-server';
|
|
4
|
+
import { createConfig } from './config.js';
|
|
5
|
+
const args = parseArgs({
|
|
6
|
+
options: {
|
|
7
|
+
connect: {
|
|
8
|
+
type: 'string'
|
|
9
|
+
},
|
|
10
|
+
db: {
|
|
11
|
+
type: 'string'
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
const config = await createConfig({
|
|
16
|
+
connect: args.values.connect,
|
|
17
|
+
database: args.values.db
|
|
18
|
+
});
|
|
19
|
+
serveProcess(config);
|
package/lib/tools/cluster.js
CHANGED
|
@@ -1 +1,79 @@
|
|
|
1
|
-
import{ClusterBuilder
|
|
1
|
+
import { ClusterBuilder, clusterModel } from '@kubun/protocol';
|
|
2
|
+
import { createTool } from '@mokei/context-server';
|
|
3
|
+
import { getProvider, notConnectedError } from '../container.js';
|
|
4
|
+
export function createClusterTools(container) {
|
|
5
|
+
const create_cluster = createTool('Create a new cluster from model definitions', {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {
|
|
8
|
+
models: {
|
|
9
|
+
type: 'array',
|
|
10
|
+
items: {
|
|
11
|
+
type: 'object'
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
required: [
|
|
16
|
+
'models'
|
|
17
|
+
],
|
|
18
|
+
additionalProperties: false
|
|
19
|
+
}, async (ctx)=>{
|
|
20
|
+
const builder = new ClusterBuilder();
|
|
21
|
+
builder.addAll(ctx.arguments.models);
|
|
22
|
+
const cluster = builder.build();
|
|
23
|
+
return {
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
type: 'text',
|
|
27
|
+
text: 'Cluster created'
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
structuredContent: {
|
|
31
|
+
cluster
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
const deploy_clusters = createTool('Deploy clusters to the Kubun backend', {
|
|
36
|
+
type: 'object',
|
|
37
|
+
properties: {
|
|
38
|
+
clusters: {
|
|
39
|
+
type: 'array',
|
|
40
|
+
items: clusterModel
|
|
41
|
+
},
|
|
42
|
+
id: {
|
|
43
|
+
type: 'string'
|
|
44
|
+
},
|
|
45
|
+
name: {
|
|
46
|
+
type: 'string'
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
required: [
|
|
50
|
+
'clusters'
|
|
51
|
+
],
|
|
52
|
+
additionalProperties: false
|
|
53
|
+
}, async (ctx)=>{
|
|
54
|
+
const provider = getProvider(container);
|
|
55
|
+
if (provider == null) return notConnectedError();
|
|
56
|
+
const result = await provider.deployGraph({
|
|
57
|
+
clusters: ctx.arguments.clusters,
|
|
58
|
+
id: ctx.arguments.id,
|
|
59
|
+
name: ctx.arguments.name
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
content: [
|
|
63
|
+
{
|
|
64
|
+
type: 'text',
|
|
65
|
+
text: `Clusters deployed to graph "${result.id}"`
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
structuredContent: {
|
|
69
|
+
id: result.id,
|
|
70
|
+
record: result.record,
|
|
71
|
+
aliases: result.aliases
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
create_cluster,
|
|
77
|
+
deploy_clusters
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SigningIdentity } from '@
|
|
1
|
+
import type { SigningIdentity } from '@kokuin/token';
|
|
2
2
|
import { createTool } from '@mokei/context-server';
|
|
3
3
|
import type { ClientContainer } from '../container.js';
|
|
4
4
|
type ToolDefinition = ReturnType<typeof createTool>;
|
package/lib/tools/connection.js
CHANGED
|
@@ -1 +1,103 @@
|
|
|
1
|
-
import{createTool
|
|
1
|
+
import { createTool } from '@mokei/context-server';
|
|
2
|
+
import { createConnection, parseDatabase } from '../client.js';
|
|
3
|
+
export function createConnectionTools(container, identity) {
|
|
4
|
+
const connect = createTool('Connect to a Kubun database. Accepts a SQLite file path, postgres:// URL, http(s):// URL, or :memory: for in-memory.', {
|
|
5
|
+
type: 'object',
|
|
6
|
+
properties: {
|
|
7
|
+
database: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
description: 'SQLite file path, postgres:// URL, http(s):// URL, or :memory:'
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
required: [
|
|
13
|
+
'database'
|
|
14
|
+
],
|
|
15
|
+
additionalProperties: false
|
|
16
|
+
}, async (ctx)=>{
|
|
17
|
+
if (container.current != null) {
|
|
18
|
+
await container.current.dispose();
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const config = parseDatabase(ctx.arguments.database);
|
|
22
|
+
const connection = await createConnection({
|
|
23
|
+
...config,
|
|
24
|
+
identity
|
|
25
|
+
});
|
|
26
|
+
container.current = connection;
|
|
27
|
+
return {
|
|
28
|
+
content: [
|
|
29
|
+
{
|
|
30
|
+
type: 'text',
|
|
31
|
+
text: `Connected to ${connection.type} database: ${connection.address}`
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
structuredContent: {
|
|
35
|
+
type: connection.type,
|
|
36
|
+
address: connection.address
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
} catch (error) {
|
|
40
|
+
container.current = null;
|
|
41
|
+
return {
|
|
42
|
+
isError: true,
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: 'text',
|
|
46
|
+
text: `Failed to connect: ${error instanceof Error ? error.message : String(error)}`
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const disconnect = createTool('Disconnect from the current Kubun database', {
|
|
53
|
+
type: 'object'
|
|
54
|
+
}, async ()=>{
|
|
55
|
+
if (container.current != null) {
|
|
56
|
+
await container.current.dispose();
|
|
57
|
+
container.current = null;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{
|
|
62
|
+
type: 'text',
|
|
63
|
+
text: 'Disconnected'
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
const connection_info = createTool('Get information about the current database connection', {
|
|
69
|
+
type: 'object'
|
|
70
|
+
}, async ()=>{
|
|
71
|
+
if (container.current == null) {
|
|
72
|
+
return {
|
|
73
|
+
content: [
|
|
74
|
+
{
|
|
75
|
+
type: 'text',
|
|
76
|
+
text: 'Not connected'
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
structuredContent: {
|
|
80
|
+
connected: false
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
content: [
|
|
86
|
+
{
|
|
87
|
+
type: 'text',
|
|
88
|
+
text: `Connected to ${container.current.type} database: ${container.current.address}`
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
structuredContent: {
|
|
92
|
+
connected: true,
|
|
93
|
+
type: container.current.type,
|
|
94
|
+
address: container.current.address
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
connect,
|
|
100
|
+
disconnect,
|
|
101
|
+
connection_info
|
|
102
|
+
};
|
|
103
|
+
}
|
package/lib/tools/graph.js
CHANGED
|
@@ -1 +1,284 @@
|
|
|
1
|
-
import{createSchema
|
|
1
|
+
import { createSchema } from '@kubun/graphql';
|
|
2
|
+
import { createTool } from '@mokei/context-server';
|
|
3
|
+
import { printSchema } from 'graphql';
|
|
4
|
+
import { getProvider, notConnectedError } from '../container.js';
|
|
5
|
+
function getModelsInfo(result) {
|
|
6
|
+
const aliases = result.aliases ?? {};
|
|
7
|
+
return Object.entries(result.record).reduce((acc, [id, model])=>{
|
|
8
|
+
const alias = aliases[id] ?? model.name;
|
|
9
|
+
acc[alias] = {
|
|
10
|
+
id,
|
|
11
|
+
behavior: model.behavior,
|
|
12
|
+
interfaces: model.interfaces,
|
|
13
|
+
fields: Object.keys(model.schema.properties)
|
|
14
|
+
};
|
|
15
|
+
return acc;
|
|
16
|
+
}, {});
|
|
17
|
+
}
|
|
18
|
+
export function createGraphTools(container) {
|
|
19
|
+
const graph_list = createTool('List all available graphs', {
|
|
20
|
+
type: 'object'
|
|
21
|
+
}, async ()=>{
|
|
22
|
+
const provider = getProvider(container);
|
|
23
|
+
if (provider == null) return notConnectedError();
|
|
24
|
+
const result = await provider.listGraphs();
|
|
25
|
+
const graphs = result.graphs.map((graph)=>`${graph.name} (${graph.id})`).join(', ');
|
|
26
|
+
return {
|
|
27
|
+
content: [
|
|
28
|
+
{
|
|
29
|
+
type: 'text',
|
|
30
|
+
text: graphs === '' ? 'No graphs available' : `Available graphs: ${graphs}`
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
structuredContent: {
|
|
34
|
+
graphs: result.graphs
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
const graph_info = createTool('Get information about a specific graph', {
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: {
|
|
41
|
+
id: {
|
|
42
|
+
type: 'string'
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
required: [
|
|
46
|
+
'id'
|
|
47
|
+
],
|
|
48
|
+
additionalProperties: false
|
|
49
|
+
}, async (ctx)=>{
|
|
50
|
+
const provider = getProvider(container);
|
|
51
|
+
if (provider == null) return notConnectedError();
|
|
52
|
+
try {
|
|
53
|
+
const result = await provider.loadGraph({
|
|
54
|
+
id: ctx.arguments.id
|
|
55
|
+
});
|
|
56
|
+
const info = getModelsInfo(result);
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: 'text',
|
|
61
|
+
text: JSON.stringify(info)
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
structuredContent: info
|
|
65
|
+
};
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return {
|
|
68
|
+
isError: true,
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: 'text',
|
|
72
|
+
text: `Failed to get GraphQL schema: ${error instanceof Error ? error.message : String(error)}`
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
const graph_schema = createTool('Get the GraphQL schema for the given graph ID. Supports selective generation to reduce schema size for LLM context.', {
|
|
79
|
+
type: 'object',
|
|
80
|
+
properties: {
|
|
81
|
+
id: {
|
|
82
|
+
type: 'string',
|
|
83
|
+
description: 'The graph ID'
|
|
84
|
+
},
|
|
85
|
+
onlyModels: {
|
|
86
|
+
type: 'array',
|
|
87
|
+
items: {
|
|
88
|
+
type: 'string'
|
|
89
|
+
},
|
|
90
|
+
description: 'Optional array of model IDs or aliases to include in schema. If not provided, all models are included.'
|
|
91
|
+
},
|
|
92
|
+
includeInterfaceDependencies: {
|
|
93
|
+
type: 'boolean',
|
|
94
|
+
description: 'Whether to include interface dependencies (default: true)'
|
|
95
|
+
},
|
|
96
|
+
includeRelationDependencies: {
|
|
97
|
+
type: 'boolean',
|
|
98
|
+
description: 'Whether to include relation dependencies (default: true)'
|
|
99
|
+
},
|
|
100
|
+
includeMutations: {
|
|
101
|
+
type: 'boolean',
|
|
102
|
+
description: 'Whether to include mutations in the schema (default: true)'
|
|
103
|
+
},
|
|
104
|
+
includeSubscriptions: {
|
|
105
|
+
type: 'boolean',
|
|
106
|
+
description: 'Whether to include subscriptions in the schema (default: true)'
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
required: [
|
|
110
|
+
'id'
|
|
111
|
+
],
|
|
112
|
+
additionalProperties: false
|
|
113
|
+
}, async (ctx)=>{
|
|
114
|
+
const provider = getProvider(container);
|
|
115
|
+
if (provider == null) return notConnectedError();
|
|
116
|
+
try {
|
|
117
|
+
const result = await provider.loadGraph({
|
|
118
|
+
id: ctx.arguments.id
|
|
119
|
+
});
|
|
120
|
+
const schema = createSchema({
|
|
121
|
+
record: result.record,
|
|
122
|
+
aliases: result.aliases,
|
|
123
|
+
onlyModels: ctx.arguments.onlyModels,
|
|
124
|
+
includeInterfaceDependencies: ctx.arguments.includeInterfaceDependencies,
|
|
125
|
+
includeRelationDependencies: ctx.arguments.includeRelationDependencies,
|
|
126
|
+
includeMutations: ctx.arguments.includeMutations,
|
|
127
|
+
includeSubscriptions: ctx.arguments.includeSubscriptions
|
|
128
|
+
});
|
|
129
|
+
return {
|
|
130
|
+
content: [
|
|
131
|
+
{
|
|
132
|
+
type: 'text',
|
|
133
|
+
text: printSchema(schema)
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
};
|
|
137
|
+
} catch (error) {
|
|
138
|
+
return {
|
|
139
|
+
isError: true,
|
|
140
|
+
content: [
|
|
141
|
+
{
|
|
142
|
+
type: 'text',
|
|
143
|
+
text: `Failed to get GraphQL schema: ${error instanceof Error ? error.message : String(error)}`
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
const graph_query = createTool('Execute a GraphQL query on the given graph ID', {
|
|
150
|
+
type: 'object',
|
|
151
|
+
properties: {
|
|
152
|
+
id: {
|
|
153
|
+
type: 'string'
|
|
154
|
+
},
|
|
155
|
+
query: {
|
|
156
|
+
type: 'string'
|
|
157
|
+
},
|
|
158
|
+
variables: {
|
|
159
|
+
type: 'object'
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
required: [
|
|
163
|
+
'id',
|
|
164
|
+
'query'
|
|
165
|
+
],
|
|
166
|
+
additionalProperties: false
|
|
167
|
+
}, async (ctx)=>{
|
|
168
|
+
const provider = getProvider(container);
|
|
169
|
+
if (provider == null) return notConnectedError();
|
|
170
|
+
try {
|
|
171
|
+
const result = await provider.queryGraph({
|
|
172
|
+
id: ctx.arguments.id,
|
|
173
|
+
text: ctx.arguments.query,
|
|
174
|
+
variables: ctx.arguments.variables ?? {}
|
|
175
|
+
});
|
|
176
|
+
if (result.errors != null && result.errors.length > 0) {
|
|
177
|
+
return {
|
|
178
|
+
isError: true,
|
|
179
|
+
content: [
|
|
180
|
+
{
|
|
181
|
+
type: 'text',
|
|
182
|
+
text: result.errors.map((e)=>e.toString()).join(', ')
|
|
183
|
+
}
|
|
184
|
+
],
|
|
185
|
+
structuredContent: {
|
|
186
|
+
errors: result.errors
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
content: [
|
|
192
|
+
{
|
|
193
|
+
type: 'text',
|
|
194
|
+
text: JSON.stringify(result.data)
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
structuredContent: {
|
|
198
|
+
data: result.data
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
} catch (error) {
|
|
202
|
+
return {
|
|
203
|
+
isError: true,
|
|
204
|
+
content: [
|
|
205
|
+
{
|
|
206
|
+
type: 'text',
|
|
207
|
+
text: `Failed to execute GraphQL query: ${error instanceof Error ? error.message : String(error)}`
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
const graph_mutate = createTool('Execute a GraphQL mutation on the given graph ID', {
|
|
214
|
+
type: 'object',
|
|
215
|
+
properties: {
|
|
216
|
+
id: {
|
|
217
|
+
type: 'string'
|
|
218
|
+
},
|
|
219
|
+
query: {
|
|
220
|
+
type: 'string'
|
|
221
|
+
},
|
|
222
|
+
variables: {
|
|
223
|
+
type: 'object'
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
required: [
|
|
227
|
+
'id',
|
|
228
|
+
'query'
|
|
229
|
+
],
|
|
230
|
+
additionalProperties: false
|
|
231
|
+
}, async (ctx)=>{
|
|
232
|
+
const provider = getProvider(container);
|
|
233
|
+
if (provider == null) return notConnectedError();
|
|
234
|
+
try {
|
|
235
|
+
const result = await provider.mutateGraph({
|
|
236
|
+
id: ctx.arguments.id,
|
|
237
|
+
text: ctx.arguments.query,
|
|
238
|
+
variables: ctx.arguments.variables ?? {}
|
|
239
|
+
});
|
|
240
|
+
if (result.errors != null && result.errors.length > 0) {
|
|
241
|
+
return {
|
|
242
|
+
isError: true,
|
|
243
|
+
content: [
|
|
244
|
+
{
|
|
245
|
+
type: 'text',
|
|
246
|
+
text: result.errors.map((e)=>e.toString()).join(', ')
|
|
247
|
+
}
|
|
248
|
+
],
|
|
249
|
+
structuredContent: {
|
|
250
|
+
errors: result.errors
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
content: [
|
|
256
|
+
{
|
|
257
|
+
type: 'text',
|
|
258
|
+
text: JSON.stringify(result.data)
|
|
259
|
+
}
|
|
260
|
+
],
|
|
261
|
+
structuredContent: {
|
|
262
|
+
data: result.data
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
} catch (error) {
|
|
266
|
+
return {
|
|
267
|
+
isError: true,
|
|
268
|
+
content: [
|
|
269
|
+
{
|
|
270
|
+
type: 'text',
|
|
271
|
+
text: `Failed to execute GraphQL mutation: ${error instanceof Error ? error.message : String(error)}`
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
return {
|
|
278
|
+
graph_list,
|
|
279
|
+
graph_info,
|
|
280
|
+
graph_schema,
|
|
281
|
+
graph_query,
|
|
282
|
+
graph_mutate
|
|
283
|
+
};
|
|
284
|
+
}
|
package/lib/tools/index.js
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
-
export{createClusterTools}from
|
|
1
|
+
export { createClusterTools } from './cluster.js';
|
|
2
|
+
export { createConnectionTools } from './connection.js';
|
|
3
|
+
export { createGraphTools } from './graph.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubun/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"license": "see LICENSE.md",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"type": "module",
|
|
@@ -18,25 +18,25 @@
|
|
|
18
18
|
],
|
|
19
19
|
"sideEffects": false,
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@
|
|
22
|
-
"@mokei/context-server": "^0.
|
|
23
|
-
"graphql": "^16.
|
|
24
|
-
"@kubun/db
|
|
25
|
-
"@kubun/db-postgres": "^0.
|
|
26
|
-
"@kubun/db": "^0.
|
|
27
|
-
"@kubun/engine": "^0.
|
|
28
|
-
"@kubun/
|
|
29
|
-
"@kubun/protocol": "^0.
|
|
30
|
-
"@kubun/
|
|
21
|
+
"@kokuin/token": "^0.1.1",
|
|
22
|
+
"@mokei/context-server": "^0.8.0",
|
|
23
|
+
"graphql": "^16.14.2",
|
|
24
|
+
"@kubun/db": "^0.11.0",
|
|
25
|
+
"@kubun/db-postgres": "^0.11.0",
|
|
26
|
+
"@kubun/db-node-sqlite": "^0.11.0",
|
|
27
|
+
"@kubun/engine": "^0.11.0",
|
|
28
|
+
"@kubun/http-client": "^0.11.0",
|
|
29
|
+
"@kubun/protocol": "^0.11.0",
|
|
30
|
+
"@kubun/graphql": "^0.11.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@enkaku/transport": "^0.
|
|
34
|
-
"@mokei/context-client": "^0.
|
|
35
|
-
"@mokei/context-protocol": "^0.
|
|
33
|
+
"@enkaku/transport": "^0.18.1",
|
|
34
|
+
"@mokei/context-client": "^0.8.0",
|
|
35
|
+
"@mokei/context-protocol": "^0.8.0"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build:clean": "del lib",
|
|
39
|
-
"build:js": "swc src -d ./lib --config-file ../../swc.json --strip-leading-paths",
|
|
39
|
+
"build:js": "swc src -d ./lib --config-file ../../node_modules/@kigu/dev/swc.json --strip-leading-paths",
|
|
40
40
|
"build:types": "tsc --emitDeclarationOnly --skipLibCheck",
|
|
41
41
|
"build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
|
|
42
42
|
"test:types": "tsc --noEmit -p tsconfig.test.json",
|