How to Use the OpenWork API: A Complete Guide to REST and MCP Endpoints

The OpenWork API consists of two complementary HTTP interfaces: the Den API (/api/den) for conventional REST operations on organizations, users, and inference, and the MCP endpoint (/mcp/agent) for JSON-RPC style capability discovery and execution.

OpenWork is an open-source AI workspace platform that exposes programmatic interfaces for building integrations, automating workflows, and connecting external agents. Whether you're scripting backend services or integrating with AI-driven tools like Claude Code or Cursor, understanding both API surfaces—implemented in the different-ai/openwork repository—is essential for effective integration.

The Two API Surfaces: Den API vs. MCP Endpoint

OpenWork deliberately splits its public interface into two distinct layers. This design separates traditional resource management from AI-native capability execution.

API Base URL Purpose Best For
Den API https://<domain>/api/den RESTful resource management (orgs, users, plugins, memory, inference) Backend services, scripts, direct data access
MCP Endpoint https://api.openworklabs.com/mcp/agent JSON-RPC capability discovery and execution AI agents, semantic search, dynamic skill invocation

Both APIs share the same Better Auth authentication system, but they differ fundamentally in interaction patterns. The Den API follows conventional REST semantics, while the MCP endpoint uses a JSON-RPC envelope designed for stateless, capability-oriented requests.

Den API: REST Operations for Resource Management

The Den API is rooted at /api/den, a prefix enforced by the DEN_WEB_PROXY_PREFIX constant in ee/apps/den-api/src/mcp/resource.ts. All routes are organized under ee/apps/den-api/src/routes/** with dedicated subdirectories for each resource type.

Authentication Routes

Authentication flows through /api/auth/*, implemented in ee/apps/den-api/src/routes/auth/index.ts. The system supports:

  • Email/password sign-in via /api/auth/sign-in/*
  • OAuth2 authorization for third-party integrations
  • SCIM provisioning for enterprise identity providers

Token validation occurs in ee/apps/den-api/src/mcp/auth.ts, where Bearer tokens are extracted from the Authorization header and verified against the Better Auth session store.

Organization and Membership Management

Organization-scoped routes live under /api/auth/organization/*, with core handlers in ee/apps/den-api/src/routes/org/core.ts. These endpoints manage:

  • Organization CRUD operations
  • Member invitations and role assignments
  • Billing and usage tracking

Memory, Plugins, and Inference

Specialized routes handle OpenWork's AI-native features:

  • /api/memory/* — Semantic memory storage and retrieval (ee/apps/den-api/src/routes/memory.ts)
  • /api/plugins/* — Plugin lifecycle management and configuration
  • /api/inference/* — Model inference proxying

The inference layer deserves particular attention. In ee/apps/den-api/src/inference.ts, OpenWork constructs provider-specific URLs from env.inferenceProxyBaseUrl and forwards requests to /api/v1 endpoints of configured providers like OpenRouter. This allows unified access to multiple model backends through a single authenticated interface.

Policy Enforcement

Before requests reach route handlers, ee/apps/den-api/src/mcp/policy.ts enforces access controls. This middleware blocks unauthorized access to sensitive paths including /api/auth internals and webhook endpoints, ensuring that only properly authenticated and authorized requests proceed.

MCP Endpoint: JSON-RPC for Capability Execution

The MCP (Model-Control-Plane) endpoint provides a different interaction model optimized for AI agents. Located at /mcp/agent and implemented in ee/apps/den-api/src/mcp/agent.ts, this single route accepts JSON-RPC 2.0 requests with two primary methods.

search_capabilities

This method scans OpenWork's capability registry for skills, plugins, and external MCP connections that match a semantic query. The search implementation in ee/apps/den-api/src/mcp/search.ts indexes:

  • User-created skills (documented workflows)
  • Installed plugins (third-party extensions)
  • Configured external MCP connections (remote capability providers)

execute_capability

Once a capability is selected, this method runs it with provided arguments. The dispatcher in ee/apps/den-api/src/mcp/agent.ts routes execution to the appropriate handler:

  • Skills — Executed within OpenWork's sandboxed runtime
  • Plugins — Delegated to the plugin's configured endpoint
  • External MCP — Proxied to the remote MCP server

JSON-RPC Request Format

All MCP requests follow this envelope structure:

{
  "jsonrpc": "2.0",
  "method": "search_capabilities|execute_capability",
  "params": { /* method-specific */ },
  "id": 1
}

Responses mirror this structure with result or error fields.

When server-side agents need to hand off users to the OpenWork desktop application, the connect-link package generates authenticated deep links.

The core function buildConnectExchangeDeepLink in packages/connect-link/src/index.ts constructs URLs with this signature:

export function buildConnectExchangeDeepLink(
  code: string,
  apiBaseUrl: string,
  scheme = "openwork"
): string

This produces links like openwork://connect?code=abcd1234&apiBaseUrl=https%3A%2F%2Fapi.openworklabs.com%2Fapi%2Fden. When clicked, the desktop client:

  1. Opens automatically via the custom URL scheme
  2. Validates the one-time code with the specified Den API
  3. Establishes an authenticated session

Code Examples: Calling the OpenWork API

Example 1: MCP Search and Execute

This TypeScript example demonstrates the complete flow of discovering and running a capability:

const MCP_URL = "https://api.openworklabs.com/mcp/agent";

async function mcpRequest(method: string, params: unknown) {
  const body = {
    jsonrpc: "2.0",
    id: Date.now(),
    method,
    params,
  };
  
  const response = await fetch(MCP_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });
  
  const json = await response.json();
  if (json.error) throw new Error(json.error.message);
  return json.result;
}

// Search for document summarization capabilities
const capabilities = await mcpRequest("search_capabilities", { 
  query: "summarize document" 
});

// Execute the first matching capability
const result = await mcpRequest("execute_capability", {
  capabilityId: capabilities[0].id,
  args: { 
    text: "OpenWork is an open-source alternative to Claude Code for collaborative AI development." 
  },
});

console.log(result);

The mcpRequest helper mirrors the envelope validation performed in ee/apps/den-api/src/mcp/agent.ts.

Example 2: Den API Direct Access

For operations that don't require capability semantics, use the REST API directly:

const DEN_BASE = "https://api.openworklabs.com/api/den";
const TOKEN = process.env.OPENWORK_API_TOKEN; // Obtain via OAuth2 flow

async function listOrganizations() {
  const response = await fetch(`${DEN_BASE}/organizations`, {
    headers: { Authorization: `Bearer ${TOKEN}` },
  });
  
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${await response.text()}`);
  }
  
  return response.json();
}

listOrganizations()
  .then(orgs => console.log(`Found ${orgs.length} organizations`))
  .catch(console.error);

This accesses the organization routes referenced from ee/apps/den-api/src/routes/org/core.ts.

Integrate the desktop hand-off flow into your application:

import { buildConnectExchangeDeepLink } from "@openwork/connect-link";

async function createConnectCode(): Promise<string> {
  const response = await fetch(`${DEN_BASE}/connect/code`, {
    method: "POST",
    headers: { Authorization: `Bearer ${TOKEN}` },
  });
  const { code } = await response.json();
  return code;
}

async function generateDesktopLink(): Promise<string> {
  const code = await createConnectCode();
  const deepLink = buildConnectExchangeDeepLink(
    code,
    DEN_BASE,
    "openwork" // URL scheme; use "openwork-beta" for test builds
  );
  return deepLink;
}

// Usage: send this link via email, Slack, or embed in a web UI
generateDesktopLink().then(link => {
  console.log("Desktop connection URL:", link);
  // openwork://connect?code=xt9k2m&apiBaseUrl=https%3A%2F%2F...
});

The underlying implementation in packages/connect-link/src/index.ts handles URL encoding and scheme selection.

Authentication Patterns

Both APIs accept Bearer tokens via the Authorization header. Tokens are obtained through:

  1. OAuth2 flow — Initiate at /api/auth/oauth2/authorize with appropriate scopes
  2. Email/password exchange — POST credentials to /api/auth/sign-in/email
  3. API key generation — Create long-lived keys via organization settings (stored in ee/apps/den-api/src/routes/auth/index.ts logic)

Token validation is centralized in ee/apps/den-api/src/mcp/auth.ts, ensuring consistent session verification across both API surfaces.

Summary

  • Den API (/api/den) provides traditional REST access to organizations, users, memory, plugins, and inference—ideal for backend integrations and data operations.
  • MCP endpoint (/mcp/agent) offers JSON-RPC capability discovery and execution—designed for AI agents and semantic workflows.
  • connect-link package generates openwork:// deep links for seamless desktop hand-offs, implemented in packages/connect-link/src/index.ts.
  • Both APIs share Better Auth authentication with Bearer tokens validated in ee/apps/den-api/src/mcp/auth.ts.
  • Policy enforcement in ee/apps/den-api/src/mcp/policy.ts guards sensitive routes before request handling.

Frequently Asked Questions

What authentication does the OpenWork API require?

The OpenWork API uses Better Auth for all authentication. Obtain a Bearer token through OAuth2, email/password sign-in, or organization-scoped API keys. Include the token in the Authorization: Bearer <token> header for all requests. Token validation is implemented in ee/apps/den-api/src/mcp/auth.ts.

When should I use the MCP endpoint instead of the Den API?

Use the MCP endpoint when building AI agent integrations that need to discover and execute capabilities dynamically. Use the Den API for direct resource manipulation—creating organizations, managing users, or running inference with explicit parameters. The MCP endpoint abstracts provider details; the Den API exposes them.

How do I connect a user from my web app to the OpenWork desktop client?

Generate a one-time code via your backend's Den API, then use buildConnectExchangeDeepLink from the connect-link package to create an openwork://connect?code=...&apiBaseUrl=... URL. When the user clicks this link, the desktop app opens and authenticates automatically. The implementation lives in packages/connect-link/src/index.ts.

Can I self-host the OpenWork API?

Yes. The ee/apps/den-api directory contains the complete API implementation. Set the DEN_WEB_PROXY_PREFIX environment variable (defaults to /api/den per ee/apps/den-api/src/mcp/resource.ts) and configure env.inferenceProxyBaseUrl for your model provider. The MCP endpoint and all REST routes deploy as a single service.

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 →