store-mcp-node 0.1.0 → 0.2.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/package.json +1 -1
- package/src/index.js +22 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "store-mcp-node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "MCP (Model Context Protocol) adapter that auto-generates tool surfaces for nodejs-store schemas (schema-driven CRUD + sandboxed GQL query + optional ask), stdio transport",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
package/src/index.js
CHANGED
|
@@ -54,6 +54,9 @@ function errorOf(e) {
|
|
|
54
54
|
if (e && e.name === 'SkinError') return { code: e.code, message: e.message };
|
|
55
55
|
if (e && e.name === 'AskExhausted') return { code: 'askExhausted', message: String(e.message) };
|
|
56
56
|
if (e && e.name === 'PermissionError') return { code: 'permissionDenied', message: String(e.message) };
|
|
57
|
+
if (e && (e.name === 'NoContextError' || e.code === 'no_context')) {
|
|
58
|
+
return { code: 'noContext', message: String(e.message) };
|
|
59
|
+
}
|
|
57
60
|
if (e && e.name === 'ProfileViolation') return { code: 'profileBlocked', message: String(e.message) };
|
|
58
61
|
return { code: 'planError', message: String((e && e.message) || e) };
|
|
59
62
|
}
|
|
@@ -87,6 +90,12 @@ const ASK_TOOL = {
|
|
|
87
90
|
inputSchema: obj({ question: { type: 'string', description: '自然语言问题' } }, ['question']),
|
|
88
91
|
};
|
|
89
92
|
|
|
93
|
+
const DESCRIBE_TOOL = {
|
|
94
|
+
name: 'describe_schemas',
|
|
95
|
+
description: '列出可用数据模型及其字段/关系/计算列(权限过滤后的紧凑 JSON)。翻译 GQL 前先调用本工具获取 schema;无权限上下文时仅返回模型名与字段名',
|
|
96
|
+
inputSchema: obj({}, []),
|
|
97
|
+
};
|
|
98
|
+
|
|
90
99
|
/**
|
|
91
100
|
* 收集工具面(归档过滤 + x-mcp 注记 + ask 启用守卫)。
|
|
92
101
|
* @returns {{tools: object[], handlers: Map<string, Function>}}
|
|
@@ -116,6 +125,10 @@ function buildSurface(store, opts = {}) {
|
|
|
116
125
|
tools.push(QUERY_TOOL);
|
|
117
126
|
handlers.set('query', queryHandler(store, opts));
|
|
118
127
|
|
|
128
|
+
// spec/01:describe_schemas —— AI 自主翻译 GQL 前的 schema 出口(零入参;ctx 走 opts,不进 inputSchema)
|
|
129
|
+
tools.push(DESCRIBE_TOOL);
|
|
130
|
+
handlers.set('describe_schemas', describeHandler(store, opts));
|
|
131
|
+
|
|
119
132
|
// spec/01:ask 仅 opts.llm 提供时注册;配 llm 缺 ctx 装配期抛错(fail-secure)
|
|
120
133
|
if (opts.llm !== undefined && opts.llm !== null) {
|
|
121
134
|
if (opts.ctx === undefined || opts.ctx === null) {
|
|
@@ -171,6 +184,15 @@ function queryHandler(store, opts) {
|
|
|
171
184
|
};
|
|
172
185
|
}
|
|
173
186
|
|
|
187
|
+
function describeHandler(store, opts) {
|
|
188
|
+
return async () => {
|
|
189
|
+
if (typeof store.describeForAi !== 'function') {
|
|
190
|
+
throw new SkinError('planError', 'store 未提供 describeForAi(需提供该门面的 nodejs-store 宿主)');
|
|
191
|
+
}
|
|
192
|
+
return store.describeForAi(opts.ctx === undefined ? null : opts.ctx);
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
174
196
|
function askHandler(opts) {
|
|
175
197
|
return async (args) => {
|
|
176
198
|
if (typeof args.question !== 'string' || !args.question.trim()) {
|