Skip to content

πŸš€ MCP Gateway with Semantic Routing β€” One API for all your MCP tools. Natural language in β†’ right tool executed. Blazing fast (Cerebras) + always reliable (multi-LLM fallback).

License

Notifications You must be signed in to change notification settings

Denis-Chistyakov/Saltare

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Saltare

Saltare

The AI Tool Mesh with Semantic Routing

Version License Go Meilisearch


What is Saltare?

Saltare is a production-grade AI tool orchestration platform that connects your AI agents to any MCP-compatible tool through a single, intelligent gateway.

Why Saltare?

  • πŸš€ Built for Speed β€” Sub-second response times with intelligent LLM routing
  • πŸ›‘οΈ Built for Reliability β€” Multi-tier fallback ensures zero downtime
  • 🎯 Built for Simplicity β€” Natural language queries, no complex configurations
  • πŸ” Built for Discovery β€” Hybrid search (keyword + semantic) finds the right tools

Instead of managing dozens of tool integrations, point your AI to Saltare β€” it understands what you need and routes requests to the right tool automatically.

"What's the weather in Tokyo?" 
    β†’ Saltare figures out you need weather.get_current 
    β†’ Extracts {city: "Tokyo"} 
    β†’ Returns the result

✨ Features

🧠 Semantic Routing with LLM Fallback

Natural language queries automatically matched to the right tool. No need to remember exact tool names or parameters β€” just describe what you want.

Blazing Fast + Rock Solid Reliability:

  • Primary: Cerebras AI β€” industry-leading speed with <1s response time
  • Fallback: OpenRouter with your choice of model β€” hundreds of options
  • Local Option: Run your own Ollama models for complete control
  • Zero Downtime: Intelligent multi-tier fallback ensures requests never fail
Primary LLM busy? β†’ Instant automatic fallback
OpenRouter down? β†’ Seamlessly switches to local Ollama
Your app stays running 24/7 βœ…

πŸ” Hybrid Search Engine (NEW!)

Choose your search backend:

Engine Best For Features
Meilisearch Hybrid/Semantic Search Vector search, AI embeddings, typo tolerance
Typesense Fast Keyword Search Instant results, faceting, filtering

Both support auto-indexing when tools are registered!

⚑ Async Job Queue

Long-running operations? No problem. Built-in job queue with real-time SSE streaming, progress tracking, and graceful cancellation.

πŸ”Œ Universal Gateway

One endpoint, multiple protocols:

  • MCP Protocol β€” Standard Model Context Protocol support
  • HTTP REST API β€” For any HTTP client
  • CLI β€” Command-line interface for scripts

πŸ”€ Dual Transport Support (NEW!)

Connect to MCP servers via HTTP or Stdio:

Transport Use Case Example
HTTP Remote MCP servers http://localhost:8082/mcp
Stdio Local npx/process servers npx @anthropic/mcp-server-filesystem

Stdio Transport Features:

  • πŸš€ Auto-spawn processes on demand
  • πŸ”„ Auto-restart on crash (configurable)
  • πŸ“Š Connection pooling for efficiency
  • ⚑ Async request/response with request ID tracking
# Example: Stdio MCP server in config
tools:
  - name: "read_file"
    transport: stdio
    stdio_config:
      command: npx
      args: ["-y", "@modelcontextprotocol/server-filesystem", "/home"]

πŸ”— MCP Proxy Server (NEW!)

saltare-mcp β€” A standalone stdio MCP proxy that aggregates multiple backends into a single server.

Perfect for:

  • 🎯 Cursor/Claude Desktop β€” One MCP server instead of many
  • πŸ”„ Tool Aggregation β€” Combine memory, context7, sequential-thinking, etc.
  • πŸ“Š Unified Interface β€” All tools prefixed by backend name
# Build the proxy
go build -o bin/saltare-mcp ./cmd/saltare-mcp

# Configure in ~/.cursor/mcp.json
{
  "mcpServers": {
    "saltare": {
      "command": "/path/to/saltare-mcp",
      "env": {
        "SALTARE_BACKENDS": "memory|stdio|npx|-y|@modelcontextprotocol/server-memory\ncontext7|stdio|npx|-y|@upstash/context7-mcp"
      }
    }
  }
}

Backend Format: name|transport|command|arg1|arg2|... (newline separated)

Example tools through proxy:

  • memory_create_entities β†’ memory backend
  • context7_resolve-library-id β†’ context7 backend
  • sequential-thinking_sequentialthinking β†’ thinking backend

πŸ“¦ Tool Mesh Architecture

Aggregate tools from multiple MCP servers into a unified registry. Search, discover, and execute tools from anywhere.

πŸ”’ Production Ready

  • Embedded BadgerDB storage (zero external dependencies)
  • Graceful shutdown with job persistence
  • Prometheus metrics out of the box
  • Health checks for Kubernetes
  • Kubernetes deployment manifests included

πŸš€ Quick Start

Install

git clone https://github.com/Denis-Chistyakov/Saltare.git
cd Saltare
go build -o saltare ./cmd/saltare

Run with Meilisearch (Recommended)

# 1. Start Meilisearch
docker-compose -f docker/docker-compose.meilisearch.yml up -d

# 2. Set your LLM API keys
export CEREBRAS_API_KEY=your-cerebras-key
export OPENROUTER_API_KEY=your-openrouter-key

# 3. Start Saltare
./saltare server --config configs/saltare.yaml

# 4. Verify
curl http://localhost:8080/api/v1/health

Try the Demo

# Terminal 1: Start services
docker-compose -f docker/docker-compose.meilisearch.yml up -d
./saltare server

# Terminal 2: Start mock server & run demo
cd tests/mock && go run weather_server.go &
cd ../../demo && ./demo.sh

The demo demonstrates:

  • βœ… Synchronous MCP calls β€” Direct tool invocation
  • βœ… Smart queries β€” Natural language in English, German, French
  • βœ… Intelligent routing β€” Weather vs Math tool selection
  • βœ… Async jobs β€” Background execution with SSE streaming

πŸ” Search Engines

Meilisearch (Default)

Meilisearch provides hybrid search combining keyword and semantic (vector) search:

# configs/saltare.yaml
storage:
  search:
    provider: meilisearch
    meilisearch:
      enabled: true
      host: http://localhost:7700
      api_key: your-master-key
      index_name: tools
      
      # OpenRouter embeddings for semantic search
      embedder:
        source: rest
        url: https://openrouter.ai/api/v1/embeddings
        api_key: ${OPENROUTER_API_KEY}
        model: openai/text-embedding-3-small
        dimensions: 1536
      
      hybrid_search:
        enabled: true
        semantic_ratio: 0.5  # 0=keyword, 1=semantic, 0.5=balanced
# Start Meilisearch
docker-compose -f docker/docker-compose.meilisearch.yml up -d

# Verify
curl http://localhost:7700/health

Typesense (Alternative)

For fast keyword-only search:

storage:
  search:
    provider: typesense
  typesense:
    enabled: true
    nodes:
      - http://localhost:8108
    api_key: your-key
# Start Typesense
docker-compose -f docker/docker-compose.typesense.yml up -d

Without External Search

Saltare works without any search backend β€” falls back to local keyword search:

./saltare server

βš™οΈ LLM Configuration

Saltare uses a multi-tier LLM strategy for maximum speed and reliability:

Primary: Cerebras AI (Fastest)

export CEREBRAS_API_KEY=your-cerebras-key
  • Sub-second response times
  • Handles 99% of requests
  • Auto-falls back if unavailable

Fallback: OpenRouter (Flexible & Reliable)

export OPENROUTER_API_KEY=your-openrouter-key
  • Seamlessly activates if primary LLM is unavailable
  • Also powers semantic search embeddings
  • Free and paid tiers available with hundreds of models
  • Ensures your application never goes down

Local: Ollama (Optional)

# If no API keys provided, uses local Ollama
ollama pull llama3.2:3b

You only need ONE of these to get started. The system automatically uses the best available option.


πŸ“š API

Tools

# List all tools
curl http://localhost:8080/api/v1/tools

# Search tools (uses Meilisearch/Typesense)
curl "http://localhost:8080/api/v1/tools?query=weather"

# Execute a tool
curl -X POST http://localhost:8080/api/v1/tools/weather.get_current/execute \
  -H "Content-Type: application/json" \
  -d '{"args": {"city": "Paris"}}'

Async Jobs

# Create async job with natural language
curl -X POST http://localhost:8080/api/v1/jobs \
  -H "Content-Type: application/json" \
  -d '{"query": "Get weather in Berlin"}'

# Check job status
curl http://localhost:8080/api/v1/jobs/{job_id}

# Stream real-time updates (SSE)
curl -N http://localhost:8080/api/v1/jobs/{job_id}/stream

# Wait for completion
curl -X POST "http://localhost:8080/api/v1/jobs/{job_id}/wait?timeout=30"

MCP Protocol

# Initialize session
curl -X POST http://localhost:8081/mcp \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'

# List available tools
curl -X POST http://localhost:8081/mcp \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

# Smart query (natural language)
curl -X POST http://localhost:8081/mcp \
  -d '{
    "jsonrpc":"2.0",
    "id":3,
    "method":"call_tool",
    "params":{"query":"What is the weather in Tokyo?"}
  }'

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           SALTARE                               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Gateway Layer                                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”                         β”‚
β”‚  β”‚   MCP   β”‚  β”‚  HTTP   β”‚  β”‚   CLI   β”‚                         β”‚
β”‚  β”‚ :8081   β”‚  β”‚ :8080   β”‚  β”‚         β”‚                         β”‚
β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜                         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Semantic Router (with LLM Fallback)                            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Intent Parser β†’ Parameter Extraction β†’ Tool Matching   β”‚   β”‚
β”‚  β”‚                                                          β”‚   β”‚
β”‚  β”‚  LLM Chain:                                              β”‚   β”‚
β”‚  β”‚  1️⃣ Cerebras AI (primary, <1s)                           β”‚   β”‚
β”‚  β”‚       ↓ (on failure)                                     β”‚   β”‚
β”‚  β”‚  2️⃣ OpenRouter (fallback, reliable)                      β”‚   β”‚
β”‚  β”‚       ↓ (if no API key)                                  β”‚   β”‚
β”‚  β”‚  3️⃣ Local Ollama (optional)                              β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Search Layer (Pluggable)                                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚     Meilisearch         β”‚  β”‚        Typesense            β”‚  β”‚
β”‚  β”‚  (Hybrid: kw+semantic)  β”‚  β”‚    (Fast keyword search)    β”‚  β”‚
β”‚  β”‚  + OpenRouter Embeddingsβ”‚  β”‚                             β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Async Job Queue                                                β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚
β”‚  β”‚ Workers β”‚  β”‚  Queue  β”‚  β”‚ Storage β”‚  β”‚   SSE   β”‚           β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Execution Layer                                                β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚     Code Mode       β”‚  β”‚         Direct Mode             β”‚  β”‚
β”‚  β”‚   (Goja Sandbox)    β”‚  β”‚      (MCP Client Pool)          β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Storage: BadgerDB (embedded)                                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

☸️ Kubernetes Deployment

Production-ready Kubernetes manifests are included:

# Deploy with Kustomize
kubectl apply -k deployments/kubernetes/

# Or manually
kubectl apply -f deployments/kubernetes/namespace.yaml
kubectl apply -f deployments/kubernetes/secrets.yaml
kubectl apply -f deployments/kubernetes/configmap.yaml
kubectl apply -f deployments/kubernetes/meilisearch.yaml
kubectl apply -f deployments/kubernetes/saltare-deployment.yaml
kubectl apply -f deployments/kubernetes/saltare-service.yaml

See deployments/kubernetes/README.md for full documentation.


βš™οΈ Configuration

Edit configs/saltare.yaml:

server:
  host: 0.0.0.0
  port: 8080

mcp:
  http:
    enabled: true
    port: 8081

llm:
  primary:
    provider: cerebras
    api_key: ${CEREBRAS_API_KEY}
    model: llama-3.3-70b
  fallback:
    api_key: ${OPENROUTER_API_KEY}
    model: google/gemini-2.0-flash-exp:free

jobs:
  num_workers: 10
  queue_size: 1000
  job_timeout: 5m

storage:
  type: badger
  badger:
    path: ./data/badger
  
  # Search engine: "meilisearch" or "typesense"
  search:
    provider: meilisearch
    meilisearch:
      enabled: true
      host: http://localhost:7700
      api_key: your-master-key
      hybrid_search:
        enabled: true
        semantic_ratio: 0.5

πŸ§ͺ Testing

# Run all tests
go test ./...

# Run with race detector
go test -race ./...

# Meilisearch integration tests
MEILISEARCH_TEST=1 go test ./internal/storage/meilisearch/...

# Run demo
./demo/demo.sh

🀝 Contributing

We welcome contributions!

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing)
  5. Open a Pull Request

πŸ“„ License

GNU Affero General Public License v3.0 (AGPL-3.0) β€” see LICENSE for details.

Commercial Licensing

For commercial licensing inquiries, please contact:


Built for developers who want AI tools that just work.

⭐ Star us on GitHub β€’ Report Bug β€’ Request Feature

About

πŸš€ MCP Gateway with Semantic Routing β€” One API for all your MCP tools. Natural language in β†’ right tool executed. Blazing fast (Cerebras) + always reliable (multi-LLM fallback).

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages