Skip to content

Progressive Discovery

Progressive discovery is NEKTE’s core innovation. Instead of loading all schemas upfront (MCP’s approach), agents fetch only what they need at the resolution they need.

The Three Levels

LevelWhat You GetCostWhen to Use
L0 — CatalogNames, categories, version hashes~8 tok/capAlways start here
L1 — SummaryDescription, input/output types, cost hints~40 tok/capDeciding which capability to use
L2 — Full SchemaTyped JSON Schema with examples~120 tok/capFirst invocation of an unknown capability

Typical Flow

  1. L0 — Discover the catalog

    The agent sends nekte.discover with level: 0. The server returns a compact list of capability IDs, categories, and version hashes.

    const catalog = await client.catalog(); // alias for discover({ level: 0 })
    // catalog.caps = [
    // { id: "sentiment", cat: "nlp", h: "a1b2c3d4" },
    // { id: "summarize", cat: "nlp", h: "e5f6g7h8" },
    // { id: "translate", cat: "nlp", h: "i9j0k1l2" },
    // ]

    Cost: ~24 tokens for 3 capabilities. MCP would spend ~363 tokens for the same tools.

  2. L1 — Get a summary (optional)

    If the agent needs to decide between capabilities, it fetches L1 for more detail:

    const detail = await client.describe('sentiment'); // alias for discover({ level: 1 })
    // {
    // id: "sentiment",
    // h: "a1b2c3d4",
    // desc: "Analyzes text sentiment. Input: text(string). Output: score(float), label(string).",
    // cost: { avg_ms: 200, avg_tokens: 50 }
    // }
  3. L2 — Full schema (rare)

    Only fetched when the agent encounters a completely new capability and needs the full typed schema to construct an invocation:

    const full = await client.discover({ level: 2, filter: { id: 'sentiment' } });
    // Includes input/output JSON Schema, examples, constraints
  4. Invoke with cached hash

    After any discovery level, the agent has the version hash. All subsequent invocations use this hash — zero extra tokens.

    const result = await client.invoke('sentiment', {
    input: { text: 'Great product!' },
    budget: { max_tokens: 50, detail_level: 'minimal' },
    });

Filtering

Discovery supports filtering by category and keyword to reduce response size:

// Only NLP capabilities
const nlpCaps = await client.discover({
level: 0,
filter: { category: 'nlp' },
});
// Search by keyword
const searchResults = await client.discover({
level: 1,
filter: { query: 'sentiment' },
});

Token Cost Comparison

With 30 tools over 15 turns:

ProtocolTotal TokensPer Turn
MCP (eager)54,4503,630
NEKTE (L0 once + invoke)1,155~77

Caching

The client SDK caches discovery results automatically:

  • L0 catalog is cached with SIEVE eviction (scan-resistant)
  • L1/L2 schemas are cached with GDSF weighting (expensive schemas survive eviction)
  • Stale-while-revalidate serves cached data immediately, refreshes in background
  • Negative caching remembers “capability not found” to avoid repeated misses

See the Cache Architecture guide for details.

Best Practices

  1. Start with L0. Always discover at L0 first. Most agents only need the catalog.
  2. Use L1 for routing. If an agent needs to pick between similar capabilities, L1 descriptions are usually enough.
  3. Fetch L2 only once. After the first L2 fetch, the version hash is cached. Subsequent invocations cost 0 extra tokens.
  4. Filter aggressively. If you know the category, filter at discovery time to reduce payload.
  5. Trust the cache. The SDK handles cache invalidation, version mismatches, and background refresh automatically.