The hard-won lessons from building a working Claude Desktop Extension
# Always check the latest official docs FIRST
curl -s https://api.github.com/repos/anthropics/dxt | jq '.pushed_at'
Essential URLs to check:
- https://github.com/anthropics/dxt/blob/main/MANIFEST.md
- https://github.com/anthropics/dxt/blob/main/README.md
- https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/overview
Key version indicators:
- DXT version is currently
"0.1"
(NOT"0.1.0"
or"1.0"
) - MCP protocol version:
"2024-11-05"
# Verify Claude Desktop version
# Check Settings โ About for latest version
# Verify system compatibility
echo "OS: $(uname -a)"
echo "Node.js: $(node --version)"
echo "Git: $(git --version)"
Problem: Documentation lags behind implementation
- Used
dxt_version: "1.0"
โ WRONG (should be"0.1"
) - Tried
server.type: "http"
โ WRONG (should be"node"
) - Missing
mcp_config
inside server object
Solution:
{
"dxt_version": "0.1",
"server": {
"type": "node",
"entry_point": "index.js",
"mcp_config": {
"command": "node",
"args": ["${__dirname}/index.js"]
}
}
}
Problem: Early examples showed HTTP servers, but DXT now requires MCP over stdio
Wrong approach:
// โ This doesn't work in current DXT
const server = http.createServer(...)
Correct approach:
// โ
MCP over stdio
process.stdin.on('data', async (data) => {
const request = JSON.parse(data.toString().trim());
// Handle MCP protocol...
});
Problem: Template literals get corrupted when copying between WSL and Windows
Solutions:
- Use string concatenation instead of template literals
- Avoid backticks in artifacts
- Test scripts in isolated environments
Problem: Gemini CLI analyzes current working directory, not project directory
Current limitation:
// Gemini analyzes wherever Claude Desktop runs from
spawn('gemini', ['-p', prompt])
Future enhancement needed:
// TODO: Add directory parameter
spawn('gemini', ['-p', prompt], { cwd: userSpecifiedDirectory })
-
Start with minimal manifest:
{ "dxt_version": "0.1", "name": "test", "version": "0.1.0", "author": {"name": "Test"}, "server": { "type": "node", "entry_point": "index.js" } }
-
Add complexity gradually
-
Test installation after each change
-
Create minimal MCP server:
process.stdin.on('data', (data) => { const request = JSON.parse(data.toString().trim()); if (request.method === 'initialize') { // Respond with minimal capabilities } });
-
Test each MCP method individually:
initialize
tools/list
tools/call
- Use Claude Code CLI for development (better for debugging)
- Test in Claude Desktop for final validation
- Verify actual tool execution
Cause: Missing required fields in server object
Fix: Add type
and proper mcp_config
Cause: Using old HTTP-based architecture
Fix: Change to MCP with "type": "node"
Cause: Missing or wrong DXT version
Fix: Use "dxt_version": "0.1"
Cause: Server type not recognized
Fix: Use "node"
, "python"
, or "binary"
- Use Claude Code CLI for development
- Use Claude Desktop for final testing
- Avoid mixing WSL/Windows paths during development
project/
โโโ manifest.json # DXT configuration
โโโ server/
โ โโโ index.js # MCP server implementation
โโโ package.json # Dependencies (if needed)
โโโ create_dxt.js # Build script
โโโ test-files/ # Sample code for testing
โโโ README.md # Usage instructions
// Always use timestamped naming
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
const outputFile = `extension_${timestamp}.dxt`;
// Clean up old versions
const oldFiles = ['old_v1.dxt', 'old_v2.dxt'];
oldFiles.forEach(file => fs.existsSync(file) && fs.unlinkSync(file));
- Create minimal test project with diverse file types
- Test locally with Gemini CLI first
- Verify DXT package creation
- Test installation in Claude Desktop
- Test actual tool execution
Current limitation: Analyzes Claude Desktop's working directory
// Enhancement needed:
{
"prompt": "Analyze this code",
"directory": "/path/to/project" // Add this parameter
}
- Better timeout management
- More descriptive error messages
- Graceful handling of missing Gemini CLI
- Gemini API model selection
- Custom analysis prompts
- Output formatting options
- DXT Spec: https://github.com/anthropics/dxt
- MCP Docs: https://modelcontextprotocol.io/
- Claude Desktop: https://support.anthropic.com/
- DXT Examples: https://github.com/anthropics/dxt/tree/main/examples
- MCP Servers: https://github.com/modelcontextprotocol/servers
- Awesome DXT: https://github.com/milisp/awesome-claude-dxt
# Check DXT package contents
unzip -l your-extension.dxt
# Validate JSON
cat manifest.json | jq '.'
# Test MCP server manually
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | node server/index.js
Installation fails?
- Check
dxt_version
is"0.1"
- Verify
server.type
is valid enum - Ensure all required fields present
- Test manifest with
jq '.' manifest.json
Tool not appearing?
- Check Claude Desktop Extensions settings
- Verify DXT package installed successfully
- Restart Claude Desktop
- Check extension logs
Tool fails to execute?
- Test Gemini CLI directly:
gemini -p "test"
- Check authentication:
gemini auth
- Verify PATH contains gemini executable
- Check Claude Desktop working directory
Development workflow broken?
- Use Claude Code CLI instead of Desktop for development
- Avoid WSL/Windows path mixing
- Test in clean environment
- Use timestamped builds to avoid confusion
You've successfully navigated the complex world of DXT development and created a working extension that bridges two AI systems. This documentation captures the hard-won lessons to save future developers from the same pitfalls.
Remember: The DXT ecosystem is rapidly evolving. Always check official sources for the latest specifications before starting development.
"The code that works is more valuable than the code that's perfect."