support npx

This commit is contained in:
yctimlin
2025-05-12 22:27:24 +08:00
parent 7a72c187a6
commit 110bb19642
8 changed files with 235 additions and 33 deletions
-8
View File
@@ -1,8 +0,0 @@
# Logging level (debug, info, warn, error)
LOG_LEVEL=info
# Enable debug mode (true/false)
DEBUG=false
# Default theme (light/dark)
DEFAULT_THEME=light
+1
View File
@@ -1,3 +1,4 @@
node_modules
.env
package-lock.json
.cursor
+56 -7
View File
@@ -1,7 +1,29 @@
# Excalidraw MCP Server: Powerful Drawing API for LLM Integration
> **📣 NEWS: We're excited to announce npx support!** You can now run Excalidraw MCP directly using `npx excalidraw-mcp` without installation. See Quick Start below for details.
A comprehensive Model Context Protocol (MCP) server that enables seamless interaction with Excalidraw diagrams and drawings. This server provides LLMs (Large Language Models) with the ability to create, modify, query, and manipulate Excalidraw drawings through a structured, developer-friendly API.
## Quick Start
You can run the Excalidraw MCP server directly using npx:
```bash
npx excalidraw-mcp
```
### Examples
Run with default options:
```bash
npx excalidraw-mcp
```
Enable debug logging:
```bash
npx excalidraw-mcp --debug
```
## Features
- **Full Excalidraw Element Control**: Create, update, delete, and query any Excalidraw element
@@ -71,13 +93,24 @@ To use this server with the Claude Desktop application, add the following config
```json
{
"mcpServers": {
"excalidraw": {
"command": "node",
"args": ["src/index.js"],
"env": {
"LOG_LEVEL": "info",
"DEBUG": "false"
}
"mcp_excalidraw": {
"command": "npx",
"args": ["-y", "excalidraw-mcp"]
}
}
}
```
## Integration with Cursor
To use this server with the Cursor application, add the following configuration to the "mcpServers" section of your `.cursor/mcp.json`:
```json
{
"mcpServers": {
"mcp_excalidraw": {
"command": "npx",
"args": ["-y", "excalidraw-mcp"]
}
}
}
@@ -172,3 +205,19 @@ Here are some practical examples of how to use the Excalidraw MCP server:
## License
This Excalidraw MCP server is licensed under the MIT License. You are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.
## Development
Clone the repository and install dependencies:
```bash
git clone <repository-url>
cd excalidraw-mcp
npm install
```
Start the development server:
```bash
npm run dev
```
+3 -9
View File
@@ -1,14 +1,8 @@
{
"mcpServers": {
"excalidraw": {
"command": "node",
"args": [
"src/index.js"
],
"env": {
"LOG_LEVEL": "info",
"DEBUG": "false"
}
"mcp_excalidraw": {
"command": "npx",
"args": ["-y", "excalidraw-mcp"]
}
}
}
+14 -2
View File
@@ -14,7 +14,8 @@
"lint": "eslint src/**/*.js",
"build": "tsc",
"docker:build": "docker build -t mcp/excalidraw .",
"docker:run": "docker run -p 3000:3000 mcp/excalidraw"
"docker:run": "docker run -p 3000:3000 mcp/excalidraw",
"prepare": "node -e \"try { require('fs').chmodSync('./src/cli.js', '755') } catch(e) { console.log(e) }\""
},
"dependencies": {
"@modelcontextprotocol/sdk": "latest",
@@ -37,5 +38,16 @@
"drawing"
],
"author": "",
"license": "MIT"
"license": "MIT",
"engines": {
"node": ">=16.0.0"
},
"publishConfig": {
"access": "public"
},
"files": [
"src/**/*",
"README.md",
"LICENSE"
]
}
+103
View File
@@ -0,0 +1,103 @@
#!/usr/bin/env node
import { parseArgs } from 'node:util';
import { resolve } from 'path';
import dotenv from 'dotenv';
import logger from './utils/logger.js';
// Load environment variables
dotenv.config();
async function main() {
try {
// Parse command line arguments
const options = {
port: {
type: 'string',
short: 'p',
default: process.env.PORT || '3000'
},
host: {
type: 'string',
short: 'h',
default: process.env.HOST || 'localhost'
},
mode: {
type: 'string',
short: 'm',
default: 'stdio'
},
debug: {
type: 'boolean',
short: 'd',
default: false
},
help: {
type: 'boolean',
short: '?',
default: false
}
};
const { values, positionals } = parseArgs({
options,
allowPositionals: true,
strict: false
});
// Show help if requested
if (values.help) {
showHelp();
process.exit(0);
}
// Set debug mode if requested
if (values.debug) {
process.env.DEBUG = 'true';
logger.level = 'debug';
logger.debug('Debug mode enabled');
}
// Set the mode for server transport
process.env.MCP_TRANSPORT_MODE = values.mode;
// Set port and host
process.env.PORT = values.port;
process.env.HOST = values.host;
// Import and run server
const { default: runServer } = await import('./index.js');
await runServer();
} catch (error) {
console.error('Error starting MCP server:', error);
process.exit(1);
}
}
function showHelp() {
console.log(`
Excalidraw MCP Server
Usage:
npx excalidraw-mcp [options]
Options:
-p, --port <port> Port to run the server on (default: 3000)
-h, --host <host> Host to bind the server to (default: localhost)
-m, --mode <mode> Transport mode: 'stdio' or 'http' (default: stdio)
-d, --debug Enable debug logging
-?, --help Show this help message
Examples:
npx excalidraw-mcp
npx excalidraw-mcp --port 4000
npx excalidraw-mcp --mode http
npx excalidraw-mcp --debug
`);
}
main().catch(error => {
console.error('Fatal error:', error);
process.exit(1);
});
+47 -5
View File
@@ -685,23 +685,65 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
return { tools };
});
// Start server with STDIO transport
// Start server with transport based on mode
async function runServer() {
try {
const transport = new StdioServerTransport();
logger.info('Starting Excalidraw MCP server...');
const transportMode = process.env.MCP_TRANSPORT_MODE || 'stdio';
let transport;
if (transportMode === 'http') {
const port = parseInt(process.env.PORT || '3000', 10);
const host = process.env.HOST || 'localhost';
logger.info(`Starting HTTP server on ${host}:${port}`);
// Here you would create an HTTP transport
// This is a placeholder - actual HTTP transport implementation would need to be added
transport = new StdioServerTransport(); // Fallback to stdio for now
} else {
// Default to stdio transport
transport = new StdioServerTransport();
}
// Add a debug message before connecting
logger.debug('Connecting to transport...');
await server.connect(transport);
logger.info('Excalidraw MCP server running on stdio');
logger.info(`Excalidraw MCP server running on ${transportMode}`);
// Keep the process running
process.stdin.resume();
} catch (error) {
logger.error('Error starting server:', error);
console.error('Failed to start MCP server:', error.message, error.stack);
process.exit(1);
}
}
runServer();
// Add global error handlers
process.on('uncaughtException', (error) => {
logger.error('Uncaught exception:', error);
console.error('UNCAUGHT EXCEPTION:', error.message, error.stack);
// Don't exit immediately to allow logging
setTimeout(() => process.exit(1), 1000);
});
process.on('unhandledRejection', (reason, promise) => {
logger.error('Unhandled promise rejection:', reason);
console.error('UNHANDLED REJECTION:', reason);
// Don't exit immediately to allow logging
setTimeout(() => process.exit(1), 1000);
});
// Only run the server directly if this file is executed directly (not imported)
if (import.meta.url === `file://${process.argv[1]}`) {
runServer();
}
// For testing and debugging purposes
if (process.env.DEBUG === 'true') {
logger.debug('Debug mode enabled');
}
export default server;
export default runServer;
+9
View File
@@ -0,0 +1,9 @@
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
console.log('MCP SDK imports successful');
console.log('Server:', Server);
console.log('StdioServerTransport:', StdioServerTransport);
// Exit gracefully
process.exit(0);