Skip to main content
Glama

Keyboard Shortcuts MCP Server

by jenova-marie
MEMORY.md8.43 kB
# Project Memory: Keyboard Shortcuts MCP Server ## Project Overview An MCP (Model Context Protocol) server that provides keyboard shortcuts for operating systems, desktop environments, and applications. Built to support Claude's computer use feature by providing context-aware keyboard shortcut information. ## Core Design Philosophy **KISS (Keep It Simple, Stupid)** - This is intentionally a relay server, not a complex search engine. It filters data by OS/desktop/app and sends everything to Claude Opus for intelligent natural language matching. ## Key Architectural Decisions ### 1. LLM-First Approach **Decision**: Use Claude Opus (claude-opus-4-20250514) for ALL query resolution, not procedural searching. **Rationale**: - User explicitly stated: "I don't even know how to write this procedurally - and don't want to discuss options atm" - Simpler implementation - just filter and relay to Opus - Better natural language understanding - Future-proof as Opus improves **Implementation**: Two-stage pipeline: 1. **Filter phase** (`data-loader.ts`): Fast in-memory filtering by os/desktop/application 2. **LLM resolution** (`opus-client.ts`): Opus intelligently matches shortcuts from filtered data ### 2. Optional Desktop Parameter **Decision**: `desktop` parameter is optional in `get_shortcuts` tool **Rationale**: CLI tools (tmux, vim, ssh) have the same shortcuts regardless of desktop environment **Data Model**: - Desktop shortcuts: `{os: "ubuntu", desktop: "gnome", application: null}` - CLI tools: `{os: "ubuntu", desktop: null, application: "tmux"}` - Desktop apps: `{os: "ubuntu", desktop: null, application: "firefox"}` (may vary by desktop in future) ### 3. In-Memory Data Storage **Decision**: Load all JSON files at startup, no database **Rationale**: - Only ~30 files currently - Fast filtering performance - Simple architecture - Designed for future SQLite migration (JSON → SQLite is straightforward) ### 4. Data Organization **Structure**: ``` data/ └── {os}/ ├── desktops/{desktop}/ # Desktop environment shortcuts ├── apps/{category}/ # Application shortcuts └── tools/ # CLI tools ``` **Why this structure?** - Clear separation of concerns - Desktop-independent tools in separate location - Easy to add new OS/desktop/apps - Mirrors real-world categorization ### 5. Test Architecture **Decision**: Use `pool: 'forks'` in vitest config **Problem**: Anthropic SDK keeps HTTP connections alive (connection pooling), preventing tests from completing **Solution**: Run test files in separate processes - connections clean up when process exits **Key Learning**: HTTP client libraries with connection pooling can cause vitest to hang waiting for event loop to drain ## Technology Stack ### Core Dependencies - **Node.js**: 20.x LTS - **TypeScript**: 5.9.3 - **Package Manager**: pnpm 10.14.0 - **MCP SDK**: @modelcontextprotocol/sdk ^1.19.1 - **Anthropic SDK**: @anthropic-ai/sdk ^0.65.0 - **Validation**: zod ^4.1.11 ### Dev Dependencies - **Testing**: vitest ^3.2.4 - **Runtime**: tsx ^4.20.6 (for dev mode) ## Data Format ### JSON Schema ```json { "os": "ubuntu", "desktop": "gnome" | null, "application": "firefox" | null, "file": "firefox", "categories": [ { "name": "Tab Management", "shortcuts": [ {"keys": "Ctrl + T", "description": "New tab"} ] } ] } ``` **Field Meanings**: - `desktop: null` - Works on any desktop OR is a CLI tool - `application: null` - Desktop environment shortcut (not app-specific) - `file` - Filename without extension (for reference) ## Important Implementation Details ### Environment Variables - `ANTHROPIC_API_KEY` - Required for Opus API access - Set in MCP client configuration or shell environment ### MCP Tool: get_shortcuts **Parameters**: - `os` (required): Operating system - `query` (required): Natural language query - `desktop` (optional): Desktop environment - `application` (optional): Specific application **Example Queries**: - `{os: "ubuntu", application: "tmux", query: "split pane vertically"}` - `{os: "ubuntu", desktop: "gnome", query: "tile window left"}` ### Data Conversion Pipeline 1. Create markdown in `docs/` with format: `- \`keys\` - description` 2. Run: `node scripts/convert-md-to-json.js` 3. Place generated JSON in appropriate `data/{os}/` subdirectory 4. Rebuild: `pnpm build` ## Testing Strategy ### Test Categories 1. **Unit tests** (mocked): Fast, isolated, no external dependencies - `opus-client.test.ts` - 6 tests with mocked Anthropic SDK - `data-loader.test.ts` - 7 tests with temporary test data directory 2. **Integration tests** (real): Slower, validates real behavior - `opus-client.integration.test.ts` - 3 tests with live Opus API - `data-loader.integration.test.ts` - 7 tests with real `data/` directory ### Test Infrastructure - **vitest config**: `pool: 'forks'` to isolate test processes - **Timeout**: 15 seconds (adequate for API calls) - **Total**: 23 tests (22 reliably pass, 1 occasionally flaky due to network timing) ### Known Issues - First Opus integration test occasionally times out (network variability) - Not a code issue - just real API calls being slower sometimes ## User Preferences & Constraints ### Working Style - **User is the designer, I am the coder**: User makes architectural decisions, I implement - **Ask before major changes**: Don't make design decisions autonomously - **KISS principle**: User explicitly values simplicity over complexity ### Key User Quotes - "this is not you just going nuts writing code - I'm the designer - you are the coder ok?" - "KISS and do not overcomplicate things" - "I don't even know how to write this procedurally - and don't want to discuss options atm" ## Future Considerations ### Planned Expansion - macOS support (data structure already supports it) - Windows support (data structure already supports it) - More desktop environments (KDE, XFCE, etc.) ### Migration Path to SQLite Current JSON structure maps cleanly to relational schema: ```sql CREATE TABLE shortcuts ( id INTEGER PRIMARY KEY, os TEXT NOT NULL, desktop TEXT, application TEXT, file TEXT NOT NULL ); CREATE TABLE categories ( id INTEGER PRIMARY KEY, shortcut_id INTEGER, name TEXT NOT NULL ); CREATE TABLE shortcut_keys ( id INTEGER PRIMARY KEY, category_id INTEGER, keys TEXT NOT NULL, description TEXT NOT NULL ); ``` ### Not Planned - Procedural search implementation (intentionally avoided) - Complex query language (Opus handles this) - Local caching beyond in-memory (keep it simple) ## Commands Reference ```bash # Development pnpm dev # Watch mode with auto-reload pnpm build # Compile TypeScript pnpm start # Run production server # Testing pnpm test # Run all tests pnpm test:ui # Run tests with UI pnpm test:coverage # Generate coverage report # Data Management node scripts/convert-md-to-json.js # Convert markdown to JSON ``` ## MCP Integration Example ```json { "mcpServers": { "keyboard-shortcuts": { "command": "node", "args": ["/absolute/path/to/dist/index.js"], "env": { "ANTHROPIC_API_KEY": "sk-ant-..." } } } } ``` ## Critical Files - `src/index.ts` - MCP server entry point, tool registration - `src/opus-client.ts` - Anthropic SDK wrapper, query handling - `src/data-loader.ts` - JSON file loading and filtering - `src/types.ts` - TypeScript type definitions - `vitest.config.ts` - Test configuration (note: pool:'forks') - `CLAUDE.md` - Project documentation for Claude Code ## Lessons Learned ### Vitest + HTTP Clients **Problem**: Tests with HTTP clients (like Anthropic SDK) hang in vitest **Root Cause**: Connection pooling keeps sockets alive, vitest waits for event loop **Solution**: Use `pool: 'forks'` to run tests in separate processes **Key Insight**: The fix is NOT to increase timeouts - that's treating symptoms ### Data Loader Testing **Problem**: `loadShortcutData()` had hardcoded path, couldn't be tested in isolation **Solution**: Added optional `customDataDir` parameter for testing **Pattern**: Make functions testable by parameterizing dependencies ### Opus Integration **Best Practice**: One fresh `OpusClient` instance per test to avoid connection reuse issues **Reality**: Tests pass reliably with `pool: 'forks'`, occasional network delays are expected

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jenova-marie/keyboard-shortcuts-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server