Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 84 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ Model Context Protocol (MCP) allows you to integrate Claude Context with your fa

### Prerequisites

**🚀 New: Zero-Config Local Mode with FAISS**

You can now use Context Please with **no external database required**! Simply provide an OpenAI API key, and FAISS will handle local storage automatically. Perfect for getting started quickly or working with small-to-medium codebases.

For production deployments or large codebases, consider using Zilliz Cloud or Qdrant:

<details>
<summary>Get a free vector database on Zilliz Cloud 👈</summary>

Expand Down Expand Up @@ -62,7 +68,19 @@ Copy your key and use it in the configuration examples below as `your-openai-api

#### Configuration

Use the command line interface to add the Claude Context MCP server:
**Option 1: Local Mode with FAISS (Recommended for Getting Started)**

The simplest way to get started - no external database required:

```bash
claude mcp add context-please \
-e OPENAI_API_KEY=sk-your-openai-api-key \
-- npx @pleaseai/context-please-mcp@latest
```

**Option 2: Cloud Mode with Zilliz (For Production/Large Codebases)**

For larger codebases or production deployments:

```bash
claude mcp add context-please \
Expand Down Expand Up @@ -483,6 +501,71 @@ npx @pleaseai/context-please-mcp@latest

For more detailed MCP environment variable configuration, see our [Environment Variables Guide](docs/getting-started/environment-variables.md).

### Using FAISS for Local-Only Deployments

**Context Please** now supports FAISS as a zero-configuration, local-only vector database option! This is perfect for:

- 🚀 **Quick Start**: No external database setup required
- 💻 **Local Development**: All data stays on your machine
- 💰 **Zero Cost**: No cloud services or infrastructure costs
- 📦 **Small-to-Medium Codebases**: Ideal for personal projects and teams

#### Quick Start with FAISS

Simply omit the Milvus/Qdrant configuration, and Context Please will automatically use FAISS:

```bash
claude mcp add context-please \
-e OPENAI_API_KEY=sk-your-openai-api-key \
-- npx @pleaseai/context-please-mcp@latest
```

That's it! Your code will be indexed to `~/.context/faiss-indexes/` automatically.

#### Advanced FAISS Configuration

You can customize the storage directory:

```bash
claude mcp add context-please \
-e OPENAI_API_KEY=sk-your-openai-api-key \
-e FAISS_STORAGE_DIR=/path/to/your/indexes \
-- npx @pleaseai/context-please-mcp@latest
```

Or explicitly specify FAISS as the vector database:

```json
{
"mcpServers": {
"context-please": {
"command": "npx",
"args": ["@pleaseai/context-please-mcp@latest"],
"env": {
"OPENAI_API_KEY": "your-openai-api-key",
"VECTOR_DB_TYPE": "faiss-local",
"FAISS_STORAGE_DIR": "~/.context/faiss-indexes"
}
}
}
}
```

#### FAISS Features

- ✅ **Hybrid Search**: Combines dense (semantic) + sparse (BM25) vectors
- ✅ **File-based Persistence**: Indexes saved as `.index` files
- ✅ **Auto-selection**: Defaults to FAISS when no external DB configured
- ✅ **Same Interface**: Compatible with all existing tools and APIs

#### Limitations

- ⚠️ **Memory**: Entire index loads into RAM (suitable for ~100K files)
- ⚠️ **Concurrency**: Single-process file access
- ⚠️ **Scalability**: For larger codebases, consider Milvus or Qdrant

For production deployments or large codebases (>100K files), we recommend using [Milvus](https://milvus.io) or [Qdrant](https://qdrant.tech).

### Using Different Embedding Models

To configure custom embedding models (e.g., `text-embedding-3-large` for OpenAI, `voyage-code-3` for VoyageAI), see the [MCP Configuration Examples](packages/mcp/README.md#embedding-provider-configuration) for detailed setup instructions for each provider.
Expand Down
20 changes: 10 additions & 10 deletions packages/core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -637,8 +637,8 @@ export class Context {
// Warn if we hit the query limit - actual collection may be larger
if (totalChunks === 100000) {
console.warn(
`[Context] ⚠️ Retrieved maximum limit of 100k chunks for ${codebasePath}. ` +
`Actual total may be higher. Stats may be incomplete.`,
`[Context] ⚠️ Retrieved maximum limit of 100k chunks for ${codebasePath}. `
+ `Actual total may be higher. Stats may be incomplete.`,
)
}

Expand All @@ -659,11 +659,11 @@ export class Context {

// Log with full context for debugging
console.error(
`[Context] ❌ Failed to retrieve collection stats\n` +
` Codebase: ${codebasePath}\n` +
` Collection: ${collectionName}\n` +
` Database: ${dbType}\n` +
` Error:`,
`[Context] ❌ Failed to retrieve collection stats\n`
+ ` Codebase: ${codebasePath}\n`
+ ` Collection: ${collectionName}\n`
+ ` Database: ${dbType}\n`
+ ` Error:`,
error,
)

Expand All @@ -673,9 +673,9 @@ export class Context {

// Known recoverable errors that should return null
if (
errorMsg.includes('collection not loaded') ||
errorMsg.includes('collection not exist') ||
errorMsg.includes('Failed to query')
errorMsg.includes('collection not loaded')
|| errorMsg.includes('collection not exist')
|| errorMsg.includes('Failed to query')
) {
console.warn(`[Context] ⚠️ Collection exists but query failed (recoverable): ${errorMsg}`)
return null
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/splitter/ast-splitter.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Parser from 'tree-sitter'
// Language parsers
const JavaScript = require('tree-sitter-javascript')
import { CodeChunk, Splitter } from './index'

import { CodeChunk, Splitter } from './index'
import { LangChainCodeSplitter } from './langchain-splitter'
const TypeScript = require('tree-sitter-typescript').typescript
const CSharp = require('tree-sitter-c-sharp')
Expand Down
76 changes: 75 additions & 1 deletion packages/core/src/vectordb/factory.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { FaissConfig } from './faiss-vectordb'
import type { MilvusRestfulConfig } from './milvus-restful-vectordb'
import type { MilvusConfig } from './milvus-vectordb'
import type { QdrantConfig } from './qdrant-vectordb'
Expand All @@ -6,6 +7,43 @@ import { MilvusRestfulVectorDatabase } from './milvus-restful-vectordb'
import { MilvusVectorDatabase } from './milvus-vectordb'
import { QdrantVectorDatabase } from './qdrant-vectordb'

// FAISS is optional - may not be available in all environments (e.g., CI without native bindings)
// Use lazy loading to avoid import errors
let FaissVectorDatabase: any
let faissAvailable: boolean | null = null // null = not checked yet
let faissCheckError: string | null = null

function checkFaissAvailability(): boolean {
if (faissAvailable !== null) {
return faissAvailable
}

try {
FaissVectorDatabase = require('./faiss-vectordb').FaissVectorDatabase
faissAvailable = true
return true
}
catch (error: any) {
const errorMsg = error.message || String(error)

// Check if it's a FAISS bindings error (allow FAISS to be unavailable)
if (errorMsg.includes('Could not locate the bindings file')
|| errorMsg.includes('faiss-node')) {
faissAvailable = false
faissCheckError = 'FAISS native bindings not available'
console.warn('[VectorDatabaseFactory] FAISS native bindings not available. FAISS support disabled.')
return false
}

// For other errors (e.g., missing file during tests), also mark as unavailable
// but don't throw to allow tests to run
faissAvailable = false
faissCheckError = errorMsg
console.warn(`[VectorDatabaseFactory] FAISS unavailable: ${errorMsg}`)
return false
}
}

/**
* Supported vector database types
*/
Expand All @@ -28,6 +66,13 @@ export enum VectorDatabaseType {
* Supports both self-hosted and Qdrant Cloud
*/
QDRANT_GRPC = 'qdrant-grpc',

/**
* FAISS local file-based vector database
* Use for local-only deployments with zero configuration
* Ideal for development and small-to-medium codebases
*/
FAISS_LOCAL = 'faiss-local',
}

/**
Expand All @@ -37,6 +82,7 @@ export interface VectorDatabaseConfig {
[VectorDatabaseType.MILVUS_GRPC]: MilvusConfig
[VectorDatabaseType.MILVUS_RESTFUL]: MilvusRestfulConfig
[VectorDatabaseType.QDRANT_GRPC]: QdrantConfig
[VectorDatabaseType.FAISS_LOCAL]: FaissConfig
}

/**
Expand Down Expand Up @@ -77,6 +123,12 @@ export class VectorDatabaseFactory {
* VectorDatabaseType.QDRANT_GRPC,
* { address: 'localhost:6334', apiKey: 'xxx' }
* );
*
* // Create FAISS local database
* const faissDb = VectorDatabaseFactory.create(
* VectorDatabaseType.FAISS_LOCAL,
* { storageDir: '~/.context/faiss-indexes' }
* );
* ```
*/
static create<T extends VectorDatabaseType>(
Expand All @@ -93,15 +145,37 @@ export class VectorDatabaseFactory {
case VectorDatabaseType.QDRANT_GRPC:
return new QdrantVectorDatabase(config as QdrantConfig)

case VectorDatabaseType.FAISS_LOCAL:
if (!checkFaissAvailability()) {
throw new Error(
`FAISS vector database is not available. ${faissCheckError || 'Native bindings could not be loaded'}. `
+ 'This usually happens in environments without C++ build tools. '
+ 'Please use another vector database type (MILVUS_GRPC, MILVUS_RESTFUL, or QDRANT_GRPC).',
)
}
return new FaissVectorDatabase(config as FaissConfig)

default:
throw new Error(`Unsupported database type: ${type}`)
}
}

/**
* Get all supported database types
* Note: FAISS may not be available if native bindings are missing
*/
static getSupportedTypes(): VectorDatabaseType[] {
return Object.values(VectorDatabaseType)
const types = Object.values(VectorDatabaseType)
if (!checkFaissAvailability()) {
return types.filter(t => t !== VectorDatabaseType.FAISS_LOCAL)
}
return types
}

/**
* Check if FAISS is available in the current environment
*/
static isFaissAvailable(): boolean {
return checkFaissAvailability()
}
}
Loading
Loading