How to Publish and Manage Skills and Plugins in the OpenWork Marketplace
Publishing skills and plugins in OpenWork requires creating a Cloud plugin, attaching it to a marketplace via the Den API, and configuring access grants through the builtin skill system.
The OpenWork marketplace, powered by the Den API MCP agent, treats every plugin as a search-capable capability. Understanding how to publish and manage skills and plugins in the OpenWork marketplace involves mastering the builtin skill workflows, grant-based visibility controls, and the search_capabilities/execute_capability interface.
Architecture Overview
The Den API and Capability Model
OpenWork’s marketplace architecture centers on the Den API, which implements an MCP agent pattern for capability discovery and execution. Every published plugin functions as a searchable capability with a standardized naming convention.
In ee/apps/den-api/src/mcp/marketplace-capabilities.ts, the system constructs capability identifiers using buildMarketplaceCapabilityName, producing strings in the format plugin:<plugin-id>:<config-object-id>. When an agent calls search_capabilities, the Den API merges three distinct sources: the native REST catalog, external MCP connections, and the Marketplace source.
Execution flows through executeMarketplaceCapability in the same file. This function resolves the plugin and config object, validates access through grantRole and resolvePluginArchGrantRole, loads the latestVersion, and returns either an instructional payload for skills or status hints for items requiring connections.
Grant-Based Visibility Control
Visibility operates through a cascading grant system defined across three database tables. The filterVisibleRows helper evaluates these grants to determine capability accessibility.
| Grant Table | Protection Scope | Validation Method |
|---|---|---|
| MarketplaceAccessGrantTable | Marketplace-level access | grantRole on marketplace rows |
| PluginAccessGrantTable | Entire plugin and contents | grantRole on plugin rows |
| ConfigObjectAccessGrantTable | Individual config objects | grantRole on config-object rows |
Plugins without marketplace attachments remain grant-only capabilities. The system reports unsynced content with content_not_synced status and provides contentNotSyncedHint guidance.
MCP Server Requirements
For config objects of type mcp, the Den API evaluates declared MCP servers through mcpDependenciesForObject. The functions marketplaceRequirementAction and statusForRequirement determine whether capabilities are ready for execution, need external connections, or require administrative setup.
Publishing Skills Using Builtins
OpenWork provides four builtin skills defined in ee/apps/den-api/src/mcp/builtin-skills.ts that automate the publishing workflow. These capabilities expose constants like BUILTIN_CREATE_SKILL_CAPABILITY and BUILTIN_ADD_TO_MARKETPLACE_CAPABILITY.
Create-Skill Capability
The Create-Skill capability (skill:create-skill) initiates the publishing pipeline by creating a new Cloud plugin containing a single skill config object. It invokes the postPlugins endpoint and returns both the plugin ID and config object ID required for subsequent steps.
Add-To-Marketplace Capability
The Add-To-Marketplace capability (skill:add-to-marketplace) attaches existing plugins to marketplaces using the postMarketplacesPlugins API. This establishes the link necessary for search_capabilities to discover the plugin through the Marketplace source.
Share-Plugin and Access Management
Two capabilities handle distribution permissions:
- Share-Plugin (
skill:share-plugin): Grants person, team, or organization-wide access to a plugin viapostPluginsAccess - Add-User-To-Marketplace (
skill:add-user-to-marketplace): Grants marketplace-level access without exposing specific plugins
Both update the respective grant tables and validate through getPluginsAccess or getMarketplacesResolved.
Step-by-Step Publishing Workflow
1. Create the Plugin
Execute the Create-Skill capability to establish the plugin container:
{
"name": "openwork-cloud_execute_capability",
"capability": "skill:create-skill",
"body": {}
}
The response contains result.plugin (the plugin UUID) and result.configObject (the skill UUID).
2. Attach to Marketplace
Invoke Add-To-Marketplace with the IDs from step 1:
{
"name": "skill:add-to-marketplace",
"capability": "skill:add-to-marketplace",
"body": {
"marketplaceId": "<marketplace-uuid>",
"pluginId": "<plugin-uuid>"
}
}
Verify publication using getMarketplacesResolved.
3. Configure Access Grants
Run Share-Plugin to distribute access:
{
"name": "skill:share-plugin",
"capability": "skill:share-plugin",
"body": {
"pluginId": "<plugin-uuid>",
"orgMembershipId": "om_12345",
"role": "viewer"
}
}
Alternatively, use Add-User-To-Marketplace for marketplace-wide permissions.
4. Discovery and Execution
Agents discover published skills through search_capabilities queries. Executing a capability name like plugin:<plugin-id>:<config-object-id> via execute_capability returns the skill's Markdown source and provenance metadata.
Code Implementation Examples
Creating a Skill via Node.js
const fetch = require('node-fetch');
async function createSkill(title, mdBody) {
const skillMd = `---\nname: ${title}\ndescription: ${title}\n---\n${mdBody}`;
const resp = await fetch('https://api.openworklabs.com/mcp/agent/execute_capability', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: 'skill:create-skill',
capability: 'skill:create-skill',
body: {}
})
});
const { result } = await resp.json();
console.log('Created plugin', result.plugin, 'configObject', result.configObject);
return result;
}
Publishing to a Marketplace
async function publishToMarketplace(pluginId, marketplaceId) {
const resp = await fetch('https://api.openworklabs.com/mcp/agent/execute_capability', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: 'skill:add-to-marketplace',
capability: 'skill:add-to-marketplace',
body: {
marketplaceId: marketplaceId,
pluginId: pluginId
}
})
});
return resp.json();
}
Granting Team Access
async function grantTeamAccess(pluginId, teamId, role = 'viewer') {
const resp = await fetch('https://api.openworklabs.com/mcp/agent/execute_capability', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: 'skill:share-plugin',
capability: 'skill:share-plugin',
body: {
pluginId: pluginId,
teamId: teamId,
role: role
}
})
});
return resp.json();
}
Searching and Executing Capabilities
async function findAndExecuteSkill(query) {
// Search capabilities
const search = await fetch(`https://api.openworklabs.com/mcp/agent/search_capabilities?q=${query}`);
const { matches } = await search.json();
const pluginCap = matches.find(m => m.name.startsWith('plugin:'));
if (!pluginCap) throw new Error('Skill not found');
// Execute capability
const exec = await fetch('https://api.openworklabs.com/mcp/agent/execute_capability', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: pluginCap.name })
});
const { result } = await exec.json();
return result.content;
}
Key Source Files and Functions
According to the different-ai/openwork source code, these files implement the marketplace publishing system:
ee/apps/den-api/src/mcp/marketplace-capabilities.ts: Core implementation ofbuildMarketplaceCapabilityName,executeMarketplaceCapability,filterVisibleRows, and MCP requirement evaluationee/apps/den-api/src/mcp/builtin-skills.ts: Definitions of the four publishing capabilities (BUILTIN_CREATE_SKILL_CAPABILITY,BUILTIN_ADD_TO_MARKETPLACE_CAPABILITY,BUILTIN_ADD_USER_TO_MARKETPLACE_CAPABILITY,BUILTIN_SHARE_PLUGIN_CAPABILITY)ee/apps/den-api/src/mcp/agent.ts: Entry point that merges marketplace sources into capability lists and routes executionee/apps/den-api/src/routes/org/plugin-system/access.ts: Grant resolution logic viaresolvePluginArchGrantRoleee/apps/den-api/src/mcp/plugin-mcp-requirement-bindings.ts: MCP connection bindings for config objects
Summary
- Create plugins using the
skill:create-skillbuiltin capability, which generates a Cloud plugin and config object viapostPlugins - Publish to marketplaces by executing
skill:add-to-marketplace, which creates the marketplace link throughpostMarketplacesPlugins - Control visibility through cascading grants checked by
filterVisibleRowsacrossMarketplaceAccessGrantTable,PluginAccessGrantTable, andConfigObjectAccessGrantTable - Discover capabilities via
search_capabilities, which identifies marketplace entries using theplugin:<id>:<id>naming convention - Execute skills through
execute_capability, which resolves grants, loadslatestVersion, and returns instructional payloads or connection hints
Frequently Asked Questions
How does the Den API verify access to marketplace plugins?
The Den API verifies access through the grantRole and resolvePluginArchGrantRole functions defined in the plugin system access routes. These functions check three hierarchical grant tables: marketplace-level grants, plugin-level grants, and config-object-level grants. The filterVisibleRows helper in marketplace-capabilities.ts applies these checks during the search_capabilities call to ensure agents only discover authorized capabilities.
What is the difference between grant-only plugins and marketplace-published plugins?
Grant-only plugins exist in the system and are searchable but lack marketplace attachments, causing the UI to display an objectHint suggesting local installation. Marketplace-published plugins appear in the Marketplace source merged by the Den API in ee/apps/den-api/src/mcp/agent.ts. Both types require proper grants from PluginAccessGrantTable, but only marketplace plugins receive the full distribution benefits of the marketplace discovery layer.
How does the system handle skills requiring external MCP connections?
When executing capabilities of type mcp, the Den API evaluates requirements through mcpDependenciesForObject and marketplaceRequirementAction. If external MCP connections are missing, executeMarketplaceCapability returns a needs_connection status and a hint containing openworkYourConnectionsUrl. The capability remains unavailable for execution until an administrator configures the required connection bindings in plugin-mcp-requirement-bindings.ts.
Can I update a skill after publishing it to the marketplace?
Yes. The Den API always loads the latestVersion when executing capabilities through executeMarketplaceCapability. To update a skill, modify the config object's content or Markdown source, which creates a new version. The marketplace capability name (plugin:<plugin-id>:<config-object-id>) remains constant, so existing grants and marketplace links continue functioning while agents receive the updated content on subsequent execute_capability calls.
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 →