# Instatic MCP Connector Architecture: Secure AI Integration for External Tools

> Explore the Instatic MCP connector architecture, enabling secure AI integration with external tools via TypeBox schemas and NDJSON. Access CMS capabilities effectively.

- Repository: [CoreBunch/Instatic](https://github.com/CoreBunch/Instatic)
- Tags: architecture
- Published: 2026-07-27

---

**Instatic implements the Model Context Protocol (MCP) as a server-side subsystem that bridges external AI clients to the CMS through TypeBox schemas, a live NDJSON editor bridge, and capability-filtered endpoints.**

The CoreBunch/Instatic repository provides a dedicated MCP connector architecture that enables external AI assistants to safely manipulate content management workflows. This server-side implementation exposes a capability-aware façade while ensuring plaintext credentials never leak to client applications. The architecture centers on three pillars: strict wire-format schemas, a live workspace bridge, and scoped security boundaries.

## MCP Connector Schemas

The **MCP Connector Schemas** define the wire format for all MCP interactions using TypeBox definitions in [`src/core/ai/mcpConnectorSchemas.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/mcpConnectorSchemas.ts). These schemas govern access grants, OAuth flows, and connection metadata to guarantee that no plaintext credentials ever leak to the client side.

When creating access tokens, the `CreateMcpAccessTokenResultSchema` enforces a single-use plaintext disclosure pattern. The server returns the raw token exactly once during creation, then persists only hashed values for subsequent validation. This ensures that database projections or API responses never expose sensitive credentials.

## Live Editor Bridge

Because most editor-side tools (e.g., page-tree mutations, content CRUD) lack pure-server implementations, Instatic routes MCP tool calls through the **Live Editor Bridge**. This component creates a long-lived NDJSON stream that connects external AI clients to the user’s active workspace in the admin UI.

The bridge implementation lives in [`server/ai/mcp/editorBridge.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/editorBridge.ts). Each bridge is created per **user + workspace scope** (either `site` or `content`) and stored in a registry keyed by `userId` and scope. The registry exposes guard functions `hasEditorBridge` and `getEditorBridgeForUser` to enforce that a connection cannot reach another user’s workspace or cross scope boundaries.

## MCP Server Endpoints

The public MCP entry point at `/_instatic/mcp` (handled in [`server/ai/mcp/server.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/server.ts)) processes three families of requests:

1.  **Capability-filtered tool catalog** – Clients fetch available tools (e.g., `publishTool`, `documentTools`) filtered according to the connection’s declared capabilities.
2.  **Headless reads** – Read-only operations (listing pages, content entries) execute directly against the database without touching the editor store.
3.  **Live workspace relay** – Mutating operations (insert node, update content, publish) forward to the appropriate `AiBrowserBridge` instance. The server emits `toolRequest` events on the NDJSON stream; the admin UI executes the tool and POSTs results back to `/admin/api/ai/tool-result`.

## Security and Lifecycle

The architecture enforces strict security boundaries through multiple mechanisms:

**OAuth and Bearer Tokens** – Two credential lifecycles are supported: a one-time bearer token for CLI/automation clients, and an OAuth authorization-code flow with PKCE for hosted MCP clients. The OAuth handler in [`server/ai/mcp/oauth/handler.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/oauth/handler.ts) manages code exchange and hashing. All tokens are stored **only as hashes**, never exposed in list projections.

**Scope-Bound Access** – The bridge registry ensures an MCP connector interacts only with workspaces owned by the authenticated user. A connection cannot reach another user’s workspace or access the site editor when the scope is `content`, and vice-versa.

**Lease and Heartbeat** – Each bridge stream maintains a 2-minute lease (`STREAM_LEASE_MS`) with a 25-second heartbeat to prevent proxy idle timeouts. If the lease expires or the client aborts, the bridge tears down and the registry clears the entry.

## Key Implementation Files

-   **[`src/core/ai/mcpConnectorSchemas.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/mcpConnectorSchemas.ts)** – TypeBox wire schemas for connections, OAuth, and token creation.
-   **[`server/ai/mcp/editorBridge.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/editorBridge.ts)** – NDJSON bridge logic that routes MCP tool calls to the admin editor.
-   **[`server/ai/mcp/server.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/server.ts)** – Main request handler for `/_instatic/mcp` that validates tokens, dispatches tools, and creates bridges.
-   **[`server/ai/mcp/oauth/handler.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/oauth/handler.ts)** – OAuth PKCE flow implementation for authorization URLs and code exchange.
-   **[`server/ai/mcp/paths.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/paths.ts)** – Canonical URL definitions for MCP, OAuth metadata, and consent endpoints.
-   **[`server/ai/mcp/tools/publishTool.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/tools/publishTool.ts)** – Server-side implementation of the `site_publish` tool with audit metadata.

## Practical Integration Examples

### Creating a Bearer Token

```typescript
import { apiRequest } from '@core/http'
import { CreateMcpAccessTokenBodySchema, CreateMcpAccessTokenResultSchema } from '@core/ai'

async function createToken(label: string, caps: string[]) {
  const body = { label, capabilities: caps }
  const result = await apiRequest('/_instatic/mcp/create-token', {
    method: 'POST',
    schema: CreateMcpAccessTokenResultSchema,
    json: body,
  })
  // `result.accessToken` is the only time the plaintext token appears.
  console.log('Save this token securely – it will not be shown again')
  return result
}

```

### Calling a Live Tool via the Bridge

```typescript
import { fetch } from 'node-fetch'

async function runPublishTool(mcpUrl: string, token: string) {
  // 1️⃣ Fetch the capability-filtered tool catalog
  const catalog = await fetch(`${mcpUrl}/tools`, {
    headers: { Authorization: `Bearer ${token}` },
  }).then(r => r.json())

  // 2️⃣ Open the NDJSON stream for tool requests/responses
  const stream = await fetch(`${mcpUrl}/stream`, {
    headers: { Authorization: `Bearer ${token}` },
  })

  // 3️⃣ Send a tool request (publishSite) down the stream
  const encoder = new TextEncoder()
  const writer = stream.body?.getWriter()
  writer?.write(encoder.encode(JSON.stringify({
    type: 'toolRequest',
    tool: 'site_publish',
    args: { /* publish options */ },
  }) + '\n'))

  // 4️⃣ Read the result event from the stream
  const reader = stream.body?.getReader()
  const { value } = await reader?.read()
  const result = JSON.parse(new TextDecoder().decode(value))
  console.log('Publish result:', result)
}

```

### Server-Side Bridge Creation

```typescript
// Inside server/ai/mcp/server.ts
import { createEditorBridgeStream } from './editorBridge'

export function handleMcpStream(req) {
  const { userId, scope } = req.auth // validated bearer token
  return createEditorBridgeStream(userId, scope, req.signal)
}

```

## Summary

-   **Instatic MCP connector architecture** exposes a secure server-side façade for external AI tools using the Model Context Protocol.
-   **TypeBox schemas** in [`src/core/ai/mcpConnectorSchemas.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/mcpConnectorSchemas.ts) enforce wire-format safety and prevent credential leakage.
-   **Live Editor Bridge** routes mutating operations through NDJSON streams to the user’s active admin UI workspace.
-   **Scoped access controls** ensure bridges are bound to specific users and workspace scopes (`site` or `content`).
-   **Hashed token storage** and PKCE OAuth flows protect against credential exposure, with tokens displayed only once at creation.
-   **Automatic lease expiration** (`STREAM_LEASE_MS`) and heartbeats manage connection lifecycle and resource cleanup.

## Frequently Asked Questions

### What is the Model Context Protocol in Instatic?

The Model Context Protocol (MCP) is a server-side subsystem in CoreBunch/Instatic that standardizes how external AI clients interact with the CMS. It provides capability-filtered tool catalogs, headless read operations, and a live relay for mutating operations that require the admin editor.

### How does the live editor bridge handle mutations?

Mutations like inserting nodes or publishing content have no pure-server implementation, so the bridge in [`server/ai/mcp/editorBridge.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/editorBridge.ts) relays them via an NDJSON stream. The server sends `toolRequest` events to the user’s active browser session, which executes the operation and returns results to `/admin/api/ai/tool-result`.

### What security measures protect MCP credentials?

Credentials are protected through TypeBox schema validation, hashed storage (never plaintext), and single-use token disclosure. OAuth flows use PKCE, and bearer tokens are generated via `/_instatic/mcp/create-token` with the plaintext shown only once during the creation response.

### How long do MCP bridge connections remain active?

Each bridge maintains a 2-minute lease (`STREAM_LEASE_MS`) refreshed by a 25-second heartbeat interval. If the client disconnects or the lease expires without renewal, the server automatically tears down the bridge and removes the registry entry to prevent stale connections.