# How to Publish and Manage Skills and Plugins in the OpenWork Marketplace

> Learn to publish and manage skills and plugins in the OpenWork marketplace. Create a cloud plugin, use the Den API, and configure access grants for seamless integration.

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

---

**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`](https://github.com/different-ai/openwork/blob/main/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`](https://github.com/different-ai/openwork/blob/main/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 via `postPluginsAccess`
- **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:

```json
{
  "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:

```json
{
  "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:

```json
{
  "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

```javascript
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

```javascript
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

```javascript
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

```javascript
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`](https://github.com/different-ai/openwork/blob/main/ee/apps/den-api/src/mcp/marketplace-capabilities.ts)**: Core implementation of `buildMarketplaceCapabilityName`, `executeMarketplaceCapability`, `filterVisibleRows`, and MCP requirement evaluation
- **[`ee/apps/den-api/src/mcp/builtin-skills.ts`](https://github.com/different-ai/openwork/blob/main/ee/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`](https://github.com/different-ai/openwork/blob/main/ee/apps/den-api/src/mcp/agent.ts)**: Entry point that merges marketplace sources into capability lists and routes execution
- **[`ee/apps/den-api/src/routes/org/plugin-system/access.ts`](https://github.com/different-ai/openwork/blob/main/ee/apps/den-api/src/routes/org/plugin-system/access.ts)**: Grant resolution logic via `resolvePluginArchGrantRole`
- **[`ee/apps/den-api/src/mcp/plugin-mcp-requirement-bindings.ts`](https://github.com/different-ai/openwork/blob/main/ee/apps/den-api/src/mcp/plugin-mcp-requirement-bindings.ts)**: MCP connection bindings for config objects

## Summary

- **Create plugins** using the `skill:create-skill` builtin capability, which generates a Cloud plugin and config object via `postPlugins`
- **Publish to marketplaces** by executing `skill:add-to-marketplace`, which creates the marketplace link through `postMarketplacesPlugins`
- **Control visibility** through cascading grants checked by `filterVisibleRows` across `MarketplaceAccessGrantTable`, `PluginAccessGrantTable`, and `ConfigObjectAccessGrantTable`
- **Discover capabilities** via `search_capabilities`, which identifies marketplace entries using the `plugin:<id>:<id>` naming convention
- **Execute skills** through `execute_capability`, which resolves grants, loads `latestVersion`, 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`](https://github.com/different-ai/openwork/blob/main/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`](https://github.com/different-ai/openwork/blob/main/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`](https://github.com/different-ai/openwork/blob/main/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.