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 configurationMarketplacePlugin: Links plugins to specific marketplacesMarketplaceAccessGrant: 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 sessioncloud.readResolvedMarketplace(): Fetches a specific marketplace with resolved arrays ofpluginNamesandskillNamesgatherMarketplaceCapabilities(): Assembles capability objects from database records while filtering by access grantsassignPluginToMarketplace(): 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:
- Validates MCP tokens to authenticate the requesting agent
- Invokes
gatherMarketplaceCapabilities()to retrieve authorized resources - Merges marketplace capabilities with core OpenWork system capabilities
- Returns the structured catalog as a JSON response
Step-by-Step Discovery Flow
The Marketplace capabilities discovery process follows this execution path:
- Authentication: The agent presents an MCP token to the
/mcp/agentendpoint inden-api - Authorization Check: The system validates the token and retrieves the member's organization scopes from the session
- Database Query: The server queries
Marketplace,MarketplacePlugin, andMarketplaceAccessGranttables using the schema defined inplugin-arch.ts - Capability Assembly: The
gatherMarketplaceCapabilities()function incloud-plugins.tsconstructs capability objects containingpluginName,skillName,marketplaceId, and UI metadata - Catalog Construction: The MCP route handler merges marketplace capabilities with platform capabilities
- 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
dev/ee/packages/den-db/src/schema/sharables/plugin-arch.ts: Defines theMarketplace,MarketplacePlugin, andMarketplaceAccessGrantdatabase schemadev/evals/packages/behaviors/src/cloud-plugins.ts: ImplementslistMarketplaces,readResolvedMarketplace, and capability gathering logicdev/ee/apps/den-api/src/routes/mcp.ts: MCP route handler serving thesearch_capabilitiesendpointdev/evals/specs/self-host-onboarding.e2e.test.ts: End-to-end test demonstrating the discovery flowdev/evals/specs/den-sidebar-ia.e2e.test.ts: UI test validating marketplace card rendering after discovery
Summary
- Marketplace capabilities are discovered via the
search_capabilitiesMCP tool exposed inden-api/src/routes/mcp.ts - The Den database schema in
plugin-arch.tsmodels marketplaces, plugins, and access grants for secure querying - Business logic in
cloud-plugins.tsenforces authorization throughMarketplaceAccessGrantchecks - 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →