# How the MCP Server Implements HTTP Transport with Origin-Guard Security in Code Review Graph

> Learn how the MCP server in Code Review Graph secures HTTP transport using origin guard, CSP headers, and strict origin verification for enhanced safety.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: internals
- Published: 2026-08-14

---

**The MCP server in the Code Review Graph VS Code extension implements HTTP transport through a message-passing channel secured by nonce-based CSP headers and strict origin verification on every incoming message.**

The *Code Review Graph* extension by `tirth8205` embeds an MCP (Micro-Code-Protocol) server directly inside the VS Code extension host rather than exposing a network port. This architecture requires a secure HTTP-like transport mechanism to communicate with the webview UI. The implementation combines Content-Security-Policy nonces with origin-guard validation to prevent cross-origin attacks.

## Webview Creation with Nonce-Based CSP Protection

The transport security begins when the extension opens a graph view. In **[`graphWebview.ts`](https://github.com/tirth8205/code-review-graph/blob/main/graphWebview.ts)** (around line 300), the code generates a `vscode.WebviewPanel` and injects a strict Content-Security-Policy header using a cryptographically secure nonce:

```typescript
const nonce = getNonce();
panel.webview.html = `
  <meta http-equiv="Content-Security-Policy"
        content="default-src 'none';
                 script-src 'nonce-${nonce}';
                 style-src 'unsafe-inline';
                 img-src ${webview.cspSource};">
`;

```

This CSP configuration achieves three critical security properties:

- **`default-src 'none'`** — Blocks all resource loading by default
- **`script-src 'nonce-${nonce}'`** — Permits execution only of scripts bearing the matching nonce
- **`img-src ${webview.cspSource}`** — Restricts images to the webview's own CSP source

The `getNonce()` utility generates a unique value per webview instance, ensuring that injected scripts cannot be replayed across sessions.

## HTTP Transport via VS Code Message Passing

Rather than raw HTTP, the MCP server uses VS Code's built-in message-passing API as its transport layer. The webview JavaScript obtains the API through `acquireVsCodeApi()`:

```typescript
<script nonce="${nonce}">
    const vscode = acquireVsCodeApi();
    // Requests travel through postMessage, not fetch/XHR
    vscode.postMessage({ command: 'buildGraph', args: [] });
</script>

```

The extension registers a listener on `webview.onDidReceiveMessage` to handle incoming requests. This creates an HTTP-like request/response pattern where messages carry commands, arguments, and metadata.

## Origin-Guard Enforcement on Every Message

The critical security layer—the **origin guard**—validates each message before processing. In **[`graphWebview.ts`](https://github.com/tirth8205/code-review-graph/blob/main/graphWebview.ts)**, the message handler performs this verification:

```typescript
panel.webview.onDidReceiveMessage(message => {
    // Origin-guard check: reject messages from unexpected origins
    if (panel.webview.cspSource !== message.origin) {
        console.warn('Rejected message with invalid origin');
        return;
    }
    // Process validated commands...
});

```

This check couples the CSP source with runtime origin verification. Only scripts that were injected with the correct nonce—proving they originated from the extension's trusted HTML generation—can successfully post messages that pass validation.

## Debounced Database Notifications

The MCP server also pushes updates from the backend to the UI. The `GraphWatcher` class in **[`watcher.ts`](https://github.com/tirth8205/code-review-graph/blob/main/watcher.ts)** monitors the on-disk SQLite database (`graph.db`) and forwards change notifications through the same secured channel:

```typescript
const debouncedOnChanged = debounce(onChanged, 500);
this.watcher.onDidChange(() => debouncedOnChanged());

```

- **Lines 37–49** implement a 500ms debounce to prevent UI flooding during rapid file changes
- Notifications traverse the `postMessage` channel, inheriting the same origin-guard protection

The debounce utility itself:

```typescript
function debounce<T extends (...args: any[]) => any>(fn: T, ms: number): T {
    let timer: ReturnType<typeof setTimeout> | undefined;
    const debounced = (...args: Parameters<T>) => {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => { timer = undefined; fn(...args); }, ms);
    };
    return debounced as unknown as T;
}

```

## Complete Implementation Example

Here's the integrated pattern from **[`graphWebview.ts`](https://github.com/tirth8205/code-review-graph/blob/main/graphWebview.ts)**:

```typescript
import * as vscode from 'vscode';
import { getNonce } from './utils';

export function createGraphWebview(context: vscode.ExtensionContext) {
    const panel = vscode.window.createWebviewPanel(
        'codeReviewGraph',
        'Code Review Graph',
        vscode.ViewColumn.One,
        { enableScripts: true }
    );

    const nonce = getNonce();
    panel.webview.html = `
        <meta http-equiv="Content-Security-Policy"
              content="default-src 'none';
                       script-src 'nonce-${nonce}';
                       style-src 'unsafe-inline';
                       img-src ${panel.webview.cspSource};">
        <script nonce="${nonce}">
            const vscode = acquireVsCodeApi();
            vscode.postMessage({ command: 'buildGraph', args: [] });
        </script>
    `;

    panel.webview.onDidReceiveMessage(message => {
        if (panel.webview.cspSource !== message.origin) {
            console.warn('Rejected message with invalid origin');
            return;
        }
        // Command handling logic...
    });
}

```

## Key Source Files

| File | Security Responsibility |
|------|------------------------|
| **[`graphWebview.ts`](https://github.com/tirth8205/code-review-graph/blob/main/graphWebview.ts)** | CSP generation, nonce injection, origin-guard verification |
| **[`watcher.ts`](https://github.com/tirth8205/code-review-graph/blob/main/watcher.ts)** | Debounced file-system monitoring, secured change notifications |
| **[`extension.ts`](https://github.com/tirth8205/code-review-graph/blob/main/extension.ts)** | Command registration, extension host entry points |

## Summary

- **Nonce-based CSP** in [`graphWebview.ts`](https://github.com/tirth8205/code-review-graph/blob/main/graphWebview.ts) prevents execution of unauthorized scripts
- **`acquireVsCodeApi()`** provides a controlled message-passing transport layer
- **Runtime origin verification** rejects messages whose origin mismatches `cspSource`
- **Debounced watchers** in [`watcher.ts`](https://github.com/tirth8205/code-review-graph/blob/main/watcher.ts) push updates without overwhelming the UI
- No network port exposure eliminates entire classes of remote attack vectors

## Frequently Asked Questions

### What makes this transport "HTTP-like" rather than true HTTP?

The channel mimics HTTP semantics—requests carry commands and payloads, responses return data—but uses `postMessage` over VS Code's internal bridge instead of TCP sockets or HTTP requests. There's no `localhost` port, no CORS headers, and no browser networking stack involved.

### Why does the origin guard check `cspSource` instead of a hardcoded value?

`webview.cspSource` is generated per-webview by VS Code itself, incorporating the extension's identifier and session context. Using this dynamic value prevents hardcoded bypasses and automatically invalidates if the webview context changes.

### Can malicious extensions bypass the origin guard?

Extensions running in the same VS Code instance operate in separate extension hosts with isolated webviews. The nonce and CSP source are not exposed through any API, so another extension cannot forge valid messages without compromising VS Code's core webview isolation.

### What happens if the SQLite database changes rapidly?

The `debounce` utility with a 500ms window in [`watcher.ts`](https://github.com/tirth8205/code-review-graph/blob/main/watcher.ts) collapses multiple rapid changes into a single notification, preventing UI thrashing while maintaining responsiveness for legitimate updates.