@totemsdk/mcp-server 0.2.0 → 0.4.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/README.md +9 -2
- package/data/sdk-index.json +1 -0
- package/dist/index-store.d.ts +18 -0
- package/dist/index-store.js +38 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.js +99 -114
- package/dist/indexer.d.ts +27 -1
- package/dist/indexer.js +344 -120
- package/dist/resources.d.ts +4 -0
- package/dist/resources.js +187 -21
- package/dist/tools.d.ts +7 -1
- package/dist/tools.js +166 -24
- package/dist/types.d.ts +24 -1
- package/package.json +6 -5
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SdkIndex } from './types.js';
|
|
2
|
+
export type IndexState = {
|
|
3
|
+
readonly ok: true;
|
|
4
|
+
readonly index: SdkIndex;
|
|
5
|
+
} | {
|
|
6
|
+
readonly ok: false;
|
|
7
|
+
readonly error: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Lazily-built, process-wide SDK index state. Never throws: an unavailable
|
|
11
|
+
* index is cached as an error so every call site can return an honest failure
|
|
12
|
+
* instead of an empty (confidently-wrong) index.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getIndexState(): IndexState;
|
|
15
|
+
/** The SDK index, or throws {@link IndexUnavailableError} when unavailable. */
|
|
16
|
+
export declare function getIndex(): SdkIndex;
|
|
17
|
+
/** Rebuild the SDK index from the filesystem (used by the `refresh-index` tool). */
|
|
18
|
+
export declare function refreshIndex(): SdkIndex;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getIndexState = getIndexState;
|
|
4
|
+
exports.getIndex = getIndex;
|
|
5
|
+
exports.refreshIndex = refreshIndex;
|
|
6
|
+
const indexer_js_1 = require("./indexer.js");
|
|
7
|
+
let _state = null;
|
|
8
|
+
/**
|
|
9
|
+
* Lazily-built, process-wide SDK index state. Never throws: an unavailable
|
|
10
|
+
* index is cached as an error so every call site can return an honest failure
|
|
11
|
+
* instead of an empty (confidently-wrong) index.
|
|
12
|
+
*/
|
|
13
|
+
function getIndexState() {
|
|
14
|
+
if (_state)
|
|
15
|
+
return _state;
|
|
16
|
+
try {
|
|
17
|
+
_state = { ok: true, index: (0, indexer_js_1.buildIndex)() };
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
_state = {
|
|
21
|
+
ok: false,
|
|
22
|
+
error: e instanceof Error ? e.message : String(e),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return _state;
|
|
26
|
+
}
|
|
27
|
+
/** The SDK index, or throws {@link IndexUnavailableError} when unavailable. */
|
|
28
|
+
function getIndex() {
|
|
29
|
+
const state = getIndexState();
|
|
30
|
+
if (!state.ok)
|
|
31
|
+
throw new indexer_js_1.IndexUnavailableError(state.error);
|
|
32
|
+
return state.index;
|
|
33
|
+
}
|
|
34
|
+
/** Rebuild the SDK index from the filesystem (used by the `refresh-index` tool). */
|
|
35
|
+
function refreshIndex() {
|
|
36
|
+
_state = null;
|
|
37
|
+
return getIndex();
|
|
38
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
declare const index: SdkIndex;
|
|
1
|
+
#!/usr/bin/env node
|
|
3
2
|
export declare const SERVER_INFO: {
|
|
4
3
|
readonly name: "@totemsdk/mcp-server";
|
|
5
|
-
readonly version:
|
|
4
|
+
readonly version: string;
|
|
6
5
|
readonly capabilities: {
|
|
7
6
|
readonly resources: {};
|
|
8
7
|
readonly tools: {};
|
|
9
8
|
readonly prompts: {};
|
|
10
9
|
};
|
|
11
10
|
};
|
|
12
|
-
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Importing this at module load forces index construction. Prefer
|
|
13
|
+
* `getIndexState()`/`getIndex()` so a missing index is handled, not thrown.
|
|
14
|
+
*/
|
|
15
|
+
export declare const sdkIndex: import("./types.js").SdkIndex;
|
package/dist/index.js
CHANGED
|
@@ -1,134 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
2
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
37
|
exports.sdkIndex = exports.SERVER_INFO = void 0;
|
|
4
38
|
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
5
39
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
40
|
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
7
|
-
const
|
|
41
|
+
const index_store_js_1 = require("./index-store.js");
|
|
8
42
|
const resources_js_1 = require("./resources.js");
|
|
9
43
|
const tools_js_1 = require("./tools.js");
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
function readPkgVersion() {
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8')).version || '0.0.0';
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return '0.0.0';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const server = new index_js_1.Server({ name: '@totemsdk/mcp-server', version: readPkgVersion() }, { capabilities: { resources: {}, tools: {}, prompts: {} } });
|
|
55
|
+
server.setRequestHandler(types_js_1.ListResourcesRequestSchema, async () => {
|
|
56
|
+
const state = (0, index_store_js_1.getIndexState)();
|
|
57
|
+
// Still advertise resources when the index is unavailable so clients see the
|
|
58
|
+
// server is alive; reads then fail with an actionable message.
|
|
59
|
+
return { resources: (0, resources_js_1.listResources)(state.ok ? state.index : {}) };
|
|
60
|
+
});
|
|
16
61
|
server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) => {
|
|
17
62
|
const { uri } = request.params;
|
|
18
|
-
const
|
|
63
|
+
const state = (0, index_store_js_1.getIndexState)();
|
|
64
|
+
if (!state.ok) {
|
|
65
|
+
throw new Error(`Resource unavailable: ${state.error}`);
|
|
66
|
+
}
|
|
67
|
+
const text = (0, resources_js_1.handleResourceRead)(uri, state.index);
|
|
19
68
|
if (text === null) {
|
|
20
69
|
throw new Error(`Resource not found: ${uri}`);
|
|
21
70
|
}
|
|
22
|
-
return { contents: [{ uri, mimeType:
|
|
71
|
+
return { contents: [{ uri, mimeType: (0, resources_js_1.resourceMimeType)(uri), text }] };
|
|
23
72
|
});
|
|
24
73
|
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
25
|
-
tools:
|
|
26
|
-
{
|
|
27
|
-
name: 'search-symbol',
|
|
28
|
-
description: 'Search for a symbol (function, type, class) across all packages',
|
|
29
|
-
inputSchema: {
|
|
30
|
-
type: 'object',
|
|
31
|
-
properties: { query: { type: 'string', description: 'Partial symbol name to search' } },
|
|
32
|
-
required: ['query'],
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
name: 'find-type',
|
|
37
|
-
description: 'Find type definitions (interfaces, classes, type aliases) matching a pattern',
|
|
38
|
-
inputSchema: {
|
|
39
|
-
type: 'object',
|
|
40
|
-
properties: { pattern: { type: 'string', description: 'Type name pattern to search' } },
|
|
41
|
-
required: ['pattern'],
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: 'dependency-graph',
|
|
46
|
-
description: 'Get dependency graph for a package — inbound dependents or outbound dependencies',
|
|
47
|
-
inputSchema: {
|
|
48
|
-
type: 'object',
|
|
49
|
-
properties: {
|
|
50
|
-
package: { type: 'string', description: 'Package name (e.g. @totemsdk/edge-opcua)' },
|
|
51
|
-
direction: { type: 'string', enum: ['in', 'out', 'all'], description: 'Dependency direction' },
|
|
52
|
-
},
|
|
53
|
-
required: ['package'],
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: 'validate-import',
|
|
58
|
-
description: 'Check whether a cross-package import is valid',
|
|
59
|
-
inputSchema: {
|
|
60
|
-
type: 'object',
|
|
61
|
-
properties: {
|
|
62
|
-
from: { type: 'string', description: 'Source package name' },
|
|
63
|
-
to: { type: 'string', description: 'Target package name' },
|
|
64
|
-
symbol: { type: 'string', description: 'Optional: specific symbol to check' },
|
|
65
|
-
},
|
|
66
|
-
required: ['from', 'to'],
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
name: 'scaffold-adapter',
|
|
71
|
-
description: 'Generate boilerplate for a new edge protocol adapter',
|
|
72
|
-
inputSchema: {
|
|
73
|
-
type: 'object',
|
|
74
|
-
properties: {
|
|
75
|
-
name: { type: 'string', description: 'Package name suffix' },
|
|
76
|
-
protocol: { type: 'string', description: 'Protocol name (PascalCase)' },
|
|
77
|
-
commands: { type: 'array', items: { type: 'string' }, description: 'Transport port methods' },
|
|
78
|
-
},
|
|
79
|
-
required: ['name', 'protocol'],
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
name: 'scaffold-package',
|
|
84
|
-
description: 'Generate boilerplate for a new @totemsdk package',
|
|
85
|
-
inputSchema: {
|
|
86
|
-
type: 'object',
|
|
87
|
-
properties: {
|
|
88
|
-
name: { type: 'string', description: 'Package name (without @totemsdk/ prefix)' },
|
|
89
|
-
deps: { type: 'array', items: { type: 'string' }, description: 'Dependency package names' },
|
|
90
|
-
},
|
|
91
|
-
required: ['name'],
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
name: 'package-stats',
|
|
96
|
-
description: 'Get statistics about a package — export counts, Rust/Go, tests, deps',
|
|
97
|
-
inputSchema: {
|
|
98
|
-
type: 'object',
|
|
99
|
-
properties: { name: { type: 'string', description: 'Package name' } },
|
|
100
|
-
required: ['name'],
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
name: 'list-exports',
|
|
105
|
-
description: 'List exports of a package',
|
|
106
|
-
inputSchema: {
|
|
107
|
-
type: 'object',
|
|
108
|
-
properties: {
|
|
109
|
-
package: { type: 'string', description: 'Package name' },
|
|
110
|
-
kind: { type: 'string', enum: ['function', 'type', 'interface', 'class', 'const', ''], description: 'Filter by export kind' },
|
|
111
|
-
filter: { type: 'string', description: 'Filter by name substring' },
|
|
112
|
-
},
|
|
113
|
-
required: ['package'],
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
name: 'suggest-template',
|
|
118
|
-
description: 'Suggest KISSVM script templates matching a use case — describes what you want to do and returns matching templates with import paths',
|
|
119
|
-
inputSchema: {
|
|
120
|
-
type: 'object',
|
|
121
|
-
properties: {
|
|
122
|
-
usecase: { type: 'string', description: 'Describe what you want to do (e.g. "time-lock funds until a block height", "vote tally with quorum", "identity verification")' },
|
|
123
|
-
},
|
|
124
|
-
required: ['usecase'],
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
],
|
|
74
|
+
tools: tools_js_1.TOOL_DEFINITIONS,
|
|
128
75
|
}));
|
|
76
|
+
/**
|
|
77
|
+
* Tools that read the SDK index. The rest (scaffolding, template suggestions)
|
|
78
|
+
* work without it, so a missing index degrades honestly instead of failing
|
|
79
|
+
* everything.
|
|
80
|
+
*/
|
|
81
|
+
const INDEX_REQUIRED_TOOLS = new Set([
|
|
82
|
+
'search-symbol',
|
|
83
|
+
'find-type',
|
|
84
|
+
'dependency-graph',
|
|
85
|
+
'validate-import',
|
|
86
|
+
'package-stats',
|
|
87
|
+
'list-exports',
|
|
88
|
+
'read-source',
|
|
89
|
+
'list-packages',
|
|
90
|
+
'search-packages',
|
|
91
|
+
'refresh-index',
|
|
92
|
+
]);
|
|
129
93
|
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
130
94
|
const { name, arguments: args } = request.params;
|
|
131
|
-
|
|
95
|
+
const state = (0, index_store_js_1.getIndexState)();
|
|
96
|
+
if (!state.ok && INDEX_REQUIRED_TOOLS.has(name)) {
|
|
97
|
+
return {
|
|
98
|
+
content: [{ type: 'text', text: `SDK index unavailable: ${state.error}` }],
|
|
99
|
+
isError: true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// Index-free tools ignore the index argument; pass the real one when present.
|
|
103
|
+
return (0, tools_js_1.handleToolCall)(name, args || {}, state.ok ? state.index : {});
|
|
132
104
|
});
|
|
133
105
|
server.setRequestHandler(types_js_1.ListPromptsRequestSchema, async () => ({
|
|
134
106
|
prompts: [
|
|
@@ -151,6 +123,11 @@ server.setRequestHandler(types_js_1.ListPromptsRequestSchema, async () => ({
|
|
|
151
123
|
}));
|
|
152
124
|
server.setRequestHandler(types_js_1.GetPromptRequestSchema, async (request) => {
|
|
153
125
|
const { name, arguments: args } = request.params;
|
|
126
|
+
const indexState = (0, index_store_js_1.getIndexState)();
|
|
127
|
+
if (!indexState.ok) {
|
|
128
|
+
throw new Error(`SDK index unavailable: ${indexState.error}`);
|
|
129
|
+
}
|
|
130
|
+
const index = indexState.index;
|
|
154
131
|
if (name === 'analyze-cross-package') {
|
|
155
132
|
const from = args?.from;
|
|
156
133
|
const to = args?.to;
|
|
@@ -224,9 +201,17 @@ server.setRequestHandler(types_js_1.GetPromptRequestSchema, async (request) => {
|
|
|
224
201
|
});
|
|
225
202
|
exports.SERVER_INFO = {
|
|
226
203
|
name: '@totemsdk/mcp-server',
|
|
227
|
-
version:
|
|
204
|
+
version: readPkgVersion(),
|
|
228
205
|
capabilities: { resources: {}, tools: {}, prompts: {} },
|
|
229
206
|
};
|
|
207
|
+
/**
|
|
208
|
+
* @deprecated Importing this at module load forces index construction. Prefer
|
|
209
|
+
* `getIndexState()`/`getIndex()` so a missing index is handled, not thrown.
|
|
210
|
+
*/
|
|
211
|
+
exports.sdkIndex = (() => {
|
|
212
|
+
const state = (0, index_store_js_1.getIndexState)();
|
|
213
|
+
return state.ok ? state.index : { generatedAt: 0, packages: {}, symbolIndex: {}, domainMap: {} };
|
|
214
|
+
})();
|
|
230
215
|
async function main() {
|
|
231
216
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
232
217
|
await server.connect(transport);
|
package/dist/indexer.d.ts
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
1
|
import type { SdkIndex } from './types.js';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when no SDK index can be produced — neither a monorepo to scan nor a
|
|
4
|
+
* bundled index shipped in the package. Callers must surface this as an error,
|
|
5
|
+
* never as an empty (and therefore confidently-wrong) index.
|
|
6
|
+
*/
|
|
7
|
+
export declare class IndexUnavailableError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
export interface BuildIndexOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Monorepo root to scan. Use `null` to force the non-monorepo path (bundled
|
|
13
|
+
* index or an error). Defaults to auto-detection.
|
|
14
|
+
*/
|
|
15
|
+
rootDir?: string | null;
|
|
16
|
+
/** Never fall back to the bundled index (used by tests / strict callers). */
|
|
17
|
+
noBundled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Scan a monorepo root into an `SdkIndex`. */
|
|
20
|
+
export declare function buildFromMonorepo(root: string, now?: number): SdkIndex;
|
|
21
|
+
/**
|
|
22
|
+
* Build the SDK index. Prefers a live monorepo scan; falls back to the bundled
|
|
23
|
+
* index shipped in the package. Throws {@link IndexUnavailableError} when
|
|
24
|
+
* neither is available — an empty index is never returned, because downstream
|
|
25
|
+
* tools would otherwise answer "not found" as if it were fact.
|
|
26
|
+
*/
|
|
27
|
+
export declare function buildIndex(options?: BuildIndexOptions): SdkIndex;
|
|
28
|
+
/** Read a file from a package's `src/` directory (for the `read-source` tool). */
|
|
3
29
|
export declare function readSourceFile(pkgName: string, filePath: string): string | null;
|