# How OpenWork MCP Server Integration Works: search_capabilities and execute_capability Tools

> Discover how OpenWork MCP server integration uses search_capabilities and execute_capability tools for AI agents to securely browse and call organization-scoped capabilities.

- Repository: [Different AI/openwork](https://github.com/different-ai/openwork)
- Tags: internals
- Published: 2026-08-01

---

**OpenWork's MCP server exposes exactly two tools—`search_capabilities` for discovery and `execute_capability` for invocation—enabling AI agents to securely browse and call organization-scoped capabilities through a minimal remote endpoint.**

The different-ai/openwork repository implements a Model-Context Protocol (MCP) server at `https://api.openworklabs.com/mcp/agent` that deliberately restricts the agent-facing surface to a strict two-tool contract. This design ensures that external AI agents can only interact with the OpenWork Cloud catalog through a deliberate discovery-then-execution workflow, maintaining security while providing full functional access.

## The Minimal Two-Tool Interface

OpenWork operates two distinct MCP endpoints with different tool visibility. The **rich `/mcp` endpoint** used by the desktop application registers every OpenAPI-derived tool plus the additive `search_capabilities` tool. In contrast, the **minimal `/mcp/agent` endpoint**—the one external agents connect to—registers *only* `search_capabilities` and `execute_capability`.

This filtering is enforced in the server code where the tools list is explicitly restricted to `["search_capabilities","execute_capability"]` according to the source in `evals/flows/mcp-search-capabilities.flow.mjs` at line 71.

### Why Limit the Tool Surface?

By exposing only these two tools, OpenWork prevents agents from directly invoking arbitrary capabilities without first discovering them through the organization's access control layer. The agent *must* use the two-step pattern: search first, then execute. This is enforced by the UI configuration where the desktop app's Cloud Control connection points at `/mcp/agent`, which offers no other tool names.

## Discovering Capabilities with search_capabilities

The `search_capabilities` tool serves as the discovery mechanism for the signed-in member's permissions. When an agent calls `tools/call` with `name: "search_capabilities"`, it submits arguments like `{ query: "gmail draft", limit: 10 }`.

The server searches the organization-scoped catalog, ranks matches, and returns a JSON payload containing each match's **name**, **pathParams**, **queryParams**, and **hasBody** flags. This response shape is defined in [`packages/types/src/den/mcp-connection-action.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/den/mcp-connection-action.ts), where the `retry` field is set to the literal `"search_capabilities"` (lines 15-19), indicating that failed discovery attempts should retry using the same tool.

## Executing Capabilities with execute_capability

Once an agent selects a capability from the search results (for example, `getOrg`), it calls `tools/call` with `name: "execute_capability"` and arguments `{ name: "<match.name>" }`.

### Internal Routing Through invoke.ts

The server forwards the request to the unchanged [`invoke.ts`](https://github.com/different-ai/openwork/blob/main/invoke.ts) implementation, which resolves the underlying OpenAPI operation and returns the real data. This guarantees that `/mcp/agent` executions behave identically to calls made through the full `/mcp` catalog, as both paths route through the same internal invocation logic.

### Error Handling for Invalid Capabilities

If an unknown capability name is supplied to `execute_capability`, the server responds with a structured error object where the `error` field equals `"unknown_capability"`. This validation occurs before any execution attempt, preventing unauthorized access to undefined operations (as shown in `evals/flows/mcp-search-capabilities.flow.mjs` at step 13).

## Step-by-Step Integration Workflow

The end-to-end flow demonstrates how these tools work together to retrieve live data. According to the evaluation flow in `evals/flows/mcp-search-capabilities.flow.mjs` (steps 6-8), the sequence is: `search_capabilities` discovers the capability, then `execute_capability` retrieves the org ID and name using the exact capability name.

### Configuring the MCP Client

To connect an MCP-compatible client like OpenCode, add the remote server configuration:

```bash

# Add the MCP entry to opencode.json

cat >> opencode.json <<'EOF'
{
  "mcp": {
    "openwork": {
      "type": "remote",
      "enabled": true,
      "url": "https://api.openworklabs.com/mcp/agent",
      "oauth": {}
    }
  }
}
EOF

```

Authenticate to bind your organization:

```bash
opencode mcp auth openwork

```

This opens a browser for sign-in and organization selection, pinning the chosen org into the access token.

### Example JSON-RPC Calls

The LLM agent internally translates plain-English prompts into these structured calls. First, the discovery request:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search_capabilities",
    "arguments": { "query": "gmail draft", "limit": 5 }
  }
}

```

Sample response showing the call shape hints:

```json
{
  "content": [
    {
      "text": "{\"matches\":[{\"name\":\"postCapabilitiesGoogleWorkspaceGmailDrafts\",\"pathParams\":[],\"queryParams\":[],\"hasBody\":true}]}"
    }
  ]
}

```

Then, the execution request using the exact capability name:

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "execute_capability",
    "arguments": {
      "name": "postCapabilitiesGoogleWorkspaceGmailDrafts",
      "body": {
        "to": "bob@example.com",
        "subject": "Hello",
        "body": "Hi!"
      }
    }
  }
}

```

Successful execution returns the actual data:

```json
{
  "content": [{ "text": "{\"draftId\":\"DRAFT_12345\"}" }]
}

```

## Summary

- **Two-tool contract**: The `/mcp/agent` endpoint deliberately exposes only `search_capabilities` and `execute_capability`, enforced by server-side filtering in `mcp-search-capabilities.flow.mjs`.
- **Discovery phase**: `search_capabilities` searches the organization-scoped catalog and returns ranked matches with parameter hints (pathParams, queryParams, hasBody).
- **Execution phase**: `execute_capability` routes through [`invoke.ts`](https://github.com/different-ai/openwork/blob/main/invoke.ts) to invoke the underlying OpenAPI operation using the exact capability name discovered previously.
- **Error safety**: Unknown capability names return `"unknown_capability"` errors before execution.
- **Client configuration**: MCP clients like OpenCode connect to `https://api.openworklabs.com/mcp/agent` via OAuth, after which the LLM automatically handles the two-step search-then-execute pattern.

## Frequently Asked Questions

### What is the difference between OpenWork's `/mcp` and `/mcp/agent` endpoints?

The `/mcp` endpoint is the rich interface used by the desktop application that registers every OpenAPI-derived tool plus `search_capabilities`. The `/mcp/agent` endpoint is the minimal external interface that exposes only `search_capabilities` and `execute_capability`, forcing AI agents through a controlled discovery workflow.

### Can I call execute_capability without first calling search_capabilities?

Technically yes, but you must know the exact capability name beforehand. The system validates the name against the catalog; if it doesn't exist, it returns an `"unknown_capability"` error. The intended workflow requires `search_capabilities` to discover valid names, as the minimal endpoint provides no other way to browse available operations.

### Where is the capability execution actually handled in the codebase?

All capability executions route through the [`invoke.ts`](https://github.com/different-ai/openwork/blob/main/invoke.ts) implementation, regardless of whether they originate from the rich `/mcp` endpoint or the minimal `/mcp/agent` endpoint. This ensures consistent behavior and authorization checks across all entry points.

### How does the retry field work in the connection action schema?

In [`packages/types/src/den/mcp-connection-action.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/den/mcp-connection-action.ts), the schema defines a `retry` field set to the literal `"search_capabilities"`. This instructs the system that if a discovery operation fails, it should retry using the same `search_capabilities` tool, maintaining the two-step contract even during error recovery.