Skip to content
published Visibility internal Owner _ Approver _ Created _ Updated _

Typesense MCP

When to Use

  • Searching across Uvilo OS repo content and published website pages
  • Getting AI-generated summaries of files by path
  • Finding documents by concept (not just exact terms)

Procedure

1. Accessing the Typesense MCP

The Typesense MCP server is a deferred tool. Use ToolSearch to load it if not already available.

Two tools are available:

  • search_knowledge — keyword search with facet filtering (department, project, type, status, visibility, owner)
  • get_file_summary — look up AI summary by relative file path

2. Searching

Use search_knowledge with a natural language query. Filter by department, project, type, status, visibility, or owner to narrow results.

Example filters:

  • department: "Forge" — restrict to Forge department
  • project: "Taxonomy" — restrict to Taxonomy project
  • type: "skill" — find skill documents
  • source: "repo" — repo docs only (exclude website)

3. File Summaries

Use get_file_summary with a relative file path (e.g., Forge/Forge_Agent_Architecture.md) to get an AI-generated summary (≤100 words, produced at index time by the indexing use case). No filesystem access needed.

4. Direct API Access (if MCP unavailable)

import json, urllib.request

def get_env(key):
    """Read an env var from /proc/1/environ (Railway), then os.environ."""
    try:
        with open("/proc/1/environ", "rb") as f:
            for entry in f.read().decode("utf-8", errors="replace").split("\0"):
                if entry.startswith(f"{key}="):
                    return entry.split("=", 1)[1]
    except Exception:
        pass
    import os
    return os.environ.get(key, "")

host = get_env("TYPESENSE_URL")
key = get_env("TYPESENSE_SEARCH_KEY")  # search-only key
url = f"{host}/multi_search"
body = json.dumps({"searches": [{"collection": "uvilo", "q": "query", "query_by": "title,summary,content", "per_page": 5}]}).encode()
req = urllib.request.Request(url, data=body, headers={"Content-Type": "application/json", "X-TYPESENSE-API-KEY": key})
resp = urllib.request.urlopen(req)

Gotchas

  • curl is available through forge-bash__run; the Python urllib example above remains a valid fallback for direct API calls
  • OPENAI_API_KEY must be read from /proc/1/environ, NOT os.environ
  • Consult Forge/Skills/Choose_AI_Model/Models/ for the indexing use case’s model-specific quirks (required parameters, rejected parameters)
  • TYPESENSE_URL and TYPESENSE_SEARCH_KEY must be set in the Railway environment. If missing, direct API calls will fail. Never hardcode these values.
  • TYPESENSE_ADMIN_KEY must be set in Railway env for indexing scripts. Never hardcode it.
  • Heading-based chunking: Long files are split by ##/### headings rather than fixed word counts. Each heading-defined section becomes its own chunk with a heading-slug ID (e.g., Forge/Forge_Infrastructure.md#alpine-container-constraints). Small sections (<50 words) are merged with their parent. Sections exceeding 800 words fall back to word-count splitting with 50-word overlap.

Status Filtering

Three rules for the status param on search_knowledge:

  1. Default: status="published" — filters out unfinished or outdated knowledge.
  2. Project-scoped: When the project param is set, omit status to search all files in that project (drafts and in-progress docs are relevant during active work).
  3. All knowledge: When the user asks to search all knowledge, omit status entirely.

Valid status values: draft, review, approved, published, archived.