@mapbox/mcp-server 0.15.1 → 0.16.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.
Files changed (131) hide show
  1. package/dist/commonjs/resources/place-photo/PlacePhotoResource.d.ts +57 -0
  2. package/dist/commonjs/resources/place-photo/PlacePhotoResource.d.ts.map +1 -0
  3. package/dist/commonjs/resources/place-photo/PlacePhotoResource.js +202 -0
  4. package/dist/commonjs/resources/place-photo/PlacePhotoResource.js.map +1 -0
  5. package/dist/commonjs/resources/resourceRegistry.d.ts +3 -1
  6. package/dist/commonjs/resources/resourceRegistry.d.ts.map +1 -1
  7. package/dist/commonjs/resources/resourceRegistry.js +5 -0
  8. package/dist/commonjs/resources/resourceRegistry.js.map +1 -1
  9. package/dist/commonjs/resources/tool-response/ToolResponseResource.d.ts +20 -0
  10. package/dist/commonjs/resources/tool-response/ToolResponseResource.d.ts.map +1 -0
  11. package/dist/commonjs/resources/tool-response/ToolResponseResource.js +83 -0
  12. package/dist/commonjs/resources/tool-response/ToolResponseResource.js.map +1 -0
  13. package/dist/commonjs/resources/ui-apps/mapAppHtml.d.ts.map +1 -1
  14. package/dist/commonjs/resources/ui-apps/mapAppHtml.js +484 -11
  15. package/dist/commonjs/resources/ui-apps/mapAppHtml.js.map +1 -1
  16. package/dist/commonjs/tools/category-list-tool/CategoryListTool.d.ts.map +1 -1
  17. package/dist/commonjs/tools/category-list-tool/CategoryListTool.input.schema.js +1 -1
  18. package/dist/commonjs/tools/category-list-tool/CategoryListTool.input.schema.js.map +1 -1
  19. package/dist/commonjs/tools/category-list-tool/CategoryListTool.js +1 -1
  20. package/dist/commonjs/tools/category-list-tool/CategoryListTool.js.map +1 -1
  21. package/dist/commonjs/tools/directions-tool/DirectionsTool.d.ts.map +1 -1
  22. package/dist/commonjs/tools/directions-tool/DirectionsTool.input.schema.js +3 -3
  23. package/dist/commonjs/tools/directions-tool/DirectionsTool.input.schema.js.map +1 -1
  24. package/dist/commonjs/tools/directions-tool/DirectionsTool.js +17 -17
  25. package/dist/commonjs/tools/directions-tool/DirectionsTool.js.map +1 -1
  26. package/dist/commonjs/tools/ground-location-tool/GroundLocationTool.d.ts.map +1 -1
  27. package/dist/commonjs/tools/ground-location-tool/GroundLocationTool.js +1 -1
  28. package/dist/commonjs/tools/ground-location-tool/GroundLocationTool.js.map +1 -1
  29. package/dist/commonjs/tools/isochrone-tool/IsochroneTool.d.ts.map +1 -1
  30. package/dist/commonjs/tools/isochrone-tool/IsochroneTool.js +6 -13
  31. package/dist/commonjs/tools/isochrone-tool/IsochroneTool.js.map +1 -1
  32. package/dist/commonjs/tools/render-map-tool/RenderMapTool.d.ts.map +1 -1
  33. package/dist/commonjs/tools/render-map-tool/RenderMapTool.input.schema.d.ts +4 -0
  34. package/dist/commonjs/tools/render-map-tool/RenderMapTool.input.schema.d.ts.map +1 -1
  35. package/dist/commonjs/tools/render-map-tool/RenderMapTool.input.schema.js +18 -2
  36. package/dist/commonjs/tools/render-map-tool/RenderMapTool.input.schema.js.map +1 -1
  37. package/dist/commonjs/tools/render-map-tool/RenderMapTool.js +9 -5
  38. package/dist/commonjs/tools/render-map-tool/RenderMapTool.js.map +1 -1
  39. package/dist/commonjs/tools/render-map-tool/RenderMapTool.output.schema.d.ts +4 -0
  40. package/dist/commonjs/tools/render-map-tool/RenderMapTool.output.schema.d.ts.map +1 -1
  41. package/dist/commonjs/utils/directionsRef.d.ts +27 -0
  42. package/dist/commonjs/utils/directionsRef.d.ts.map +1 -0
  43. package/dist/commonjs/utils/directionsRef.js +52 -0
  44. package/dist/commonjs/utils/directionsRef.js.map +1 -0
  45. package/dist/commonjs/utils/index.d.ts +6 -0
  46. package/dist/commonjs/utils/index.d.ts.map +1 -1
  47. package/dist/commonjs/utils/index.js +14 -1
  48. package/dist/commonjs/utils/index.js.map +1 -1
  49. package/dist/commonjs/utils/mapAppPayload.d.ts +21 -0
  50. package/dist/commonjs/utils/mapAppPayload.d.ts.map +1 -1
  51. package/dist/commonjs/utils/mapAppPayload.js +5 -1
  52. package/dist/commonjs/utils/mapAppPayload.js.map +1 -1
  53. package/dist/commonjs/utils/responseRef.d.ts +33 -0
  54. package/dist/commonjs/utils/responseRef.d.ts.map +1 -0
  55. package/dist/commonjs/utils/responseRef.js +73 -0
  56. package/dist/commonjs/utils/responseRef.js.map +1 -0
  57. package/dist/commonjs/utils/serverInstructions.d.ts +2 -2
  58. package/dist/commonjs/utils/serverInstructions.js +2 -2
  59. package/dist/commonjs/utils/storeMapPayload.js +1 -1
  60. package/dist/commonjs/utils/storeMapPayload.js.map +1 -1
  61. package/dist/commonjs/utils/urlSafety.d.ts +6 -0
  62. package/dist/commonjs/utils/urlSafety.d.ts.map +1 -1
  63. package/dist/commonjs/utils/urlSafety.js +15 -4
  64. package/dist/commonjs/utils/urlSafety.js.map +1 -1
  65. package/dist/commonjs/version.json +3 -3
  66. package/dist/esm/resources/place-photo/PlacePhotoResource.d.ts +57 -0
  67. package/dist/esm/resources/place-photo/PlacePhotoResource.d.ts.map +1 -0
  68. package/dist/esm/resources/place-photo/PlacePhotoResource.js +198 -0
  69. package/dist/esm/resources/place-photo/PlacePhotoResource.js.map +1 -0
  70. package/dist/esm/resources/resourceRegistry.d.ts +3 -1
  71. package/dist/esm/resources/resourceRegistry.d.ts.map +1 -1
  72. package/dist/esm/resources/resourceRegistry.js +5 -0
  73. package/dist/esm/resources/resourceRegistry.js.map +1 -1
  74. package/dist/esm/resources/tool-response/ToolResponseResource.d.ts +20 -0
  75. package/dist/esm/resources/tool-response/ToolResponseResource.d.ts.map +1 -0
  76. package/dist/esm/resources/tool-response/ToolResponseResource.js +79 -0
  77. package/dist/esm/resources/tool-response/ToolResponseResource.js.map +1 -0
  78. package/dist/esm/resources/ui-apps/mapAppHtml.d.ts.map +1 -1
  79. package/dist/esm/resources/ui-apps/mapAppHtml.js +484 -11
  80. package/dist/esm/resources/ui-apps/mapAppHtml.js.map +1 -1
  81. package/dist/esm/tools/category-list-tool/CategoryListTool.d.ts.map +1 -1
  82. package/dist/esm/tools/category-list-tool/CategoryListTool.input.schema.js +1 -1
  83. package/dist/esm/tools/category-list-tool/CategoryListTool.input.schema.js.map +1 -1
  84. package/dist/esm/tools/category-list-tool/CategoryListTool.js +1 -1
  85. package/dist/esm/tools/category-list-tool/CategoryListTool.js.map +1 -1
  86. package/dist/esm/tools/directions-tool/DirectionsTool.d.ts.map +1 -1
  87. package/dist/esm/tools/directions-tool/DirectionsTool.input.schema.js +3 -3
  88. package/dist/esm/tools/directions-tool/DirectionsTool.input.schema.js.map +1 -1
  89. package/dist/esm/tools/directions-tool/DirectionsTool.js +17 -17
  90. package/dist/esm/tools/directions-tool/DirectionsTool.js.map +1 -1
  91. package/dist/esm/tools/ground-location-tool/GroundLocationTool.d.ts.map +1 -1
  92. package/dist/esm/tools/ground-location-tool/GroundLocationTool.js +1 -1
  93. package/dist/esm/tools/ground-location-tool/GroundLocationTool.js.map +1 -1
  94. package/dist/esm/tools/isochrone-tool/IsochroneTool.d.ts.map +1 -1
  95. package/dist/esm/tools/isochrone-tool/IsochroneTool.js +6 -13
  96. package/dist/esm/tools/isochrone-tool/IsochroneTool.js.map +1 -1
  97. package/dist/esm/tools/render-map-tool/RenderMapTool.d.ts.map +1 -1
  98. package/dist/esm/tools/render-map-tool/RenderMapTool.input.schema.d.ts +4 -0
  99. package/dist/esm/tools/render-map-tool/RenderMapTool.input.schema.d.ts.map +1 -1
  100. package/dist/esm/tools/render-map-tool/RenderMapTool.input.schema.js +18 -2
  101. package/dist/esm/tools/render-map-tool/RenderMapTool.input.schema.js.map +1 -1
  102. package/dist/esm/tools/render-map-tool/RenderMapTool.js +9 -5
  103. package/dist/esm/tools/render-map-tool/RenderMapTool.js.map +1 -1
  104. package/dist/esm/tools/render-map-tool/RenderMapTool.output.schema.d.ts +4 -0
  105. package/dist/esm/tools/render-map-tool/RenderMapTool.output.schema.d.ts.map +1 -1
  106. package/dist/esm/utils/directionsRef.d.ts +27 -0
  107. package/dist/esm/utils/directionsRef.d.ts.map +1 -0
  108. package/dist/esm/utils/directionsRef.js +49 -0
  109. package/dist/esm/utils/directionsRef.js.map +1 -0
  110. package/dist/esm/utils/index.d.ts +6 -0
  111. package/dist/esm/utils/index.d.ts.map +1 -1
  112. package/dist/esm/utils/index.js +9 -0
  113. package/dist/esm/utils/index.js.map +1 -1
  114. package/dist/esm/utils/mapAppPayload.d.ts +21 -0
  115. package/dist/esm/utils/mapAppPayload.d.ts.map +1 -1
  116. package/dist/esm/utils/mapAppPayload.js +5 -1
  117. package/dist/esm/utils/mapAppPayload.js.map +1 -1
  118. package/dist/esm/utils/responseRef.d.ts +33 -0
  119. package/dist/esm/utils/responseRef.d.ts.map +1 -0
  120. package/dist/esm/utils/responseRef.js +68 -0
  121. package/dist/esm/utils/responseRef.js.map +1 -0
  122. package/dist/esm/utils/serverInstructions.d.ts +2 -2
  123. package/dist/esm/utils/serverInstructions.js +2 -2
  124. package/dist/esm/utils/storeMapPayload.js +1 -1
  125. package/dist/esm/utils/storeMapPayload.js.map +1 -1
  126. package/dist/esm/utils/urlSafety.d.ts +6 -0
  127. package/dist/esm/utils/urlSafety.d.ts.map +1 -1
  128. package/dist/esm/utils/urlSafety.js +14 -4
  129. package/dist/esm/utils/urlSafety.js.map +1 -1
  130. package/dist/esm/version.json +3 -3
  131. package/package.json +9 -2
@@ -75,12 +75,51 @@ function renderMapAppHtml(params) {
75
75
  box-shadow: 0 2px 6px rgba(0,0,0,0.4);
76
76
  cursor: pointer;
77
77
  }
78
+ #side-panel {
79
+ position: absolute; top: 12px; right: 12px; bottom: 12px; z-index: 10;
80
+ width: 280px; max-width: calc(100% - 24px);
81
+ background: rgba(15, 23, 42, 0.88); color: #f1f5f9;
82
+ border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.3);
83
+ display: flex; flex-direction: column; overflow: hidden;
84
+ }
85
+ #side-panel .panel-head {
86
+ padding: 10px 12px; font-size: 13px; font-weight: 600;
87
+ border-bottom: 1px solid rgba(255,255,255,0.12); flex: 0 0 auto;
88
+ display: flex; justify-content: space-between; gap: 8px; cursor: pointer;
89
+ }
90
+ /* Click the heading to collapse the list (see togglePanel). */
91
+ #side-panel .panel-head::after { content: '▾'; opacity: 0.7; }
92
+ #side-panel.collapsed { bottom: auto; }
93
+ #side-panel.collapsed .panel-list { display: none; }
94
+ #side-panel.collapsed .panel-head { border-bottom: none; }
95
+ #side-panel.collapsed .panel-head::after { content: '▸'; }
96
+ #side-panel .panel-list { list-style: none; margin: 0; padding: 6px; overflow-y: auto; flex: 1; }
97
+ #side-panel .panel-item {
98
+ display: flex; align-items: flex-start; gap: 6px; padding: 6px; border-radius: 6px; cursor: pointer;
99
+ }
100
+ #side-panel .panel-item:hover { background: rgba(255,255,255,0.08); }
101
+ /* Only added once a photo has loaded (see loadPanelPhoto), at the end of
102
+ the row so names stay aligned whether or not a row has one. */
103
+ #side-panel .panel-thumb {
104
+ flex: 0 0 auto; width: 40px; height: 40px; border-radius: 6px; margin-left: auto;
105
+ background-size: cover; background-position: center;
106
+ }
107
+ /* Visit-order badge, matching the numbered map marker. */
108
+ #side-panel .panel-badge {
109
+ flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%; margin-top: 1px;
110
+ background: #f97316; color: #1a0f04;
111
+ display: flex; align-items: center; justify-content: center;
112
+ font-size: 10px; font-weight: 700;
113
+ }
114
+ #side-panel .panel-name { font-size: 12.5px; font-weight: 600; }
115
+ #side-panel .panel-meta { font-size: 11px; color: #cbd5e1; margin-top: 2px; }
78
116
  </style>
79
117
  </head>
80
118
  <body>
81
119
  <div id="map"></div>
82
120
  <div id="summary" style="display:none"></div>
83
121
  <div id="legend" style="display:none"></div>
122
+ <div id="side-panel" style="display:none"></div>
84
123
  <div id="loading">Loading…</div>
85
124
  <div id="error" style="display:none"></div>
86
125
  ${initialDataScript}
@@ -94,6 +133,11 @@ ${initialDataScript}
94
133
  var errorEl = document.getElementById('error');
95
134
  var summaryEl = document.getElementById('summary');
96
135
  var legendEl = document.getElementById('legend');
136
+ var panelEl = document.getElementById('side-panel');
137
+ // Populated by buildSearchMiniPayload's marker tagging so the panel (click
138
+ // -> flyTo) and Place Details enrichment can find a marker by mapbox_id
139
+ // without re-querying the map for it.
140
+ var markersById = {};
97
141
 
98
142
  var map = null;
99
143
  var mapLoaded = false;
@@ -113,7 +157,9 @@ ${initialDataScript}
113
157
  var messageId = 0;
114
158
  var pendingRequests = new Map();
115
159
 
116
- function sendRequest(method, params) {
160
+ // timeoutMs (optional) rejects a request nobody answers, for hosts that
161
+ // don't implement the method.
162
+ function sendRequest(method, params, timeoutMs) {
117
163
  var id = ++messageId;
118
164
  try {
119
165
  window.parent.postMessage({
@@ -122,6 +168,13 @@ ${initialDataScript}
122
168
  } catch (_) {}
123
169
  return new Promise(function(resolve, reject) {
124
170
  pendingRequests.set(id, { resolve: resolve, reject: reject });
171
+ if (timeoutMs) {
172
+ setTimeout(function() {
173
+ if (!pendingRequests.has(id)) return;
174
+ pendingRequests.delete(id);
175
+ reject(new Error(method + ' timed out'));
176
+ }, timeoutMs);
177
+ }
125
178
  });
126
179
  }
127
180
  function sendNotification(method, params) {
@@ -156,13 +209,22 @@ ${initialDataScript}
156
209
  }
157
210
  });
158
211
 
212
+ // Set once a host answers ui/initialize, even with an error. A page from
213
+ // export_map_html_tool framed by some other site never gets an answer.
214
+ var hostAnswered = false;
159
215
  sendRequest('ui/initialize', {
160
216
  protocolVersion: '2026-01-26',
161
217
  appCapabilities: {},
162
218
  appInfo: { name: 'Mapbox Map', version: '1.0.0' }
163
219
  }).then(
164
- function() { sendNotification('ui/notifications/initialized', {}); },
165
- function() { sendNotification('ui/notifications/initialized', {}); }
220
+ function() {
221
+ hostAnswered = true;
222
+ sendNotification('ui/notifications/initialized', {});
223
+ },
224
+ function() {
225
+ hostAnswered = true;
226
+ sendNotification('ui/notifications/initialized', {});
227
+ }
166
228
  );
167
229
 
168
230
  // --- Map setup ------------------------------------------------------------
@@ -366,6 +428,13 @@ ${initialDataScript}
366
428
  trackedLayerIds = [];
367
429
  trackedSourceIds = [];
368
430
  trackedMarkers = [];
431
+ markersById = {};
432
+ panelEl.style.display = 'none';
433
+ clearPanel();
434
+ // Place Details responses still in flight belong to the old render.
435
+ panelGeneration += 1;
436
+ panelCount = 0;
437
+ panelIds = {};
369
438
  }
370
439
 
371
440
  function bboxAccumulator() {
@@ -451,14 +520,108 @@ ${initialDataScript}
451
520
  if (m.popup) marker.setPopup(new mapboxgl.Popup().setText(m.popup));
452
521
  marker.addTo(map);
453
522
  trackedMarkers.push(marker);
523
+ // Tagged by buildSearchMiniPayload with the result's mapbox_id so the
524
+ // side panel (click-to-flyTo) and Place Details enrichment can look the
525
+ // marker back up later without walking trackedMarkers.
526
+ if (m.id) markersById[m.id] = { marker: marker, popupText: m.popup || '' };
454
527
  bbox.extend(m.coordinates);
455
528
  }
456
529
 
530
+ // Guarantees a marker that opts into the side panel (has .id) also gets
531
+ // a visible number on the map matching its panel row, unless the caller
532
+ // already gave it an explicit label. Without this, a caller that builds
533
+ // plain unlabeled pins for POI markers (observed live: Claude did this
534
+ // for inline markers, leaving the map showing generic blue pins with no
535
+ // way to tell which panel row is which) breaks the whole point of the
536
+ // panel numbering. Mutates markers in place, so it must run before
537
+ // addOneMarker draws them.
538
+ //
539
+ // Numbering runs across the whole render, not per call: a render can
540
+ // draw inline markers and then merge in self-fetched search results, and
541
+ // each set arrives numbered from 1. The first set keeps the caller's
542
+ // numbers when they're unique (a visit order, say); a later set, or one
543
+ // with repeated numbers, is renumbered to continue the panel's count.
544
+ // Letter labels ("A") are kept as they are. A place already in the panel
545
+ // this render is dropped rather than drawn and listed twice. Returns the
546
+ // markers to draw.
547
+ function applyPanelNumbering(markers) {
548
+ if (!Array.isArray(markers)) return [];
549
+ var seen = {};
550
+ var fresh = markers.filter(function(m) {
551
+ if (!m || !m.id) return true;
552
+ if (panelIds[m.id] || seen[m.id]) return false;
553
+ seen[m.id] = true;
554
+ return true;
555
+ });
556
+ var keep = panelCount === 0;
557
+ var used = {};
558
+ fresh.forEach(function(m) {
559
+ if (!m || !m.id || !isWholeNumber(m.label)) return;
560
+ if (used[m.label]) keep = false;
561
+ used[m.label] = true;
562
+ });
563
+ if (keep) {
564
+ Object.keys(used).forEach(function(n) {
565
+ panelCount = Math.max(panelCount, parseInt(n, 10));
566
+ });
567
+ }
568
+ fresh.forEach(function(m) {
569
+ if (!m || !m.id) return;
570
+ if (m.label && (keep || !isWholeNumber(m.label))) return;
571
+ panelCount += 1;
572
+ var n = String(panelCount);
573
+ if (!m.label) {
574
+ if (m.style !== 'start' && m.style !== 'end') m.style = 'numbered';
575
+ if (!m.color) m.color = '#f97316';
576
+ } else if (typeof m.popup === 'string' && m.popup.indexOf(m.label + '. ') === 0) {
577
+ // Search popups start with the old number ("3. Name").
578
+ m.popup = n + '. ' + m.popup.slice(String(m.label).length + 2);
579
+ }
580
+ m.label = n;
581
+ });
582
+ return fresh;
583
+ }
584
+
585
+ function isWholeNumber(label) {
586
+ if (label === undefined || label === null || label === '') return false;
587
+ var n = parseInt(label, 10);
588
+ return n > 0 && String(n) === String(label);
589
+ }
590
+
591
+ // Bottom padding that keeps fitted data out from under the legend
592
+ // (bottom-left), unless the map is too short to spare the room.
593
+ function bottomPadding() {
594
+ if (legendEl.style.display !== 'block') return 50;
595
+ var bottom = (legendEl.offsetHeight || 0) + 24;
596
+ var el = document.getElementById('map');
597
+ var height = (el && el.clientHeight) || window.innerHeight || 0;
598
+ if (bottom <= 50 || (height && height - bottom - 70 < 160)) return 50;
599
+ return bottom;
600
+ }
601
+
602
+ // Right padding that keeps fitted data out from under an open panel. On
603
+ // a narrow map there's no room beside it, so fit as if it weren't there
604
+ // (the panel starts collapsed there anyway; see appendPanelRows).
605
+ function rightPadding() {
606
+ if (panelEl.style.display !== 'flex' || panelCollapsed) return 30;
607
+ var right = (panelEl.offsetWidth || 280) + 24;
608
+ var mapWidth = mapContainerWidth();
609
+ if (mapWidth && mapWidth - right < 240) return 30;
610
+ return right;
611
+ }
612
+
613
+ function mapContainerWidth() {
614
+ var el = document.getElementById('map');
615
+ return (el && el.clientWidth) || window.innerWidth || 0;
616
+ }
617
+
618
+ var lastFitBounds = null;
457
619
  function fitToBounds(bounds) {
620
+ lastFitBounds = bounds;
458
621
  setTimeout(function() {
459
622
  map.resize();
460
623
  map.fitBounds(bounds, {
461
- padding: { top: 70, bottom: 50, left: 30, right: 30 },
624
+ padding: { top: 70, bottom: bottomPadding(), left: 30, right: rightPadding() },
462
625
  duration: 600
463
626
  });
464
627
  }, 60);
@@ -474,13 +637,13 @@ ${initialDataScript}
474
637
  (Array.isArray(payload.layers) ? payload.layers : []).forEach(function(layer) {
475
638
  addOneLayer(layer, bbox);
476
639
  });
477
- (Array.isArray(payload.markers) ? payload.markers : []).forEach(function(m) {
478
- addOneMarker(m, bbox);
479
- });
640
+ var markers = applyPanelNumbering(payload.markers);
641
+ markers.forEach(function(m) { addOneMarker(m, bbox); });
480
642
  if (payload.summary && summaryEl.style.display === 'none') {
481
643
  summaryEl.textContent = payload.summary;
482
644
  summaryEl.style.display = 'block';
483
645
  }
646
+ maybeShowSidePanel(markers, payload.summary);
484
647
  var bounds = bbox.bounds();
485
648
  if (bounds) fitToBounds(bounds);
486
649
  }
@@ -519,10 +682,14 @@ ${initialDataScript}
519
682
 
520
683
  var bbox = bboxAccumulator();
521
684
  var layers = Array.isArray(payload.layers) ? payload.layers : [];
522
- var markers = Array.isArray(payload.markers) ? payload.markers : [];
523
-
524
685
  layers.forEach(function(layer) { addOneLayer(layer, bbox); });
686
+ var markers = applyPanelNumbering(payload.markers);
525
687
  markers.forEach(function(m) { addOneMarker(m, bbox); });
688
+ // Covers both inline markers (a caller-composed payload) and self-fetch
689
+ // markers (merged in later via mergeAdditionalPayload) — see
690
+ // maybeShowSidePanel below. Whichever path produced id-bearing POI
691
+ // markers gets the same results panel.
692
+ maybeShowSidePanel(markers, payload.summary);
526
693
 
527
694
  // Legend
528
695
  if (Array.isArray(payload.legend) && payload.legend.length > 0) {
@@ -1233,12 +1400,22 @@ ${initialDataScript}
1233
1400
  popupParts.push(Math.round(props.distance) + ' m');
1234
1401
  }
1235
1402
  var coords = f.geometry.coordinates;
1403
+ // id/name/category/distanceMeters are the same generic POI fields an
1404
+ // inline (hand-composed) marker can carry — see maybeShowSidePanel,
1405
+ // which builds the results panel from either source identically.
1406
+ // mapbox_id is missing on the rare result that lacks one; the panel
1407
+ // just skips that row rather than show an unclickable/unenrichable
1408
+ // entry.
1236
1409
  markers.push({
1410
+ id: props.mapbox_id,
1237
1411
  coordinates: coords,
1238
1412
  style: 'numbered',
1239
1413
  label: String(i + 1),
1240
1414
  color: '#f97316',
1241
- popup: popupParts.join(' — ')
1415
+ popup: popupParts.join(' — '),
1416
+ name: props.name || ('Result ' + (i + 1)),
1417
+ category: Array.isArray(props.poi_category) ? props.poi_category[0] : undefined,
1418
+ distanceMeters: typeof props.distance === 'number' ? props.distance : undefined
1242
1419
  });
1243
1420
  features.push({
1244
1421
  type: 'Feature',
@@ -1270,6 +1447,296 @@ ${initialDataScript}
1270
1447
  return { summary: summary, layers: layers, markers: markers };
1271
1448
  }
1272
1449
 
1450
+ // --- Side panel: result list + Place Details enrichment ----------------
1451
+ // Triggered generically by maybeShowSidePanel for ANY marker set that
1452
+ // includes id-bearing entries — self-fetch search/category-search
1453
+ // results (via mergeAdditionalPayload) and hand-composed inline markers
1454
+ // from render_map_tool's own "markers" input (via renderBody) both funnel
1455
+ // through the same path. Renders the initial (Search Box-only, or
1456
+ // whatever the caller already provided) list immediately so the panel
1457
+ // never blocks on the slower enrichment call. sourceLabel is plain text
1458
+ // shown as the panel heading (e.g. the query, category, or the payload's
1459
+ // own summary).
1460
+ function derivePanelItems(markers) {
1461
+ if (!Array.isArray(markers)) return [];
1462
+ var items = [];
1463
+ markers.forEach(function(m) {
1464
+ if (!m || !m.id) return;
1465
+ // The pin's own label, so a row reads the same as its pin ("A" too).
1466
+ var badge = isWholeNumber(m.label) ? parseInt(m.label, 10)
1467
+ : (m.label ? String(m.label) : items.length + 1);
1468
+ items.push({
1469
+ id: m.id,
1470
+ number: badge,
1471
+ name: m.name || ('Result ' + (items.length + 1)),
1472
+ category: m.category,
1473
+ distanceMeters: typeof m.distanceMeters === 'number' ? m.distanceMeters : undefined,
1474
+ color: m.color
1475
+ });
1476
+ });
1477
+ return items;
1478
+ }
1479
+ // Exposed so tests can exercise the pure derivation logic without a DOM.
1480
+ window.__derivePanelItems = derivePanelItems;
1481
+
1482
+ // Adds rows for places not yet in this render's panel and enriches just
1483
+ // those. A response is applied only if no newer render has started since
1484
+ // (panelGeneration), so a slow lookup can't write into a newer panel.
1485
+ function maybeShowSidePanel(markers, summary) {
1486
+ var items = derivePanelItems(markers).filter(function(it) {
1487
+ return !panelIds[it.id];
1488
+ });
1489
+ if (items.length === 0) return;
1490
+ items.forEach(function(it) { panelIds[it.id] = true; });
1491
+ appendPanelRows(items, summary || 'Results');
1492
+ var generation = panelGeneration;
1493
+ fetchPlaceDetailsBatch(
1494
+ items.map(function(it) { return it.id; }),
1495
+ TOKEN,
1496
+ API_ENDPOINT
1497
+ ).then(function(result) {
1498
+ if (generation === panelGeneration) enrichSidePanel(result);
1499
+ });
1500
+ }
1501
+
1502
+ // Keyed by mapbox_id -> { li, meta } elements, so enrichSidePanel can
1503
+ // update a row directly once Place Details resolves, without re-parsing
1504
+ // panelEl's markup back into a queryable DOM (innerHTML + querySelector
1505
+ // round-trips don't work in every MCP Apps host's iframe sandbox, and
1506
+ // building real nodes up front is simpler to reason about either way).
1507
+ // Reset by clearPanel, same lifecycle as the panel itself.
1508
+ var panelRowsById = {};
1509
+ // Bumped by teardown(), so responses from an earlier render are dropped.
1510
+ var panelGeneration = 0;
1511
+ // Id-bearing markers numbered so far this render, and the ids listed.
1512
+ var panelCount = 0;
1513
+ var panelIds = {};
1514
+ // The viewer's collapse choice, kept across renders; null until the first
1515
+ // panel decides a default from the map's width.
1516
+ var panelCollapsed = null;
1517
+ var panelListEl = null;
1518
+
1519
+ function buildPanelRow(it) {
1520
+ var li = document.createElement('li');
1521
+ li.className = 'panel-item';
1522
+
1523
+ var badge = document.createElement('span');
1524
+ badge.className = 'panel-badge';
1525
+ badge.textContent = String(it.number);
1526
+ // Match the pin when the caller colored it (e.g. gray for "other
1527
+ // results" next to a legend); the default orange is in the CSS.
1528
+ if (typeof it.color === 'string' && it.color.toLowerCase() !== '#f97316' &&
1529
+ (/^#[0-9a-f]{3,8}$/i).test(it.color)) {
1530
+ badge.style.background = it.color;
1531
+ badge.style.color = '#fff';
1532
+ }
1533
+
1534
+ var name = document.createElement('div');
1535
+ name.className = 'panel-name';
1536
+ name.textContent = it.name;
1537
+
1538
+ var metaParts = [];
1539
+ if (it.category) metaParts.push(it.category);
1540
+ if (typeof it.distanceMeters === 'number') {
1541
+ metaParts.push(Math.round(it.distanceMeters) + ' m');
1542
+ }
1543
+ var meta = document.createElement('div');
1544
+ meta.className = 'panel-meta';
1545
+ meta.textContent = metaParts.join(' · ');
1546
+
1547
+ var body = document.createElement('div');
1548
+ body.appendChild(name);
1549
+ body.appendChild(meta);
1550
+ li.appendChild(badge);
1551
+ li.appendChild(body);
1552
+
1553
+ li.addEventListener('click', function() {
1554
+ var entry = markersById[it.id];
1555
+ if (entry) map.flyTo({ center: entry.marker.getLngLat(), zoom: 15, duration: 500 });
1556
+ });
1557
+
1558
+ panelRowsById[it.id] = { li: li, meta: meta };
1559
+ return li;
1560
+ }
1561
+
1562
+ function clearPanel() {
1563
+ while (panelEl.firstChild) panelEl.removeChild(panelEl.firstChild);
1564
+ panelRowsById = {};
1565
+ panelListEl = null;
1566
+ }
1567
+
1568
+ function applyPanelCollapsed() {
1569
+ panelEl.className = panelCollapsed ? 'collapsed' : '';
1570
+ }
1571
+
1572
+ function togglePanel() {
1573
+ panelCollapsed = !panelCollapsed;
1574
+ applyPanelCollapsed();
1575
+ if (lastFitBounds) fitToBounds(lastFitBounds);
1576
+ }
1577
+
1578
+ // Creates the panel on the render's first id-bearing markers, and adds
1579
+ // rows to it for later ones (e.g. search results merged in after inline
1580
+ // markers), so every numbered pin has a row.
1581
+ function appendPanelRows(items, sourceLabel) {
1582
+ if (!Array.isArray(items) || items.length === 0) return;
1583
+ if (!panelListEl) {
1584
+ var head = document.createElement('div');
1585
+ head.className = 'panel-head';
1586
+ head.textContent = sourceLabel || 'Results';
1587
+ head.addEventListener('click', togglePanel);
1588
+
1589
+ panelListEl = document.createElement('ul');
1590
+ panelListEl.className = 'panel-list';
1591
+
1592
+ panelEl.appendChild(head);
1593
+ panelEl.appendChild(panelListEl);
1594
+ // On a narrow map the open panel would cover most of it.
1595
+ if (panelCollapsed === null) {
1596
+ var width = mapContainerWidth();
1597
+ panelCollapsed = width > 0 && width < 560;
1598
+ }
1599
+ applyPanelCollapsed();
1600
+ panelEl.style.display = 'flex';
1601
+ }
1602
+ var list = panelListEl;
1603
+ items.forEach(function(it) { list.appendChild(buildPanelRow(it)); });
1604
+ }
1605
+
1606
+ // Search Box results mix Mapbox-native POI ids (decode to
1607
+ // "urn:mbxpoi:<uuid>") with OSM-sourced ones (decode to
1608
+ // "urn:mbxpoi-osm:n<osm-node-id>") — confirmed live against a real
1609
+ // category_search_tool-style query near Herndon, VA, where 2 of 10
1610
+ // "cafe" results were OSM-sourced. The Places API's batch endpoint
1611
+ // rejects the ENTIRE request with a 422 if even one id isn't its native
1612
+ // scheme (same 422 PlaceDetailsTool.ts already works around server-side
1613
+ // for boundary ids) — so filter client-side before sending, rather than
1614
+ // let one incompatible id in a 10-result batch silently zero out
1615
+ // enrichment for the other 9. The prefix alone isn't enough: near Union
1616
+ // Square, SF, a Starbucks decodes to "urn:mbxpoi:mapbox-n408854", which
1617
+ // the endpoint also rejects, so require the UUID form.
1618
+ var PLACES_ID = /^urn:mbxpoi:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1619
+ function isPlacesApiCompatibleId(id) {
1620
+ if (typeof id !== 'string' || id.length === 0) return false;
1621
+ try {
1622
+ return PLACES_ID.test(atob(id));
1623
+ } catch (e) {
1624
+ return false;
1625
+ }
1626
+ }
1627
+
1628
+ // Places API Details endpoint — batch form. Mirrors the single-record
1629
+ // GET src/tools/place-details-tool/PlaceDetailsTool.ts calls server-side,
1630
+ // but the panel needs details for every result at once, so this uses the
1631
+ // POST /details/retrieve batch form (up to 100 ids) instead of one
1632
+ // request per pin. Docs: https://docs.mapbox.com/api/search/places/
1633
+ // Like every other self-fetch call, this runs client-side against the
1634
+ // public token — the Places API's docs list no secret scope requirement
1635
+ // for this endpoint, same as Search Box/Directions/etc.
1636
+ function fetchPlaceDetailsBatch(ids, publicToken, apiEndpoint) {
1637
+ var compatibleIds = (Array.isArray(ids) ? ids : []).filter(isPlacesApiCompatibleId);
1638
+ if (compatibleIds.length === 0) return Promise.resolve(null);
1639
+ var qp = new URLSearchParams();
1640
+ qp.append('access_token', publicToken);
1641
+ var url = apiEndpoint + 'places/v1/details/retrieve?' + qp.toString();
1642
+ var post = function(batch, retried) {
1643
+ return fetch(url, {
1644
+ method: 'POST',
1645
+ headers: { 'Content-Type': 'application/json' },
1646
+ body: JSON.stringify({ ids: batch })
1647
+ }).then(function(res) {
1648
+ // 206 is a partial batch (some ids missing/unprocessed) — still
1649
+ // has usable "results", so treat it the same as 200.
1650
+ if (res.ok || res.status === 206) return res.json();
1651
+ // A 422 names the one id it rejected ("Invalid mapbox_id format:
1652
+ // <id>"), in case an id format slips past the filter above. Drop
1653
+ // that id and try once more, rather than lose the whole batch.
1654
+ if (res.status !== 422 || retried) return null;
1655
+ return res.json().then(function(body) {
1656
+ var msg = body && typeof body.message === 'string' ? body.message : '';
1657
+ var bad = msg.slice(msg.lastIndexOf(' ') + 1).split('=')[0];
1658
+ var rest = batch.filter(function(id) { return id.split('=')[0] !== bad; });
1659
+ if (!bad || rest.length === batch.length || rest.length === 0) return null;
1660
+ return post(rest, true);
1661
+ });
1662
+ });
1663
+ };
1664
+ return post(compatibleIds.slice(0, 100), false)
1665
+ // Enrichment is a nice-to-have on top of an already-rendered panel —
1666
+ // Public Preview quota (1,000 records/month) or a transient error
1667
+ // here should never surface as a map error, just leave the
1668
+ // Search-Box-only rows as they are.
1669
+ .catch(function() { return null; });
1670
+ }
1671
+
1672
+ // Place Details photos are hosted wherever each business's site hosts
1673
+ // them, so the in-chat CSP (mapAppCsp.ts) can't allow them. Inside a host,
1674
+ // the page asks the server for the photo (PlacePhotoResource, by mapbox_id)
1675
+ // and shows it as a data: URL. A standalone page from export_map_html_tool
1676
+ // has no host and no CSP, so it loads the photo URL directly.
1677
+ var MAX_PANEL_PHOTOS = 10;
1678
+ var EMBEDDED = window.parent !== window;
1679
+ var PHOTO_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
1680
+ var PHOTO_TIMEOUT_MS = 15000;
1681
+
1682
+ function loadPanelPhoto(row, id, photoUrl) {
1683
+ var show = function(src) {
1684
+ // A later render may have replaced the panel while this loaded.
1685
+ if (panelRowsById[id] !== row) return;
1686
+ var thumb = document.createElement('span');
1687
+ thumb.className = 'panel-thumb';
1688
+ thumb.style.backgroundImage = 'url("' + src.replace(/"/g, '') + '")';
1689
+ row.li.appendChild(thumb);
1690
+ };
1691
+ if (!EMBEDDED || !hostAnswered) {
1692
+ // No MCP host (a standalone or framed exported page), so no CSP of
1693
+ // ours either. Load it first: some sites refuse hotlinked photos (403), which
1694
+ // would leave an empty box in the row.
1695
+ if (photoUrl.indexOf('https://') !== 0 || typeof Image !== 'function') return;
1696
+ var img = new Image();
1697
+ img.onload = function() { show(photoUrl); };
1698
+ img.src = photoUrl;
1699
+ return;
1700
+ }
1701
+ // Hosts that don't support resources/read (ChatGPT) may never answer.
1702
+ sendRequest('resources/read', {
1703
+ uri: 'mapbox://place-photo/' + encodeURIComponent(id)
1704
+ }, PHOTO_TIMEOUT_MS).then(function(rr) {
1705
+ var c = rr && Array.isArray(rr.contents) ? rr.contents[0] : null;
1706
+ if (c && typeof c.blob === 'string' &&
1707
+ PHOTO_TYPES.indexOf(c.mimeType) !== -1) {
1708
+ show('data:' + c.mimeType + ';base64,' + c.blob);
1709
+ }
1710
+ }, function() {});
1711
+ }
1712
+
1713
+ function enrichSidePanel(detailsResult) {
1714
+ if (!detailsResult || !Array.isArray(detailsResult.results)) return;
1715
+ var photosRequested = 0;
1716
+ detailsResult.results.forEach(function(place) {
1717
+ if (!place || !place.mapbox_id) return;
1718
+ var row = panelRowsById[place.mapbox_id];
1719
+ if (row) {
1720
+ var photoUrl = place.photos && place.photos[0] && place.photos[0].url;
1721
+ if (typeof photoUrl === 'string' && photosRequested < MAX_PANEL_PHOTOS) {
1722
+ photosRequested++;
1723
+ loadPanelPhoto(row, place.mapbox_id, photoUrl);
1724
+ }
1725
+ if (place.score && typeof place.score.popularity === 'number') {
1726
+ var extra = Math.round(place.score.popularity * 100) + '% popularity';
1727
+ row.meta.textContent = row.meta.textContent ? row.meta.textContent + ' · ' + extra : extra;
1728
+ }
1729
+ }
1730
+
1731
+ var entry = markersById[place.mapbox_id];
1732
+ if (entry && place.phone) {
1733
+ entry.marker.setPopup(
1734
+ new mapboxgl.Popup().setText(entry.popupText + ' — ' + place.phone)
1735
+ );
1736
+ }
1737
+ });
1738
+ }
1739
+
1273
1740
  function selfFetchSearch(params) {
1274
1741
  if (!TOKEN || !isSafeSearchParams(params)) {
1275
1742
  showError('Could not fetch search results: missing token or invalid parameters.');
@@ -1599,11 +2066,15 @@ ${initialDataScript}
1599
2066
  parts.push(Math.round(poi.distance_meters) + ' m');
1600
2067
  }
1601
2068
  markers.push({
2069
+ id: poi.id,
1602
2070
  coordinates: [poi.longitude, poi.latitude],
1603
2071
  style: 'numbered',
1604
2072
  label: String(i + 1),
1605
2073
  color: '#f97316',
1606
- popup: parts.join(' — ')
2074
+ popup: parts.join(' — '),
2075
+ name: poi.name,
2076
+ category: poi.category,
2077
+ distanceMeters: typeof poi.distance_meters === 'number' ? poi.distance_meters : undefined
1607
2078
  });
1608
2079
  });
1609
2080
  return { summary: place, layers: [], markers: markers };
@@ -1662,8 +2133,10 @@ ${initialDataScript}
1662
2133
  var props = f.properties || {};
1663
2134
  var coords = (f.geometry && f.geometry.coordinates) || [params.longitude, params.latitude];
1664
2135
  return {
2136
+ id: props.mapbox_id,
1665
2137
  name: props.name || 'Unknown',
1666
2138
  address: props.full_address || props.place_formatted,
2139
+ category: Array.isArray(props.poi_category) ? props.poi_category[0] : undefined,
1667
2140
  longitude: coords[0],
1668
2141
  latitude: coords[1],
1669
2142
  distance_meters: props.distance
@@ -1 +1 @@
1
- {"version":3,"file":"mapAppHtml.js","sourceRoot":"","sources":["../../../../src/resources/ui-apps/mapAppHtml.ts"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,kCAAkC;;;AAqBlC,4CAgpDC;AAjqDD;;;;;;;;;GASG;AAEH,yEAAyE;AACzE,wEAAwE;AACxE,6EAA6E;AAC7E,8CAA8C;AACjC,QAAA,iBAAiB,GAAG,QAAQ,CAAC;AAE1C,SAAgB,gBAAgB,CAAC,MAKhC;IACC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;IAC5C,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,yBAAyB,CAAC;IACpE,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,yBAAiB,CAAC;IAExD,MAAM,iBAAiB,GAAG,WAAW;QACnC,CAAC,CAAC,qDAAqD,eAAe,CAClE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAC5B,WAAW;QACd,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;;mDAM0C,SAAS;oDACR,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkD3D,iBAAiB;;;;gBAIH,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;uBACpB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAikD1C,CAAC;AACT,CAAC;AAED,SAAS,eAAe,CAAC,CAAS;IAChC,OAAO,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;AAClD,CAAC"}
1
+ {"version":3,"file":"mapAppHtml.js","sourceRoot":"","sources":["../../../../src/resources/ui-apps/mapAppHtml.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CategoryListTool.d.ts","sourceRoot":"","sources":["../../../../src/tools/category-list-tool/CategoryListTool.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAiBjF;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,kBAAkB,CACtD,OAAO,uBAAuB,EAC9B,OAAO,0BAA0B,CAClC;IACC,IAAI,SAAwB;IAC5B,WAAW,SAC0iB;IACrjB,WAAW;;;;;;MAMT;gBAEU,MAAM,EAAE;QAAE,WAAW,EAAE,WAAW,CAAA;KAAE;cAQhC,OAAO,CACrB,KAAK,EAAE,iBAAiB,EACxB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC;CAmE3B"}
1
+ {"version":3,"file":"CategoryListTool.d.ts","sourceRoot":"","sources":["../../../../src/tools/category-list-tool/CategoryListTool.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAiBjF;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,kBAAkB,CACtD,OAAO,uBAAuB,EAC9B,OAAO,0BAA0B,CAClC;IACC,IAAI,SAAwB;IAC5B,WAAW,SACgY;IAC3Y,WAAW;;;;;;MAMT;gBAEU,MAAM,EAAE;QAAE,WAAW,EAAE,WAAW,CAAA;KAAE;cAQhC,OAAO,CACrB,KAAK,EAAE,iBAAiB,EACxB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC;CAmE3B"}
@@ -12,7 +12,7 @@ exports.CategoryListInputSchema = zod_1.z.object({
12
12
  .min(1)
13
13
  .max(100)
14
14
  .optional()
15
- .describe('Number of categories to return (1-100). WARNING: Only use this parameter if you need to optimize token usage. If using pagination, please make multiple calls to retrieve all categories before proceeding with other tasks. If not specified, returns all categories.'),
15
+ .describe('Number of categories to return (1-100). If not specified, returns all categories.'),
16
16
  offset: zod_1.z
17
17
  .number()
18
18
  .min(0)
@@ -1 +1 @@
1
- {"version":3,"file":"CategoryListTool.input.schema.js","sourceRoot":"","sources":["../../../../src/tools/category-list-tool/CategoryListTool.input.schema.ts"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,kCAAkC;;;AAElC,6BAAwB;AACxB,uDAAyD;AAE5C,QAAA,uBAAuB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC9C,QAAQ,EAAE,0BAAc,CAAC,QAAQ,EAAE;IACnC,KAAK,EAAE,OAAC;SACL,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,GAAG,CAAC;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,wQAAwQ,CACzQ;IACH,MAAM,EAAE,OAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,OAAO,CAAC,CAAC,CAAC;SACV,QAAQ,CAAC,4DAA4D,CAAC;CAC1E,CAAC,CAAC"}
1
+ {"version":3,"file":"CategoryListTool.input.schema.js","sourceRoot":"","sources":["../../../../src/tools/category-list-tool/CategoryListTool.input.schema.ts"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,kCAAkC;;;AAElC,6BAAwB;AACxB,uDAAyD;AAE5C,QAAA,uBAAuB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC9C,QAAQ,EAAE,0BAAc,CAAC,QAAQ,EAAE;IACnC,KAAK,EAAE,OAAC;SACL,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,GAAG,CAAC;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,mFAAmF,CACpF;IACH,MAAM,EAAE,OAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,OAAO,CAAC,CAAC,CAAC;SACV,QAAQ,CAAC,4DAA4D,CAAC;CAC1E,CAAC,CAAC"}
@@ -12,7 +12,7 @@ const CategoryListTool_output_schema_js_1 = require("./CategoryListTool.output.s
12
12
  */
13
13
  class CategoryListTool extends MapboxApiBasedTool_js_1.MapboxApiBasedTool {
14
14
  name = 'category_list_tool';
15
- description = '[DEPRECATED: Use resource_reader_tool with "mapbox://categories" URI instead] Tool for retrieving the list of supported categories from Mapbox Search API. This tool is kept for backward compatibility with clients that do not support MCP resources. Use this when another function requires a list of categories. Returns all available category IDs by default. Only use pagination (limit/offset) if token usage optimization is required. If using pagination, make multiple calls to retrieve ALL categories before proceeding with other tasks to ensure complete data.';
15
+ description = '[DEPRECATED: Use resource_reader_tool with "mapbox://categories" URI instead] Tool for retrieving the list of supported categories from Mapbox Search API. This tool is kept for backward compatibility with clients that do not support MCP resources. Use this when another function requires a list of categories. Returns all available category IDs by default. Supports limit/offset pagination.';
16
16
  annotations = {
17
17
  title: 'Category List Tool (Deprecated)',
18
18
  readOnlyHint: true,