Back to blogs

Revit MCP: Read data from Active document

Jun 2026

I have used MCP to expose some of the revit api to LLM so that it can talk to it.

WPF (.NET 8)Model Context ProtocolRevit DB APINamed Pipes
View project
Revit MCP: Read data from Active document

Overview

Revit MCP is a desktop assistant that lets you talk to an Revit model in plain language. Instead of clicking through menus or writing one: off scripts, you describe what you want, and the app decides which tools to call against the active document.

The stack is split across two runtimes on purpose:

  • WPF (.NET 8) hosts the UI and Gemini integration
  • Revit add-in (.NET Framework 4.8) talks to the Revit DB API inside the Revit main thread.

The bridge between those two is Named Pipe

I have exposed some ( three ) APIs through MCP Server. Those are

  • GetWallLength
public object GetWallLength(string wallId)
        {
            var id = new ElementId(long.Parse(wallId));
            var wall = _doc.GetElement(id) as Wall;
            if (wall == null) return new { error = "Wall not found" };

            var lengthInternal = wall.get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH).AsDouble();
            var lengthMm = UnitUtils.ConvertFromInternalUnits(lengthInternal, UnitTypeId.Millimeters);
            var lengthM = UnitUtils.ConvertFromInternalUnits(lengthInternal, UnitTypeId.Meters);

            return new
            {
                wall_id = wallId,
                length_mm = System.Math.Round(lengthMm, 2),
                length_m = System.Math.Round(lengthM, 3)
            };
        }
  • GetFloorArea
public object GetFloorArea(string levelName)
        {
            var level = new FilteredElementCollector(_doc)
                .OfClass(typeof(Level))
                .Cast<Level>()
                .FirstOrDefault(l => l.Name == levelName);

            if (level == null) return new { error = $"Level '{levelName}' not found" };

            var floors = new FilteredElementCollector(_doc)
                .OfClass(typeof(Floor))
                .Cast<Floor>()
                .Where(f => f.LevelId == level.Id)
                .ToList();

            var totalArea = floors
                .Sum(f => f.get_Parameter(BuiltInParameter.HOST_AREA_COMPUTED).AsDouble() * 0.0929);

            return new { level = levelName, area_sqm = System.Math.Round(totalArea, 2) };
        }

  • ListRoomsByLevel - which is way easier as you only have to write one LINQ...
var rooms = new FilteredElementCollector(_doc)
                .OfClass(typeof(SpatialElement))
                .OfType<Room>()
                .Where(r => r.Level?.Name == levelName)
                .Select(r => new
                {
                    name = r.Name,
                    number = r.Number,
                    area_sqm = System.Math.Round(r.Area * 0.0929, 2)
                })
                .ToList();

Full Request Flow

User types prompt in WPF UI
        ↓
GeminiService.SendPromptAsync()
        ↓ HTTPS
Google Gemini API (gemini-2.5-flash)
        ↓ tool_use: open_revit_document
McpClientService.CallToolAsync()
        ↓ stdio (MCP protocol)
RevitMCP.Server.exe
        ↓ named pipe (RevitMCPPipe)
RevitMCP.Addin (inside Revit.exe)
        ↓ Revit DB API
Real Revit data (.rvt file)
        ↑ JSON result
Back through pipe → MCP server → Gemini
        ↑ tool_result
Gemini reasons, calls more tools if needed
        ↑ final text answer
ResponseText shown in WPF UI

2 cents and conclusion

It took me 12 days to build this while I was automating Revit workflows. As a new-generation engineer, I thought, "Why not build AI projects?"

They are very simple and easy to do in my openion. I think this is way simpler than automating Revit workflows and writing those LINQs, yet it will still be considered a very good project for a resume. Haha.

This is my first blog post and I hope to write more in the future. let's see if I can keep this up or it dies like my other projects. chop chop !!!

Revit MCP Demo