# Paperclip Agent Adapter Interface: The ServerAdapterModule Contract Explained

> Understand the ServerAdapterModule contract, the standard interface for Paperclip agent adapters. Learn how to build custom adapters for your projects.

- Repository: [Paperclip/paperclip](https://github.com/paperclipai/paperclip)
- Tags: api-reference
- Published: 2026-08-14

---

**The standard interface for Paperclip agent adapters is the `ServerAdapterModule` TypeScript interface, defined in [`packages/adapter-utils/src/types.ts`](https://github.com/paperclipai/paperclip/blob/main/packages/adapter-utils/src/types.ts).**

Every adapter in the Paperclip ecosystem—whether built-in or external—must implement this contract to be discovered, configured, and executed by the control plane. This article breaks down the `ServerAdapterModule` structure, its required methods, and how adapters register with the platform according to the actual source code in `paperclipai/paperclip`.

---

## Core Interface: ServerAdapterModule

The canonical definition lives at **[`packages/adapter-utils/src/types.ts`](https://github.com/paperclipai/paperclip/blob/main/packages/adapter-utils/src/types.ts) (line 419)**. All server-side adapters must satisfy this interface:

```typescript
export interface ServerAdapterModule {
  /** Unique identifier for the adapter – also used as the UI label */
  type: string;

  /** Human-readable name shown in the UI (optional – defaults to `type`) */
  label?: string;

  /** Optional JSON-schema that describes the adapter's configuration UI */
  configSchema?: AdapterConfigSchema;

  /** Optional capability flags (e.g. supports streaming, file upload, etc.) */
  capabilities?: AdapterCapabilities;

  /** Optional environment support definition (e.g. required env vars) */
  environment?: AdapterEnvironmentSupport;

  /** Core entry point – runs a task on the adapter */
  execute: (
    ctx: AdapterExecutionContext,
  ) => Promise<AdapterExecutionResult>;

  /** Optional lifecycle hooks */
  init?: () => Promise<void>;
  shutdown?: () => Promise<void>;

  /** Optional session-management or multi-process communication helpers */
  sessionManagement?: AdapterSessionManagement;

  /** Optional access-control policy for the adapter */
  acp?: AdapterRuntimeMcpAccess;
}

```

The **`execute`** property is the only strictly required method beyond `type`. All other fields are optional but enable richer integration with Paperclip's UI and runtime.

---

## Required Methods and Properties

### `type: string`

The unique identifier for the adapter. This string appears in:
- The adapter registry lookup
- UI labels (unless `label` is explicitly provided)
- Route parameters when invoking adapters

### `execute`: The Runtime Entry Point

Every adapter must implement **`execute`** with this signature:

```typescript
execute: (
  ctx: AdapterExecutionContext,
) => Promise<AdapterExecutionResult>

```

This method receives an `AdapterExecutionContext` containing the task definition, input data, and execution environment, then returns a promise resolving to `AdapterExecutionResult` with `success`, `output`, and `logs` fields.

---

## Optional Lifecycle Hooks and Configuration

### `init` and `shutdown`

Adapters can implement **`init`** and **`shutdown`** for setup and teardown:

- **`init?(): Promise<void>`** — Called once when the adapter is first loaded
- **`shutdown?(): Promise<void>`** — Called during server shutdown for graceful cleanup

### `configSchema`: Dynamic UI Generation

The optional **`configSchema`** property accepts an **`AdapterConfigSchema`** object. Paperclip uses this to auto-generate configuration forms in the UI, eliminating the need for custom frontend code per adapter.

### `capabilities`: Feature Flags

Use **`capabilities`** (type `AdapterCapabilities`) to declare supported features like:
- Streaming responses
- File upload handling
- Multi-turn conversation support

The control plane reads these flags to adapt its behavior per adapter.

---

## Adapter Registration in the Paperclip Registry

Built-in adapters are declared as **`const …Adapter: ServerAdapterModule`** in **[`server/src/adapters/registry.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/adapters/registry.ts)**. This file imports the `ServerAdapterModule` type from **[`server/src/adapters/types.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/adapters/types.ts)**, which re-exports it from the core utilities.

Example registration pattern:

```typescript
// server/src/adapters/registry.ts
import { claudeLocalAdapter } from "./claude-local/index.js";
import { codexAdapter } from "./codex/index.js";
import { cursorAdapter } from "./cursor/index.js";

registerServerAdapter(claudeLocalAdapter);
registerServerAdapter(codexAdapter);
registerServerAdapter(cursorAdapter);

```

The registry supports both built-in adapters and external NPM packages. Any module exporting a `ServerAdapterModule`-compatible object can be loaded dynamically.

---

## Minimal Adapter Implementation Example

Here's a complete "noop" adapter that satisfies the `ServerAdapterModule` contract:

```typescript
// packages/adapters/noop/src/index.ts
import type { ServerAdapterModule } from "@paperclipai/adapter-utils";

export const noopAdapter: ServerAdapterModule = {
  type: "noop",
  label: "No-Op Adapter",
  
  execute: async ({ task, context }) => ({
    success: true,
    output: `Task "${task.name}" completed with no side effects.`,
    logs: [],
  }),
};

```

Register it in the server:

```typescript
// server/src/adapters/registry.ts
import { noopAdapter } from "@paperclipai/adapters-noop";
registerServerAdapter(noopAdapter);

```

---

## Execution Flow: How the Server Invokes Adapters

Routes resolve adapters by `type` and call `execute` directly. From **[`server/src/routes/adapters.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/routes/adapters.ts)**:

```typescript
import type { ServerAdapterModule } from "../adapters/types.js";

export async function runAdapter(
  adapterType: string,
  runPayload: { taskId: string; input: unknown },
) {
  const adapter = requireServerAdapter(adapterType);
  const ctx = buildExecutionContext(runPayload);
  const result = await adapter.execute(ctx);
  return result;
}

```

The `requireServerAdapter` utility performs a registry lookup by `type`, validating that the returned object conforms to `ServerAdapterModule` before invocation.

---

## UI-Side Adapter Discovery

The same contract propagates to the frontend via **[`ui/src/adapters/registry.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/adapters/registry.ts)**. This enables:
- Consistent adapter metadata across server and client
- Shared `configSchema` validation
- Type-safe adapter configuration forms

When you add an adapter to the server registry, the UI automatically discovers its metadata through this shared interface.

---

## Summary

- **`ServerAdapterModule`** in [`packages/adapter-utils/src/types.ts`](https://github.com/paperclipai/paperclip/blob/main/packages/adapter-utils/src/types.ts) is the mandatory contract for all Paperclip agent adapters
- **`execute`** is the only required method—everything else enables richer platform integration
- Adapters register via `registerServerAdapter()` in [`server/src/adapters/registry.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/adapters/registry.ts)
- The interface supports built-in and external adapters through a single, type-safe API surface
- Optional fields (`configSchema`, `capabilities`, `environment`) power automatic UI generation and runtime adaptation

---

## Frequently Asked Questions

### What happens if an adapter is missing the `execute` method?

The TypeScript compiler will reject the adapter at build time. At runtime, `requireServerAdapter()` throws if the resolved module lacks `execute`, preventing the server from accepting tasks for that adapter type.

### Can external NPM packages implement Paperclip adapters?

Yes. Any NPM package that default-exports or named-exports an object satisfying `ServerAdapterModule` can be loaded by the server. The registry dynamically imports these packages and validates their shape against the interface.

### How does the UI know which configuration fields an adapter needs?

The optional `configSchema` field contains a JSON Schema describing the adapter's configuration UI. The Paperclip frontend reads this schema to render appropriate form controls without custom code per adapter.