ms-project-mcp
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., "@ms-project-mcpadd 5 tasks to the open schedule, link them finish-to-start, and show the critical path"
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.
ms-project-mcp
Drive Microsoft Project desktop from any MCP-capable agent.
Create the plan, wire the dependencies, level the resources, save baselines, audit the critical path, export the report — all against the real .mpp open in Project.
Why this exists
Microsoft Project desktop has no public HTTP API. The only way to automate it is COM — a single-threaded, apartment-bound automation surface that is easy to get subtly wrong. This server turns that surface into 51 typed MCP tools with a stable id scheme, field-name-based reads and writes, dry runs, and real error messages, so an agent can do project management work instead of fighting COM.
It talks to the application you have open, not a cloud copy. If you can click it, the agent can usually do it — and you can watch it happen.
Related MCP server: project-mcp
What it can do
Area | Capabilities |
Projects | Attach to the running window, list/switch open files, create, open |
Tasks | Bulk create with WBS nesting, update, delete, indent/outdent, reorder, read/write almost every field, custom fields, paging and filters |
Dependencies | FS / SS / FF / SF links with lag or lead, append or replace, parsed successors |
Resources | Work, material, and cost resources; rates, max units, calendars, groups; assign with allocation units, reassign, unassign |
Calendars | Base calendars, holidays and exception ranges, per-day working shifts, project calendar |
Baselines & value | Save/clear baselines 0–10, per-task variance, earned value (BCWS/BCWP/ACWP/SPI/CPI) |
Analysis | Critical path, schedule audit, what-if delay with automatic revert, timephased data |
Export | CSV, PDF, full JSON snapshot, open existing Project XML |
Escape hatches | Run an existing VBA macro, or inject arbitrary VBA (opt-in) with results and errors returned |
Architecture
┌──────────────────────────┐
│ Agent (Command Code, │
│ Claude, Cursor, …) │
└────────────┬─────────────┘
│ stdio · JSON-RPC (MCP)
┌────────────▼─────────────┐
│ MCP tools │ thin, typed, annotated
├──────────────────────────┤
│ MSProjectClient │ domain logic, field registry
├──────────────────────────┤
│ ComBridge │ ONE STA thread · serialized queue
│ │ busy-retry · timeouts
├──────────────────────────┤
│ WINPROJ.EXE │ attaches, or launches if needed
└──────────────────────────┘Office COM objects are apartment-threaded. Calling them from several threads
produces intermittent RPC_E_WRONG_THREAD and "Call was rejected by callee"
errors, so every COM call is marshalled onto one dedicated thread and
executed serially. If you click around in Project while an agent works, rejected
calls are retried instead of failing.
Requirements
Windows with desktop Microsoft Project installed (2016 / 2019 / 2021 / Microsoft 365). Verified end to end against Project 16.0 (Microsoft 365).
Python 3.10+ (developed on 3.13).
No project file needs to be open at startup.
Project Online / for the Web is a different product with a different API (Graph/CSOM). This server targets the desktop application only.
Install
git clone https://github.com/iamsammy-ak/ms-project-mcp.git
cd ms-project-mcp
python -m venv .venv
.\.venv\Scripts\python -m pip install -e .Check that it can see Project:
.\.venv\Scripts\python -c "from msproject_mcp.core import MSProjectClient; print(MSProjectClient().status())"Prefer a global command? pipx install . gives you msproject-mcp on PATH.
To ship it to another machine, build a wheel and copy that:
python -m pip wheel --no-deps -w dist .
# elsewhere: pip install msproject_mcp-0.1.0-py3-none-any.whlConnect your agent
Use the absolute path to your interpreter (or the msproject-mcp shim).
Command Code
cmdc mcp add --scope user --env MSPROJECT_MCP_ALLOW_VBA=1 msproject -- "C:\path\to\ms-project-mcp\.venv\Scripts\python.exe" -m msproject_mcpClaude Desktop / Claude Code / Cursor / VS Code
{
"mcpServers": {
"msproject": {
"command": "C:\\path\\to\\ms-project-mcp\\.venv\\Scripts\\python.exe",
"args": ["-m", "msproject_mcp"],
"env": { "MSPROJECT_MCP_ALLOW_VBA": "1" }
}
}
}Remote agents can use the HTTP transport instead:
python -m msproject_mcp --transport streamable-http --port 8765Keep it bound to 127.0.0.1 unless you understand the exposure — it drives your
desktop applications.
Try it
With Project open (or not — the agent can start it):
"What's the critical path in the open project?"
"Create a launch plan: Discovery 5d, Design 8d, Build 15d, Test 6d,
UAT 4d, Launch 1d — link them finish-to-start, indent Build..Test
under a Delivery phase."
"Alice is 50% available and Bob is out for two weeks. Fix the
resource overload and tell me what slipped."
"Save baseline 0, then show every task that is more than 3 days late."
"Export the schedule to C:\Temp\launch.csv and a PDF next to it."
"Add our Eid holidays to the Standard calendar for 2026."Tool reference
Tool | What it does |
| Is Project running, which files are open, which is active, is VBA enabled |
| Every open project with task/resource counts |
| Switch active project by index, name, fragment, or path |
| New blank project with title and start date |
| Open |
| Save in place |
| Save as |
| Close a project, optionally saving |
| Quit the application |
| Show or hide the Project window |
Tool | What it does |
| Title, dates, calendar, minutes/day and any requested fields |
| Update title, manager, status date, calendar, scheduling options, currency… |
| Every valid field name for tasks, resources, or the project |
Tool | What it does |
| List with name/level/summary/milestone filters and paging |
| Read one task with any field set |
| Append tasks in order; |
| Bulk field edits with |
| Delete by id, with preview |
| Promote/demote in the WBS |
| Reorder a row (uses Project's cut/paste) |
Tool | What it does |
| FS/SS/FF/SF links with lag/lead; replace or append |
| Parsed predecessors and successors |
Tool | What it does |
| Resource pool with filters and paging |
| Add work/material/cost resources |
| Change rates, units, calendar, grouping, custom fields |
| Remove resources and their assignments |
| Assign with units; creates missing resources on request |
| Remove assignments |
| Work, actual/remaining work, cost, dates, % complete |
Tool | What it does |
| Base calendars and the project calendar |
| New calendar copied from an existing one |
| Holiday or exception date range |
| Exceptions with their index |
| Remove an exception |
| Per-day shifts, or mark a day non-working |
Tool | What it does |
| Recalculate and return the new finish date |
| Run Project's automatic leveling |
| Baseline 0–10 |
| Finish slip, duration/work/cost variance per task |
| BCWS/BCWP/ACWP/SV/CV/SPI/CPI and totals |
| Critical tasks in chronological order with slack |
| Overdue, negative slack, hard constraints, missing resources/links |
| What-if delay, then revert automatically |
| Per-day/week/month work, cost, actual, remaining, baseline |
Tool | What it does |
| UTF-8 CSV of the task table |
| PDF through Project's own exporter |
| JSON snapshot of tasks, resources, and metadata |
| Open a Project XML file |
| Run an existing VBA macro |
| Inject and run VBA (opt-in) |
Fields instead of a tool per property
Rather than hundreds of narrow tools, task/resource/project tools accept a
fields list keyed by stable names. get_field_catalog returns the whole set.
get_tasks(fields=["name", "duration", "start", "finish", "text1", "number1"])
update_tasks([{"unique_id": 12, "set": {"duration": "8d", "percent_complete": 40}}])Conventions:
Ids accept
UniqueID(stable across edits) or the visible rowID. UniqueID is matched first; every row returns both.Durations accept
"5d","12h","480m", or raw minutes. Reads return bothduration: "5d"andduration_minutes: 2400.Percentages are
0–100; a non-integer0.0–1.0value is a fraction.New tasks are auto-scheduled (
manual: false) so links and durations recalculate. Pass"manual": trueto pin a task's dates.Every bulk mutation supports
dry_run.
Custom fields are first-class: text1–text30, number1–number20,
flag1–flag20, date1–date10, cost1–cost10, duration1–duration10.
VBA escape hatch
run_vba closes the last gap: dialog-only operations and expressions no COM
property exposes. It is off by default.
Start the server with
MSPROJECT_MCP_ALLOW_VBA=1.In Project: File → Options → Trust Center → Trust Center Settings → Macro Settings → Trust access to the VBA project object model.
The code is injected into a temporary module, executed, and the module is
removed. Assign your result to MspMcpEval:
Dim t As Task
Set t = ActiveProject.Tasks(3)
MspMcpEval = t.Name & " / " & t.FinishRuntime errors come back as readable tool errors (VBA error: 11: Division by zero).
Configuration
Variable | Default | Purpose |
|
| Show the Project window while working |
|
| Enable |
|
| Seconds before a single COM call is abandoned |
| — | Project to use when several are open |
|
| Row cap for list tools |
|
|
|
|
| Logs go to stderr only |
What working with Project 16 actually taught us
These are baked into the code, and they are the difference between a demo and a tool that works:
Behaviour | Consequence |
| Links and durations would never propagate; new tasks default to auto-scheduled |
| WBS moves use |
| Assignments are created with |
PDF export lives on |
|
Saving to XML through COM opens a modal dialog | XML export is intentionally not exposed; CSV/PDF/snapshot are |
Rates come back localized ( | Numeric fields parse currency strings and also return the raw text |
Dates arrive UTC-tagged but represent local wall-clock time | Converting to local (not stripping the tz) keeps dates correct |
| VBA results are written to a temp file and read back |
Limitations
One automation client per Project instance. A modal dialog in Project blocks calls until dismissed; they surface as a clear timeout.
No undo. Project's COM undo is one level deep and unreliable. Use
dry_runandsnapshot_projectbefore destructive batches.save_project_asrebinds the open project, exactly like Project's own Save As. Only.mppand.mptare supported.move_taskuses cut/paste, so it touches the Windows clipboard.Dialog-only features (recurring-task insert, report designer) have no COM entry point;
run_vbacovers most of them.Timephased queries over multi-year ranges are slow — keep ranges modest.
Windows only, and desktop Project only.
Testing
.\.venv\Scripts\python tests\smoke_live.py # 47 steps against real Project
.\.venv\Scripts\python tests\mcp_e2e.py # real server over stdio MCPsmoke_live.py launches Project, creates a throwaway schedule, exercises every
tool group, and closes only what it created. mcp_e2e.py spawns the server over
stdio and drives it through an MCP client, including the error path.
Both require Microsoft Project and are therefore not run in CI.
Contributing
Issues and PRs are welcome. Please keep the invariants:
All COM access goes through
ComBridge— never call COM from another thread.New fields go in
fields.py; new behaviour goes incore.py; tools stay thin.Add a live test step for anything that touches Project.
License
MIT © 2026 iamsammy-ak
This server cannot be deployed
Maintenance
Related MCP Connectors
Remote MCP server to read and edit GanttFather projects: tasks, dates, dependencies, critical path.
Project management shared by people and AI agents, with persistent project state through MCP.
Project management MCP for AI agents with safe task reads and writes.
Read, analyze, and safely edit Microsoft Project MPP files.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables MCP-aware agents to interact with the classic Outlook desktop client for mail, calendar, contacts, tasks, and Out-of-Office settings via the COM API, without Azure or OAuth.201 PyPI36MIT
- AlicenseNot gradedqualityCmaintenanceMCP server that enables LLMs to read and analyze Microsoft Project schedules, including critical path, resources, and advanced construction planning layers (AWP and LPS) for work packages and Lean planning.MIT
- AlicenseNot gradedqualityAmaintenanceEnables MCP-compatible AI clients to query, analyze, and mutate Oracle Primavera P6 schedules from XER files or live P6 EPPM, with tools for critical path, DCMA compliance, earned value, resources, baselines, and exports.31 PyPI1MIT
- AlicenseNot gradedqualityCmaintenanceEnables Claude and other AI agents to build, edit, and analyze Microsoft Project desktop schedules on Windows through natural language, covering tasks, WBS, dependencies, resources, calendars, baselines, critical path, resource leveling, and earned value, with live changes in Project and single-step undo. It also exports results to PDF or CSV and reads project health and time-phased data for S-curves and histograms.MIT