@kepler.gl/mcp 0.0.0-stage → 3.3.0-alpha.19

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.
Files changed (73) hide show
  1. package/dist/cjs/commands/add-column-command.js +192 -0
  2. package/dist/cjs/commands/basemap-command.js +80 -0
  3. package/dist/cjs/commands/boundary-command.js +81 -0
  4. package/dist/cjs/commands/command-wrappers.js +122 -0
  5. package/dist/cjs/commands/dataset-context-command.js +87 -0
  6. package/dist/cjs/commands/index.js +230 -0
  7. package/dist/cjs/commands/layer-creation-command.js +534 -0
  8. package/dist/cjs/commands/layer-style-command.js +136 -0
  9. package/dist/cjs/commands/load-data-command.js +270 -0
  10. package/dist/cjs/commands/save-data-command.js +118 -0
  11. package/dist/cjs/commands/split-view-command.js +261 -0
  12. package/dist/cjs/commands/table-command.js +199 -0
  13. package/dist/cjs/commands/time-filter-command.js +289 -0
  14. package/dist/cjs/commands/toggle-time-filter-command.js +155 -0
  15. package/dist/cjs/commands/types.js +6 -0
  16. package/dist/cjs/commands/utils.js +536 -0
  17. package/dist/cjs/commands/view-mode-command.js +94 -0
  18. package/dist/cjs/index.js +39 -0
  19. package/dist/cjs/map-contract.js +6 -0
  20. package/dist/cjs/server/bridge-server.js +435 -0
  21. package/dist/cjs/server/index.js +31 -0
  22. package/dist/cjs/server/stdio.js +201 -0
  23. package/dist/cjs/types.js +30 -0
  24. package/dist/commands/add-column-command.d.ts +4 -0
  25. package/dist/commands/basemap-command.d.ts +4 -0
  26. package/dist/commands/boundary-command.d.ts +4 -0
  27. package/dist/commands/command-wrappers.d.ts +52 -0
  28. package/dist/commands/dataset-context-command.d.ts +4 -0
  29. package/dist/commands/index.d.ts +31 -0
  30. package/dist/commands/layer-creation-command.d.ts +8 -0
  31. package/dist/commands/layer-style-command.d.ts +4 -0
  32. package/dist/commands/load-data-command.d.ts +4 -0
  33. package/dist/commands/save-data-command.d.ts +4 -0
  34. package/dist/commands/split-view-command.d.ts +4 -0
  35. package/dist/commands/table-command.d.ts +4 -0
  36. package/dist/commands/time-filter-command.d.ts +13 -0
  37. package/dist/commands/toggle-time-filter-command.d.ts +4 -0
  38. package/dist/commands/types.d.ts +132 -0
  39. package/dist/commands/utils.d.ts +138 -0
  40. package/dist/commands/view-mode-command.d.ts +4 -0
  41. package/dist/esm/commands/add-column-command.js +185 -0
  42. package/dist/esm/commands/basemap-command.js +72 -0
  43. package/dist/esm/commands/boundary-command.js +73 -0
  44. package/dist/esm/commands/command-wrappers.js +114 -0
  45. package/dist/esm/commands/dataset-context-command.js +79 -0
  46. package/dist/esm/commands/index.js +51 -0
  47. package/dist/esm/commands/layer-creation-command.js +527 -0
  48. package/dist/esm/commands/layer-style-command.js +130 -0
  49. package/dist/esm/commands/load-data-command.js +264 -0
  50. package/dist/esm/commands/save-data-command.js +112 -0
  51. package/dist/esm/commands/split-view-command.js +255 -0
  52. package/dist/esm/commands/table-command.js +194 -0
  53. package/dist/esm/commands/time-filter-command.js +280 -0
  54. package/dist/esm/commands/toggle-time-filter-command.js +147 -0
  55. package/dist/esm/commands/types.js +3 -0
  56. package/dist/esm/commands/utils.js +521 -0
  57. package/dist/esm/commands/view-mode-command.js +86 -0
  58. package/dist/esm/index.js +20 -0
  59. package/dist/esm/map-contract.js +3 -0
  60. package/dist/esm/server/bridge-server.js +428 -0
  61. package/dist/esm/server/index.js +13 -0
  62. package/dist/esm/server/stdio.js +198 -0
  63. package/dist/esm/types.js +24 -0
  64. package/dist/index.d.ts +15 -0
  65. package/dist/map-contract.d.ts +31 -0
  66. package/dist/server/bridge-server.d.ts +53 -0
  67. package/dist/server/index.d.ts +9 -0
  68. package/dist/server/stdio.d.ts +2 -0
  69. package/dist/types.d.ts +24 -0
  70. package/package.json +84 -4
  71. package/skill/kepler/SKILL.md +438 -0
  72. package/skill/kepler/skill.yaml +4 -0
  73. package/README.md +0 -3
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env node
2
+
3
+ // SPDX-License-Identifier: MIT
4
+ // Copyright contributors to the kepler.gl project
5
+
6
+ /**
7
+ * `kepler-mcp` — a stdio MCP server for the kepler.gl map surface.
8
+ *
9
+ * The agent starts this process (it speaks MCP on stdin/stdout); the process
10
+ * also listens for the map page on a loopback WebSocket. It prints a URL that
11
+ * carries the one-time token — open that URL and the page connects, after which
12
+ * every map.* tool call executes against the live map.
13
+ *
14
+ * stdout belongs to the MCP protocol: every log line here goes to stderr.
15
+ */
16
+ import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
17
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
18
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
19
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
20
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
21
+ import { readFileSync } from 'node:fs';
22
+ import { dirname, join } from 'node:path';
23
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
24
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
25
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
26
+ import { KeplerMcpBridge, formatResult } from './bridge-server';
27
+ var DEFAULT_MAP_URL = 'http://localhost:8080';
28
+ function readVersion() {
29
+ if (typeof __dirname === 'undefined') return '0.0.0';
30
+ var directory = __dirname;
31
+ // Walk up until the package manifest is found, so this works both from src/
32
+ // (babel-node, tests) and from dist/cjs/server (the published bin).
33
+ for (var depth = 0; depth < 5; depth++) {
34
+ try {
35
+ var manifest = JSON.parse(readFileSync(join(directory, 'package.json'), 'utf8'));
36
+ if (manifest.name === '@kepler.gl/mcp') return manifest.version;
37
+ } catch (_unused) {
38
+ // no manifest at this level — keep walking
39
+ }
40
+ directory = dirname(directory);
41
+ }
42
+ return '0.0.0';
43
+ }
44
+ function usage() {
45
+ return ['Usage: kepler-mcp [--port <n>] [--host <h>] [--map-url <url>]', '', 'Runs a stdio MCP server for the kepler.gl map surface and waits for a', 'kepler.gl page to connect over a loopback WebSocket.', '', ' --port <n> WebSocket port for the page (default 8765)', ' --host <h> loopback host to bind (default 127.0.0.1)', " --map-url <url> page URL printed with the token (default ".concat(DEFAULT_MAP_URL, ")")].join('\n');
46
+ }
47
+ function parseArgs(argv) {
48
+ var options = {};
49
+ for (var i = 0; i < argv.length; i++) {
50
+ var arg = argv[i];
51
+ if (arg === '--help' || arg === '-h') {
52
+ options.help = true;
53
+ } else if (arg === '--port') {
54
+ var value = Number(argv[++i]);
55
+ if (!Number.isInteger(value) || value < 0 || value > 65535) {
56
+ throw new Error("Invalid --port value: ".concat(argv[i]));
57
+ }
58
+ options.port = value;
59
+ } else if (arg === '--host') {
60
+ options.host = argv[++i];
61
+ } else if (arg === '--map-url') {
62
+ options.mapUrl = argv[++i];
63
+ } else {
64
+ throw new Error("Unknown argument: ".concat(arg));
65
+ }
66
+ }
67
+ return options;
68
+ }
69
+ function main() {
70
+ return _main.apply(this, arguments);
71
+ }
72
+ function _main() {
73
+ _main = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
74
+ var options, bridge, started, server, shutdown;
75
+ return _regeneratorRuntime.wrap(function _callee4$(_context4) {
76
+ while (1) switch (_context4.prev = _context4.next) {
77
+ case 0:
78
+ options = parseArgs(process.argv.slice(2));
79
+ if (!options.help) {
80
+ _context4.next = 4;
81
+ break;
82
+ }
83
+ console.error(usage());
84
+ return _context4.abrupt("return");
85
+ case 4:
86
+ bridge = new KeplerMcpBridge(options);
87
+ _context4.next = 7;
88
+ return bridge.start();
89
+ case 7:
90
+ started = _context4.sent;
91
+ server = new Server({
92
+ name: 'kepler-mcp',
93
+ version: readVersion()
94
+ }, {
95
+ capabilities: {
96
+ tools: {}
97
+ }
98
+ });
99
+ server.setRequestHandler(ListToolsRequestSchema, /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
100
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
101
+ while (1) switch (_context.prev = _context.next) {
102
+ case 0:
103
+ return _context.abrupt("return", {
104
+ tools: bridge.getTools().map(function (tool) {
105
+ return {
106
+ name: tool.name,
107
+ description: tool.description,
108
+ inputSchema: tool.inputSchema
109
+ };
110
+ })
111
+ });
112
+ case 1:
113
+ case "end":
114
+ return _context.stop();
115
+ }
116
+ }, _callee);
117
+ })));
118
+ server.setRequestHandler(CallToolRequestSchema, /*#__PURE__*/function () {
119
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(request) {
120
+ var _request$params, name, args, result, _formatResult, text, isError;
121
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
122
+ while (1) switch (_context2.prev = _context2.next) {
123
+ case 0:
124
+ _request$params = request.params, name = _request$params.name, args = _request$params.arguments;
125
+ _context2.prev = 1;
126
+ _context2.next = 4;
127
+ return bridge.callTool(name, args !== null && args !== void 0 ? args : {});
128
+ case 4:
129
+ result = _context2.sent;
130
+ _formatResult = formatResult(result), text = _formatResult.text, isError = _formatResult.isError;
131
+ return _context2.abrupt("return", _objectSpread({
132
+ content: [{
133
+ type: 'text',
134
+ text: text
135
+ }]
136
+ }, isError ? {
137
+ isError: true
138
+ } : {}));
139
+ case 9:
140
+ _context2.prev = 9;
141
+ _context2.t0 = _context2["catch"](1);
142
+ return _context2.abrupt("return", {
143
+ content: [{
144
+ type: 'text',
145
+ text: _context2.t0 instanceof Error ? _context2.t0.message : String(_context2.t0)
146
+ }],
147
+ isError: true
148
+ });
149
+ case 12:
150
+ case "end":
151
+ return _context2.stop();
152
+ }
153
+ }, _callee2, null, [[1, 9]]);
154
+ }));
155
+ return function (_x) {
156
+ return _ref2.apply(this, arguments);
157
+ };
158
+ }());
159
+ shutdown = /*#__PURE__*/function () {
160
+ var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
161
+ return _regeneratorRuntime.wrap(function _callee3$(_context3) {
162
+ while (1) switch (_context3.prev = _context3.next) {
163
+ case 0:
164
+ _context3.next = 2;
165
+ return bridge.close();
166
+ case 2:
167
+ process.exit(0);
168
+ case 3:
169
+ case "end":
170
+ return _context3.stop();
171
+ }
172
+ }, _callee3);
173
+ }));
174
+ return function shutdown() {
175
+ return _ref3.apply(this, arguments);
176
+ };
177
+ }();
178
+ process.on('SIGINT', shutdown);
179
+ process.on('SIGTERM', shutdown);
180
+ _context4.next = 16;
181
+ return server.connect(new StdioServerTransport());
182
+ case 16:
183
+ console.error("[kepler-mcp] bridge listening on ws://".concat(started.host, ":").concat(started.port, "/ws"));
184
+ console.error("[kepler-mcp] open http://".concat(started.host, ":").concat(started.port, "/ in a browser \u2014 it redirects ") + 'to the map page with the token — so the agent can drive the map');
185
+ console.error("[kepler-mcp] or open ".concat(started.pageUrl));
186
+ case 19:
187
+ case "end":
188
+ return _context4.stop();
189
+ }
190
+ }, _callee4);
191
+ }));
192
+ return _main.apply(this, arguments);
193
+ }
194
+ main()["catch"](function (error) {
195
+ console.error("[kepler-mcp] ".concat(error instanceof Error ? error.message : String(error)));
196
+ process.exit(1);
197
+ });
198
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZGVmaW5lUHJvcGVydHkiLCJfYXN5bmNUb0dlbmVyYXRvciIsIm93bktleXMiLCJlIiwiciIsInQiLCJPYmplY3QiLCJrZXlzIiwiZ2V0T3duUHJvcGVydHlTeW1ib2xzIiwibyIsImZpbHRlciIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsImVudW1lcmFibGUiLCJwdXNoIiwiYXBwbHkiLCJfb2JqZWN0U3ByZWFkIiwiYXJndW1lbnRzIiwibGVuZ3RoIiwiZm9yRWFjaCIsImdldE93blByb3BlcnR5RGVzY3JpcHRvcnMiLCJkZWZpbmVQcm9wZXJ0aWVzIiwiZGVmaW5lUHJvcGVydHkiLCJfcmVnZW5lcmF0b3JSdW50aW1lIiwicmVhZEZpbGVTeW5jIiwiZGlybmFtZSIsImpvaW4iLCJTZXJ2ZXIiLCJTdGRpb1NlcnZlclRyYW5zcG9ydCIsIkNhbGxUb29sUmVxdWVzdFNjaGVtYSIsIkxpc3RUb29sc1JlcXVlc3RTY2hlbWEiLCJLZXBsZXJNY3BCcmlkZ2UiLCJmb3JtYXRSZXN1bHQiLCJERUZBVUxUX01BUF9VUkwiLCJyZWFkVmVyc2lvbiIsIl9fZGlybmFtZSIsImRpcmVjdG9yeSIsImRlcHRoIiwibWFuaWZlc3QiLCJKU09OIiwicGFyc2UiLCJuYW1lIiwidmVyc2lvbiIsIl91bnVzZWQiLCJ1c2FnZSIsImNvbmNhdCIsInBhcnNlQXJncyIsImFyZ3YiLCJvcHRpb25zIiwiaSIsImFyZyIsImhlbHAiLCJ2YWx1ZSIsIk51bWJlciIsImlzSW50ZWdlciIsIkVycm9yIiwicG9ydCIsImhvc3QiLCJtYXBVcmwiLCJtYWluIiwiX21haW4iLCJtYXJrIiwiX2NhbGxlZTQiLCJicmlkZ2UiLCJzdGFydGVkIiwic2VydmVyIiwic2h1dGRvd24iLCJ3cmFwIiwiX2NhbGxlZTQkIiwiX2NvbnRleHQ0IiwicHJldiIsIm5leHQiLCJwcm9jZXNzIiwic2xpY2UiLCJjb25zb2xlIiwiZXJyb3IiLCJhYnJ1cHQiLCJzdGFydCIsInNlbnQiLCJjYXBhYmlsaXRpZXMiLCJ0b29scyIsInNldFJlcXVlc3RIYW5kbGVyIiwiX2NhbGxlZSIsIl9jYWxsZWUkIiwiX2NvbnRleHQiLCJnZXRUb29scyIsIm1hcCIsInRvb2wiLCJkZXNjcmlwdGlvbiIsImlucHV0U2NoZW1hIiwic3RvcCIsIl9yZWYyIiwiX2NhbGxlZTIiLCJyZXF1ZXN0IiwiX3JlcXVlc3QkcGFyYW1zIiwiYXJncyIsInJlc3VsdCIsIl9mb3JtYXRSZXN1bHQiLCJ0ZXh0IiwiaXNFcnJvciIsIl9jYWxsZWUyJCIsIl9jb250ZXh0MiIsInBhcmFtcyIsImNhbGxUb29sIiwiY29udGVudCIsInR5cGUiLCJ0MCIsIm1lc3NhZ2UiLCJTdHJpbmciLCJfeCIsIl9yZWYzIiwiX2NhbGxlZTMiLCJfY2FsbGVlMyQiLCJfY29udGV4dDMiLCJjbG9zZSIsImV4aXQiLCJvbiIsImNvbm5lY3QiLCJwYWdlVXJsIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZlci9zdGRpby50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIjIS91c3IvYmluL2VudiBub2RlXG5cbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVRcbi8vIENvcHlyaWdodCBjb250cmlidXRvcnMgdG8gdGhlIGtlcGxlci5nbCBwcm9qZWN0XG5cbi8qKlxuICogYGtlcGxlci1tY3BgIOKAlCBhIHN0ZGlvIE1DUCBzZXJ2ZXIgZm9yIHRoZSBrZXBsZXIuZ2wgbWFwIHN1cmZhY2UuXG4gKlxuICogVGhlIGFnZW50IHN0YXJ0cyB0aGlzIHByb2Nlc3MgKGl0IHNwZWFrcyBNQ1Agb24gc3RkaW4vc3Rkb3V0KTsgdGhlIHByb2Nlc3NcbiAqIGFsc28gbGlzdGVucyBmb3IgdGhlIG1hcCBwYWdlIG9uIGEgbG9vcGJhY2sgV2ViU29ja2V0LiBJdCBwcmludHMgYSBVUkwgdGhhdFxuICogY2FycmllcyB0aGUgb25lLXRpbWUgdG9rZW4g4oCUIG9wZW4gdGhhdCBVUkwgYW5kIHRoZSBwYWdlIGNvbm5lY3RzLCBhZnRlciB3aGljaFxuICogZXZlcnkgbWFwLiogdG9vbCBjYWxsIGV4ZWN1dGVzIGFnYWluc3QgdGhlIGxpdmUgbWFwLlxuICpcbiAqIHN0ZG91dCBiZWxvbmdzIHRvIHRoZSBNQ1AgcHJvdG9jb2w6IGV2ZXJ5IGxvZyBsaW5lIGhlcmUgZ29lcyB0byBzdGRlcnIuXG4gKi9cblxuaW1wb3J0IHtyZWFkRmlsZVN5bmN9IGZyb20gJ25vZGU6ZnMnO1xuaW1wb3J0IHtkaXJuYW1lLCBqb2lufSBmcm9tICdub2RlOnBhdGgnO1xuaW1wb3J0IHtTZXJ2ZXJ9IGZyb20gJ0Btb2RlbGNvbnRleHRwcm90b2NvbC9zZGsvc2VydmVyL2luZGV4LmpzJztcbmltcG9ydCB7U3RkaW9TZXJ2ZXJUcmFuc3BvcnR9IGZyb20gJ0Btb2RlbGNvbnRleHRwcm90b2NvbC9zZGsvc2VydmVyL3N0ZGlvLmpzJztcbmltcG9ydCB7Q2FsbFRvb2xSZXF1ZXN0U2NoZW1hLCBMaXN0VG9vbHNSZXF1ZXN0U2NoZW1hfSBmcm9tICdAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3R5cGVzLmpzJztcbmltcG9ydCB7S2VwbGVyTWNwQnJpZGdlLCBmb3JtYXRSZXN1bHR9IGZyb20gJy4vYnJpZGdlLXNlcnZlcic7XG5pbXBvcnQgdHlwZSB7S2VwbGVyTWNwQnJpZGdlT3B0aW9uc30gZnJvbSAnLi9icmlkZ2Utc2VydmVyJztcblxuY29uc3QgREVGQVVMVF9NQVBfVVJMID0gJ2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MCc7XG5cbmZ1bmN0aW9uIHJlYWRWZXJzaW9uKCk6IHN0cmluZyB7XG4gIGlmICh0eXBlb2YgX19kaXJuYW1lID09PSAndW5kZWZpbmVkJykgcmV0dXJuICcwLjAuMCc7XG4gIGxldCBkaXJlY3RvcnkgPSBfX2Rpcm5hbWU7XG4gIC8vIFdhbGsgdXAgdW50aWwgdGhlIHBhY2thZ2UgbWFuaWZlc3QgaXMgZm91bmQsIHNvIHRoaXMgd29ya3MgYm90aCBmcm9tIHNyYy9cbiAgLy8gKGJhYmVsLW5vZGUsIHRlc3RzKSBhbmQgZnJvbSBkaXN0L2Nqcy9zZXJ2ZXIgKHRoZSBwdWJsaXNoZWQgYmluKS5cbiAgZm9yIChsZXQgZGVwdGggPSAwOyBkZXB0aCA8IDU7IGRlcHRoKyspIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhqb2luKGRpcmVjdG9yeSwgJ3BhY2thZ2UuanNvbicpLCAndXRmOCcpKTtcbiAgICAgIGlmIChtYW5pZmVzdC5uYW1lID09PSAnQGtlcGxlci5nbC9tY3AnKSByZXR1cm4gbWFuaWZlc3QudmVyc2lvbjtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIG5vIG1hbmlmZXN0IGF0IHRoaXMgbGV2ZWwg4oCUIGtlZXAgd2Fsa2luZ1xuICAgIH1cbiAgICBkaXJlY3RvcnkgPSBkaXJuYW1lKGRpcmVjdG9yeSk7XG4gIH1cbiAgcmV0dXJuICcwLjAuMCc7XG59XG5cbmZ1bmN0aW9uIHVzYWdlKCk6IHN0cmluZyB7XG4gIHJldHVybiBbXG4gICAgJ1VzYWdlOiBrZXBsZXItbWNwIFstLXBvcnQgPG4+XSBbLS1ob3N0IDxoPl0gWy0tbWFwLXVybCA8dXJsPl0nLFxuICAgICcnLFxuICAgICdSdW5zIGEgc3RkaW8gTUNQIHNlcnZlciBmb3IgdGhlIGtlcGxlci5nbCBtYXAgc3VyZmFjZSBhbmQgd2FpdHMgZm9yIGEnLFxuICAgICdrZXBsZXIuZ2wgcGFnZSB0byBjb25uZWN0IG92ZXIgYSBsb29wYmFjayBXZWJTb2NrZXQuJyxcbiAgICAnJyxcbiAgICAnICAtLXBvcnQgPG4+ICAgICAgIFdlYlNvY2tldCBwb3J0IGZvciB0aGUgcGFnZSAoZGVmYXVsdCA4NzY1KScsXG4gICAgJyAgLS1ob3N0IDxoPiAgICAgICBsb29wYmFjayBob3N0IHRvIGJpbmQgKGRlZmF1bHQgMTI3LjAuMC4xKScsXG4gICAgYCAgLS1tYXAtdXJsIDx1cmw+ICBwYWdlIFVSTCBwcmludGVkIHdpdGggdGhlIHRva2VuIChkZWZhdWx0ICR7REVGQVVMVF9NQVBfVVJMfSlgXG4gIF0uam9pbignXFxuJyk7XG59XG5cbmZ1bmN0aW9uIHBhcnNlQXJncyhhcmd2OiBzdHJpbmdbXSk6IEtlcGxlck1jcEJyaWRnZU9wdGlvbnMgJiB7aGVscD86IGJvb2xlYW59IHtcbiAgY29uc3Qgb3B0aW9uczogS2VwbGVyTWNwQnJpZGdlT3B0aW9ucyAmIHtoZWxwPzogYm9vbGVhbn0gPSB7fTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmd2Lmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgYXJnID0gYXJndltpXTtcbiAgICBpZiAoYXJnID09PSAnLS1oZWxwJyB8fCBhcmcgPT09ICctaCcpIHtcbiAgICAgIG9wdGlvbnMuaGVscCA9IHRydWU7XG4gICAgfSBlbHNlIGlmIChhcmcgPT09ICctLXBvcnQnKSB7XG4gICAgICBjb25zdCB2YWx1ZSA9IE51bWJlcihhcmd2WysraV0pO1xuICAgICAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHZhbHVlKSB8fCB2YWx1ZSA8IDAgfHwgdmFsdWUgPiA2NTUzNSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgLS1wb3J0IHZhbHVlOiAke2FyZ3ZbaV19YCk7XG4gICAgICB9XG4gICAgICBvcHRpb25zLnBvcnQgPSB2YWx1ZTtcbiAgICB9IGVsc2UgaWYgKGFyZyA9PT0gJy0taG9zdCcpIHtcbiAgICAgIG9wdGlvbnMuaG9zdCA9IGFyZ3ZbKytpXTtcbiAgICB9IGVsc2UgaWYgKGFyZyA9PT0gJy0tbWFwLXVybCcpIHtcbiAgICAgIG9wdGlvbnMubWFwVXJsID0gYXJndlsrK2ldO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gYXJndW1lbnQ6ICR7YXJnfWApO1xuICAgIH1cbiAgfVxuICByZXR1cm4gb3B0aW9ucztcbn1cblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3Qgb3B0aW9ucyA9IHBhcnNlQXJncyhwcm9jZXNzLmFyZ3Yuc2xpY2UoMikpO1xuICBpZiAob3B0aW9ucy5oZWxwKSB7XG4gICAgY29uc29sZS5lcnJvcih1c2FnZSgpKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBicmlkZ2UgPSBuZXcgS2VwbGVyTWNwQnJpZGdlKG9wdGlvbnMpO1xuICBjb25zdCBzdGFydGVkID0gYXdhaXQgYnJpZGdlLnN0YXJ0KCk7XG5cbiAgY29uc3Qgc2VydmVyID0gbmV3IFNlcnZlcihcbiAgICB7bmFtZTogJ2tlcGxlci1tY3AnLCB2ZXJzaW9uOiByZWFkVmVyc2lvbigpfSxcbiAgICB7Y2FwYWJpbGl0aWVzOiB7dG9vbHM6IHt9fX1cbiAgKTtcblxuICBzZXJ2ZXIuc2V0UmVxdWVzdEhhbmRsZXIoTGlzdFRvb2xzUmVxdWVzdFNjaGVtYSwgYXN5bmMgKCkgPT4gKHtcbiAgICB0b29sczogYnJpZGdlLmdldFRvb2xzKCkubWFwKHRvb2wgPT4gKHtcbiAgICAgIG5hbWU6IHRvb2wubmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiB0b29sLmRlc2NyaXB0aW9uLFxuICAgICAgaW5wdXRTY2hlbWE6IHRvb2wuaW5wdXRTY2hlbWEgYXMge3R5cGU6ICdvYmplY3QnOyBba2V5OiBzdHJpbmddOiB1bmtub3dufVxuICAgIH0pKVxuICB9KSk7XG5cbiAgc2VydmVyLnNldFJlcXVlc3RIYW5kbGVyKENhbGxUb29sUmVxdWVzdFNjaGVtYSwgYXN5bmMgcmVxdWVzdCA9PiB7XG4gICAgY29uc3Qge25hbWUsIGFyZ3VtZW50czogYXJnc30gPSByZXF1ZXN0LnBhcmFtcztcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYnJpZGdlLmNhbGxUb29sKG5hbWUsIChhcmdzID8/IHt9KSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik7XG4gICAgICBjb25zdCB7dGV4dCwgaXNFcnJvcn0gPSBmb3JtYXRSZXN1bHQocmVzdWx0KTtcbiAgICAgIHJldHVybiB7Y29udGVudDogW3t0eXBlOiAndGV4dCcgYXMgY29uc3QsIHRleHR9XSwgLi4uKGlzRXJyb3IgPyB7aXNFcnJvcjogdHJ1ZX0gOiB7fSl9O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBjb250ZW50OiBbXG4gICAgICAgICAge3R5cGU6ICd0ZXh0JyBhcyBjb25zdCwgdGV4dDogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfVxuICAgICAgICBdLFxuICAgICAgICBpc0Vycm9yOiB0cnVlXG4gICAgICB9O1xuICAgIH1cbiAgfSk7XG5cbiAgY29uc3Qgc2h1dGRvd24gPSBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgYnJpZGdlLmNsb3NlKCk7XG4gICAgcHJvY2Vzcy5leGl0KDApO1xuICB9O1xuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBzaHV0ZG93bik7XG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCBzaHV0ZG93bik7XG5cbiAgYXdhaXQgc2VydmVyLmNvbm5lY3QobmV3IFN0ZGlvU2VydmVyVHJhbnNwb3J0KCkpO1xuXG4gIGNvbnNvbGUuZXJyb3IoYFtrZXBsZXItbWNwXSBicmlkZ2UgbGlzdGVuaW5nIG9uIHdzOi8vJHtzdGFydGVkLmhvc3R9OiR7c3RhcnRlZC5wb3J0fS93c2ApO1xuICBjb25zb2xlLmVycm9yKFxuICAgIGBba2VwbGVyLW1jcF0gb3BlbiBodHRwOi8vJHtzdGFydGVkLmhvc3R9OiR7c3RhcnRlZC5wb3J0fS8gaW4gYSBicm93c2VyIOKAlCBpdCByZWRpcmVjdHMgYCArXG4gICAgICAndG8gdGhlIG1hcCBwYWdlIHdpdGggdGhlIHRva2VuIOKAlCBzbyB0aGUgYWdlbnQgY2FuIGRyaXZlIHRoZSBtYXAnXG4gICk7XG4gIGNvbnNvbGUuZXJyb3IoYFtrZXBsZXItbWNwXSBvciBvcGVuICR7c3RhcnRlZC5wYWdlVXJsfWApO1xufVxuXG5tYWluKCkuY2F0Y2goZXJyb3IgPT4ge1xuICBjb25zb2xlLmVycm9yKGBba2VwbGVyLW1jcF0gJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCk7XG4g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
@@ -0,0 +1,24 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright contributors to the kepler.gl project
3
+
4
+ /**
5
+ * Shared contract types for the kepler.gl map surface.
6
+ *
7
+ * This module is the home of the reusable *map surface* contract — the map.*
8
+ * tool namespace that any AI client can drive. It defines the map.* tool ids
9
+ * and the `ToolResult` shape so any host (the demo-app browser page, the
10
+ * kepler-assistant library, or a future MCP server) can implement or consume
11
+ * the same contract.
12
+ */
13
+
14
+ /** A command/tool execution result. */
15
+
16
+ /**
17
+ * The v1 map tool surface. These are the command ids the kepler.gl demo-app's
18
+ * assistant actually registers, reconciled with the kepler-mcp proposal. Most
19
+ * commands are pure map actuation (set-basemap, add-layer, ...); the table ops
20
+ * (map.create-table, map.add-column, map.save-data) are DuckDB-backed and are
21
+ * included because they mutate the map's datasets in place.
22
+ */
23
+ export var MAP_TOOL_IDS = ['map.set-basemap', 'map.get-boundary', 'map.add-layer', 'map.update-layer-color', 'map.load-data', 'map.save-data', 'map.create-table', 'map.add-column', 'map.add-time-filter', 'map.toggle-time-filter', 'map.split-view', 'map.get-dataset-context'];
24
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNQVBfVE9PTF9JRFMiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvdHlwZXMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVFxuLy8gQ29weXJpZ2h0IGNvbnRyaWJ1dG9ycyB0byB0aGUga2VwbGVyLmdsIHByb2plY3RcblxuLyoqXG4gKiBTaGFyZWQgY29udHJhY3QgdHlwZXMgZm9yIHRoZSBrZXBsZXIuZ2wgbWFwIHN1cmZhY2UuXG4gKlxuICogVGhpcyBtb2R1bGUgaXMgdGhlIGhvbWUgb2YgdGhlIHJldXNhYmxlICptYXAgc3VyZmFjZSogY29udHJhY3Qg4oCUIHRoZSBtYXAuKlxuICogdG9vbCBuYW1lc3BhY2UgdGhhdCBhbnkgQUkgY2xpZW50IGNhbiBkcml2ZS4gSXQgZGVmaW5lcyB0aGUgbWFwLiogdG9vbCBpZHNcbiAqIGFuZCB0aGUgYFRvb2xSZXN1bHRgIHNoYXBlIHNvIGFueSBob3N0ICh0aGUgZGVtby1hcHAgYnJvd3NlciBwYWdlLCB0aGVcbiAqIGtlcGxlci1hc3Npc3RhbnQgbGlicmFyeSwgb3IgYSBmdXR1cmUgTUNQIHNlcnZlcikgY2FuIGltcGxlbWVudCBvciBjb25zdW1lXG4gKiB0aGUgc2FtZSBjb250cmFjdC5cbiAqL1xuXG4vKiogQSBjb21tYW5kL3Rvb2wgZXhlY3V0aW9uIHJlc3VsdC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVG9vbFJlc3VsdCB7XG4gIHN1Y2Nlc3M6IGJvb2xlYW47XG4gIGRhdGE/OiB1bmtub3duO1xuICBlcnJvcj86IHN0cmluZztcbn1cblxuLyoqXG4gKiBUaGUgdjEgbWFwIHRvb2wgc3VyZmFjZS4gVGhlc2UgYXJlIHRoZSBjb21tYW5kIGlkcyB0aGUga2VwbGVyLmdsIGRlbW8tYXBwJ3NcbiAqIGFzc2lzdGFudCBhY3R1YWxseSByZWdpc3RlcnMsIHJlY29uY2lsZWQgd2l0aCB0aGUga2VwbGVyLW1jcCBwcm9wb3NhbC4gTW9zdFxuICogY29tbWFuZHMgYXJlIHB1cmUgbWFwIGFjdHVhdGlvbiAoc2V0LWJhc2VtYXAsIGFkZC1sYXllciwgLi4uKTsgdGhlIHRhYmxlIG9wc1xuICogKG1hcC5jcmVhdGUtdGFibGUsIG1hcC5hZGQtY29sdW1uLCBtYXAuc2F2ZS1kYXRhKSBhcmUgRHVja0RCLWJhY2tlZCBhbmQgYXJlXG4gKiBpbmNsdWRlZCBiZWNhdXNlIHRoZXkgbXV0YXRlIHRoZSBtYXAncyBkYXRhc2V0cyBpbiBwbGFjZS5cbiAqL1xuZXhwb3J0IGNvbnN0IE1BUF9UT09MX0lEUyA9IFtcbiAgJ21hcC5zZXQtYmFzZW1hcCcsXG4gICdtYXAuZ2V0LWJvdW5kYXJ5JyxcbiAgJ21hcC5hZGQtbGF5ZXInLFxuICAnbWFwLnVwZGF0ZS1sYXllci1jb2xvcicsXG4gICdtYXAubG9hZC1kYXRhJyxcbiAgJ21hcC5zYXZlLWRhdGEnLFxuICAnbWFwLmNyZWF0ZS10YWJsZScsXG4gICdtYXAuYWRkLWNvbHVtbicsXG4gICdtYXAuYWRkLXRpbWUtZmlsdGVyJyxcbiAgJ21hcC50b2dnbGUtdGltZS1maWx0ZXInLFxuICAnbWFwLnNwbGl0LXZpZXcnLFxuICAnbWFwLmdldC1kYXRhc2V0LWNvbnRleHQnXG5dIGFzIGNvbnN0O1xuXG5leHBvcnQgdHlwZSBNYXBUb29sSWQgPSAodHlwZW9mIE1BUF9UT09MX0lEUylbbnVtYmVyXTtcbiJdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPLElBQU1BLFlBQVksR0FBRyxDQUMxQixpQkFBaUIsRUFDakIsa0JBQWtCLEVBQ2xCLGVBQWUsRUFDZix3QkFBd0IsRUFDeEIsZUFBZSxFQUNmLGVBQWUsRUFDZixrQkFBa0IsRUFDbEIsZ0JBQWdCLEVBQ2hCLHFCQUFxQixFQUNyQix3QkFBd0IsRUFDeEIsZ0JBQWdCLEVBQ2hCLHlCQUF5QixDQUNqQiIsImlnbm9yZUxpc3QiOltdfQ==
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @kepler.gl/mcp — the kepler.gl map surface.
3
+ *
4
+ * Only the map contract + the map.* commands live here, plus dependency-light
5
+ * helper utilities (e.g. `commands/utils.ts`) that hosts are meant to reuse.
6
+ * No analysis and no app-specific wiring glue — those belong to
7
+ * kepler-assistant, which imports this package for the commands and implements
8
+ * the `KeplerContext` glue seam.
9
+ *
10
+ * This root entry stays browser-safe. The stdio MCP server (which needs `ws`
11
+ * and Node APIs) lives in the `./server` subpath and is never imported here.
12
+ */
13
+ export * from './map-contract';
14
+ export * from './types';
15
+ export * from './commands';
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The kepler.gl map tool contract — the "map surface".
3
+ *
4
+ * kepler.gl's contract is "accept data, actuate the map, introspect, render."
5
+ * The surface is map-focused: no spatial analysis and no charts — those belong
6
+ * to the analysis service (kepler-assistant). A few table ops (map.create-table,
7
+ * map.add-column, map.save-data) are DuckDB-backed and mutate the map's datasets
8
+ * in place; they are part of the surface because they change what the map shows.
9
+ *
10
+ * This module is intentionally dependency-light. It defines the map.* tool ids
11
+ * and a `MapContract` interface so any host (the demo-app browser page, the
12
+ * kepler-assistant library, or a future MCP server) can implement or consume
13
+ * the same contract.
14
+ */
15
+ import type { MapToolId, ToolResult } from './types';
16
+ /**
17
+ * The map tool surface. Mostly pure map actuation (set-basemap, add-layer, ...);
18
+ * a few table ops (map.create-table, map.add-column, map.save-data) are included
19
+ * because they mutate the map's datasets in place.
20
+ */
21
+ export interface MapContract {
22
+ readonly toolIds: readonly MapToolId[];
23
+ /** List the tools this surface exposes (id + input JSON Schema, if known). */
24
+ listTools(): Array<{
25
+ id: MapToolId;
26
+ inputSchema?: unknown;
27
+ description?: string;
28
+ }>;
29
+ /** Execute a map tool. Returns a trimmed, model-facing result. */
30
+ callTool(id: MapToolId, input: Record<string, unknown>): Promise<ToolResult>;
31
+ }
@@ -0,0 +1,53 @@
1
+ import type { RoomCommandResult } from '../commands/types';
2
+ export type MapTool = {
3
+ /** MCP tool name, e.g. `map_add_layer` (dots are not allowed in tool names). */
4
+ name: string;
5
+ /** The `map.*` command id the call is forwarded to. */
6
+ commandId: string;
7
+ description: string;
8
+ inputSchema: Record<string, unknown>;
9
+ };
10
+ export type KeplerMcpBridgeOptions = {
11
+ port?: number;
12
+ host?: string;
13
+ /** Base URL of the map page, printed with the token. */
14
+ mapUrl?: string;
15
+ callTimeoutMs?: number;
16
+ };
17
+ export type KeplerMcpBridgeStart = {
18
+ host: string;
19
+ port: number;
20
+ token: string;
21
+ /** What a human should open: `<mapUrl>?mcp=<token>`. */
22
+ pageUrl: string;
23
+ };
24
+ /** MCP tool names are commonly restricted to [A-Za-z0-9_-]; `map.add-layer` → `map_add_layer`. */
25
+ export declare function toToolName(commandId: string): string;
26
+ /** The map surface as declared by this package, independent of any page. */
27
+ export declare function getMapTools(): MapTool[];
28
+ /** RoomCommandResult → the text an MCP client shows for a tool call. */
29
+ export declare function formatResult(result: RoomCommandResult): {
30
+ text: string;
31
+ isError: boolean;
32
+ };
33
+ export declare class KeplerMcpBridge {
34
+ private readonly options;
35
+ private readonly staticTools;
36
+ private pageTools;
37
+ private socket;
38
+ private wss;
39
+ private httpServer;
40
+ private readonly pending;
41
+ private token;
42
+ private pageUrl;
43
+ constructor(options?: KeplerMcpBridgeOptions);
44
+ /** Tools the MCP client can call right now. */
45
+ getTools(): MapTool[];
46
+ get connected(): boolean;
47
+ start(): Promise<KeplerMcpBridgeStart>;
48
+ callTool(name: string, input?: Record<string, unknown>): Promise<RoomCommandResult>;
49
+ close(): Promise<void>;
50
+ private handleConnection;
51
+ private handleMessage;
52
+ private rejectPending;
53
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Server-side entry point of `@kepler.gl/mcp`.
3
+ *
4
+ * Browser bundles must not import this module: it pulls in `ws` and Node APIs.
5
+ * The map contracts and commands stay in the package root; this subpath is for
6
+ * the stdio MCP server (`kepler-mcp`) and for tests.
7
+ */
8
+ export { KeplerMcpBridge, formatResult, getMapTools, toToolName } from './bridge-server';
9
+ export type { KeplerMcpBridgeOptions, KeplerMcpBridgeStart, MapTool } from './bridge-server';
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Shared contract types for the kepler.gl map surface.
3
+ *
4
+ * This module is the home of the reusable *map surface* contract — the map.*
5
+ * tool namespace that any AI client can drive. It defines the map.* tool ids
6
+ * and the `ToolResult` shape so any host (the demo-app browser page, the
7
+ * kepler-assistant library, or a future MCP server) can implement or consume
8
+ * the same contract.
9
+ */
10
+ /** A command/tool execution result. */
11
+ export interface ToolResult {
12
+ success: boolean;
13
+ data?: unknown;
14
+ error?: string;
15
+ }
16
+ /**
17
+ * The v1 map tool surface. These are the command ids the kepler.gl demo-app's
18
+ * assistant actually registers, reconciled with the kepler-mcp proposal. Most
19
+ * commands are pure map actuation (set-basemap, add-layer, ...); the table ops
20
+ * (map.create-table, map.add-column, map.save-data) are DuckDB-backed and are
21
+ * included because they mutate the map's datasets in place.
22
+ */
23
+ export declare const MAP_TOOL_IDS: readonly ["map.set-basemap", "map.get-boundary", "map.add-layer", "map.update-layer-color", "map.load-data", "map.save-data", "map.create-table", "map.add-column", "map.add-time-filter", "map.toggle-time-filter", "map.split-view", "map.get-dataset-context"];
24
+ export type MapToolId = (typeof MAP_TOOL_IDS)[number];
package/package.json CHANGED
@@ -1,6 +1,86 @@
1
1
  {
2
2
  "name": "@kepler.gl/mcp",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "author": "Shan He <heshan0131@gmail.com>",
4
+ "version": "3.3.0-alpha.19",
5
+ "description": "The kepler.gl map surface for AI agents: map.* commands, command contract + JSON Schemas + types, a stdio MCP server that bridges to an open kepler.gl page, and the kepler map-management skill",
6
+ "license": "MIT",
7
+ "main": "dist/cjs/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "bin": {
10
+ "kepler-mcp": "dist/cjs/server/stdio.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/esm/index.js",
16
+ "require": "./dist/cjs/index.js",
17
+ "default": "./dist/cjs/index.js"
18
+ },
19
+ "./server": {
20
+ "types": "./dist/server/index.d.ts",
21
+ "import": "./dist/esm/server/index.js",
22
+ "require": "./dist/cjs/server/index.js",
23
+ "default": "./dist/cjs/server/index.js"
24
+ },
25
+ "./skill/kepler/SKILL.md": "./skill/kepler/SKILL.md",
26
+ "./skill/kepler/skill.yaml": "./skill/kepler/skill.yaml"
27
+ },
28
+ "keywords": [
29
+ "kepler",
30
+ "kepler.gl",
31
+ "map",
32
+ "mcp",
33
+ "ai"
34
+ ],
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/keplergl/kepler.gl.git"
38
+ },
39
+ "scripts": {
40
+ "build": "rm -fr dist && babel src --out-dir dist/cjs --source-maps inline --extensions '.ts,.tsx,.js,.jsx' --ignore '**/*.d.ts,**/*.spec.ts,**/*.test.ts' && BABEL_ENV=esm babel src --out-dir dist/esm --source-maps inline --extensions '.ts,.tsx,.js,.jsx' --ignore '**/*.d.ts,**/*.spec.ts,**/*.test.ts'",
41
+ "build:types": "tsc --project ./tsconfig.production.json",
42
+ "prepublishOnly": "babel-node ../../scripts/license-header/bin --license ../../FILE-HEADER && yarn build && yarn build:types",
43
+ "stab": "mkdir -p dist/cjs dist/esm && echo \"'use strict'; Object.assign(module.exports, require('../../src'));\" > dist/cjs/index.js && echo \"export * from '../../src';\" > dist/esm/index.js"
44
+ },
45
+ "files": [
46
+ "dist",
47
+ "skill"
48
+ ],
49
+ "dependencies": {
50
+ "@kepler.gl/actions": "3.3.0-alpha.19",
51
+ "@kepler.gl/constants": "3.3.0-alpha.19",
52
+ "@kepler.gl/layers": "3.3.0-alpha.19",
53
+ "@kepler.gl/processors": "3.3.0-alpha.19",
54
+ "@kepler.gl/reducers": "3.3.0-alpha.19",
55
+ "@kepler.gl/table": "3.3.0-alpha.19",
56
+ "@kepler.gl/types": "3.3.0-alpha.19",
57
+ "@modelcontextprotocol/sdk": "^1.32.2",
58
+ "apache-arrow": "^17.0.0",
59
+ "ws": "^8.22.0",
60
+ "zod": "^4.4.0"
61
+ },
62
+ "devDependencies": {
63
+ "@babel/cli": "^7.12.1",
64
+ "@babel/node": "^7.12.1",
65
+ "@types/ws": "^8.18.2"
66
+ },
67
+ "nyc": {
68
+ "sourceMap": false,
69
+ "instrument": false
70
+ },
71
+ "maintainers": [
72
+ "Shan He <heshan0131@gmail.com>",
73
+ "Igor Dykhta <dikhta.igor@gmail.com>",
74
+ "Ilya Boyandin <ilya@boyandin.me>",
75
+ "Xun Li <lixun910@gmail.com>"
76
+ ],
77
+ "engines": {
78
+ "node": ">=20"
79
+ },
80
+ "volta": {
81
+ "node": "20.19.3",
82
+ "yarn": "4.4.0"
83
+ },
84
+ "packageManager": "yarn@4.4.0",
85
+ "module": "dist/esm/index.js"
86
+ }