{"id":"1256a2fd-7ba9-47c9-99a4-44e7c2d6cc81","slug":"letsmcp","kind":"mcp","name":"letsmcp","summary":"TypeScript MCP and REST service for multi-provider AI, job extraction, resume analysis, and JobOS integrations.","owner":"shanebe-ai","repoUrl":"https://github.com/shanebe-ai/letsmcp","license":"MIT","licenseTier":"permissive","trust":"community","stars":1,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-01-13T23:05:18.000Z","addedAt":"2026-10-21T05:45:03.121Z","logoUrl":"https://avatars.githubusercontent.com/u/232604355?u=5c41cd57a7fa13ed28841bbf3cd7e40ee7159459&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["browser-web","memory-knowledge"],"tags":["playwright","rest-api","ai-agents","typescript"],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-21T05:45:12.233Z","sample":false,"url":"https://conduits.dev/tools/letsmcp","language":"TypeScript","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# LetsMCP: AI-Powered MCP Server\n\nA TypeScript [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server with integrated AI capabilities. Supports multiple AI providers (Groq, Claude, Gemini) with automatic fallback, LinkedIn job scraping, and a REST API for external application integration.\n\n## Why it exists\n\nLetsMCP gives MCP clients and web applications a shared service boundary for AI generation, structured job extraction, resume analysis, and optional browser-based workflows.\n\n## Architecture\n\n```mermaid\nflowchart LR\n  C[MCP clients] --> S[LetsMCP service]\n  R[REST clients / JobOS] --> S\n  S --> V[Zod validation]\n  V --> O[Provider adapter and fallback]\n  O --> G[Groq]\n  O --> A[Anthropic]\n  O --> M[Gemini]\n  S --> Q[Job persistence]\n  S --> P[Playwright browser automation]\n```\n\n## Trust boundaries\n\n- Run command execution and file operations only in a trusted environment with least-privilege access.\n- Do not expose configuration endpoints publicly without authentication and authorization.\n- Keep provider keys in environment variables or a secret manager; never commit `.env` files.\n- Treat third-party content returned through browser automation as untrusted.\n- Add request limits, rate limits, timeouts, audit logging, and retention rules before shared hosting.\n- Provider fallback can change cost, latency, and model behavior; log the selected provider and surface failures.\n\n## Features\n\n### MCP Server\n- ✅ **Stdio Transport**: Standard MCP transport for Claude Desktop, Cursor, and Antigravity\n- ✅ **HTTP Health Endpoint**: Monitor server status at `/health`\n- ✅ **8 MCP Tools**: File operations, command execution, web scraping, and more\n- ✅ **One Resource**: `server://info` (provides server metadata)\n\n### AI Integration\n- ✅ **Multi-Provider AI**: Groq (Llama 3.1), Claude (Anthropic), and Google Gemini\n- ✅ **Automatic Fallback**: If one provider fails, automatically tries the next\n- ✅ **REST API**: HTTP endpoints for external applications (like JobOS)\n- ✅ **LinkedIn Scraping**: Browser-based job scraping with Playwright\n- ✅ **Job Extraction**: AI-powered extraction of job details from text/URLs\n- ✅ **Resume Analysis**: Compare resumes against job descriptions\n- ✅ **Email Drafting**: Generate professional outreach emails with strict formatting controls (JSON-safe).\n\n### Infrastructure\n- ✅ **TypeScript**: Full type safety with the official MCP SDK\n- ✅ **Comprehensive Tests**: Unit tests with Vitest\n- ✅ **Deployment options**: Error handling, validation, and self-hosting configurations\n- ✅ **Deployment Ready**: Railway, Render, Fly.io support\n\n## Quick Start\n\n### Installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/shanebe-ai/letsmcp.git\ncd letsmcp\n\n# Install dependencies\nnpm install\n\n# Copy environment file and add your API keys\ncp .env.example .env\n```\n\n### Configuration\n\nEdit `.env` with your API keys:\n\n```env\n# Server Configuration\nPORT=3002\nHOST=0.0.0.0\n\n# AI Provider API Keys (at least one required for AI features)\nGROQ_API_KEY=your_groq_key_here\nGROQ_MODEL=llama-3.1-70b-versatile\n\nCLAUDE_API_KEY=your_claude_key_here\nCLAUDE_MODEL=claude-3-5-sonnet-20241022\n\nGEMINI_API_KEY=your_gemini_key_here\nGEMINI_MODEL=gemini-1.5-flash\n\n# Default AI provider (groq, claude, or gemini)\nDEFAULT_AI_PROVIDER=groq\n```\n\nGet your API keys from:\n- **Groq**: https://console.groq.com/keys\n- **Claude**: https://console.anthropic.com/settings/keys\n- **Gemini**: https://aistudio.google.com/app/apikey\n\n### Running\n\n```bash\n# Development mode (with auto-reload)\nnpm run dev\n\n# Production mode\nnpm run build\nnpm start\n```\n\nThe server will start with:\n- **MCP communication**: stdio (standard input/output)\n- **HTTP API**: `http://localhost:3002/api/*`\n- **Health endpoint**: `http://localhost:3002/health`\n\n## REST API Endpoints\n\n### Status & Configuration\n\n#### `GET /api/status`\nReturns server status and configured AI providers.\n\n```bash\ncurl http://localhost:3002/api/status\n```\n\nResponse:\n```json\n{\n  \"status\": \"ok\",\n  \"version\": \"2.0.0\",\n  \"providers\": [\"groq\", \"gemini\"],\n  \"hasAI\": true\n}\n```\n\n#### `POST /api/config`\nUpdate AI provider configuration at runtime.\n\n```bash\ncurl -X POST http://localhost:3002/api/config \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"groq\": {\"apiKey\": \"your_key\"}, \"defaultProvider\": \"groq\"}'\n```\n\n### AI Features\n\n#### `POST /api/generate`\nGenerate text using AI.\n\n```bash\ncurl -X POST http://localhost:3002/api/generate \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"prompt\": \"Write a brief introduction for a software engineer\", \"provider\": \"groq\"}'\n```\n\n#### `POST /api/extract-job`\nExtract job details from text or URL. Automatically uses LinkedIn scraper for LinkedIn URLs.\n\n```bash\n# From text\ncurl -X POST http://localhost:3002/api/extract-job \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"text\": \"Senior Software Engineer at Google, Mountain View, CA...\"}'\n\n# From LinkedIn URL\ncurl -X POST http://localhost:3002/api/extract-job \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://www.linkedin.com/jobs/view/123456789\"}'\n```\n\nResponse:\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"title\": \"Senior Software Engineer\",\n    \"company\": \"Google\",\n    \"location\": \"Mountain View, CA\",\n    \"description\": \"...\",\n    \"salary\": \"$150,000 - $200,000\"\n  },\n  \"provider\": \"groq\"\n}\n```\n\n#### `POST /api/scrape-linkedin`\nDirectly scrape a LinkedIn job posting.\n\n```bash\ncurl -X POST http://localhost:3002/api/scrape-linkedin \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://www.linkedin.com/jobs/view/123456789\", \"screenshot\": false}'\n```\n\n#### `POST /api/analyze-resume`\nAnalyze how well a resume matches a job description.\n\n```bash\ncurl -X POST http://localhost:3002/api/analyze-resume \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"jobDescription\": \"We are looking for a React developer...\",\n    \"resumeText\": \"5 years experience with React, TypeScript...\"\n  }'\n```\n\nResponse:\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"matchScore\": 85,\n    \"strengths\": [\"React experience\", \"TypeScript proficiency\"],\n    \"gaps\": [\"No mention of testing frameworks\"],\n    \"recommendations\": [\"Add Jest/Cypress experience\"],\n    \"keywords\": {\n      \"matched\": [\"React\", \"TypeScript\", \"Node.js\"],\n      \"missing\": [\"Jest\", \"CI/CD\"]\n    }\n  },\n  \"provider\": \"groq\"\n}\n```\n\n#### `POST /api/draft-email`\nDraft a professional outreach email.\n\n```bash\ncurl -X POST http://localhost:3002/api/draft-email \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"recipientName\": \"John Smith\",\n    \"recipientRole\": \"Engineering Manager\",\n    \"companyName\": \"TechCorp\",\n    \"jobTitle\": \"Senior Engineer\",\n    \"tone\": \"Professional\",\n    \"intent\": \"Connect\"\n  }'\n```\n\nResponse:\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"subject\": \"Connecting about opportunities at TechCorp\",\n    \"body\": \"Hi John,\\n\\nI've been following TechCorp's work...\",\n    \"confidence\": 85\n  },\n  \"provider\": \"groq\"\n}\n```\n\n**Intent options**: `Connect`, `FollowUp`, `ReferralRequest`, `PeerOutreach`\n**Tone options**: `Formal`, `Casual`, `Enthusiastic`, `Professional`\n\n### Job Queue Management\n\n#### `POST /api/jobs`\nSave a job to the queue (used by Chrome extension).\n\n```bash\ncurl -X POST http://localhost:3002/api/jobs \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"title\": \"Senior Engineer\",\n    \"company\": \"TechCorp\",\n    \"location\": \"San Francisco, CA\",\n    \"workType\": \"Remote\",\n    \"description\": \"<p>Job description...</p>\",\n    \"url\": \"https://linkedin.com/jobs/view/123\"\n  }'\n```\n\nResponse:\n```json\n{\n  \"success\": true,\n  \"message\": \"Job saved to queue\"\n}\n```\n\n#### `GET /api/jobs`\nRetrieve all queued jobs.\n\n```bash\ncurl http://localhost:3002/api/jobs\n```\n\nResponse:\n```json\n{\n  \"success\": true,\n  \"count\": 5,\n  \"data\": [\n    {\n      \"id\": \"job_1768634456345_0\",\n      \"title\": \"Senior Engineer\",\n      \"company\": \"TechCorp\",\n      \"location\": \"San Francisco, CA\",\n      \"workType\": \"Remote\",\n      \"description\": \"<p>Job description...</p>\",\n      \"url\": \"https://linkedin.com/jobs/view/123\",\n      \"scrapedAt\": \"2026-01-17T04:14:07.702Z\",\n      \"source\": \"visual-fallback\"\n    }\n  ]\n}\n```\n\n#### `DELETE /api/jobs/:id`\nDelete a specific job from the queue.\n\n```bash\ncurl -X DELETE http://localhost:3002/api/jobs/job_1768634456345_0\n```\n\nResponse:\n```json\n{\n  \"success\": true,\n  \"message\": \"Job deleted\"\n}\n```\n\n#### `DELETE /api/jobs`\nClear all jobs from the queue.\n\n```bash\ncurl -X DELETE http://localhost:3002/api/jobs\n```\n\nResponse:\n```json\n{\n  \"success\": true,\n  \"message\": \"Job queue cleared\"\n}\n```\n\n## MCP Tools\n\n### Core Tools\n\n| Tool | Description |\n|------|-------------|\n| `saveToFile` | Save text content to a file with auto directory creation |\n| `readFile` | Read file contents as text |\n| `searchFiles` | Search for patterns in files using regex |\n| `executeCommand` | Execute shell commands |\n| `webFetch` | Fetch and parse web content |\n| `scrapeLinkedInJob` | Scrape LinkedIn job postings with Playwright |\n\n### Utility Tools\n\n| Tool | Description |\n|------|-------------|\n| `echoText` | Echo back text (for testing) |\n| `summarizeDirectory` | List directory contents with metadata |\n\n> **📖 For detailed tool documentation, see [TOOL_GUIDE.md](./TOOL_GUIDE.md)**\n\n## Connecting MCP Clients\n\n### Claude Desktop\n\nAdd to your Claude Desktop configuration:\n\n**Windows**: `%APPDATA%\\Claude\\claude_desktop_config.json`\n**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`\n\n```json\n{\n  \"mcpServers\": {\n    \"letsmcp\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/letsmcp/dist/index.js\"],\n      \"env\": {\n        \"PORT\": \"3002\",\n        \"HOST\": \"localhost\",\n        \"GROQ_API_KEY\": \"your_key_here\"\n      }\n    }\n  }\n}\n```\n\n### Cursor IDE\n\nAdd to Cursor configuration:\n\n**Windows**: `%APPDATA%\\Cursor\\User\\globalStorage\\cursor-mcp\\config.json`\n**macOS**: `~/Library/Application Support/Cursor/User/globalStorage/cursor-mcp/config.json`\n\n```json\n{\n  \"mcpServers\": {\n    \"letsmcp\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/letsmcp/dist/index.js\"],\n      \"env\": {\n        \"PORT\": \"3002\",\n        \"GROQ_API_KEY\": \"your_key_here\"\n      }\n    }\n  }\n}\n```\n\n> **📖 See [MCP_CONFIG.md](./MCP_CONFIG.md) for more configuration options**\n\n## Integration with External Apps\n\nLetsMCP provides a REST API that can be used by any application. For example, [JobOS](https://github.com/shanebe-ai/JobOS) uses LetsMCP for:\n\n- **Magic Paste**: Extracts job details from pasted text or LinkedIn URLs\n- **Resume Analyst**: AI-powered resume vs job description analysis\n- **Email Drafter**: Generates professional outreach emails\n\n### Example: JobOS Integration\n\n```typescript\n// Check if LetsMCP is available\nconst response = await fetch('http://localhost:3002/api/status');\nconst { hasAI } = await response.json();\n\nif (hasAI) {\n  // Use LetsMCP for AI features\n  const result = await fetch('http://localhost:3002/api/extract-job', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({ url: linkedInUrl })\n  });\n}\n```\n\n## Project Structure\n\n```\nletsmcp/\n├── src/\n│   ├── index.ts              # Main entry (HTTP server + MCP stdio)\n│   ├── server.ts             # MCP server initialization\n│   ├── tools.ts              # MCP tool definitions\n│   ├── api/\n│   │   ├── index.ts          # API exports\n│   │   └── routes.ts         # REST API route handlers\n│   └── ai/\n│       ├── index.ts          # AI exports\n│       ├── types.ts          # TypeScript interfaces\n│       ├── prompts.ts        # Shared AI prompts\n│       ├── service.ts        # Unified AI service with fallback\n│       └── providers/\n│           ├── index.ts      # Provider exports\n│           ├── groq.ts       # Groq (Llama 3.1) provider\n│           ├── claude.ts     # Claude (Anthropic) provider\n│           └── gemini.ts     # Google Gemini provider\n├── src/__tests__/            # Unit tests\n├── dist/                     # Compiled JavaScript\n├── .env.example              # Environment template\n├── package.json              # Project configuration\n├── tsconfig.json             # TypeScript configuration\n└── README.md                 # This file\n```\n\n## Development\n\n```bash\n# Type checking\nnpm run typecheck\n\n# Run tests\nnpm test\n\n# Run tests in watch mode\nnpm run test:watch\n\n# Build for production\nnpm run build\n```\n\n## Testing\n\n```bash\n# Run all tests\nnpm test\n\n# Test with coverage\nnpm run test:coverage\n\n# Quick health check\ncurl http://localhost:3002/health\n\n# Test AI status\ncurl http://localhost:3002/api/status\n```\n\n## Deployment\n\n### Using PM2 (Recommended for VPS)\n\n```bash\n# Install PM2\nnpm install -g pm2\n\n# Start with PM2\ncd /path/to/letsmcp\nPORT=3002 pm2 start npm --name \"letsmcp\" -- run dev\n\n# Save for auto-restart\npm2 save\npm2 startup\n```\n\n### Cloud Platforms\n\nSee [DEPLOYMENT.md](./DEPLOYMENT.md) for deployment guides for:\n- Railway\n- Render\n- Fly.io\n- Docker\n\n## Troubleshooting\n\n### No AI providers showing\n- Check your `.env` file has valid API keys\n- Restart the server after changing `.env`: `pm2 restart letsmcp --update-env`\n\n### LinkedIn scraping fails\n- LinkedIn may require authentication for some job pages\n- Try using the job description text directly instead of URL\n\n### CORS errors from browser\n- The server has CORS enabled for all origins in development\n- For production, configure allowed origins in `src/index.ts`\n\n### Port already in use\n- Change the port in `.env`: `PORT=3003`\n- Or kill the existing process: `fuser -k 3002/tcp`\n\n## Author\n\n**shanebe-ai** (shanbe@live.com)\n\n## License\n\nMIT\n"}