Skip to main content
Glama

AI Ops Hub

An MCP server that gives AI assistants safe, sandboxed hands on your machine — notes, tasks, web pages, and hybrid search (FTS5 + embeddings) over a personal document corpus. Built with TypeScript, SQLite, and a security-first design.

CI TypeScript Node License: MIT

MCP (Model Context Protocol) is the open standard that lets AI clients like Claude Desktop call external tools. This server implements it twice from one codebase: over stdio for local clients and over HTTP for remote access.

What it looks like in practice

Once connected to Claude Desktop, conversations like this just work:

You: Find my notes about the Postgres migration and add a task to finish it by Friday.

Claude:rag_search("postgres migration") — 3 matching chunks from your corpus → task_create("Finish Postgres migration", due: "2026-07-31") "Found your migration notes — the remaining step was the index rebuild. Task created for Friday."

Every step happens inside the sandbox you configured: Claude can only touch the notes directory you allowed, only fetch from hosts you allowlisted, and only through the tools below.

Related MCP server: KnowledgeMCP

Tools

Tool

What it does

rag_search

Search the corpus — keyword (FTS5), vector (embeddings), or hybrid (both, fused with Reciprocal Rank Fusion)

rag_add_document

Add or update a document: auto-chunked, FTS-indexed, embedded when vector search is configured

rag_stats

Corpus statistics: documents, chunks, embeddings, backend availability

file_read / file_write / file_list

Notes access — sandboxed to NOTES_DIR, allowlisted extensions only

web_fetch

Fetch a page from allowlisted hosts only, stripped to clean text (cheerio)

task_create / task_list / task_complete

Tasks stored as plain, human-editable markdown

Hybrid search is the default when OPENAI_API_KEY is set: FTS5 and cosine-similarity results are merged with Reciprocal Rank Fusion — rank-based fusion that needs no score normalization between bm25 and cosine scales. If the vector backend fails mid-query, hybrid degrades gracefully to keyword results.

Security model

Local tool access for an LLM is a security problem before it is anything else. The interesting engineering here:

  • Path sandboxing that survives the classic bypasses. Every path resolves against NOTES_DIR; absolute paths, ../ traversal, and the sibling-prefix bypass (notes vs notes-evil — a bug most naive startsWith checks have) are rejected. Extension allowlist is enforced on both read and write.

  • Web fetching is deny-by-default. web_fetch refuses any host not in WEB_ALLOWED_HOSTS. Subdomains of allowed hosts pass; lookalikes (example.com.evil.com) do not. HTTP(S) only.

  • The protocol channel stays clean. All logging goes to stderr — on a stdio MCP server, stdout belongs to JSON-RPC and a single stray console.log corrupts the stream.

  • Typed failure paths. The persistence layer returns neverthrow Result types instead of throwing; inputs are validated with zod.

All of this is pinned down by 45 unit tests targeting exactly these properties — traversal attempts, prefix bypasses, lookalike domains, protocol filtering, rank fusion, and registry dispatch — running in CI on Node 20 and 22.

Architecture

Both transports consume one ToolRegistry — a single source of truth for tool definitions and dispatch, so the stdio and HTTP surfaces can never drift apart.

flowchart LR
    CD[Claude Desktop] -- "stdio (JSON-RPC)" --> REG[ToolRegistry<br/>definitions + dispatch]
    RC[Remote client] -- "HTTP :3333" --> REG
    REG --> FS["FileService<br/>sandboxed notes"]
    REG --> WS["WebService<br/>allowlisted fetch"]
    REG --> TS["TaskService<br/>markdown store"]
    REG --> RAG["RAGService<br/>keyword | vector | hybrid"]
    RAG -- "FTS5 (bm25)" --> POOL["ConnectionPool"]
    RAG -- "embeddings + cosine" --> VEC["VectorRAGService"]
    VEC --> POOL
    RAG -- "RRF fusion" --> RAG
    POOL --> DB[("SQLite<br/>docs + chunks<br/>chunks_fts + chunk_vecs")]
src/
  server.ts               MCP entrypoint (SDK 1.x): wires services into the registry
  tools/
    registry.ts           single source of truth: tool schemas + dispatch
  transports/
    http-transport.ts     thin HTTP facade over the registry: /health, /tools, /call, /status
  connectors/
    file-service.ts       sandboxed file access
    web-service.ts        allowlisted web fetching + HTML cleaning
    task-service.ts       markdown-backed task store
  rag/
    rag-service.ts        search facade: keyword / vector / hybrid modes
    fusion.ts             Reciprocal Rank Fusion (pure, unit-tested)
    sqlite-client.ts      SQLite persistence: FTS5, chunking, migrations (neverthrow API)
    vector-rag-service.ts vector search with OpenAI embeddings
    embedding-service.ts  embedding generation (text-embedding-3-small)
  db/
    connection-pool.ts    SQLite connection pooling

Quick start

git clone https://github.com/Galiusbro/ai-ops-hub.git && cd ai-ops-hub
npm install
cp .env.example .env    # adjust paths and allowlist
npm run build

npm start               # stdio only (for Claude Desktop)
npm run start:http      # stdio + HTTP facade on :3333

The HTTP facade is opt-in (--http flag or HTTP_ENABLED=1) so that MCP clients can spawn multiple server instances without port clashes.

Connect to Claude Desktop

{
  "mcpServers": {
    "ai-ops-hub": {
      "command": "node",
      "args": ["/absolute/path/to/dist/server.js"],
      "env": {
        "NOTES_DIR": "/path/to/your/notes",
        "RAG_DB_PATH": "/path/to/your/rag.db"
      }
    }
  }
}

Or talk to it over HTTP

curl http://localhost:3333/health
curl http://localhost:3333/tools
curl -X POST http://localhost:3333/call \
  -H "Content-Type: application/json" \
  -d '{"name":"rag_search","arguments":{"query":"postgres migration"}}'

Configuration

Variable

Default

Purpose

NOTES_DIR

./notes

Directory the file tools are sandboxed to

TASKS_FILE

./tasks.md

Markdown file behind the task tools

RAG_DB_PATH

./data/rag.db

SQLite database for the corpus

WEB_ALLOWED_HOSTS

example.com,developer.mozilla.org

Comma-separated allowlist for web_fetch

HTTP_PORT

3333

HTTP transport port

OPENAI_API_KEY

Enables vector + hybrid search (embeddings)

Development

npm run dev          # run from source (tsx)
npm test             # vitest unit suite
npm run type-check   # tsc --noEmit
npm run lint

Roadmap

  • MCP server over stdio + HTTP

  • Sandboxed file / web / task tools

  • SQLite FTS5 corpus with trigger-synced index

  • Unit tests for the security-critical paths + CI

  • Shared tool registry between the two transports

  • Vector search wired in: hybrid mode with Reciprocal Rank Fusion

  • @modelcontextprotocol/sdk 1.x

  • Streamable HTTP transport from the SDK (replace the custom REST facade)

  • Audit logging

  • Local embedding backend as an alternative to OpenAI

Why this exists

I built this to understand MCP from the inside — the protocol, the transports, and what it actually takes to hand an LLM safe access to a real machine. It grew into a working local-first assistant backend: the FTS5 corpus, the sandboxing, and the test suite are the parts I'd reuse in production.

License

MIT

Install Server
A
license - permissive license
B
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

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/Galiusbro/ai-ops-hub'

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