fix: misc fixes for pdf-server, map-server, and say-server (#329)

* fix(map-server): simplify location update message format

* fix(say-server): pass host to streamable_http_app for non-localhost deployments

* refactor(pdf-server): simplify to stateless range-query architecture

- Remove caching/indexing in favor of direct HTTP Range requests
- Use HEAD requests to get file size (no full download)
- Use Range requests to proxy byte chunks (no caching)
- Local files: fs.read with offset/length
- Remote files: HTTP Range header
- Zero memory footprint (no PDF caching)
- Truly stateless (no session management needed)
- Single server.ts (~350 lines) + main.ts CLI entry point
- Instant startup (no preloading)
- Security: whitelist local files, allowed origins

Removed files:
- src/pdf-indexer.ts
- src/pdf-loader.ts
- src/types.ts

* feat(pdf-server): add dark mode support

- Add CSS variables with light-dark() function for automatic theme switching
- Sync theme with host via applyDocumentTheme()
- Apply host CSS variables via applyHostStyleVariables()

* feat(pdf-server): add list_pdfs tool back

Lists local files and allowed remote origins.
Also moves CHUNK_SIZE to module level constant.

* feat(pdf-server): improve tool descriptions and increase context limit

- display_pdf: list all allowed domains in description
- Increase MAX_MODEL_CONTEXT_LENGTH to 15000
- Move CHUNK_SIZE to module level constant

* chore(say-server): remove deployment docs from repo

Keep server.py fix for non-localhost deployments.
Deployment docs kept locally but not in repo.

* refactor(pdf-server): simplify updateModelContext format

- Add widget ID for multi-widget disambiguation
- Use concise header: 'PDF viewer (id) | title | Current Page: X/Y'
- Add 'Page content:' prefix before text
- Keep selection markers (<pdf-selection>...</pdf-selection>)

* refactor: rename widgetUUID to viewUUID for consistency

Aligns with main's standardization on 'view' terminology (PR #325).
Also dynamically generate allowed domains in display_pdf description.

* viewUUID

* fix(map-server): fix syntax error in location update message

* fix(pdf-server): restore package.json, improve server docs

- Restore --external pdfjs-dist in build
- Rewrite server.ts header for newcomers (list tools, not implementation details)
- Minimize main.ts diff

* chore(pdf-server): remove unused addAllowedOrigin/addAllowedLocalFile

* docs(pdf-server): update README for new architecture

* docs(pdf-server): restore full README, add theming section, remove get_pdf_info

* rm

* fix(pdf-server): restore createMcpExpressApp and error handling

- Use createMcpExpressApp for DNS rebinding protection
- Restore error callback in app.listen()

* fix(say-server): pass host to streamable_http_app for non-localhost deployments

* chore(say-server): remove deployment docs from repo

* widgetId->tool id

* fix(map-server): add null check for center in location update

chore(pdf-server): dedupe and sort allowed origins

* fix(map-server): use transparent background for rounded corners

* prettier
This commit is contained in:
Olivier Chafik 2026-01-23 12:35:07 +00:00 • committed by GitHub
commit 023f1fd233
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 452 additions and 495 deletions

View file

@ -14,6 +14,7 @@
padding: 0;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: transparent;
}
#cesiumContainer {
width: 100%;

View file

@ -404,40 +404,24 @@ function scheduleLocationUpdate(cesiumViewer: any): void {
const center = getCameraCenter(cesiumViewer);
const extent = getVisibleExtent(cesiumViewer);
if (!extent) {
log.info("No visible extent (camera looking at sky?)");
if (!extent || !center) {
log.info("No visible extent or center (camera looking at sky?)");
return;
}
const { widthKm, heightKm } = getScaleDimensions(extent);
log.info(`Extent: ${widthKm.toFixed(1)}km × ${heightKm.toFixed(1)}km`);
// Get places visible in the extent (samples multiple points for large areas)
const places = await getVisiblePlaces(extent);
// Build structured markdown with YAML frontmatter (like pdf-server)
// Note: tool name isn't in the notification protocol, so we hardcode it
const frontmatter = [
"---",
`tool: show-map`,
center
? `center: [${center.lat.toFixed(4)}, ${center.lon.toFixed(4)}]`
: null,
`extent: [${extent.west.toFixed(4)}, ${extent.south.toFixed(4)}, ${extent.east.toFixed(4)}, ${extent.north.toFixed(4)}]`,
`extent-size: ${widthKm.toFixed(1)}km × ${heightKm.toFixed(1)}km`,
places.length > 0 ? `visible-places: [${places.join(", ")}]` : null,
"---",
]
.filter(Boolean)
.join("\n");
log.info("Updating model context:", frontmatter);
// Update the model's context with the current map location.
// If the host doesn't support this, the request will silently fail.
const content = [
`The map view of ${app.getHostContext()?.toolInfo?.id} is now ${widthKm.toFixed(1)}km wide × ${heightKm.toFixed(1)}km tall `,
`and has changed to the following location: [${places.join(", ")}] `,
`lat. / long. of center of map = [${center.lat.toFixed(4)}, ${center.lon.toFixed(4)}]`,
].join("\n");
log.info("Updating model context:", content);
app.updateModelContext({
content: [{ type: "text", text: frontmatter }],
content: [{ type: "text", text: content }],
});
}, 1500);
}