# How Instatic Integrates External AI Tools with MCP Connectors: A Complete Architecture Guide

> Discover how Instatic integrates external AI tools with MCP connectors. Explore its architecture for seamless tool invocation within the live Yjs editor.

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

---

**Instatic integrates external AI tools with MCP connectors through a Model-Context-Protocol (MCP) stack that exposes an HTTP endpoint for JSON-RPC requests, persists connector credentials in TypeBox-schematized tables, and bridges tool invocations into the live Yjs editor via a persistent workspace stream.**

Instatic, an open-source CMS, treats external AI services as first-class collaborators. To integrate external AI tools with MCP connectors, the platform implements a typed, secure protocol layer that translates AI driver requests directly into document mutations. This architecture separates transport concerns from business logic while maintaining real-time synchronization with the editor state.

## The Three-Layer MCP Architecture

Instatic's integration consists of three tightly-coupled components that handle authentication, request routing, and editor synchronization.

### 1. MCP Server Endpoint

The entry point is a dedicated HTTP endpoint (`/_instatic/mcp`) registered in [[`server/router.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/router.ts)](https://github.com/CoreBunch/Instatic/blob/main/server/router.ts). This route delegates to `handleMcpHttp`, which accepts JSON-RPC-style payloads from any external AI driver. The transport layer validates requests against TypeBox schemas defined in [[`src/core/ai/mcpConnectorSchemas.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/mcpConnectorSchemas.ts)](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/mcpConnectorSchemas.ts) before forwarding them to the bridge.

### 2. Connector Store and Authentication Schemas

Persistent connector records live in database tables created by migrations in [[`server/db/migrations-pg.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/db/migrations-pg.ts)](https://github.com/CoreBunch/Instatic/blob/main/server/db/migrations-pg.ts) and [[`server/db/migrations-sqlite.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/db/migrations-sqlite.ts)](https://github.com/CoreBunch/Instatic/blob/main/server/db/migrations-sqlite.ts), specifically `ai_mcp_connectors` and `ai_mcp_oauth_clients`. The wire-level contracts are governed by [[`src/core/ai/mcpConnectorSchemas.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/mcpConnectorSchemas.ts)](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/mcpConnectorSchemas.ts), which defines:

- **Bearer connectors**: Created via `POST /admin/api/ai/mcp/connections` using `CreateMcpAccessTokenBodySchema`, returning a one-time token via `CreateMcpAccessTokenResultSchema`.
- **OAuth connectors**: Provisioned through the OAuth flow at `/admin/api/ai/mcp/oauth/authorization`.

Security is enforced by storing hashed tokens (`token_hash`) in the database and never returning raw secrets after initial creation.

### 3. Workspace Bridge

The [[`server/ai/mcp/editorBridge.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/editorBridge.ts)](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/editorBridge.ts) module opens a per-connector stream that forwards MCP tool calls into the editor's Yjs document. The admin UI consumes this bridge via the React hook [[`src/admin/ai/useMcpWorkspaceBridge.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/admin/ai/useMcpWorkspaceBridge.ts)](https://github.com/CoreBunch/Instatic/blob/main/src/admin/ai/useMcpWorkspaceBridge.ts).

When initialized, the bridge registers the connector's scope (e.g., `mcp offline_access`) and attaches a Yjs mutation listener. Incoming requests are deserialized, routed to the appropriate tool implementation (such as `insertHtml` or `readStyles`), and results are streamed back. Errors and connection-loss events are logged with the consistent prefix `[mcp-workspace-bridge:<scope>]`.

## Authenticating External AI Drivers

Instatic supports two authentication patterns for MCP connectors, each suited to different deployment scenarios.

### Creating Bearer Token Connectors

For server-to-server integrations, generate a bearer token through the admin API. The client-side implementation in [[`src/admin/ai/api.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/admin/ai/api.ts)](https://github.com/CoreBunch/Instatic/blob/main/src/admin/ai/api.ts) uses the `MCP_CONNECTIONS_BASE` constant to route requests:

```typescript
// POST /admin/api/ai/mcp/connections
import { apiRequest } from '@core/http';
import { CreateMcpAccessTokenBodySchema, CreateMcpAccessTokenResultSchema } from '@core/ai/mcpConnectorSchemas';

const body = {
  label: 'CLI tool',
  capabilities: ['site-read', 'site-write'],
  ttlDays: 30,
};

const result = await apiRequest('/admin/api/ai/mcp/connections', {
  method: 'POST',
  schema: CreateMcpAccessTokenResultSchema,
  json: body,
});

console.log('Access token (one‑time):', result.accessToken);

```

The API returns the raw token only once; subsequent storage uses the hashed value for validation.

### OAuth 2.0 Connector Flow

For user-authorized integrations, implement the PKCE-enhanced OAuth flow using the `MCP_OAUTH_AUTHORIZATION_PATH` constant:

```typescript
// 1. Request authorization URL
const authUrl = await apiRequest('/admin/api/ai/mcp/oauth/authorization', {
  method: 'POST',
  schema: McpOAuthAuthorizationViewSchema,
  json: {
    clientId: 'my-client',
    redirectUri: 'https://myapp.com/callback',
    codeChallenge: pkceChallenge,
    codeChallengeMethod: 'S256',
    scope: 'site-read',
    resource: 'http://localhost/_instatic/mcp',
  },
});

window.location.href = authUrl.authorizeUrl;

// 2. After redirect, exchange code for tokens
const tokenResult = await apiRequest('/admin/api/ai/mcp/oauth/tokens', {
  method: 'POST',
  schema: McpOAuthAuthorizationResultSchema,
  json: { code: returnedCode, codeVerifier: pkceVerifier },
});

```

This flow creates persistent OAuth credentials in the `ai_mcp_oauth_clients` table while adhering to the schemas defined in [`mcpConnectorSchemas.ts`](https://github.com/CoreBunch/Instatic/blob/main/mcpConnectorSchemas.ts).

## Bridging MCP Calls into the Live Editor

Once authenticated, AI drivers interact with the CMS through the workspace bridge. The React hook `useMcpWorkspaceBridge` manages the persistent connection:

```tsx
import { useMcpWorkspaceBridge } from '@admin/ai/useMcpWorkspaceBridge';

function MyMcpComponent({ connectorId }: { connectorId: string }) {
  const { stream, send } = useMcpWorkspaceBridge(connectorId);

  // Example: ask the AI to insert a styled paragraph
  const insertParagraph = async () => {
    const resp = await send({
      tool: 'mcp__instatic__insertHtml',
      args: { html: '<p>Hello from AI</p>' },
    });
    console.log('Insert result:', resp);
  };

  return <button onClick={insertParagraph}>Insert via AI</button>;
}

```

Under the hood, [[`server/ai/mcp/transports/http.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/transports/http.ts)](https://github.com/CoreBunch/Instatic/blob/main/server/ai/mcp/transports/http.ts) validates the request format and forwards valid calls to [`editorBridge.ts`](https://github.com/CoreBunch/Instatic/blob/main/editorBridge.ts), which then invokes the registered tool handlers.

## Implementing Custom MCP Tools

Server-side tool implementations reside in `src/core/ai/` and follow the `ToolHandler` interface. To modify the document tree, use the `mutateActiveTree` utility:

```typescript
// src/core/ai/tools/insertHtml.ts
import { ToolHandler } from '@core/ai/toolSchemas';
import { mutateActiveTree } from '@core/page-tree/mutations';

export const insertHtml: ToolHandler = async (ctx, { html }) => {
  // Use the page‑tree mutation API to add a node
  await mutateActiveTree((tree) => {
    tree.insertNode({
      type: 'html',
      props: { content: html },
      parentId: ctx.currentNodeId,
    });
  });
  return { ok: true };
};

```

Register the handler in [[`src/core/ai/index.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/index.ts)](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/index.ts) to make it available to the bridge. Each tool receives a context object (`ctx`) containing the current node ID and other editor state, ensuring mutations occur at the correct location in the document.

## Data Flow and Security Model

The complete request lifecycle follows this path:

1. External AI driver sends an HTTP POST to `/_instatic/mcp` with a JSON-RPC payload.
2. [`server/router.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/router.ts) delegates to `handleMcpHttp`, which authenticates the request against stored credentials.
3. Valid requests enter [`editorBridge.ts`](https://github.com/CoreBunch/Instatic/blob/main/editorBridge.ts), which deserializes the method call and routes it to the appropriate tool implementation in `src/core/ai/`.
4. The tool executes Yjs operations via `mutateActiveTree`, modifying the live document.
5. Results or errors stream back to the AI driver through the same HTTP connection.

Security boundaries are enforced at multiple layers: the HTTP transport validates request shapes against TypeBox schemas, the database stores only hashed tokens (`token_hash`), and the bridge logs all operations with scoped prefixes for auditability.

## Summary

- **Instatic integrates external AI tools with MCP connectors** via a three-layer architecture: an HTTP endpoint in [`server/router.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/router.ts), credential storage in `ai_mcp_connectors` tables, and a workspace bridge in [`editorBridge.ts`](https://github.com/CoreBunch/Instatic/blob/main/editorBridge.ts).
- **Authentication** supports both bearer tokens (for servers) and OAuth 2.0 with PKCE (for user-authorized apps), managed through schemas in [`mcpConnectorSchemas.ts`](https://github.com/CoreBunch/Instatic/blob/main/mcpConnectorSchemas.ts).
- **Real-time editing** is enabled by `useMcpWorkspaceBridge`, which streams tool calls into Yjs document mutations.
- **Custom tools** implement the `ToolHandler` interface and register in [`src/core/ai/index.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/index.ts) to access the page-tree mutation API.
- **Security** relies on TypeBox schema validation, hashed token storage, and scoped logging prefixes.

## Frequently Asked Questions

### What is the MCP endpoint URL in Instatic?

The MCP server exposes JSON-RPC requests at the path `/_instatic/mcp`, defined by the `MCP_ENDPOINT_PATH` constant and registered in [[`server/router.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/router.ts)](https://github.com/CoreBunch/Instatic/blob/main/server/router.ts). This endpoint accepts POST requests from external AI drivers after they authenticate via bearer token or OAuth credentials.

### How does Instatic handle MCP authentication securely?

Instatic stores connector credentials in tables like `ai_mcp_connectors` and `ai_mcp_oauth_clients`, persisting only hashed tokens (`token_hash`) in the database. Raw access tokens are returned only once during the `CreateMcpAccessTokenResultSchema` response. All incoming requests are validated against TypeBox schemas in [`mcpConnectorSchemas.ts`](https://github.com/CoreBunch/Instatic/blob/main/mcpConnectorSchemas.ts) before reaching the tool implementation layer.

### How do I create a custom tool for the Instatic MCP bridge?

Define a server-side handler in `src/core/ai/tools/` that implements the `ToolHandler` interface, then register it in [[`src/core/ai/index.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/index.ts)](https://github.com/CoreBunch/Instatic/blob/main/src/core/ai/index.ts). Use `mutateActiveTree` from `@core/page-tree/mutations` to perform document operations. The tool receives a context object with the current node ID, allowing precise insertion or modification of content within the Yjs-based editor.

### What database tables support MCP connectors in Instatic?

The platform creates dedicated tables through migrations in [[`server/db/migrations-pg.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/db/migrations-pg.ts)](https://github.com/CoreBunch/Instatic/blob/main/server/db/migrations-pg.ts) and [[`server/db/migrations-sqlite.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/db/migrations-sqlite.ts)](https://github.com/CoreBunch/Instatic/blob/main/server/db/migrations-sqlite.ts), specifically `ai_mcp_connectors` for bearer token metadata and `ai_mcp_oauth_clients` for OAuth app registrations. These tables store connection labels, capability scopes, and hashed credential data.