Topo Shadow Box
MCP Server to generate Topographic 3D Prints
Ask AI about Topo Shadow Box
Powered by Claude · Grounded in docs
I know everything about Topo Shadow Box. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
topo-shadow-box
An MCP (Model Context Protocol) server that generates 3D-printable topographic shadow boxes. Given a geographic area, it fetches real elevation data and OpenStreetMap features, then produces multi-material 3MF files ready for slicing and printing.
Features
- Terrain mesh from AWS Terrain-RGB elevation tiles (free, global coverage)
- OpenStreetMap overlay: roads, water bodies, and buildings
- GPX track visualization as raised strips on the terrain
- Multiple output shapes: square, circle, hexagon, rectangle
- Export to 3MF (multi-material), OpenSCAD
.scad, or SVG map insert - Live 3D preview via a local Three.js viewer (port 3333)
- Session save/load to resume work across server restarts
Installation
Download a prebuilt binary from GitHub Releases, or build from source with Go:
cd go
go build -o /usr/local/bin/topo-shadow-box ./cmd/topo-shadow-box
Adding to Claude Code
/plugin marketplace add huslage/topo-shadow-box
/plugin install topo-shadow-box@topo-shadow-box
The MCP server starts automatically when you install the plugin.
Adding to Codex
Add this to ~/.codex/config.toml:
[mcp_servers.topo-shadow-box]
command = "topo-shadow-box"
args = ["serve"]
Then restart Codex.
Permissions
The first time Claude calls each tool, it will ask for permission. Click "Allow always" (not "Allow") so the approval is saved and you won't be asked again.
If you'd rather pre-approve everything upfront, add this to your ~/.claude/settings.json:
{
"permissions": {
"allow": ["mcp__plugin_topo-shadow-box_topo-shadow-box__*"]
}
}
CLI Usage
The Go binary supports two modes:
topo-shadow-box servestarts the MCP server (Claude Code plugin mode).topo-shadow-box [flags]runs one-shot CLI generation and writes an output file.
Build the Binary
cd go
go build -o /usr/local/bin/topo-shadow-box ./cmd/topo-shadow-box
Quickstart Examples
# Circle area -> 3MF
topo-shadow-box --lat 35.99 --lon -78.90 --radius 5000 --output durham.3mf
# Bounding box -> OpenSCAD
topo-shadow-box --north 36.1 --south 35.9 --east -78.8 --west -79.0 --output area.scad
# GPX track area -> SVG
topo-shadow-box --gpx /path/to/ride.gpx --output ride.svg
# Custom model options + subset of map features
topo-shadow-box \
--lat 35.99 --lon -78.90 --radius 5000 \
--output model.3mf \
--width 150 \
--vertical-scale 2.0 \
--base-height 8 \
--shape circle \
--resolution 250 \
--features roads,water \
--color-terrain "#8B7355" \
--color-water "#4A90D9"
CLI Flag Reference
| Flag | Default | Description |
|---|---|---|
--lat, --lon, --radius | — | Circular area input (radius in meters) |
--north, --south, --east, --west | — | Explicit bounding box input |
--gpx | — | GPX file path (uses GPX bounds + default padding) |
--output, -o | — | Output path; extension selects format (.3mf, .scad, .svg) |
--width | 200 | Model width in mm |
--vertical-scale | 1.5 | Elevation exaggeration multiplier |
--base-height | 10 | Solid base thickness in mm |
--shape | square | square, circle, hexagon, rectangle |
--resolution | 200 | Elevation grid resolution per axis |
--features | roads,water,buildings | CSV feature list; use empty string to skip features |
--color-terrain | #C8A882 | Terrain color |
--color-roads | #D4C5A9 | Roads color |
--color-water | #4682B4 | Water color |
--color-buildings | #E8D5B7 | Buildings color |
--color-gpx-track | #FF0000 | GPX track color |
Validation Rules
- Exactly one input mode is required:
--lat+--lon+--radius--north+--south+--east+--west--gpx
--outputis required.--shapemust be one ofsquare,circle,hexagon,rectangle.- Colors must be
#RRGGBB. - Output format is inferred from file extension.
Run as MCP Server
topo-shadow-box serve
CLI Troubleshooting
-
error: --output is required- Add
--output <path>(or-o <path>). The extension must be.3mf,.scad, or.svg.
- Add
-
one of --lat/--lon/--radius, --north/--south/--east/--west, or --gpx is required- Provide exactly one input mode. Do not mix coordinate/bbox/GPX inputs.
-
--lat/--lon/--radius ... are mutually exclusive(or bbox/GPX equivalent)- Remove extra input flags so only one area-definition method is used.
-
cannot infer output format from extension ...- Use a supported output extension:
.3mf,.scad, or.svg.
- Use a supported output extension:
-
invalid --shape ...- Use one of:
square,circle,hexagon,rectangle.
- Use one of:
-
Color format errors (
must be in #RRGGBB format)- Use 6-digit hex with leading
#, e.g.#C8A882.
- Use 6-digit hex with leading
-
Network/data fetch failures during elevation or feature steps
- Retry command (transient network issues are common).
- Try smaller area or lower
--resolutionif requests are timing out. - For feature-only failures, you can still generate terrain by setting
--features ''.
-
GPX errors (
open gpx..., parse failures, or no bounds)- Verify the file exists and is valid GPX XML with track points.
- Try exporting the GPX again from your source app/device.
-
Preview tool reports no mesh generated (MCP mode)
- Run
generate_modelfirst, then callpreview.
- Run
Example Agent Conversations
These show how to prompt Claude (or any MCP-capable agent) to generate a shadow box. The agent calls the tools automatically — you just describe what you want.
Example 1: Shadow box from coordinates
User:
Make me a 3D-printable shadow box of downtown Asheville, NC. Hexagon shape, 150mm wide. Save it to my Desktop.
Agent:
⏺ set_area_from_coordinates(lat=35.5951, lon=-82.5515, radius_m=2000)
↳ Area set: 35.545°N–35.645°N, 82.596°W–82.507°W (≈4.0×4.0 km)
⏺ validate_area()
↳ OK — area 16.0 km², elevation relief 312 m
⏺ fetch_elevation(resolution=200)
↳ Elevation grid fetched: 200×200 (40 000 points), range 606–918 m
⏺ fetch_features()
↳ Fetched 87 roads, 12 water bodies, 43 buildings from OpenStreetMap
⏺ set_model_params(width_mm=150, shape="hexagon", vertical_scale=1.5)
↳ Model params updated
⏺ generate_model()
↳ Terrain mesh … roads … water … buildings … frame — done (6 meshes)
⏺ export_3mf(output_path="/Users/you/Desktop/asheville.3mf")
↳ Exported 6-material 3MF to /Users/you/Desktop/asheville.3mf (4.2 MB)
Agent reply:
Done!
asheville.3mfis on your Desktop. It has six material slots: terrain, roads, water, buildings, frame, and base. Open it in PrusaSlicer or Bambu Studio and assign a filament color to each slot.
Example 2: Shadow box from a GPX track
User:
I have a GPX file of my morning ride at
/Users/you/rides/morning_ride.gpx. Generate a shadow box showing the route with the terrain underneath. Circle shape. Export to/tmp/ride.3mf.
Agent:
⏺ set_area_from_gpx(file_path="/Users/you/rides/morning_ride.gpx", padding_m=500)
↳ GPX loaded: 1 track, 2 043 points. Area set with 500 m padding.
⏺ validate_area()
↳ OK — area 28.4 km², elevation relief 487 m
⏺ fetch_elevation(resolution=200)
↳ Elevation grid fetched: 200×200, range 312–799 m
⏺ fetch_features(include=["roads", "water"])
↳ Fetched 134 roads, 8 water bodies
⏺ set_model_params(shape="circle", vertical_scale=2.0)
↳ Model params updated
⏺ generate_model()
↳ Terrain mesh … roads … water … GPX track strip … frame — done (5 meshes)
⏺ export_3mf(output_path="/tmp/ride.3mf")
↳ Exported 5-material 3MF to /tmp/ride.3mf (5.8 MB)
Agent reply:
Your ride shadow box is at
/tmp/ride.3mf. The GPX track is its own material object so you can print it in a contrasting color. The circle footprint clips the terrain and roads cleanly to the boundary.
Tool Reference
See docs/tool-reference.md for the full tool reference, typical workflows, output formats, and data sources.
Development
See docs/development.md.
License
See LICENSE.
