How to Extend DesktopCommanderMCP with Plugins: A Complete Guide
Yes, DesktopCommanderMCP supports plugin extension through a manifest-based discovery system that automatically loads custom tools and UI resources from the plugins/ directory without requiring modifications to the core server.
DesktopCommanderMCP is built as a Model Context Protocol (MCP) server that implements a flexible plugin architecture. According to the source code in wonderwhy-er/DesktopCommanderMCP, the server discovers extensions via a top-level plugin.yaml manifest (lines 5-61) and loads individual plugin descriptors from plugin.json files located in subdirectories under plugins/. This design enables third-party developers to add new functionality by declaring tools, schemas, and resources in a standardized format.
Understanding the Plugin Architecture
The extension system leverages the standard Agenium plugin schema to register capabilities dynamically. When the MCP server starts, the SDK scans the plugins/ directory (or paths referenced in plugin.yaml) and automatically registers each discovered plugin's tools and resources.
The core extensibility points are implemented in src/server.ts (lines 13-30), which registers generic handlers for ListResourcesRequestSchema and ReadResourceRequestSchema. These handlers serve UI assets for any plugin that contributes resources, meaning the core server does not need code changes to support new plugins.
Key configuration files include:
plugin.yaml(lines 5-61): Declares the server as a discoverable MCP plugin with runtime requirements (runtime.language: typescript,transport: stdio)src/server.ts: Contains the generic resource and tool handlers that expose plugin capabilities viaListResourcesRequestSchemaandReadResourceRequestSchemasrc/tools/schemas.ts: Provides Zod schema templates for tool argument validation
Creating a Custom DesktopCommanderMCP Plugin
Developing a plugin requires four main components: a directory structure, a plugin descriptor, tool implementation, and optional UI resources.
Step 1: Define the Plugin Structure
Create a new directory under plugins/ following this layout:
plugins/my-custom-tool/
├─ .my-custom-plugin/plugin.json ← Plugin descriptor
├─ src/
│ └─ myTool.ts ← Tool implementation
└─ ui/
└─ my-ui.html ← Optional UI resource
Step 2: Configure the plugin.json Descriptor
The plugin.json file declares your tool's metadata, input schemas, and runtime requirements. Based on the reference implementations in plugins/cursor/.cursor-plugin/plugin.json and plugins/claude/.claude-plugin/plugin.json, a minimal descriptor looks like this:
{
"name": "my-custom-tool",
"display_name": "My Custom Tool",
"description": "A sample tool that echoes back user text.",
"version": "0.1.0",
"author": {
"name": "Your Name",
"url": "https://github.com/yourname"
},
"runtime": {
"language": "typescript",
"min_node": "18"
},
"tools": [
{
"name": "myEcho",
"description": "Returns the supplied string.",
"input_schema": {
"type": "object",
"properties": {
"text": { "type": "string" }
},
"required": ["text"]
},
"handler": "./src/myTool.ts"
}
],
"resources": [
{
"uri": "my-ui.html",
"path": "./ui/my-ui.html"
}
]
}
Step 3: Implement Tool Logic
Create the tool implementation file referenced in the handler field. This file must export a function matching the expected signature:
import { ToolResult } from "@modelcontextprotocol/sdk/types.js";
export async function myEcho(args: { text: string }): Promise<ToolResult> {
return { result: `Echo: ${args.text}` };
}
Place your implementation in src/tools/ or the path specified in your plugin.json. The function receives validated arguments based on your Zod schema (use src/tools/schemas.ts as a template for complex validation) and returns a ToolResult.
Step 4: Add Optional UI Resources
If your plugin requires a user interface, place HTML or asset files in a ui/ folder. The generic resource handlers in src/server.ts automatically serve these files via the MCP resources/list and resources/read methods. Clients can access these resources using URIs defined in the resources array of your plugin.json.
How Plugin Discovery Works
The MCP server loads plugins through the following mechanism:
- Manifest Scanning: On startup, the server reads
plugin.yamlto confirm it is operating as a DesktopCommanderMCP instance withtransport: stdio. - Directory Scanning: The SDK scans the
plugins/directory for subdirectories containing.[plugin-name]/plugin.jsondescriptors (following the pattern seen in.cursor-plugin/and.claude-plugin/). - Registration: Tools are registered with the MCP framework using their declared names and schemas. Resources are indexed for the generic handlers.
- Runtime Execution: When a client calls a tool via the
tools/callJSON-RPC method, the server routes the request to the appropriate handler function defined in your plugin's TypeScript file.
Examples from the Repository
The plugins/ directory contains reference implementations demonstrating the extension pattern:
plugins/cursor/.cursor-plugin/plugin.json: Shows how Cursor-specific integrations declare tools and UI contractsplugins/claude/.claude-plugin/plugin.json: Provides an example of Claude-specific plugin configurationsrc/ui/contracts.ts: Defines URI patterns used by the resource handlers to serve plugin assets
These examples serve as templates for creating new extensions that integrate with specific AI clients while maintaining compatibility with the core MCP protocol.
Summary
- DesktopCommanderMCP uses a manifest-based plugin system defined in
plugin.yaml(lines 5-61) and individualplugin.jsondescriptors - Plugins reside in the
plugins/directory and require no core server modifications to function - The generic handlers in
src/server.ts(lines 13-30) automatically expose tools and resources declared inplugin.jsonfiles - Tool implementations use TypeScript with Zod schemas for input validation, following patterns in
src/tools/schemas.ts - UI resources in
ui/folders are served automatically via the MCP resources protocol throughresources/listandresources/readhandlers
Frequently Asked Questions
Do I need to modify the core server code to add a plugin?
No. DesktopCommanderMCP is designed so that the core server never requires modification for plugin installation. The generic resources and tools handlers in src/server.ts automatically discover and register capabilities from plugin.json files found in the plugins/ directory. You only need to add your plugin folder and restart the server.
What is the difference between plugin.yaml and plugin.json?
plugin.yaml is the top-level manifest (lines 5-61) that declares the entire repository as an MCP plugin for the Agenium platform, specifying runtime language (typescript) and transport settings (stdio). plugin.json files exist inside individual plugin subdirectories (like plugins/cursor/.cursor-plugin/) and define specific tools, schemas, and resources for that particular extension. Think of plugin.yaml as the server declaration and plugin.json as individual feature modules.
Can DesktopCommanderMCP plugins include custom user interfaces?
Yes. Plugins can bundle UI resources such as HTML files in a ui/ folder, declared in the resources array of plugin.json. The MCP server serves these via the standard resources/list and resources/read handlers already implemented in src/server.ts. Clients can request these resources by URI (e.g., my-ui.html) to display plugin-specific interfaces within the chat context.
How does the server discover new plugins?
The MCP SDK scans the plugins/ directory at startup, looking for subdirectories containing plugin descriptors. Following the pattern of plugins/cursor/ and plugins/claude/, each plugin should have a configuration folder (e.g., .my-plugin/) containing plugin.json. The server validates these descriptors against the schema and registers tools automatically, making them available via JSON-RPC tools/call requests without manual configuration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →