How Marketplace Capabilities Are Discovered in OpenWork

Marketplace capabilities in OpenWork are discovered through the search_capabilities MCP tool, which authenticates the caller via MCP token, queries the Den database for authorized marketplace plugins and skills, and returns a normalized capability catalog.

The different-ai/openwork repository implements a multi-layered discovery pipeline that connects AI agents to marketplace resources. Understanding how Marketplace capabilities are discovered requires examining the database schema, business logic, and API endpoint that orchestrate this process.

MCP search_capabilities Architecture

Database Schema in plugin-arch.ts

The discovery process originates in dev/ee/packages/den-db/src/schema/sharables/plugin-arch.ts, which defines the three core tables governing marketplace access:

  • Marketplace: Stores marketplace metadata and configuration
  • MarketplacePlugin: Links plugins to specific marketplaces
  • MarketplaceAccessGrant: Controls which organization members can access specific marketplace resources

These tables establish the relationships required for capability discovery. When an agent requests resources, the system performs joins across these tables to enforce authorization at the database level.

Business Logic in cloud-plugins.ts

The dev/evals/packages/behaviors/src/cloud-plugins.ts file contains the core functions that implement marketplace discovery logic. According to the OpenWork source code, key operations include:

  • cloud.listMarketplaces(): Retrieves all marketplaces accessible to the current session
  • cloud.readResolvedMarketplace(): Fetches a specific marketplace with resolved arrays of pluginNames and skillNames
  • gatherMarketplaceCapabilities(): Assembles capability objects from database records while filtering by access grants
  • assignPluginToMarketplace(): Associates plugins with marketplaces (admin function)
  • createMarketplace(): Provisions new marketplace instances

These functions enforce row-level security by checking MarketplaceAccessGrant entries before returning data.

Route Handler in mcp.ts

The dev/ee/apps/den-api/src/routes/mcp.ts file implements the Model Context Protocol (MCP) HTTP endpoint that exposes the search_capabilities tool. This route handler:

  1. Validates MCP tokens to authenticate the requesting agent
  2. Invokes gatherMarketplaceCapabilities() to retrieve authorized resources
  3. Merges marketplace capabilities with core OpenWork system capabilities
  4. Returns the structured catalog as a JSON response

Step-by-Step Discovery Flow

The Marketplace capabilities discovery process follows this execution path:

  1. Authentication: The agent presents an MCP token to the /mcp/agent endpoint in den-api
  2. Authorization Check: The system validates the token and retrieves the member's organization scopes from the session
  3. Database Query: The server queries Marketplace, MarketplacePlugin, and MarketplaceAccessGrant tables using the schema defined in plugin-arch.ts
  4. Capability Assembly: The gatherMarketplaceCapabilities() function in cloud-plugins.ts constructs capability objects containing pluginName, skillName, marketplaceId, and UI metadata
  5. Catalog Construction: The MCP route handler merges marketplace capabilities with platform capabilities
  6. Response Delivery: The endpoint returns a JSON payload that the client renders as Marketplace Plugin cards

Practical Code Examples

Querying Marketplace Capabilities from an Agent

// Example: Discovering available marketplace plugins
const result = await callTool(
  den.ref.apiUrl,                     // Den base URL
  mcpToken,                           // MCP authentication token
  "search_capabilities",
  { query: "marketplace", limit: 20 } // Optional filtering parameters
);

const matches = result.payload.matches; // Array of capability objects
console.log(matches.map(m => m.name));  // ["My Awesome Plugin", ...]

The returned capability objects match this structure:

{
  "id": "plugin-abc123",
  "name": "My Awesome Plugin",
  "skillName": "my_awesome_skill",
  "marketplaceId": "mk-001",
  "type": "plugin"
}

Reading Resolved Marketplace Data

import { readResolvedMarketplace } from "dev/evals/packages/behaviors/src/cloud-plugins";

const marketplace = await readResolvedMarketplace(memberSession, "mk-001");
console.log(marketplace.pluginNames); // ["My Awesome Plugin", ...]
console.log(marketplace.skillNames);  // ["my_awesome_skill", ...]

Admin: Creating and Populating Marketplaces

import { assignPluginToMarketplace, createMarketplace } from "dev/evals/packages/behaviors/src/cloud-plugins";

// Create a new marketplace
const mk = await createMarketplace(adminSession, { name: "Team Marketplace" });

// Assign a plugin to the marketplace
await assignPluginToMarketplace(adminSession, mk.id, pluginId);

Key Source Files

Summary

  • Marketplace capabilities are discovered via the search_capabilities MCP tool exposed in den-api/src/routes/mcp.ts
  • The Den database schema in plugin-arch.ts models marketplaces, plugins, and access grants for secure querying
  • Business logic in cloud-plugins.ts enforces authorization through MarketplaceAccessGrant checks
  • Authentication requires valid MCP tokens, which scope all results to authorized resources only
  • The discovery flow merges marketplace plugins and skills with core platform capabilities for unified consumption

Frequently Asked Questions

How does OpenWork secure Marketplace capability discovery?

OpenWork secures discovery through MCP token authentication and database-level access control. The MarketplaceAccessGrant table in plugin-arch.ts defines which organization members can view specific marketplace resources. When search_capabilities is called, the gatherMarketplaceCapabilities() function joins this table with Marketplace and MarketplacePlugin to filter results, ensuring agents only receive capabilities they are explicitly authorized to use.

What is the difference between listMarketplaces and readResolvedMarketplace?

The cloud.listMarketplaces() function returns a catalog of marketplace summaries accessible to the session, optimized for discovery UIs. In contrast, cloud.readResolvedMarketplace() fetches complete details for a specific marketplace ID, including fully resolved arrays of pluginNames and skillNames. Use list operations for browsing and resolved reads for execution contexts requiring full configuration data.

Can agents filter capabilities when calling search_capabilities?

Yes, the search_capabilities endpoint accepts optional parameters including query strings and limit values. Agents can pass { query: "specific-term", limit: 10 } to filter the capability catalog. However, the backend in cloud-plugins.ts always enforces access grant restrictions regardless of client-side filters, ensuring security boundaries remain intact.

Where is the database schema for marketplace plugins defined?

The database schema resides in dev/ee/packages/den-db/src/schema/sharables/plugin-arch.ts. This file defines the Marketplace, MarketplacePlugin, and MarketplaceAccessGrant tables using the Den database ORM. These definitions establish the relationships required for the discovery system to join marketplace resources with user permissions and drive the search_capabilities response.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →