Example: MCP Toolsets
Hands-on walkthrough for registering sample toolsets and invoking them from an AI client. For authoring guides, see MCP .NET and MCP Python.
Samples
| Sample | Link | Backend |
|---|---|---|
| Python toolset | samples/PythonDemo/mcp_toolset | Python folder + *mcp.py entry file |
| .NET demo | samples/McpToolsetDemo | C# assembly (minimal) |
| Revit toolset | samples/RevitMcpToolSet | C# assembly (full Revit surface) |
RevitMcpToolSet and PythonDemo/mcp_toolset implement the same tool surface per TOOLSET-SPEC.md. Load one implementation per host instance — do not register Python and C# toolsets with overlapping tool names at the same time.
What Each Sample Shows
| Sample | Purpose |
|---|---|
| McpToolsetDemo | .NET tools, prompts, and resources — parser and schema edge cases |
| RevitMcpToolSet | Production-style Revit MCP tools, resource templates, prompts |
| PythonDemo/mcp_toolset | Python layout, DTOs, services, parser test files |
Register in Settings
Toolsets are not auto-discovered from script folders. Register each toolset explicitly:
- Open the RevitDevTool panel → Settings → MCP
- Add a toolset entry:
- .NET: path to the built assembly (e.g.
RevitMcpToolSet.dllafterdotnet build) - Python: folder path containing a
*mcp.pyentry file
- .NET: path to the built assembly (e.g.
- Save settings and wait for the host catalog to reload
- Open the MCP registry view in the host UI — confirm tools, resources, and prompts appear
- From your AI client,
search_dynamicfor a tool name (e.g.revit_find_elementsorget_demo_status) andinvoke_dynamicwith the returnedcapabilityId
The MCP server tools/list still shows only infrastructure tools. Custom toolset tools appear only through search_dynamic.
Build the .NET Samples
dotnet build samples/McpToolsetDemo/McpToolsetDemo.csproj
dotnet build samples/RevitMcpToolSet/RevitMcpToolSet.csproj
Point Settings → MCP at the built DLL under bin/. See MCP C# SDK for project setup and attribute patterns.
Python Folder
Register the folder that contains a *mcp.py entry file. Dependencies belong in that entry file's PEP 723 header; conftest.py is not used for MCP registration. See MCP Python SDK for the sample layout and @mcp.tool conventions. Wire names use snake_case only (no Field(alias=) on parameters).
Run / Try
- Build the .NET sample (if testing assembly-based discovery)
- Register the assembly path or Python folder in Settings → MCP
- Confirm entries in the host MCP registry UI
- Confirm your AI client MCP config uses
--stdio(see MCP .NET or MCP Python) - In the AI client:
search_dynamic(query="<tool_name>")→invoke_dynamic(capabilityId=...) - Call a read-only tool first (e.g.
get_demo_status,revit_get_model_summary), then mutating tools
Troubleshooting
| Symptom | Check |
|---|---|
| Toolset not in registry UI | Path registered in Settings → MCP; .NET DLL built for correct host/API version |
| Python toolset not visible | Folder contains a *mcp.py file; its PEP 723 dependencies resolve successfully; the entry module imports without errors |
search_dynamic finds nothing | Host running with add-in loaded; MCP pipe exists (DevToolsMcp_*); toolset registered and catalog reloaded |
invoke_dynamic stale ID | Host disconnected or catalog changed — search_dynamic again, then invoke new capabilityId |
| Tool appears but call fails | Test a read-only tool first; check host document/selection preconditions |
| AI client cannot connect | MCP config points to DevTools.Daemon.exe with args: ["--stdio"]; .NET 10 installed |
| AI client connects but no hosts | At least one host open with RevitDevTool loaded; use list_host_instances |