# How OpenWork's Tool Catalog and Capability Inventory System Works: MCP Discovery and Validation

> Discover how OpenWorks MCP tool catalog and capability inventory system works. Learn about LLM-safe catalogs with pagination, schema validation, and byte-size constraints.

- Repository: [Different AI/openwork](https://github.com/different-ai/openwork)
- Tags: internals
- Published: 2026-08-09

---

**OpenWork separates MCP tool discovery from remote skill inventory, enforcing strict pagination limits, schema validation, and byte-size constraints to ensure LLM-safe catalogs.**

The `different-ai/openwork` repository implements a dual-layer discovery architecture that distinguishes between local MCP tool catalogs and remote capability inventories. This design ensures AI agents only receive validated, size-constrained tool definitions while maintaining a separate registry of cloud-hosted skills. Understanding how the tool catalog and capability inventory system works is essential for developers building secure, scalable agentic workflows.

## Enterprise MCP Tool Catalog Architecture

The **Enterprise MCP Tool Catalog** handles discovery and validation of local MCP-exposed tools. Implemented in [`packages/enterprise-mcp-client/src/tool-catalog.ts`](https://github.com/different-ai/openwork/blob/main/packages/enterprise-mcp-client/src/tool-catalog.ts), the `collectEnterpriseMcpTools` function orchestrates pagination, validation, and strict resource limits to prevent malformed tools from reaching the LLM context.

### Pagination and Hard Collection Limits

The catalog enforces aggressive pagination boundaries to prevent resource exhaustion. **Page limit** (`ENTERPRISE_MCP_TOOL_PAGE_LIMIT`) caps discovery at 20 pages, while the **item limit** (`ENTERPRISE_MCP_TOOL_ITEM_LIMIT`) stops collection at 2,000 tools. Exceeding either threshold triggers specific error codes: `MCP_CATALOG_PAGE_LIMIT` or `MCP_CATALOG_ITEM_LIMIT`.

```typescript
// Conceptual flow from tool-catalog.ts
for (let page = 0; page < ENTERPRISE_MCP_TOOL_PAGE_LIMIT; page++) {
  const result = await listPage(cursor, opts);
  // Collection logic with limits...
  if (tools.length >= ENTERPRISE_MCP_TOOL_ITEM_LIMIT) {
    throw new EnterpriseMcpCatalogError('MCP_CATALOG_ITEM_LIMIT');
  }
}

```

### Schema Validation and Safety Constraints

Every tool undergoes rigorous validation via the `assertTool` function. **Name uniqueness** is enforced through a `Set` tracking tool names; duplicates raise `MCP_CATALOG_DUPLICATE_TOOL`. Schema validation uses `measureSchema` to inspect `inputSchema` and `outputSchema`, rejecting cyclic references, depth exceeding 64 levels, or schemas larger than 512 KB.

**Byte budgeting** accumulates `catalogBytes` against `ENTERPRISE_MCP_CATALOG_LIMIT_BYTES` (8 MiB). Exceeding this total catalog size aborts collection with `MCP_CATALOG_BYTE_LIMIT`. Cursor safety validates `nextCursor` size, detects pagination loops, and enforces `ENTERPRISE_MCP_CURSOR_LIMIT_BYTES`.

### Typed Error Handling

All validation failures surface as `EnterpriseMcpCatalogError` instances with specific error codes. This typing allows calling code to translate technical failures into user-friendly messages or fallback behaviors without parsing raw error strings.

## OpenWork Connect Capability Inventory

The **Capability Inventory** manages discovery of remote agent skills hosted on OpenWork Cloud. Located in [`apps/server/src/connect-skill-catalog.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/connect-skill-catalog.ts), this system retrieves skill metadata from MCP endpoints, validates payloads, and renders instructions for LLM system prompts.

### Remote Skill Discovery and Validation

The `readMcpSkillIndex` function contacts OpenWork-cloud MCP endpoints by executing an `initialize` RPC followed by reading the `skill://index.json` resource. Raw JSON responses are parsed and validated against `skillIndexSchema` using **Zod**, enforcing name patterns, length limits, and required fields like `capability` strings.

```typescript
// From connect-skill-catalog.ts
const text = await readResource('skill://index.json');
const parsed = skillIndexSchema.parse(JSON.parse(text));

```

### Multi-Source Resolution and Caching

`readOpenWorkConnectSkillCatalog` implements a cascading resolution strategy. It first checks server-level MCP configuration, then falls back to workspace runtime configs. Successfully resolved workspace configs are promoted to server scope for future reads, optimizing subsequent calls.

Results are cached per-configuration hash for `CATALOG_CACHE_TTL_MS` (30 seconds) to minimize network round-trips. The cache stores expiration timestamps and validated values, ensuring stale entries are refreshed automatically.

### Graceful Degradation

If any discovery step fails—whether from invalid URLs, disabled configurations, transport errors, or malformed RPC responses—the function returns an empty array rather than throwing. This **safe fallback** allows agent operations to continue even when remote skills are temporarily unavailable.

### Prompt Integration for LLM Consumption

The `renderOpenWorkConnectSkillInstruction` function converts validated `OpenWorkConnectSkill` objects into XML-like instruction blocks injected into system prompts. The generated `<available_skills>` block explicitly marks these capabilities as **remote**, requiring invocation via `openwork-cloud_execute_capability` with exact capability strings.

When `OPENWORK_DEV_MODE=1` is set, the renderer logs injected marketplace skills for debugging purposes.

## How Tool Catalog and Capability Inventory Work Together

**Tool Catalog** operates at the MCP transport layer, providing validated tool definitions (names, schemas, descriptions) for local execution. **Capability Inventory** operates at the OpenWork Connect layer, aggregating metadata about remote skills hosted in the cloud.

In practice, when a user requests tool execution, the server first uses `collectEnterpriseMcpTools` to verify the tool exists and conforms to size limits. For remote operations, the server calls `readOpenWorkConnectSkillCatalog` to embed skill metadata in the prompt via `renderOpenWorkConnectSkillInstruction`, allowing the LLM to select and invoke remote capabilities through the MCP transport.

## Practical Implementation Examples

### Fetching the Enterprise MCP Tool Catalog

```typescript
import { collectEnterpriseMcpTools } from "@/tool-catalog";
import { mcpClient } from "@modelcontextprotocol/sdk/client";

async function getTools() {
  const tools = await collectEnterpriseMcpTools({
    listPage: (cursor, opts) => mcpClient.listTools({ cursor }, opts),
    requestOptions: { timeoutMs: 5000 },
  });
  console.log(`Found ${tools.length} validated tools`);
  return tools;
}

```

This implementation handles pagination automatically, enforces all 2,000-item and 8-MiB limits, and throws typed `EnterpriseMcpCatalogError` exceptions for validation failures.

### Reading the Remote Skill Catalog

```typescript
import { readOpenWorkConnectSkillCatalog } from "@/connect-skill-catalog";
import type { ServerConfig } from "@/types";

async function listSkills(config: ServerConfig) {
  const skills = await readOpenWorkConnectSkillCatalog(config);
  skills.forEach((s) => {
    console.log(`${s.title ?? s.name}: ${s.description}`);
    console.log(`Capability: ${s.capability}`);
  });
}

```

This function automatically resolves configuration across server and workspace scopes, leverages the 30-second cache, and always returns an array—empty if discovery fails.

### Rendering Skill Instructions for LLM Prompts

```typescript
import { renderOpenWorkConnectSkillInstruction } from "@/connect-skill-catalog";

function buildPrompt(skills) {
  const instruction = renderOpenWorkConnectSkillInstruction(skills);
  return `
You are an AI assistant. ${instruction}
Your task: …
`;
}

```

The rendered `<available_skills>` block provides deterministic capability inventory for model reasoning while enforcing the requirement to use `openwork-cloud_execute_capability` for remote invocations.

## Summary

- **Dual-layer architecture**: OpenWork separates local MCP tool catalogs ([`tool-catalog.ts`](https://github.com/different-ai/openwork/blob/main/tool-catalog.ts)) from remote capability inventories ([`connect-skill-catalog.ts`](https://github.com/different-ai/openwork/blob/main/connect-skill-catalog.ts)) to enforce different validation rules for each.
- **Strict limits**: The tool catalog enforces hard caps of 20 pages, 2,000 tools, 8 MiB total size, and 64-level schema depth to protect LLM context windows.
- **Zod validation**: Remote skills are validated against `skillIndexSchema` with 30-second caching to balance freshness and performance.
- **Graceful degradation**: The capability inventory returns empty arrays on failure, ensuring agent continuity during network outages or configuration errors.
- **Typed errors**: `EnterpriseMcpCatalogError` provides specific codes (`MCP_CATALOG_ITEM_LIMIT`, `MCP_CATALOG_DUPLICATE_TOOL`) for precise error handling.

## Frequently Asked Questions

### What is the maximum number of tools OpenWork can catalog?

The Enterprise MCP Tool Catalog limits collection to **2,000 tools** (`ENTERPRISE_MCP_TOOL_ITEM_LIMIT`) across a maximum of **20 pages** (`ENTERPRISE_MCP_TOOL_PAGE_LIMIT`). Exceeding either limit throws an `EnterpriseMcpCatalogError` with codes `MCP_CATALOG_ITEM_LIMIT` or `MCP_CATALOG_PAGE_LIMIT` respectively.

### How does OpenWork handle invalid or oversized tool schemas?

Each tool schema is validated using `measureSchema` in [`packages/enterprise-mcp-client/src/tool-catalog.ts`](https://github.com/different-ai/openwork/blob/main/packages/enterprise-mcp-client/src/tool-catalog.ts). Schemas exceeding **512 KB**, containing cyclic references, or nesting deeper than **64 levels** are rejected. The entire catalog is also capped at **8 MiB** (`ENTERPRISE_MCP_CATALOG_LIMIT_BYTES`) to prevent context window overflow.

### What happens when the remote skill catalog is unreachable?

The `readOpenWorkConnectSkillCatalog` function in [`apps/server/src/connect-skill-catalog.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/connect-skill-catalog.ts) implements graceful degradation. If the MCP endpoint returns errors, the URL is invalid, or the configuration is disabled, the function catches exceptions and returns an empty array, allowing the agent to continue operating with local tools only.

### How do tool catalogs differ from capability inventories in OpenWork?

**Tool catalogs** contain local MCP tool definitions (names, input/output schemas) validated for immediate execution via `collectEnterpriseMcpTools`. **Capability inventories** contain remote skill metadata fetched from OpenWork Cloud endpoints, cached for 30 seconds, and rendered into prompts via `renderOpenWorkConnectSkillInstruction` to inform the LLM about available remote actions without exposing implementation details.