Performance
Faster MCP tool discovery with connected-only loading, caching, and Code Mode
Cold-start tool discovery is the most common performance issue in production apps with many integrations. This guide covers patterns that keep chat and automation startup fast.
Problem: N integrations × network round-trips
getEnabledToolsAsync() fetches tool schemas via list_tools_by_integration once per configured integration. With 100+ integrations and concurrency 8, a cold serverless instance can still take several seconds before the first chat turn.
Mitigations (use together):
connectedOnly: true: only fetch integrations the user has OAuth tokens formode: 'code': expose 2 AI tools instead of hundreds (Code Mode)hydrateToolCache: skip network discovery when metadata is already known- Raise
fetchConcurrencywhen you must fetch many integrations at once
Connected-only discovery
await serverClient.getEnabledToolsAsync({
connectedOnly: true,
context: { userId },
fetchConcurrency: 8, // default in v0.10.0+
});For AI helpers:
await getVercelAITools(serverClient, {
context: { userId },
connectedOnly: true,
mode: "code",
});Invalidate your app-level cache when tokens change (OAuth connect/disconnect).
Built-in tool discovery cache (v0.10.0+)
Pass a cache adapter to getVercelAITools instead of hand-rolling Redis + hydrateToolCache:
import {
getVercelAITools,
createMemoryToolDiscoveryCache,
createToolDiscoveryCacheInvalidator,
} from "integrate-sdk/server";
const cache = createMemoryToolDiscoveryCache();
const tools = await getVercelAITools(serverClient, {
context: { userId },
connectedOnly: true,
mode: "code",
cache: { cache, ttlMs: 5 * 60 * 1000 },
});
// In drizzleAdapter onTokenChange:
createToolDiscoveryCacheInvalidator(cache)({ userId });Implement ToolDiscoveryCacheAdapter for Redis (see production Next.js guide). Keys default to userId:provider1,provider2.
hydrateToolCache for serverless
The SDK exposes hydrateToolCache on the server client so you can restore tool metadata without per-integration fetches:
// After a previous discovery pass, persist stubs (name, description, inputSchema)
serverClient.hydrateToolCache(cachedStubs);
// Subsequent getEnabledToolsAsync / getVercelAITools calls use the cache
const tools = await getVercelAITools(serverClient, {
context: { userId },
connectedOnly: true,
});Production pattern: persist stubs in Redis keyed by userId (and connected-provider set). On cold start, hydrate before calling getVercelAITools. Clear the cache when onTokenChange fires from your database adapter.
Include connected providers in your cache key so reconnecting OAuth invalidates stale tool lists:
const cacheKey = `${userId}:${connectedProviders.sort().join(",")}`;Code Mode default
Code Mode still runs discovery internally, but the model only receives execute_code and get_types. Always set codeMode.publicUrl or INTEGRATE_URL on the server:
createMCPServer({
codeMode: { publicUrl: process.env.INTEGRATE_URL },
// ...
});Usage tracking
Tool calls must include your server apiKey so the MCP server can attribute usage to the correct customer. Ensure:
INTEGRATE_API_KEYis set in your app (server-only)- Your dashboard
/api/usageroute is reachable from the MCP server (no auth session redirect) MCP_SERVER_SECRETmatches between MCP server and dashboardAPP_BASE_URLon the MCP server points at your dashboard origin
See your dashboard ENV_SETUP.md for the full usage pipeline.
Related
- MCP Tool Scoping
- Code Mode
- Database hooks:
onTokenChangefor cache invalidation