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 via ListResourcesRequestSchema and ReadResourceRequestSchema
  • src/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:

  1. Manifest Scanning: On startup, the server reads plugin.yaml to confirm it is operating as a DesktopCommanderMCP instance with transport: stdio.
  2. Directory Scanning: The SDK scans the plugins/ directory for subdirectories containing .[plugin-name]/plugin.json descriptors (following the pattern seen in .cursor-plugin/ and .claude-plugin/).
  3. Registration: Tools are registered with the MCP framework using their declared names and schemas. Resources are indexed for the generic handlers.
  4. Runtime Execution: When a client calls a tool via the tools/call JSON-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:

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 individual plugin.json descriptors
  • 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 in plugin.json files
  • 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 through resources/list and resources/read handlers

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →