MCP Server#
NREL-shift includes a Model Context Protocol (MCP) server that exposes the full framework to LLM-based agents. The server provides 33 tools, 3 resource templates, and 3 prompt templates that enable AI assistants to build synthetic distribution feeder models interactively.
Installation#
Install the MCP optional dependencies:
pip install -e ".[mcp]"
Running the Server#
# Via console script
shift-mcp-server
# Via Python module
python -m shift.mcp_server
The server uses stdio transport by default.
Claude Desktop Configuration#
Add the following to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"nrel-shift": {
"command": "shift-mcp-server"
}
}
}
Architecture#
src/shift/mcp_server/
├── __init__.py
├── __main__.py # Entry point
├── server.py # FastMCP instance, lifespan, registration
├── config.py # ServerConfig (Pydantic model)
├── state.py # AppContext — in-memory session state
├── serializers.py # JSON serialization helpers
├── tools/
│ ├── data_acquisition/
│ │ ├── parcels.py # fetch_parcels, fetch_parcels_in_polygon
│ │ ├── roads.py # fetch_road_network
│ │ └── clustering.py # cluster_parcels
│ ├── graph/
│ │ ├── management.py # create_graph, delete_graph, list_graphs
│ │ ├── nodes.py # add_node, remove_node, get_node
│ │ ├── edges.py # add_edge, remove_edge, get_edge
│ │ ├── query.py # query_graph
│ │ └── builder.py # build_graph_from_groups
│ ├── mapper/
│ │ ├── phase.py # configure_phase_mapper, get_phase_mapping
│ │ ├── voltage.py # configure_voltage_mapper, get_voltage_mapping
│ │ └── equipment.py # configure_equipment_mapper, get_equipment_mapping
│ ├── system/
│ │ ├── builder.py # build_system, get_system_summary, list_systems
│ │ └── export.py # export_system_json
│ ├── utilities/
│ │ ├── geo.py # distance_between_points, polygon_from_points
│ │ ├── network.py # create_mesh_network, split_edges
│ │ └── nearest.py # find_nearest_points
│ └── documentation/
│ ├── search.py # search_docs
│ └── read.py # list_docs, read_doc
├── resources/
│ └── docs.py # shift://docs, shift://docs/{name}, shift://graphs
└── prompts/
└── workflows.py # build_feeder_from_location, inspect_network, explore_api
Session State#
The server is stateful — graphs, mappers, and systems are held in memory for the duration of a session via the AppContext dataclass. Each tool receives the context through FastMCP’s lifespan mechanism.
Key state containers:
Container |
Type |
Contents |
|---|---|---|
|
|
In-memory distribution graphs |
|
|
Phase mapper instances |
|
|
Voltage mapper instances |
|
|
Equipment mapper instances |
|
|
Built distribution systems |
|
|
Indexed documentation content |
Tools Reference#
Data Acquisition (3 tools)#
Tool |
Description |
|---|---|
|
Fetch building parcels from OpenStreetMap for a given location |
|
Fetch building parcels within a polygon boundary |
|
Fetch the road network from OpenStreetMap around a location |
Graph Management (8 tools)#
Tool |
Description |
|---|---|
|
Create a new empty distribution graph |
|
Delete a distribution graph and its associated mappers |
|
List all distribution graphs in the current session |
|
Add a node to a distribution graph |
|
Remove a node from a distribution graph |
|
Get details of a specific node |
|
Add an edge (line or transformer) to a distribution graph |
|
Remove an edge from a distribution graph |
|
Get details of a specific edge |
|
Query information about a distribution graph (summary, nodes, edges, vsource, dfs_tree) |
|
Build a complete distribution graph from parcel groups using the PRSG algorithm |
Mappers (6 tools)#
Tool |
Description |
|---|---|
|
Configure balanced phase mapping for a distribution graph |
|
Get phase assignments (nodes, assets, or transformers) |
|
Configure voltage mapping for a distribution graph |
|
Get voltage assignments for all nodes |
|
Configure equipment mapping using an equipment catalog |
|
Get equipment assignments for all edges |
System (3 tools)#
Tool |
Description |
|---|---|
|
Build a complete distribution system from a configured graph |
|
Get a summary of a built distribution system |
|
List all built distribution systems in the current session |
|
Export a distribution system to JSON format |
Utilities (5 tools)#
Tool |
Description |
|---|---|
|
Cluster geographic points into groups using K-means |
|
Calculate geodesic distance between two points |
|
Create a polygon boundary from a set of points |
|
Create a regular 2D mesh/grid network |
|
Split long edges into shorter segments |
|
Find the nearest target point for each source point |
Documentation (3 tools)#
Tool |
Description |
|---|---|
|
List all available documentation files |
|
Search across all documentation for a keyword or phrase |
|
Read a specific documentation file, optionally by section |
Resource Templates#
URI |
Description |
|---|---|
|
List all indexed documentation files |
|
Read a specific documentation file by name |
|
List all in-memory distribution graphs |
Prompt Templates#
Prompt |
Description |
|---|---|
|
Guides through the full pipeline: fetch → cluster → build graph → map phases → map voltages → map equipment → build system → export |
|
Inspect an existing distribution graph and summarize its topology |
|
Explore the NREL-shift API documentation on a given topic |
Configuration#
The server loads configuration from a ServerConfig Pydantic model. Defaults can be overridden by placing a shift_mcp_config.yaml file in the working directory.
Setting |
Default |
Description |
|---|---|---|
|
|
Server display name |
|
|
Server version |
|
|
Default parcel/road search radius (meters) |
|
|
Maximum allowed search radius (meters) |
|
|
Default number of K-means clusters |
|
|
Override path to documentation directory |
|
|
Logging level |
Example Workflow#
A typical agent-driven workflow:
User: Build a small distribution feeder for Golden, CO
Agent:
1. fetch_parcels(location="Golden, CO", distance_meters=300)
→ 24 parcels found
2. cluster_parcels(points=[...], num_clusters=6)
→ 6 groups created
3. build_graph_from_groups(groups=[...], source_longitude=-105.22, source_latitude=39.75)
→ graph "graph-a1b2" created with 31 nodes, 30 edges
4. configure_phase_mapper(graph_id="graph-a1b2", transformer_configs=[...])
→ phase mapper configured
5. configure_voltage_mapper(graph_id="graph-a1b2", transformer_voltages=[...])
→ voltage mapper configured
6. configure_equipment_mapper(graph_id="graph-a1b2", catalog_path="...")
→ equipment mapper configured
7. build_system(system_name="golden_feeder", graph_id="graph-a1b2")
→ system built
8. export_system_json(system_name="golden_feeder", output_path="./golden_feeder.json")
→ exported to ./golden_feeder.json
Known Limitations#
Pydantic version conflict:
grid-data-models==2.2.1pinspydantic~=2.10, whilemcp[cli]may requirepydantic>=2.12. You may need to relax the pin or install in a separate environment.Network-dependent tools:
fetch_parcels,fetch_parcels_in_polygon, andfetch_road_networkrequire internet access to query OpenStreetMap.Single session: The stdio transport serves one client at a time. For multi-client scenarios, wrap with a proxy or use the SSE transport.