@totemsdk/mcp-server 0.1.0 → 0.3.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/tools.js CHANGED
@@ -1,6 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TOOL_DEFINITIONS = void 0;
3
4
  exports.handleToolCall = handleToolCall;
5
+ const template_catalog_js_1 = require("./template-catalog.js");
6
+ const indexer_js_1 = require("./indexer.js");
7
+ const index_store_js_1 = require("./index-store.js");
8
+ /**
9
+ * The single source of truth for the MCP tool catalog. `index.ts` advertises
10
+ * these and `handleToolCall` dispatches them; the `mcp.test.ts` drift guard
11
+ * asserts the two never diverge.
12
+ */
13
+ exports.TOOL_DEFINITIONS = [
14
+ { name: 'search-symbol', description: 'Search for a symbol (function, type, class) across all packages', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Partial symbol name to search' } }, required: ['query'] } },
15
+ { name: 'find-type', description: 'Find type definitions (interfaces, classes, type aliases) matching a pattern', inputSchema: { type: 'object', properties: { pattern: { type: 'string', description: 'Type name pattern to search' } }, required: ['pattern'] } },
16
+ { name: 'dependency-graph', description: 'Get dependency graph for a package — inbound dependents or outbound dependencies', inputSchema: { type: 'object', properties: { package: { type: 'string', description: 'Package name (e.g. @totemsdk/edge-opcua)' }, direction: { type: 'string', enum: ['in', 'out', 'all'], description: 'Dependency direction' } }, required: ['package'] } },
17
+ { name: 'validate-import', description: 'Check whether a cross-package import is valid', inputSchema: { type: 'object', properties: { from: { type: 'string', description: 'Source package name' }, to: { type: 'string', description: 'Target package name' }, symbol: { type: 'string', description: 'Optional: specific symbol to check' } }, required: ['from', 'to'] } },
18
+ { name: 'scaffold-adapter', description: 'Generate boilerplate for a new edge protocol adapter', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Package name suffix' }, protocol: { type: 'string', description: 'Protocol name (PascalCase)' }, commands: { type: 'array', items: { type: 'string' }, description: 'Transport port methods' } }, required: ['name', 'protocol'] } },
19
+ { name: 'scaffold-package', description: 'Generate boilerplate for a new @totemsdk package', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Package name (without @totemsdk/ prefix)' }, deps: { type: 'array', items: { type: 'string' }, description: 'Dependency package names' } }, required: ['name'] } },
20
+ { name: 'package-stats', description: 'Get statistics about a package — export counts, Rust/Go, tests, deps', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Package name' } }, required: ['name'] } },
21
+ { name: 'list-exports', description: 'List exports of a package', inputSchema: { type: 'object', properties: { package: { type: 'string', description: 'Package name' }, kind: { type: 'string', enum: ['function', 'type', 'interface', 'class', 'const', ''], description: 'Filter by export kind' }, filter: { type: 'string', description: 'Filter by name substring' } }, required: ['package'] } },
22
+ { name: 'suggest-template', description: 'Suggest KISSVM script templates matching a use case — describes what you want to do and returns matching templates with import paths', inputSchema: { type: 'object', properties: { 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")' } }, required: ['usecase'] } },
23
+ { name: 'read-source', description: "Read a source file from a package's src/ directory (e.g. package '@totemsdk/core', path 'treekey.ts')", inputSchema: { type: 'object', properties: { package: { type: 'string', description: 'Package name (e.g. @totemsdk/core)' }, path: { type: 'string', description: 'Path relative to the package src/ directory' } }, required: ['package', 'path'] } },
24
+ { name: 'list-packages', description: 'List SDK packages, optionally filtered by domain or name substring', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Optional domain filter (e.g. edge/runtime... see totemsdk://domain-map)' }, filter: { type: 'string', description: 'Optional package-name substring filter' } } } },
25
+ { name: 'search-packages', description: 'Search packages by keyword across name, description, keywords and exports (e.g. "wots lease coordination")', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Free-text query' }, domain: { type: 'string', description: 'Optional domain filter' }, limit: { type: 'number', description: 'Max results (default 15)' } }, required: ['query'] } },
26
+ { name: 'refresh-index', description: 'Rebuild the SDK index from the filesystem (development convenience) and report counts', inputSchema: { type: 'object', properties: {} } },
27
+ ];
4
28
  function handleToolCall(name, args, index) {
5
29
  switch (name) {
6
30
  case 'search-symbol': return searchSymbol(args, index);
@@ -11,9 +35,94 @@ function handleToolCall(name, args, index) {
11
35
  case 'scaffold-package': return scaffoldPackage(args);
12
36
  case 'package-stats': return packageStats(args, index);
13
37
  case 'list-exports': return listExports(args, index);
38
+ case 'suggest-template': return suggestTemplate(args);
39
+ case 'read-source': return readSource(args);
40
+ case 'list-packages': return listPackages(args, index);
41
+ case 'search-packages': return searchPackages(args, index);
42
+ case 'refresh-index': return refreshIndexTool();
14
43
  default: return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };
15
44
  }
16
45
  }
46
+ function refreshIndexTool() {
47
+ const idx = (0, index_store_js_1.refreshIndex)();
48
+ return {
49
+ content: [{
50
+ type: 'text',
51
+ text: `Index rebuilt: ${Object.keys(idx.packages).length} packages, ${Object.keys(idx.symbolIndex).length} symbols, ${Object.keys(idx.domainMap).length} domains.`,
52
+ }],
53
+ };
54
+ }
55
+ function searchPackages(args, index) {
56
+ const query = String(args.query || '').toLowerCase().trim();
57
+ if (!query)
58
+ return { content: [{ type: 'text', text: 'query is required' }], isError: true };
59
+ const domain = args.domain;
60
+ const limit = Number.isFinite(args.limit) ? Number(args.limit) : 15;
61
+ const terms = query.split(/\s+/).filter(Boolean);
62
+ const scored = Object.values(index.packages)
63
+ .filter(p => !domain || p.domain === domain)
64
+ .map(p => {
65
+ const haystackName = p.name.toLowerCase();
66
+ const haystackDesc = p.description.toLowerCase();
67
+ const haystackKw = (p.keywords ?? []).join(' ').toLowerCase();
68
+ const haystackExports = [
69
+ ...p.exports.functions, ...p.exports.types, ...p.exports.classes, ...p.exports.interfaces, ...p.exports.consts,
70
+ ].join(' ').toLowerCase();
71
+ let score = 0;
72
+ for (const t of terms) {
73
+ if (haystackName.includes(t))
74
+ score += 4;
75
+ if (haystackKw.includes(t))
76
+ score += 3;
77
+ if (haystackExports.includes(t))
78
+ score += 2;
79
+ if (haystackDesc.includes(t))
80
+ score += 1;
81
+ }
82
+ return { p, score };
83
+ })
84
+ .filter(r => r.score > 0)
85
+ .sort((a, b) => b.score - a.score || a.p.name.localeCompare(b.p.name))
86
+ .slice(0, limit);
87
+ if (scored.length === 0) {
88
+ return { content: [{ type: 'text', text: `No packages matched '${query}'` }] };
89
+ }
90
+ return {
91
+ content: [{
92
+ type: 'text',
93
+ text: `Found ${scored.length} package(s) for '${query}':\n\n` +
94
+ scored.map(r => ` ${r.p.name}@${r.p.version} [${r.p.domain}] (score ${r.score}) — ${r.p.description}`).join('\n'),
95
+ }],
96
+ };
97
+ }
98
+ function readSource(args) {
99
+ const pkg = args.package;
100
+ const file = args.path;
101
+ if (!pkg || !file)
102
+ return { content: [{ type: 'text', text: 'package and path are required' }], isError: true };
103
+ const content = (0, indexer_js_1.readSourceFile)(pkg, file);
104
+ if (content === null) {
105
+ return { content: [{ type: 'text', text: `Source not found: ${pkg}/src/${file}` }], isError: true };
106
+ }
107
+ return { content: [{ type: 'text', text: content }] };
108
+ }
109
+ function listPackages(args, index) {
110
+ const domain = args.domain;
111
+ const filter = args.filter?.toLowerCase();
112
+ const rows = Object.values(index.packages)
113
+ .filter(p => (!domain || p.domain === domain) && (!filter || p.name.toLowerCase().includes(filter)))
114
+ .sort((a, b) => a.name.localeCompare(b.name));
115
+ if (rows.length === 0) {
116
+ return { content: [{ type: 'text', text: 'No packages matched' }] };
117
+ }
118
+ return {
119
+ content: [{
120
+ type: 'text',
121
+ text: `${rows.length} package(s):\n\n` +
122
+ rows.map(p => ` ${p.name}@${p.version} [${p.domain}] — ${p.description}`).join('\n'),
123
+ }],
124
+ };
125
+ }
17
126
  function searchSymbol(args, index) {
18
127
  const query = (args.query || '').toLowerCase();
19
128
  if (!query)
@@ -22,7 +131,13 @@ function searchSymbol(args, index) {
22
131
  for (const [symbol, entries] of Object.entries(index.symbolIndex)) {
23
132
  if (symbol.toLowerCase().includes(query)) {
24
133
  for (const entry of entries) {
25
- results.push({ symbol, package: entry.package, kind: entry.kind });
134
+ results.push({
135
+ symbol,
136
+ package: entry.package,
137
+ kind: entry.kind,
138
+ ...(entry.signature !== undefined ? { signature: entry.signature } : {}),
139
+ ...(entry.deprecated ? { deprecated: true } : {}),
140
+ });
26
141
  }
27
142
  }
28
143
  }
@@ -34,7 +149,10 @@ function searchSymbol(args, index) {
34
149
  content: [{
35
150
  type: 'text',
36
151
  text: `Found ${results.length} match(es) for '${query}':\n\n` +
37
- results.map(r => ` ${r.symbol} (${r.kind}) — ${r.package}`).join('\n'),
152
+ results
153
+ .map(r => ` ${r.symbol} (${r.kind}) — ${r.package}${r.deprecated ? ' [deprecated]' : ''}` +
154
+ (r.signature ? `\n ${r.signature}` : ''))
155
+ .join('\n'),
38
156
  }],
39
157
  };
40
158
  }
@@ -44,17 +162,16 @@ function findType(args, index) {
44
162
  return { content: [{ type: 'text', text: 'pattern is required' }], isError: true };
45
163
  const results = [];
46
164
  for (const [pkgName, pkg] of Object.entries(index.packages)) {
47
- for (const t of pkg.exports.interfaces) {
48
- if (t.toLowerCase().includes(pattern))
49
- results.push({ package: pkgName, type: t, kind: 'interface' });
50
- }
51
- for (const t of pkg.exports.types) {
52
- if (t.toLowerCase().includes(pattern))
53
- results.push({ package: pkgName, type: t, kind: 'type' });
54
- }
55
- for (const c of pkg.exports.classes) {
56
- if (c.toLowerCase().includes(pattern))
57
- results.push({ package: pkgName, type: c, kind: 'class' });
165
+ for (const entry of typeEntries(pkg)) {
166
+ if (entry.name.toLowerCase().includes(pattern)) {
167
+ results.push({
168
+ package: pkgName,
169
+ type: entry.name,
170
+ kind: entry.kind,
171
+ ...(entry.signature !== undefined ? { signature: entry.signature } : {}),
172
+ ...(entry.deprecated ? { deprecated: true } : {}),
173
+ });
174
+ }
58
175
  }
59
176
  }
60
177
  results.sort((a, b) => a.type.localeCompare(b.type));
@@ -65,10 +182,31 @@ function findType(args, index) {
65
182
  content: [{
66
183
  type: 'text',
67
184
  text: `Found ${results.length} type(s) for '${pattern}':\n\n` +
68
- results.map(r => ` ${r.type} (${r.kind}) — ${r.package}`).join('\n'),
185
+ results
186
+ .map(r => ` ${r.type} (${r.kind}) — ${r.package}${r.deprecated ? ' [deprecated]' : ''}` +
187
+ (r.signature ? `\n ${r.signature}` : ''))
188
+ .join('\n'),
69
189
  }],
70
190
  };
71
191
  }
192
+ /** Type/interface/class entries for a package (uses `symbols` when present, else `exports`). */
193
+ function typeEntries(pkg) {
194
+ if (pkg.symbols && Object.keys(pkg.symbols).length > 0) {
195
+ return Object.entries(pkg.symbols)
196
+ .filter(([, m]) => m.kind === 'type' || m.kind === 'interface' || m.kind === 'class')
197
+ .map(([name, m]) => ({
198
+ name,
199
+ kind: m.kind,
200
+ ...(m.signature !== undefined ? { signature: m.signature } : {}),
201
+ ...(m.deprecated ? { deprecated: true } : {}),
202
+ }));
203
+ }
204
+ return [
205
+ ...pkg.exports.interfaces.map(n => ({ name: n, kind: 'interface' })),
206
+ ...pkg.exports.types.map(n => ({ name: n, kind: 'type' })),
207
+ ...pkg.exports.classes.map(n => ({ name: n, kind: 'class' })),
208
+ ];
209
+ }
72
210
  function dependencyGraph(args, index) {
73
211
  const pkgName = args.package;
74
212
  const direction = args.direction || 'out';
@@ -338,6 +476,40 @@ function scaffoldPackage(args) {
338
476
  }],
339
477
  };
340
478
  }
479
+ function suggestTemplate(args) {
480
+ const usecase = (args.usecase || '').toLowerCase();
481
+ if (!usecase) {
482
+ return { content: [{ type: 'text', text: 'usecase is required — describe what you want to do (e.g. "time-lock funds until a block height")' }], isError: true };
483
+ }
484
+ const results = (0, template_catalog_js_1.searchTemplates)(usecase);
485
+ if (results.length === 0) {
486
+ return { content: [{ type: 'text', text: `No templates found matching '${usecase}'. Try different keywords (e.g. "lock", "vote", "payment", "identity", "state machine").` }] };
487
+ }
488
+ const lines = [`Found ${results.length} template(s) matching '${args.usecase}':`, ''];
489
+ for (const r of results) {
490
+ lines.push(`## ${r.template}`);
491
+ lines.push(`${r.description}`);
492
+ lines.push('');
493
+ lines.push(`**Functions:**`);
494
+ for (const fn of r.functions) {
495
+ lines.push(` - \`import { ${fn} } from '@totemsdk/kissvm'\``);
496
+ }
497
+ if (r.configTypes.length > 0) {
498
+ lines.push('');
499
+ lines.push(`**Config types:**`);
500
+ for (const t of r.configTypes) {
501
+ lines.push(` - \`${t}\``);
502
+ }
503
+ }
504
+ if (r.package) {
505
+ const pkgs = Array.isArray(r.package) ? r.package : [r.package];
506
+ lines.push('');
507
+ lines.push(`**Related package(s):** ${pkgs.map(p => `\`@totemsdk/${p}\``).join(', ')}`);
508
+ }
509
+ lines.push('');
510
+ }
511
+ return { content: [{ type: 'text', text: lines.join('\n') }] };
512
+ }
341
513
  function packageStats(args, index) {
342
514
  const pkgName = args.name;
343
515
  if (!pkgName || !index.packages[pkgName]) {
@@ -348,6 +520,18 @@ function packageStats(args, index) {
348
520
  pkg.exports.classes.length + pkg.exports.interfaces.length + pkg.exports.consts.length;
349
521
  const totemDeps = pkg.dependencies.filter(d => d.startsWith('@totemsdk/'));
350
522
  const externalDeps = pkg.dependencies.filter(d => !d.startsWith('@totemsdk/'));
523
+ const pkgDir = pkg.name.replace('@totemsdk/', '');
524
+ const templates = (0, template_catalog_js_1.getTemplatesForPackage)(pkgDir);
525
+ const templateSection = templates.length > 0
526
+ ? [
527
+ ``,
528
+ `**KISSVM Templates:**`,
529
+ ...templates.flatMap(t => [
530
+ ` - **${t.template}** — ${t.description}`,
531
+ ...t.functions.map(fn => ` - \`import { ${fn} } from '@totemsdk/kissvm'\``),
532
+ ]),
533
+ ]
534
+ : [];
351
535
  return {
352
536
  content: [{
353
537
  type: 'text',
@@ -371,6 +555,7 @@ function packageStats(args, index) {
371
555
  `| Tests | ${pkg.hasTests ? 'Yes' : 'No'} |`,
372
556
  `| @totemsdk/* deps | ${totemDeps.length} |`,
373
557
  `| External deps | ${externalDeps.length} |`,
558
+ ...templateSection,
374
559
  ``,
375
560
  ].join('\n'),
376
561
  }],
@@ -385,30 +570,36 @@ function listExports(args, index) {
385
570
  }
386
571
  const pkg = index.packages[pkgName];
387
572
  const sections = [];
573
+ const render = (s) => {
574
+ const m = pkg.symbols?.[s];
575
+ const dep = m?.deprecated ? ' · deprecated' : '';
576
+ return ` - \`${s}\`${dep}${m?.signature ? `\n ${m.signature}` : ''}`;
577
+ };
578
+ const pick = (list) => (filter ? list.filter(s => s.toLowerCase().includes(filter)) : list);
388
579
  if (!kind || kind === 'function') {
389
- const items = filter ? pkg.exports.functions.filter(s => s.toLowerCase().includes(filter)) : pkg.exports.functions;
580
+ const items = pick(pkg.exports.functions);
390
581
  if (items.length)
391
- sections.push(`**Functions (${items.length}):**\n` + items.map(s => ` - \`${s}\``).join('\n'));
582
+ sections.push(`**Functions (${items.length}):**\n` + items.map(render).join('\n'));
392
583
  }
393
584
  if (!kind || kind === 'interface') {
394
- const items = filter ? pkg.exports.interfaces.filter(s => s.toLowerCase().includes(filter)) : pkg.exports.interfaces;
585
+ const items = pick(pkg.exports.interfaces);
395
586
  if (items.length)
396
- sections.push(`**Interfaces (${items.length}):**\n` + items.map(s => ` - \`${s}\``).join('\n'));
587
+ sections.push(`**Interfaces (${items.length}):**\n` + items.map(render).join('\n'));
397
588
  }
398
589
  if (!kind || kind === 'type') {
399
- const items = filter ? pkg.exports.types.filter(s => s.toLowerCase().includes(filter)) : pkg.exports.types;
590
+ const items = pick(pkg.exports.types);
400
591
  if (items.length)
401
- sections.push(`**Named Types (${items.length}):**\n` + items.map(s => ` - \`${s}\``).join('\n'));
592
+ sections.push(`**Named Types (${items.length}):**\n` + items.map(render).join('\n'));
402
593
  }
403
594
  if (!kind || kind === 'class') {
404
- const items = filter ? pkg.exports.classes.filter(s => s.toLowerCase().includes(filter)) : pkg.exports.classes;
595
+ const items = pick(pkg.exports.classes);
405
596
  if (items.length)
406
- sections.push(`**Classes (${items.length}):**\n` + items.map(s => ` - \`${s}\``).join('\n'));
597
+ sections.push(`**Classes (${items.length}):**\n` + items.map(render).join('\n'));
407
598
  }
408
599
  if (!kind || kind === 'const') {
409
- const items = filter ? pkg.exports.consts.filter(s => s.toLowerCase().includes(filter)) : pkg.exports.consts;
600
+ const items = pick(pkg.exports.consts);
410
601
  if (items.length)
411
- sections.push(`**Constants (${items.length}):**\n` + items.map(s => ` - \`${s}\``).join('\n'));
602
+ sections.push(`**Constants (${items.length}):**\n` + items.map(render).join('\n'));
412
603
  }
413
604
  return {
414
605
  content: [{ type: 'text', text: sections.join('\n\n') || `No exports found for '${pkgName}'` }],
package/dist/types.d.ts CHANGED
@@ -3,12 +3,17 @@ export interface PackageIndex {
3
3
  dir: string;
4
4
  version: string;
5
5
  description: string;
6
+ keywords?: string[];
6
7
  dependencies: string[];
7
8
  devDependencies: string[];
8
9
  hasRust: boolean;
9
10
  hasGo: boolean;
10
11
  hasTests: boolean;
11
12
  exports: PackageExports;
13
+ /** Per-symbol metadata (signature, doc, deprecation) keyed by symbol name. */
14
+ symbols?: {
15
+ [name: string]: SymbolMeta;
16
+ };
12
17
  domain: string;
13
18
  }
14
19
  export interface PackageExports {
@@ -18,9 +23,22 @@ export interface PackageExports {
18
23
  interfaces: string[];
19
24
  consts: string[];
20
25
  }
26
+ export type SymbolKind = 'function' | 'type' | 'class' | 'interface' | 'const' | 'variable';
27
+ export interface SymbolMeta {
28
+ kind: SymbolKind;
29
+ /** Best-effort declaration text (params/return/extends), whitespace-normalized. */
30
+ signature?: string;
31
+ /** Leading JSDoc/line-comment text, if any. */
32
+ doc?: string;
33
+ /** True when the doc contains an `@deprecated` tag. */
34
+ deprecated?: boolean;
35
+ }
21
36
  export interface SymbolEntry {
22
37
  package: string;
23
- kind: 'function' | 'type' | 'class' | 'interface' | 'const' | 'variable';
38
+ kind: SymbolKind;
39
+ signature?: string;
40
+ doc?: string;
41
+ deprecated?: boolean;
24
42
  }
25
43
  export interface DomainMap {
26
44
  [domain: string]: string[];
@@ -35,6 +53,11 @@ export interface SdkIndex {
35
53
  };
36
54
  domainMap: DomainMap;
37
55
  }
56
+ export interface ToolDefinition {
57
+ name: string;
58
+ description: string;
59
+ inputSchema: unknown;
60
+ }
38
61
  export interface ToolResponse {
39
62
  content: Array<{
40
63
  type: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@totemsdk/mcp-server",
3
- "version": "0.1.0",
4
- "description": "MCP server exposing the full Totem SDK package set — metadata, types, exports, dependency graphs, and scaffolding tools for 53 packages",
3
+ "version": "0.3.0",
4
+ "description": "MCP server exposing the full Totem SDK package set — metadata, types, exports, dependency graphs, and scaffolding tools",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "bin": {
@@ -14,18 +14,20 @@
14
14
  "import": "./dist/index.js"
15
15
  }
16
16
  },
17
- "scripts": {
18
- "build": "tsc",
19
- "prepare": "",
20
- "clean": "rm -rf dist",
21
- "start": "node dist/index.js"
22
- },
23
- "files": ["dist", "README.md", "LICENSE"],
17
+ "files": [
18
+ "dist",
19
+ "data",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
24
23
  "dependencies": {
25
- "@modelcontextprotocol/sdk": "^1.29.0"
24
+ "@modelcontextprotocol/sdk": "^1.30.0"
26
25
  },
27
26
  "devDependencies": {
27
+ "@types/jest": "^30.0.0",
28
28
  "@types/node": "^20.0.0",
29
+ "jest": "^30.4.2",
30
+ "ts-jest": "^29.0.0",
29
31
  "typescript": "^7.0.2"
30
32
  },
31
33
  "engines": {
@@ -36,14 +38,26 @@
36
38
  },
37
39
  "license": "MIT",
38
40
  "author": "Totem SDK",
39
- "homepage": "https://totem.ing",
41
+ "homepage": "https://docs.totem.ing",
40
42
  "bugs": {
41
- "url": "https://github.com/totem-sdk/totem-sdk/issues"
43
+ "url": "https://github.com/Totem-Edge/totem-sdk/issues"
42
44
  },
43
45
  "repository": {
44
46
  "type": "git",
45
- "url": "git+https://github.com/totem-sdk/totem-sdk.git",
46
- "directory": "packages/totem-sdk/packages/mcp-server"
47
- },
48
- "keywords": ["totem", "totemsdk", "mcp", "model-context-protocol", "sdk-index"]
49
- }
47
+ "url": "git+https://github.com/Totem-Edge/totem-sdk.git",
48
+ "directory": "packages/mcp-server"
49
+ },
50
+ "keywords": [
51
+ "totem",
52
+ "totemsdk",
53
+ "mcp",
54
+ "model-context-protocol",
55
+ "sdk-index"
56
+ ],
57
+ "scripts": {
58
+ "build": "tsc && node ../../scripts/build-mcp-bundle.mjs",
59
+ "clean": "rm -rf dist data",
60
+ "start": "node dist/index.js",
61
+ "test": "jest"
62
+ }
63
+ }