How Instatic Integrates External AI Tools with MCP Connectors: A Complete Architecture Guide
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). 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) 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) and [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), which defines:
- Bearer connectors: Created via
POST /admin/api/ai/mcp/connectionsusingCreateMcpAccessTokenBodySchema, returning a one-time token viaCreateMcpAccessTokenResultSchema. - 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) 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).
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) uses the MCP_CONNECTIONS_BASE constant to route requests:
// 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:
// 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.
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:
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) validates the request format and forwards valid calls to 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:
// 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) 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:
- External AI driver sends an HTTP POST to
/_instatic/mcpwith a JSON-RPC payload. server/router.tsdelegates tohandleMcpHttp, which authenticates the request against stored credentials.- Valid requests enter
editorBridge.ts, which deserializes the method call and routes it to the appropriate tool implementation insrc/core/ai/. - The tool executes Yjs operations via
mutateActiveTree, modifying the live document. - 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, credential storage inai_mcp_connectorstables, and a workspace bridge ineditorBridge.ts. - Authentication supports both bearer tokens (for servers) and OAuth 2.0 with PKCE (for user-authorized apps), managed through schemas in
mcpConnectorSchemas.ts. - Real-time editing is enabled by
useMcpWorkspaceBridge, which streams tool calls into Yjs document mutations. - Custom tools implement the
ToolHandlerinterface and register insrc/core/ai/index.tsto 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). 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 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). 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) and [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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →