Skip to main content
Glama
RanneG

linkup-mcp

by RanneG

Cursor Linkup MCP Server

Custom MCP (Model Context Protocol) server for Cursor IDE with:

  • 🌐 Web Search - Deep web searches using Linkup API

  • πŸ“š RAG (Retrieval Augmented Generation) - Query documents using LlamaIndex with Ollama

✨ Key Features

  • βœ… Local AI - Uses Ollama (llama3.2) for complete privacy

  • βœ… Zero API Costs - RAG tool is completely free (uses local models)

  • βœ… Source Citations - Know where answers come from

  • βœ… Multiple Document Types - Supports PDF, DOCX, MD, TXT, and more

  • βœ… Cursor Integration - Works seamlessly in Cursor IDE

Related MCP server: Web Search MCP

πŸ“‹ Prerequisites

  • Python 3.12+

  • uv package manager

  • Ollama installed locally with llama3.2 model

  • Linkup API key (optional, only for web search)

πŸš€ Quick Start

1. Clone & Install Dependencies

git clone https://github.com/RanneG/linkup_mcp.git
cd linkup_mcp
uv sync

Default install (uv sync / pip install -e .) is Cursor MCP + RAG only (lighter venv). For stitch_rag_bridge.py, face/OAuth/Gmail, and server-side voice STT, add --extra stitch-bridge. For ElevenLabs voice/music asset generation (elevenlabs-gen CLI), add --extra elevenlabs β€” see docs/elevenlabs/README.md.

2. Install Ollama & Model

# Download from https://ollama.ai/download
# Then pull the model:
ollama pull llama3.2

3. Configure Environment (Optional)

Create a .env file for web search (RAG works without API keys):

LINKUP_API_KEY=your_linkup_api_key  # Optional, for web_search tool

4. Configure Cursor

Add to ~/.cursor/mcp.json (or C:\Users\<username>\.cursor\mcp.json on Windows):

{
  "mcpServers": {
    "linkup-server": {
      "command": "C:\\Users\\YOUR_USERNAME\\AppData\\Local\\Microsoft\\WindowsApps\\python.exe",
      "args": [
        "-m", "uv", "run",
        "--directory", "C:\\path\\to\\linkup_mcp",
        "python", "server.py"
      ]
    }
  }
}

Replace YOUR_USERNAME and path with your actual values.

5. Free local dev ports (optional)

If 8765 (Stitch bridge / bundled UI), 1420 (Tauri), or 5173 (Vite) are stuck after a crash, run Close-DevPorts.bat at the repo root (or .\scripts\Close-StitchDevPorts.ps1). Use -DryRun to list listeners without killing. This stops processes listening on those ports, not β€œlocalhost” itself.

6. Restart Cursor & Use!

In Cursor's chat:

  • "Use the rag tool to tell me about [topic]"

  • "Use the rag_stitch tool to get a UI-ready answer payload"

  • "Search the web for [query]" (requires Linkup API key)

  • Local Whisper (no Linkup): whisper_stt_status then transcribe_wav_file with a path to a .wav file. Requires pip install -e ".[stitch-whisper]" and a Cursor MCP restart.

7. Voice-to-prompt hotkey tool (offline)

Use voice_prompt_tool.py for one-shot dictation directly into your coding flow:

uv sync --extra stitch-whisper --extra voice-prompt
python voice_prompt_tool.py --hotkey ctrl+shift+v

What it does:

  • global start/stop hotkey for microphone capture

  • local faster-whisper transcription (offline)

  • file reference extraction (auth.ts -> @auth.ts)

  • prompt envelope copied to clipboard:

    • [FILE REFERENCE: ...]

    • [TASK: ...]

Optional direct paste after copy:

python voice_prompt_tool.py --autopaste

πŸ“š Using the RAG Tool

Add documents to the data/ folder:

data/
β”œβ”€β”€ document1.pdf
β”œβ”€β”€ notes.md
└── research/
    └── paper.pdf

Supported: PDF, DOCX, TXT, MD, HTML, and more.

Stitch-style response shape

The rag tool now returns a JSON string with:

  • answer: final synthesized answer text

  • confidence: low, medium, or high

  • fallback: true when evidence is weak/insufficient

  • sources: ranked source snippets (source_id, score, snippet)

The rag_stitch tool returns a UI-oriented JSON string:

  • state: answered or fallback

  • answer

  • confidence (low, medium, or high)

  • source_cards (empty when state is fallback so the UI stays clean)

  • show_sources (false on fallback)

  • debug_retrieval_cards (only when STITCH_RAG_DEBUG=1 and fallback β€” raw top chunks for debugging)

Repository split (Stitch production)

The Stitch desktop app (React + Tauri) is migrating to RanneG/stitch-app; linkup_mcp remains the MCP server and HTTP bridge for local RAG, OAuth, subscriptions, face, and in-app help. Cutover checklist and file inventory: docs/stitch/MIGRATION.md (see docs/stitch/README.md).

stitch-api-types (TypeScript)

NPM workspace packages/stitch-api-types publishes .d.ts for POST /api/rag/stitch, POST /api/rag/stitch-help, GET /api/health, and related payloads. Build from repo root: npm run build:stitch-api-types. stitch-app can depend on it with a file: path (see stitch-app docs/BACKEND.md).

Stitch HTTP bridge (for the Stitch desktop app)

Run a small Flask server that exposes the same payload as rag_stitch, plus optional local face verification (/api/face/*, DeepFace + OpenCV liveness β€” see face_verification/). Requires stitch-bridge extras:

uv sync --extra stitch-bridge
.\.venv\Scripts\python.exe stitch_rag_bridge.py

Then point the Stitch app’s Vite dev proxy at http://127.0.0.1:8765 (see stitch-app docs/BACKEND.md or integrations/stitch/README.md; proxy /api for RAG, face, auth, subscriptions, and help routes).

Who needs what: Anyone can run the Stitch UI from stitch-app with Node (see docs/RUNNING.md). linkup_mcp is required for /api/* backend capabilities (auth, data, RAG, face, server-backed Help).

Develop Stitch UI from this repo (optional)

Root scripts npm run dev:browser, npm run dev:desktop, npm run build:stitch-web, npm run build:stitch-app use scripts/run-stitch-ui.mjs, which resolves STITCH_APP_ROOT or sibling ../stitch-app only. See docs/stitch/MIGRATION.md.

Stitch single-window GUI

The canonical bundled flow now starts from stitch-app (Stitch.bat there). It uses this repo for backend bridge capabilities when needed.

  1. Build the Stitch desktop bundle inside stitch-app (npm run build).

  2. Run Stitch.bat from stitch-app root.

  3. Keep this repo available for the bridge runtime (stitch_rag_bridge.py) on 127.0.0.1:8765.

Stitch as a native desktop app (no long manual command chain)

Stitch’s apps/desktop package uses Tauri for a real windowed app (npm run dev there = tauri dev). Run these from stitch-app:

Goal

What to do

One double-click (bridge + sync + Tauri)

Run Stitch-Desktop.bat in the stitch-app repo root.

Same from a terminal

npm run dev (stitch-app)

Bridge already running

Start Stitch from stitch-app and keep this repo bridge on 127.0.0.1:8765

Tauri only (you start the bridge yourself)

npm run dev:desktop

Browser tab only (no Tauri)

npm run dev:browser (uses stitch-app via run-stitch-ui.mjs)

Packaged .exe / installer

npm run build:stitch-app (after Tauri prerequisites and a stitch-app clone)

You need Node on PATH and a local stitch-app clone (sibling ../stitch-app or STITCH_APP_ROOT). The first Tauri dev run may compile Rust dependencies (one-time wait).

Quick regression run

To run the v1 prompt suite against your local PDF corpus:

python rag_regression.py

This prints each response payload and a small summary (sourced count, fallback count, low-confidence count).

Stitch JSON contract tests

python -m unittest tests.test_rag_stitch_contract -v

Validates rag_stitch_contract._to_stitch_view shapes (answered vs fallback, show_sources, optional debug_retrieval_cards).

If MCP-security prompts fall back, add the MCP landscape paper to data/:

πŸ› οΈ Project Structure

linkup_mcp/
β”œβ”€β”€ server.py             # MCP entrypoint (stdio) β€” all MCP tools live here
β”œβ”€β”€ agents.py             # spawn_agent sub-agent system (Ollama)
β”œβ”€β”€ rag.py                # RAGWorkflow (LlamaIndex + Ollama)
β”œβ”€β”€ rag_heuristics.py     # Pure scoring heuristics (unit-tested, no LLM imports)
β”œβ”€β”€ rag_runtime.py        # Lazy shared RAG index (MCP + bridge)
β”œβ”€β”€ rag_stitch_contract.py  # Stitch view JSON contract + guide-grounded help
β”œβ”€β”€ local_whisper_stt.py  # faster-whisper loader/transcribe (MCP + bridge share it)
β”œβ”€β”€ stitch_rag_bridge.py  # HTTP bridge ENTRYPOINT β€” owns Flask app, registers bridge/
β”œβ”€β”€ bridge/               # Bridge route modules (one per concern)
β”‚   β”œβ”€β”€ rag_routes.py     #   /api/rag/stitch, /api/rag/stitch-help, /api/stitch-user-guide
β”‚   β”œβ”€β”€ voice_routes.py   #   /api/voice/transcribe + STT engine selection
β”‚   β”œβ”€β”€ face_routes.py    #   /api/face/* (DeepFace imports deferred)
β”‚   β”œβ”€β”€ health.py         #   /health + /api/health (shared payload)
β”‚   β”œβ”€β”€ spa.py            #   /, /favicon.ico, optional built-SPA serving
β”‚   β”œβ”€β”€ cors.py           #   STITCH_ALLOWED_ORIGINS handling
β”‚   └── errors.py         #   JSON error handler for /api/face|auth|subscriptions
β”œβ”€β”€ stitch_auth/          # Google OAuth (PKCE), sessions, subscriptions SQLite
β”œβ”€β”€ face_verification/    # Local 1:1 face match + liveness (used by bridge)
β”œβ”€β”€ integrations/stitch/  # Pointer README β€” UI lives in stitch-app repo
β”œβ”€β”€ docs/                 # e.g. stitch_user_guide.md (bridge Help / Ask Stitch)
β”œβ”€β”€ data/                 # Your documents
β”œβ”€β”€ tests/                # Contract + unit tests (see CI commands below)
β”œβ”€β”€ pyproject.toml        # Dependencies + extras
β”œβ”€β”€ .cursorrules          # AI context for Cursor
└── .env                  # Environment variables (create this)

Where to add things

Change

Where

New MCP tool

server.py (@mcp.tool()); shared logic in a root module

New bridge HTTP route

New/existing module in bridge/ (Flask blueprint), register in stitch_rag_bridge.py

Auth / subscriptions route

stitch_auth/flask_routes.py

RAG scoring/threshold tweak

rag_heuristics.py (pure, unit-tested) or per-instance attrs on RAGWorkflow

Bridge JSON shape change

rag_stitch_contract.py and packages/stitch-api-types (keep in sync, bump that package)

stitch_rag_bridge.py must keep exporting app and register_stitch_spa_routes β€” stitch-app's stitch_gui.py imports them by name.

Test matrix

# Default profile (uv sync):
python -m unittest tests.test_rag_stitch_contract tests.test_rag_heuristics -v

# With stitch-bridge extra:
python -m unittest tests.test_face_storage tests.test_bridge_routes tests.test_stitch_auth_helpers -v

πŸ”§ How It Works

Cursor IDE β†’ MCP Server (server.py)
                 ↓
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  RAG Tool   β”‚  Web Searchβ”‚
    β”‚  (rag.py)   β”‚  (Linkup)  β”‚
    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           ↓
    Ollama (llama3.2) - runs locally

πŸ’° Cost

Tool

Cost

RAG

$0 (local Ollama)

Web Search

~$10-50/month (Linkup API)

Ollama

$0 (runs locally)

πŸ› Troubleshooting

MCP server not loading?

  1. Check Ollama is running: ollama list

  2. Verify path in mcp.json

  3. Check Cursor logs: %APPDATA%\Cursor\logs\

Ollama connection refused?

ollama serve

πŸ” Privacy

  • βœ… RAG Tool: 100% local, documents never leave your machine

  • βœ… Ollama: Runs locally, no cloud API calls

  • ⚠️ Web Search: Queries sent to Linkup servers

Repository

Purpose

chatbot-rag-core

Reusable Python RAG library

chatbot-api-server

Production Docker API server

πŸŽ“ Resources

πŸ“ License

MIT License - See LICENSE

πŸ™ Credits


Made with ❀️ for Cursor IDE users

Related MCP Connectors

Related MCP Servers