Smart Home MCP Server with VSCode Copilot
What is MCP? My short definition is: A protocol that lets LLMs talk to your code. For example, if you have an API that returns a list of warehouses, how could you get Copilot to call your API and return a list of those warehouses? Or use the list internally to answer your questions about your warehouses? The answer is MCP. These clients can use it https://modelcontextprotocol.io/clients VSCode is in that list. They have added support for MCP https://code.visualstudio.com/docs/copilot/chat/mcp-servers What can I write my MCP server in? Python SDK TypeScript SDK Java SDK Kotlin SDK C# SDK Using CSharp I followed this tutorial, I will simplify here and adapt for my Smart Home https://devblogs.microsoft.com/dotnet/build-a-model-context-protocol-mcp-server-in-csharp/ Create a .NET app: dotnet new console -n SmartHomeMCPServer dotnet add package ModelContextProtocol dotnet add package Microsoft.Extensions.Logging.Console dotnet add package Microsoft.Extensions.Hosting dotnet add package RestEase (http client helper https://github.com/canton7/RestEase) I am using a Hubitat with an API plugin https://hubitat.com/. This is what the API plugin shows me: I used Copilot edit mode to generate my app after feeding in the API spec above. I also fed it the RestEase docs which is just the entire README.md. This is the HTTP client it generated with RestEase: public interface IHubitatApi { [Get("apps/api/60/devices/all")] Task GetAllDevicesAsync([Query("access_token")] string accessToken); [Get("apps/api/60/devices/{deviceId}/{command}/{secondaryValue}")] Task SendDeviceCommandAsync( [Path("deviceId")] string deviceId, [Path("command")] string command, [Path("secondaryValue")] string secondaryValue, [Query("access_token")] string accessToken ); [Get("apps/api/60/devices/{deviceId}/{command}")] Task SendDeviceCommandAsync( [Path("deviceId")] string deviceId, [Path("command")] string command, [Query("access_token")] string accessToken ); } public class Device { public string Id { get; set; } public string Name { get; set; } public string Label { get; set; } public string Type { get; set; } public string Room { get; set; } public string Date { get; set; } public string Model { get; set; } public string Manufacturer { get; set; } public List Capabilities { get; set; } public Attributes Attributes { get; set; } public List Commands { get; set; } } // ... After that, I wrapped the client around an MCP server: [McpServerToolType] public static class HubitatTool { [McpServerTool, Description("Fetches all devices from the Hubitat API.")] public static async Task GetAllDevices() { const string baseUrl = "http://192.168.1.120"; const string accessToken = "YOUR-TOKEN"; var api = RestClient.For(baseUrl); return await api.GetAllDevicesAsync(accessToken); } [McpServerTool, Description("Send a command to a specific device.")] public static async Task SendDeviceCommand(string deviceId, string command, string secondaryValue = null) { const string baseUrl = "http://192.168.1.120"; const string accessToken = "YOUR-TOKEN"; var api = RestClient.For(baseUrl); // Ensure secondaryValue is handled properly if (string.IsNullOrWhiteSpace(secondaryValue)) { await api.SendDeviceCommandAsync(deviceId, command, accessToken); } else { await api.SendDeviceCommandAsync(deviceId, command, secondaryValue.Trim(), accessToken); } } } I "vibe coded" the above, in a real world scenario id have a .env file for tokens and URLs. Finally, you can ask the LLM to list your devices!

What is MCP?
My short definition is: A protocol that lets LLMs talk to your code.
For example, if you have an API that returns a list of warehouses, how could you get Copilot to call your API and return a list of those warehouses? Or use the list internally to answer your questions about your warehouses?
The answer is MCP. These clients can use it https://modelcontextprotocol.io/clients
VSCode is in that list. They have added support for MCP https://code.visualstudio.com/docs/copilot/chat/mcp-servers
What can I write my MCP server in?
- Python SDK
- TypeScript SDK
- Java SDK
- Kotlin SDK
- C# SDK
Using CSharp
I followed this tutorial, I will simplify here and adapt for my Smart Home
https://devblogs.microsoft.com/dotnet/build-a-model-context-protocol-mcp-server-in-csharp/
Create a .NET app:
dotnet new console -n SmartHomeMCPServer
dotnet add package ModelContextProtocol
dotnet add package Microsoft.Extensions.Logging.Console
dotnet add package Microsoft.Extensions.Hosting
-
dotnet add package RestEase
(http client helper https://github.com/canton7/RestEase)
I am using a Hubitat with an API plugin https://hubitat.com/.
This is what the API plugin shows me:
I used Copilot edit mode to generate my app after feeding in the API spec above. I also fed it the RestEase docs which is just the entire README.md. This is the HTTP client it generated with RestEase:
public interface IHubitatApi
{
[Get("apps/api/60/devices/all")]
Task<List<Device>> GetAllDevicesAsync([Query("access_token")] string accessToken);
[Get("apps/api/60/devices/{deviceId}/{command}/{secondaryValue}")]
Task SendDeviceCommandAsync(
[Path("deviceId")] string deviceId,
[Path("command")] string command,
[Path("secondaryValue")] string secondaryValue,
[Query("access_token")] string accessToken
);
[Get("apps/api/60/devices/{deviceId}/{command}")]
Task SendDeviceCommandAsync(
[Path("deviceId")] string deviceId,
[Path("command")] string command,
[Query("access_token")] string accessToken
);
}
public class Device
{
public string Id { get; set; }
public string Name { get; set; }
public string Label { get; set; }
public string Type { get; set; }
public string Room { get; set; }
public string Date { get; set; }
public string Model { get; set; }
public string Manufacturer { get; set; }
public List<string> Capabilities { get; set; }
public Attributes Attributes { get; set; }
public List<Command> Commands { get; set; }
}
// ...
After that, I wrapped the client around an MCP server:
[McpServerToolType]
public static class HubitatTool
{
[McpServerTool, Description("Fetches all devices from the Hubitat API.")]
public static async Task<List<Device>> GetAllDevices()
{
const string baseUrl = "http://192.168.1.120";
const string accessToken = "YOUR-TOKEN";
var api = RestClient.For<IHubitatApi>(baseUrl);
return await api.GetAllDevicesAsync(accessToken);
}
[McpServerTool, Description("Send a command to a specific device.")]
public static async Task SendDeviceCommand(string deviceId, string command, string secondaryValue = null)
{
const string baseUrl = "http://192.168.1.120";
const string accessToken = "YOUR-TOKEN";
var api = RestClient.For<IHubitatApi>(baseUrl);
// Ensure secondaryValue is handled properly
if (string.IsNullOrWhiteSpace(secondaryValue))
{
await api.SendDeviceCommandAsync(deviceId, command, accessToken);
}
else
{
await api.SendDeviceCommandAsync(deviceId, command, secondaryValue.Trim(), accessToken);
}
}
}
I "vibe coded" the above, in a real world scenario id have a .env file for tokens and URLs.
Finally, you can ask the LLM to list your devices!