Skip to content
Conduit

mcp server

letsmcp

TypeScript MCP and REST service for multi-provider AI, job extraction, resume analysis, and JobOS integrations.

shanebe-ai/letsmcpcommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 21, 2026

LetsMCP: AI-Powered MCP Server

A TypeScript Model Context Protocol (MCP) 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.

Why it exists

LetsMCP gives MCP clients and web applications a shared service boundary for AI generation, structured job extraction, resume analysis, and optional browser-based workflows.

Architecture

flowchart LR
  C[MCP clients] --> S[LetsMCP service]
  R[REST clients / JobOS] --> S
  S --> V[Zod validation]
  V --> O[Provider adapter and fallback]
  O --> G[Groq]
  O --> A[Anthropic]
  O --> M[Gemini]
  S --> Q[Job persistence]
  S --> P[Playwright browser automation]

Trust boundaries

  • Run command execution and file operations only in a trusted environment with least-privilege access.
  • Do not expose configuration endpoints publicly without authentication and authorization.
  • Keep provider keys in environment variables or a secret manager; never commit .env files.
  • Treat third-party content returned through browser automation as untrusted.
  • Add request limits, rate limits, timeouts, audit logging, and retention rules before shared hosting.
  • Provider fallback can change cost, latency, and model behavior; log the selected provider and surface failures.

Features

MCP Server

  • ✅ Stdio Transport: Standard MCP transport for Claude Desktop, Cursor, and Antigravity
  • ✅ HTTP Health Endpoint: Monitor server status at /health
  • ✅ 8 MCP Tools: File operations, command execution, web scraping, and more
  • ✅ One Resource: server://info (provides server metadata)

AI Integration

  • ✅ Multi-Provider AI: Groq (Llama 3.1), Claude (Anthropic), and Google Gemini
  • ✅ Automatic Fallback: If one provider fails, automatically tries the next
  • ✅ REST API: HTTP endpoints for external applications (like JobOS)
  • ✅ LinkedIn Scraping: Browser-based job scraping with Playwright
  • ✅ Job Extraction: AI-powered extraction of job details from text/URLs
  • ✅ Resume Analysis: Compare resumes against job descriptions
  • ✅ Email Drafting: Generate professional outreach emails with strict formatting controls (JSON-safe).

Infrastructure

  • ✅ TypeScript: Full type safety with the official MCP SDK
  • ✅ Comprehensive Tests: Unit tests with Vitest
  • ✅ Deployment options: Error handling, validation, and self-hosting configurations
  • ✅ Deployment Ready: Railway, Render, Fly.io support

Quick Start

Installation

# Clone the repository
git clone https://github.com/shanebe-ai/letsmcp.git
cd letsmcp

# Install dependencies
npm install

# Copy environment file and add your API keys
cp .env.example .env

Configuration

Edit .env with your API keys:

# Server Configuration
PORT=3002
HOST=0.0.0.0

# AI Provider API Keys (at least one required for AI features)
GROQ_API_KEY=your_groq_key_here
GROQ_MODEL=llama-3.1-70b-versatile

CLAUDE_API_KEY=your_claude_key_here
CLAUDE_MODEL=claude-3-5-sonnet-20241022

GEMINI_API_KEY=your_gemini_key_here
GEMINI_MODEL=gemini-1.5-flash

# Default AI provider (groq, claude, or gemini)
DEFAULT_AI_PROVIDER=groq

Get your API keys from:

Running

# Development mode (with auto-reload)
npm run dev

# Production mode
npm run build
npm start

The server will start with:

  • MCP communication: stdio (standard input/output)
  • HTTP API: http://localhost:3002/api/*
  • Health endpoint: http://localhost:3002/health

REST API Endpoints

Status & Configuration

GET /api/status

Returns server status and configured AI providers.

curl http://localhost:3002/api/status

Response:

{
  "status": "ok",
  "version": "2.0.0",
  "providers": ["groq", "gemini"],
  "hasAI": true
}

POST /api/config

Update AI provider configuration at runtime.

curl -X POST http://localhost:3002/api/config \
  -H "Content-Type: application/json" \
  -d '{"groq": {"apiKey": "your_key"}, "defaultProvider": "groq"}'

AI Features

POST /api/generate

Generate text using AI.

curl -X POST http://localhost:3002/api/generate \
  -H "Content-Type: application/json" \
  -d '{"prompt": "Write a brief introduction for a software engineer", "provider": "groq"}'

POST /api/extract-job

Extract job details from text or URL. Automatically uses LinkedIn scraper for LinkedIn URLs.

# From text
curl -X POST http://localhost:3002/api/extract-job \
  -H "Content-Type: application/json" \
  -d '{"text": "Senior Software Engineer at Google, Mountain View, CA..."}'

# From LinkedIn URL
curl -X POST http://localhost:3002/api/extract-job \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.linkedin.com/jobs/view/123456789"}'

Response:

{
  "success": true,
  "data": {
    "title": "Senior Software Engineer",
    "company": "Google",
    "location": "Mountain View, CA",
    "description": "...",
    "salary": "$150,000 - $200,000"
  },
  "provider": "groq"
}

POST /api/scrape-linkedin

Directly scrape a LinkedIn job posting.

curl -X POST http://localhost:3002/api/scrape-linkedin \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.linkedin.com/jobs/view/123456789", "screenshot": false}'

POST /api/analyze-resume

Analyze how well a resume matches a job description.

curl -X POST http://localhost:3002/api/analyze-resume \
  -H "Content-Type: application/json" \
  -d '{
    "jobDescription": "We are looking for a React developer...",
    "resumeText": "5 years experience with React, TypeScript..."
  }'

Response:

{
  "success": true,
  "data": {
    "matchScore": 85,
    "strengths": ["React experience", "TypeScript proficiency"],
    "gaps": ["No mention of testing frameworks"],
    "recommendations": ["Add Jest/Cypress experience"],
    "keywords": {
      "matched": ["React", "TypeScript", "Node.js"],
      "missing": ["Jest", "CI/CD"]
    }
  },
  "provider": "groq"
}

POST /api/draft-email

Draft a professional outreach email.

curl -X POST http://localhost:3002/api/draft-email \
  -H "Content-Type: application/json" \
  -d '{
    "recipientName": "John Smith",
    "recipientRole": "Engineering Manager",
    "companyName": "TechCorp",
    "jobTitle": "Senior Engineer",
    "tone": "Professional",
    "intent": "Connect"
  }'

Response:

{
  "success": true,
  "data": {
    "subject": "Connecting about opportunities at TechCorp",
    "body": "Hi John,\n\nI've been following TechCorp's work...",
    "confidence": 85
  },
  "provider": "groq"
}

Intent options: Connect, FollowUp, ReferralRequest, PeerOutreach Tone options: Formal, Casual, Enthusiastic, Professional

Job Queue Management

POST /api/jobs

Save a job to the queue (used by Chrome extension).

curl -X POST http://localhost:3002/api/jobs \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Senior Engineer",
    "company": "TechCorp",
    "location": "San Francisco, CA",
    "workType": "Remote",
    "description": "<p>Job description...</p>",
    "url": "https://linkedin.com/jobs/view/123"
  }'

Response:

{
  "success": true,
  "message": "Job saved to queue"
}

GET /api/jobs

Retrieve all queued jobs.

curl http://localhost:3002/api/jobs

Response:

{
  "success": true,
  "count": 5,
  "data": [
    {
      "id": "job_1768634456345_0",
      "title": "Senior Engineer",
      "company": "TechCorp",
      "location": "San Francisco, CA",
      "workType": "Remote",
      "description": "<p>Job description...</p>",
      "url": "https://linkedin.com/jobs/view/123",
      "scrapedAt": "2026-01-17T04:14:07.702Z",
      "source": "visual-fallback"
    }
  ]
}

DELETE /api/jobs/:id

Delete a specific job from the queue.

curl -X DELETE http://localhost:3002/api/jobs/job_1768634456345_0

Response:

{
  "success": true,
  "message": "Job deleted"
}

DELETE /api/jobs

Clear all jobs from the queue.

curl -X DELETE http://localhost:3002/api/jobs

Response:

{
  "success": true,
  "message": "Job queue cleared"
}

MCP Tools

Core Tools

ToolDescription
saveToFileSave text content to a file with auto directory creation
readFileRead file contents as text
searchFilesSearch for patterns in files using regex
executeCommandExecute shell commands
webFetchFetch and parse web content
scrapeLinkedInJobScrape LinkedIn job postings with Playwright

Utility Tools

ToolDescription
echoTextEcho back text (for testing)
summarizeDirectoryList directory contents with metadata

📖 For detailed tool documentation, see TOOL_GUIDE.md

Connecting MCP Clients

Claude Desktop

Add to your Claude Desktop configuration:

Windows: %APPDATA%\Claude\claude_desktop_config.json macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

{
  "mcpServers": {
    "letsmcp": {
      "command": "node",
      "args": ["/path/to/letsmcp/dist/index.js"],
      "env": {
        "PORT": "3002",
        "HOST": "localhost",
        "GROQ_API_KEY": "your_key_here"
      }
    }
  }
}

Cursor IDE

Add to Cursor configuration:

Windows: %APPDATA%\Cursor\User\globalStorage\cursor-mcp\config.json macOS: ~/Library/Application Support/Cursor/User/globalStorage/cursor-mcp/config.json

{
  "mcpServers": {
    "letsmcp": {
      "command": "node",
      "args": ["/path/to/letsmcp/dist/index.js"],
      "env": {
        "PORT": "3002",
        "GROQ_API_KEY": "your_key_here"
      }
    }
  }
}

📖 See MCP_CONFIG.md for more configuration options

Integration with External Apps

LetsMCP provides a REST API that can be used by any application. For example, JobOS uses LetsMCP for:

  • Magic Paste: Extracts job details from pasted text or LinkedIn URLs
  • Resume Analyst: AI-powered resume vs job description analysis
  • Email Drafter: Generates professional outreach emails

Example: JobOS Integration

// Check if LetsMCP is available
const response = await fetch('http://localhost:3002/api/status');
const { hasAI } = await response.json();

if (hasAI) {
  // Use LetsMCP for AI features
  const result = await fetch('http://localhost:3002/api/extract-job', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ url: linkedInUrl })
  });
}

Project Structure

letsmcp/
├── src/
│   ├── index.ts              # Main entry (HTTP server + MCP stdio)
│   ├── server.ts             # MCP server initialization
│   ├── tools.ts              # MCP tool definitions
│   ├── api/
│   │   ├── index.ts          # API exports
│   │   └── routes.ts         # REST API route handlers
│   └── ai/
│       ├── index.ts          # AI exports
│       ├── types.ts          # TypeScript interfaces
│       ├── prompts.ts        # Shared AI prompts
│       ├── service.ts        # Unified AI service with fallback
│       └── providers/
│           ├── index.ts      # Provider exports
│           ├── groq.ts       # Groq (Llama 3.1) provider
│           ├── claude.ts     # Claude (Anthropic) provider
│           └── gemini.ts     # Google Gemini provider
├── src/__tests__/            # Unit tests
├── dist/                     # Compiled JavaScript
├── .env.example              # Environment template
├── package.json              # Project configuration
├── tsconfig.json             # TypeScript configuration
└── README.md                 # This file

Development

# Type checking
npm run typecheck

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Build for production
npm run build

Testing

# Run all tests
npm test

# Test with coverage
npm run test:coverage

# Quick health check
curl http://localhost:3002/health

# Test AI status
curl http://localhost:3002/api/status

Deployment

Using PM2 (Recommended for VPS)

# Install PM2
npm install -g pm2

# Start with PM2
cd /path/to/letsmcp
PORT=3002 pm2 start npm --name "letsmcp" -- run dev

# Save for auto-restart
pm2 save
pm2 startup

Cloud Platforms

See DEPLOYMENT.md for deployment guides for:

  • Railway
  • Render
  • Fly.io
  • Docker

Troubleshooting

No AI providers showing

  • Check your .env file has valid API keys
  • Restart the server after changing .env: pm2 restart letsmcp --update-env

LinkedIn scraping fails

  • LinkedIn may require authentication for some job pages
  • Try using the job description text directly instead of URL

CORS errors from browser

  • The server has CORS enabled for all origins in development
  • For production, configure allowed origins in src/index.ts

Port already in use

  • Change the port in .env: PORT=3003
  • Or kill the existing process: fuser -k 3002/tcp

Author

shanebe-ai (shanbe@live.com)

License

MIT

↑↓ navigate openesc close