dc-twin
Allows importing ArcGIS Indoors GeoJSON exports of building layouts, including units, details, walls, doors, and levels, to use in the digital twin simulation.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@dc-twinsimulate Halloween week at Norcross with current staff"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
digitaltwin_mcp
A digital twin of a candy distribution center. candystore_mcp decides what its stores sell and which of its two distribution centers supplies them; this project runs those two buildings minute by minute. Supplier trucks, unloading, receiving, putaway, pick-face replenishment, store-order picking, packing, loading, and the people, forklifts and doors doing it, through the Halloween and Christmas peaks. An MCP server over a discrete-event simulation, with a small web page.
Live site: https://digitaltwin-mcp.vercel.app · Import your building: https://digitaltwin-mcp.vercel.app/import
3D twin: https://digitaltwin-mcp.vercel.app/twin
Remote MCP endpoint: https://digitaltwin-mcp.vercel.app/mcp
Local MCP server: npm run mcp:stdio (adds render_floor, which writes the floor plan to an HTML file, and imports files by path, IFC included)
This is the fourth project in a portfolio sequence: census-mcp (a stateless tool server), atl-mcp (a spatial engine with scenarios), candystore_mcp (a market model with a supply chain), and this one, which takes candystore's supply chain down to the floor.
The company, its buildings and its people are fictional. candystore's demand comes from real demographics.
The question
candystore says Norcross can ship $383k a week and Fulton Industrial $350k. Can they? Those are numbers on a spreadsheet. The twin answers with doors, forklifts, pick faces, cutoffs and a crew of three or four.
Can the buildings take candystore's expansion, and what breaks first?
Is each center ready for Halloween, when a week runs 2.1× an average one?
What happens when the only forklift breaks, or the one person who can drive it is out?
Who should work which day on what, and where would one absence stop a skill?
Is re-slotting the pick faces worth the labor to move them?
Related MCP server: KPI-Lens
What the twin found (baseline data, mock standards)
Both buildings are small and lean. Norcross ships about 7,700 display boxes a week with four people; Fulton about 3,800 with three. Labor utilization in an ordinary week is 45–55%, but the pick window between the start of shift and the 14:00 truck is what binds.
candystore's capacity assumption is optimistic.
find_capacityputs Norcross at roughly 1.2× today's demand before trucks start leaving late (about $240k in an average-season week, 63% of candystore's assumed cap) and Fulton at about 1.25× (37%). Norcross runs out of picker time; Fulton runs out of forklift, because it has one.Halloween breaks Norcross as staffed. In week 44 the simulation ships 7 trucks late and cuts 6% of display boxes; one temp selector fixes fill but not lateness, because forklift hours are the gap and temps cannot drive.
Most of slotting's value is face sizing, not walking. In a building this size a pick line is mostly handling. Giving fast movers a week of stock on the face halves forklift replenishments; a 20-swap partial re-slot pays back in under a week.
Fulton is fragile. Three people, one forklift: in a stress test with ordinary breakdown and absence rates, most fortnights ship at least one truck late, and a Tuesday with the lead out leaves nobody who can pick.
Your own building
The twin runs in any building you bring. Upload a floor plan on the web page, or import it through MCP, and every simulation tool takes the result as layout: the building comes from your file, while demand, crew and equipment still come from a center (dc).
Format | What it reads | How it's read |
DXF (CAD) | Rack blocks or outlines, shelving, dock-door blocks, walls, outline, rooms | Layer and block names matched to roles (pick, reserve, mixed, rack, door, receiving/shipping door, wall, outline, staging, office, ignore), with NCS names such as A-WALL, A-EQPM and A-FLOR-OTLN recognised. Units come from |
WMS location CSV | Every location's zone, aisle, side, bay, level, optional x/y, door rows | Column names matched loosely; aisle-side groups become rack runs. Without coordinates, aisles are laid out at standard pitches. |
ArcGIS Indoors GeoJSON | Units (USE_TYPE, NAME), Details (walls, doors, openings), Levels | Features To JSON exports, several files at once; Web Mercator or WGS84 |
IMDF archive | fixture (racks as equipment or furniture), opening (service or automobile doors), unit, detail, footprint, level | OGC CS 20-094 zip in WGS84; the level with the most racks, or |
IFC (BIM) | Walls, doors, slabs, spaces, and furnishing or proxy elements named as racks | web-ifc (MPL-2.0), ground floor only. Web page and local server only. |
Every import goes through the same pipeline:
Classify each shape by its layer or category.
Orient the building so rack runs point away from the dock wall, which becomes the front.
Build rack runs. Bay-sized rectangles merge into runs, and double-deep boxes split into back-to-back rows.
Find aisles from the gaps between facing rack runs.
Pick dock doors. Personnel doors, and doors away from the dock wall, are dropped.
Report how every layer was read, what was assumed, and the pick faces and reserve positions the twin will simulate.
If a layer was read wrong, override it with roleMap (or the role table on the page) and import again.
Nothing is stored. The page parses the file in your browser, and only the compact layout spec (a few KB) goes to the server when you run the twin. The MCP tools return the spec to the caller.
Size limits, set by where the file is parsed:
Where | Limit | Why |
Web page, parsed in the browser | DXF, IFC, GeoJSON 50 MB; IMDF zip 25 MB (100 MB unzipped, 200 files); CSV 10 MB | A few seconds in a Web Worker on a laptop |
Local MCP server, reading a path | DXF and IFC 200 MB; CSV, GeoJSON and IMDF 50 MB | Your machine, no network |
Hosted MCP, content inline in a tool call | 256 KB; no IFC | Content travels through the model at about 300 tokens per KB, and Vercel caps requests at 4.5 MB |
Any layout spec | 1 MB; ≤25,000 pick faces, ≤50,000 reserve positions, ≤100 doors, ≤2,000 ft a side, one floor | Keeps a simulation under ~10 s on Vercel |
All of them live in lib/layout/limits.ts. public/samples/ has the same sample warehouse in every format (npm run samples rebuilds them).
Watch it run in 3D
https://digitaltwin-mcp.vercel.app/twin plays a run back in three dimensions in your browser: supplier trucks backing onto the doors, pallets unloaded and put away, pickers walking S-shape tours through the aisles, forklifts replenishing faces, pallets packed, staged and loaded, and the store trucks leaving on time or late, with the queues, the pick faces and the KPIs as they accrue.
Same engine, same numbers. The page runs
lib/twin/operations.tsin a Web Worker and records its event stream. Nothing is animated that the engine did not do, and the HUD's figures equal the tools' KPIs at the end of the run. What the engine does not decide (which forklift, which door, walking between jobs, staging lanes, the yard) is synthesized as a deterministic function of the event stream, so the same seed always plays back the same way and the animation never feeds back into the results. The inspector shows engine facts and synthesized detail separately, with how each job's animation was fitted into its engine duration.Seed 1 replays a tool's first run.
simulate_operationsandwhat_ifend with a link carrying the building, week, days and scenario.replicate()runs seeds 1..runs, so the page's seed 1 is run 1 of the table. The URL hash holds everything (lib/twin-ui/hash.ts: the scenario deflated and base64url-encoded, 6 KB at most); the server is never involved.Scenarios. Every scenario field, in tabs: labor (shifts, operating days, roster, cross-training, per-worker productivity, standards), supply (forecast, service level, supplier lead times and delays, inbound window and lateness), deliveries (demand, shocks, delivery days, release and departure times), space (slotting, face sizes, doors, forklifts, rack zones; an imported building comes from the
/importpage's "Open in 3D") and disruptions (door, forklift and WMS outages). Compare a run against the previous one on the timeline.Playback. Scrub, 1× to 1800×, skip the hours when nobody is on the floor, follow a worker or a truck, walk the floor in first person, presets for the dock, the pick module, the reserve and the yard. Lighting follows the simulated clock.
Report. The Report tab writes up the run on screen: the headline KPIs, the bottleneck, ranked recommendations that name the scenario field and tab to change (an order selector on the late days, a forklift, more face cases, a higher service level, a later departure), and a day-by-day table of fill rate, trucks and lateness, labor cost, overtime, utilization and the process that queued most that day, with the processes, the crew and the late trucks behind it. Download it as Markdown, the day table as CSV, or everything as JSON; with a previous run on the Compare tab the Markdown adds every KPI's delta. The numbers are the engine's; the recommendations are rules over them (
lib/twin-ui/report.ts), not an optimizer.Optimize. The Optimize tab runs the
optimize_operationssearch in the browser's Web Worker, on the same engine: pick an objective preset (service first, balanced, cost first; they differ only in how dearly a late truck is priced) and the levers the search may move (crew added by role, cross-training, flexing and the overtime cap, slotting and face cases, forklifts, pallet jacks and doors, service level, forecast, truck departure), set the population, generations and engine seeds, and watch the best weekly cost fall generation by generation. What the Scenario tab already holds (demand, outages, an imported building) is the base every candidate is built on. The result lists the plan's changes, its KPIs and cost breakdown against the operation as it is, and the runners-up; apply the plan to the Scenario tab and run it to watch it in 3D, since the winner was scored on the seeds the page plays. Nothing leaves the browser, and there is no time cap, unlike the hosted tool's 60 s.
Nothing is stored. The run lives in the browser tab, and an imported drawing stays there too.
Model
Network. candystore's market model sets each store's annual retail dollars by category (traditional, plus specialty candy for heritage segments) and its supplying center. data/network.json is a snapshot of candystore's live API; tools that take a candystore scenario (stores added or closed) call the API for that scenario instead.
Demand. General stores get deliveries Monday, Wednesday and Friday; specialty stores Tuesday and Friday. A delivery carries the store's weekly category dollars ÷ deliveries × candystore's seasonal index for the week, split across SKUs by velocity share and turned into display boxes ("inners") at retail price, with a Poisson draw per SKU.
Building. Rack locations, doors and a pick depot in feet. Pick tours use S-shape routing and split when the cart is full. Forklift trips are rectilinear with lift time per level. Picks outside golden levels 2–3 pay a bend-or-reach allowance.
Operations. A discrete-event simulation by the minute. Orders drop at 17:00, are allocated against put-away stock, and are picked from 06:30 for a 14:00 truck. Every task is a job in a queue: tours, replenishments (routine at a face's last case, hot when a pick finds it short, then a re-pick), packing, loading, and unloading, receiving and putaway for supplier trucks. A worker takes the most urgent job their primary skill allows, then anything else they're cross-trained for. Jobs also wait for forklifts, pallet jacks and doors. Durations are engineered standards ÷ worker productivity. The last shift stays on overtime, to a cap, while trucks due before the next shift aren't loaded. Waits count floor time only.
Inventory. Periodic review on each supplier's order day, order-up-to S = mean demand over review + lead time + z·σ. The seasonal forecast looks ahead through the candy calendar; trailing averages four weeks. Suppliers ship full single-SKU pallets and consolidate remainders onto mixed pallets. Eight weeks of warm-up. Stores don't backorder: what can't be allocated is cut.
Slotting. Current: catalog order, uniform 3-case faces. Optimized: the most-picked SKUs in the cheapest slots, faces sized to five days of demand. A partial re-slot makes only the highest-gain swaps.
Workforce. Workload = expected volume × standards, by shift and skill. Requirement = workload ÷ productivity ÷ target utilization ÷ (1 − absenteeism). The schedule gives full-timers every operating day and part-timers their heaviest days, assigns primaries scarcest-skill-first to the least flexible people, and lets cross-trained spare hours cover short skills. The season plan closes the rest with overtime, then temps (slower, never forklift-certified), and flags forklift hours that only cross-training or hiring can cover, with lead times.
Capacity. Scale every store's demand until on-time or fill misses the target, and compare the most the building ships with candystore's assumption.
Optimizer. A genetic algorithm over the operation's levers (lib/twin/optimize.ts): people added by role, cross-training, flexing, the overtime cap, slotting and face cases, forklifts, pallet jacks, doors, service level, forecast and truck departure. Each candidate is a scenario the twin accepts, run on the floor and scored as one weekly cost: labor, amortized hires and training, equipment and doors beyond the building's, the carrying cost of the stock held, and priced penalties for late trucks, trucks never loaded and orders cut. The three presets (service first, balanced, cost first) differ only in the price of a late truck; every price is an input and comes back with the plan. Generation 0 holds the operation as it is and every one-lever step from it, so an obvious single fix is found at once; then elites, tournament selection, crossover, mutation and an immigrant per generation, with early stopping and memoized candidates. Deterministic for a spec and seed, and every candidate is scored on engine seeds 1..n, so the winner replays exactly on the 3D page. The result is the best plan found, not a proof of optimality.
Everything is implemented from these rules in lib/twin/ with tests.
Tools
Thirteen tools on both transports; render_floor is a fourteenth that exists only on the local stdio server.
Tool | Purpose |
| Network, buildings, crews, and a baseline run of each center. Call first. |
| DXF, WMS CSV, ArcGIS Indoors, IMDF (and IFC locally) → a layout spec every tool accepts, with a report of how it was read. |
| Zones, faces, doors, equipment, fastest SKUs and where they sit, face sizes. |
| Roster, skills, single points of failure, labor standards, cost rates. |
| Run the floor for up to 8 weeks: service, labor, flow, queues, crew, days, bottleneck. |
| Baseline against a scenario with the same random draws. |
| Random breakdowns, outages, sick leave, supplier delays and surges over many runs. |
| The most candystore demand the building ships on time, and what breaks first. |
| A genetic search over crew, training, overtime, slotting, equipment, doors, supply policy and truck departure for the cheapest plan by stated prices; service, balanced or cost first; the plan as a scenario. |
| Current, partial and full re-slot: labor saved, moves, payback, floor check. |
| Stock by category, open POs, weekly projection, stockouts, both forecast methods. |
| Week-by-week requirement, gaps, overtime, temps, cost, and a floor check of the peak. |
| Who works which day on what; hours needed and covered; one-absence risks. |
| Local only. Self-contained HTML floor plan shaded by pick frequency. |
optimize_operations takes the same scenario fields as the base operation the levers do not touch, plus objective, levers, population, generations, seeds, seed and assumptions (the prices behind the score). The hosted call is capped at 600 evaluation-weeks (population × generations+1 × seeds × days/7) to finish inside Vercel's 60 s; the 3D page's Optimize tab runs the same search in the browser without a cap.
Every simulation tool takes the same scenario fields, so a conversation can chain "plan labor, test the fix, stress-test it" with one set of assumptions:
Building:
layout(fromimport_layoutor the web page).Demand:
demandScale,demandShocks,candystore(live store scenario).Policy:
slotting,forecast,serviceLevel,flex,overtimeMaxHours,targetUtilization.People:
addWorkers,removeWorkers,crossTrain,workerLeave,absenteeism.Facility:
forklifts,palletJacks,inboundDoors,outboundDoors,faceCases.Disruptions:
doorOutages,forkliftOutages,wmsOutages,supplierDelays.Added with the 3D twin:
shifts(patterns, breaks, indirect time),operatingDays,times(order release, truck departure, inbound window),deliveryDaysby store type,workerOverrides(productivity, weekly hours, wage),standards(the engineered minutes and speeds),supplierOverrides(lead time, its variability, order day),inboundLatenessSdMin, andrackZonesto re-rack a built-in building (ignored, with a note, when alayoutis imported).
Days count from 0, the Monday of startWeek. Three prompts package common chains: peak_readiness, disruption_drill, expansion_impact. Resources expose the manifest, the candystore snapshot, the buildings and the method.
Remote
claude mcp add --transport http dc-twin https://digitaltwin-mcp.vercel.app/mcpLocal, with the floor-plan renderer
git clone https://github.com/Jaysunnn8solutions/digitaltwin_mcp.git
cd digitaltwin_mcp && npm install
claude mcp add dc-twin-local -- npx tsx /absolute/path/to/digitaltwin_mcp/mcp/stdio.tsThen ask: "Is Norcross ready for Halloween? If not, what's the cheapest fix?"
Data
File | What | Source |
| Centers, stores, weekly dollars by category, assumed capacity | candystore_mcp live API ( |
| 281 SKUs, 11 suppliers, pack sizes, cube, velocity, lead times | Generated, fixed seed; generic product types, no brands |
| 7 workers by id, role, skills, productivity, wage | Generated, fixed seed; no names |
| Buildings, zones, doors, equipment, delivery days, clock, shifts | Hand-written |
| Labor standards and cost rates | Placeholders |
Architecture
pipeline/ candystore snapshot, catalog and roster generators
data/ committed network, catalog, roster, sites, manifest
lib/util/ seeded random streams, event heap
lib/layout/ layout spec and limits; DXF, CSV, GeoJSON (IMDF, Indoors) and IFC importers; the shared assembler; samples
lib/twin/ season, layout (aisles and locations from a spec), demand, slotting, inventory, workforce, operations (DES, with trace hooks), replicate, twin (scenario → context), scenario-ext (the 3D twin's fields)
lib/trace/ the engine's event contract and the compiler: world, exact paths, identities (which forklift, door, lane), fit, running KPIs, cursor → typed-array playback
lib/three/ the three.js renderer: building, racks, actors, cameras, walk mode, picking, lighting, labels, viewer
lib/twin-worker/ the browser run: bundled data, buildTwin, runOperations with a tracer, compile, transfer
lib/twin-ui/ the URL hash codec shared by the page and the tools' links
lib/tools/ MCP tools, prompts, resources, one registration for both transports
lib/render/ the floor-plan SVG, shared by page, browser preview and render_floor
components/ the import workbench and its Web Worker; components/twin/ the 3D workbench, scene, timeline, inspector and the simulation worker
app/mcp/ remote MCP endpoint (mcp-handler)
app/api/twin/ stateless simulation of an imported layout
app/page.tsx the web page; app/import/ the upload page; app/twin/ the 3D twin
mcp/stdio.ts local MCP server (StdioServerTransport) + render_floorRunning locally
npm install
npm run dev # http://localhost:3000
npm test
npm run type-check && npm run lint
npm run pipeline # refresh the candystore snapshot; CANDYSTORE_URL overrides the source
npm run test:client -- http://localhost:3000 # every tool over HTTP
npm run test:client -- stdio # every tool over stdio, plus render_floorLimitations
The volumes are candystore's, and candystore is five stores, so the buildings are small. The dynamics (time-window capacity, single points of failure, face sizing) are what carry over to a real building, not the headcounts.
Standards, costs, the roster and the buildings are placeholders. Calibrate
lib/twin/standards.tsanddata/before trusting a number.One shift, Monday to Friday, by default. The
shiftsandoperatingDaysscenario fields change that; the planner and the simulation both read them, but the default calendar was only tuned for one shift.The 3D page runs in the browser and stops at 28 days (the tools go to 56). candystore store scenarios go through the tools only, because candystore's API is fetched server-side. A second shift is approximated: planning assigns the outbound work to the shift on the floor 2½ hours after the order release (19:30 with the default 17:00 release), and the animation of a job that spans a shift change is fitted, not re-planned.
Reserve locations are fixed per SKU and capacity is checked, not enforced: overflow is reported, not simulated as floor stacking.
The labor plan works in weekly hours and the floor in cutoffs, so a plan that balances can still ship late.
plan_laborchecks its peak week on the floor for that reason.Imports read plan geometry, not engineering detail: DXF arc bulges become straight segments and HATCH fills are skipped; rack levels come from the
levelsoption unless a CSV or IFC says otherwise; one floor is modelled; and aisles are assumed to run front to back from a cross aisle on the dock side. Always read the import report before trusting a result.Replications are few by default for speed. Raise
runswhen a decision rests on a small difference.
This server cannot be deployed
Maintenance
Related MCP Connectors
Supply-chain network design via simulation, optimization, and greenfield analysis.
Healthcare staffing simulator — ED, walk-in clinic, and appointment office DES tools.
Public MCP digital twin with synthetic systems and an agent firewall. No customer data.
Governed data discovery, exact queries, decisions, simulations, and runtime utilities over MCP.
Related MCP Servers
- AlicenseAqualityDmaintenanceControl and automate FlexSim simulations through AI assistants like Claude, enabling manufacturing and warehouse digital twin analysis, parameter studies, and real-time model manipulation via tools for opening models, running simulations, evaluating FlexScript, and exporting results.156MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server for supply chain intelligence that enables conversational querying of eight operational KPIs and anomaly detection data through Claude. It allows users to analyze performance metrics like OTIF and inventory turnover while providing LLM-generated root-cause explanations.11MIT
- AlicenseAqualityDmaintenanceThe first logistics/WMS MCP server for AI agents. Rate shopping, inventory management, order tracking, fleet logistics, AI-powered route optimization, demand forecasting, and supply chain analytics. 18 tools across 3 tiers.206 npm1MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to manage logistics operations including orders, shipments, tracking, and warehouse management through standardized MCP tools.-