@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.
@@ -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
- import type { SdkIndex } from './types.js';
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: "0.2.0";
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
- export { index as sdkIndex };
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 indexer_js_1 = require("./indexer.js");
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 index = (0, indexer_js_1.buildIndex)();
11
- exports.sdkIndex = index;
12
- const server = new index_js_1.Server({ name: '@totemsdk/mcp-server', version: '0.1.0' }, { capabilities: { resources: {}, tools: {}, prompts: {} } });
13
- server.setRequestHandler(types_js_1.ListResourcesRequestSchema, async () => ({
14
- resources: (0, resources_js_1.listResources)(index),
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 text = (0, resources_js_1.handleResourceRead)(uri, index);
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: 'text/plain', text }] };
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
- return (0, tools_js_1.handleToolCall)(name, args || {}, index);
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: '0.2.0',
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
- export declare function buildIndex(): SdkIndex;
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;