# How to Build MCP Servers with Deno

Building MCP servers with Deno provides a secure way to expose tools for AI agents. The Model Context Protocol (MCP) allows streamable tool calls over HTTP or SSE. Deno's permission system handles untrusted agents safely. This tutorial shows how to set up a server, implement core endpoints, add security, integrate Fresh, and deploy.

Source: https://fast.io/resources/building-mcp-servers-deno/
Last reviewed: 2026-02-19

## What is an MCP Server?

An MCP server implements the Model Context Protocol, a streaming protocol for AI agent tools. It handles requests like tool discovery, execution, and state management.

Fastio runs a remote MCP server at https://mcp.fast.io/mcp with a consolidated toolset for file storage and collaboration. Building your own lets you expose custom tools securely.

Key features include:
* Streamable HTTP at /mcp
* SSE fallback at /sse
* Session state for auth tokens
* Dynamic resource listing for files

Deno fits perfectly. It runs TypeScript natively and bundles to a single executable binary. Permissions like --deny-net protect against malicious agents.

Helpful references: [Fastio Workspaces](/product/workspaces/), [Fastio Collaboration](/product/collaboration/), and [Fastio AI](/product/ai/).

## Why Deno for MCP Servers?

Deno emphasizes security for untrusted code, ideal for agent tools.

Advantages:
* Built-in TypeScript support, no config needed
* Permission flags (--allow-net, --deny-all) for fine-grained control
* Bundles to single binary with `deno compile`
* Fast runtime with V8 isolates
* Native HTTP server APIs

Compared to Node.js, Deno avoids npm vulnerabilities and package.json hell.

## Prerequisites

Install Deno 2.0+:

```
curl -fsSL https://deno.land/install.sh | sh
```

Verify:

```
deno --version
```

Create project:

```
mkdir mcp-server-deno
cd mcp-server-deno
deno init
```

## Set Up Fresh Framework

Fresh provides file-based routing and islands for agent UIs.

Add Fresh:

```
deno add @fresh/core @preact/signals-react fresh
```

main.ts:

```ts
import manifest from "./fresh.gen.ts";

import { start } from "@fresh/server";
import { type Plugin } from "$fresh/server.ts";

const plugins: Plugin[] = [];

await start(manifest, { plugins });
```

routes/api/mcp.ts for MCP endpoint.

## Implement MCP Endpoints

Create /api/mcp POST handler for streamable calls.

Example handler:

```ts
import { HandlerContext } from "$fresh/server.ts";

export const handler = {
  async POST(req: Request, ctx: HandlerContext) {
    const sessionId = ctx.state.sessionId || crypto.randomUUID();
    // Parse MCP request
    const body = await req.json();
    const { tool, action, params } = body;

// Route to tool action
    let result;
    if (tool === "storage") {
      result = await handleStorage(action, params, sessionId);
    } // etc

// Stream response
    const stream = new ReadableStream({
      start(controller) {
        controller.enqueue(JSON.stringify({ result }));
        controller.close();
      }
    });

return new Response(stream, {
      headers: { "Content-Type": "application/json-stream" }
    });
  }
};
```

Add session state with Deno KV for persistence.

## Agent Permissions and Security

Deno permissions protect against untrusted agents.

Run with:

```
deno run --allow-net --allow-env --deny-all main.ts
```

Explicitly allow only needed perms.

In code, validate agent requests:

```ts
if (!isTrustedAgent(req.headers.get("User-Agent"))) {
  return new Response("Unauthorized", { status: 401 });
}
```

Use Deno's secure defaults: no file access unless allowed.

For production, add rate limiting and auth tokens per agent.

## Deploy to Deno Deploy

Bundle and deploy.

deno.json:

```json
{
  "compilerOptions": {
    "lib": ["deno.unstable"]
  },
  "tasks": {
    "deploy": "deno task start"
  },
  "deploy": "./main.ts"
}
```

Deploy:

```
deployctl deploy --project=my-mcp
```

Flags: --allow-net for HTTP, Deno Deploy handles scaling.

## Testing Your MCP Server

Test with curl:

```
curl -X POST http://localhost:8000/api/mcp \\
  -H "Content-Type: application/json" \\
  -d '{"tool":"storage","action":"list"}'
```

works alongside agents using MCP clients.

Define clear tool contracts and fallback behavior so agents fail safely when dependencies are unavailable. This improves reliability in production workflows.

## Frequently asked questions

### What are Deno MCP permissions?

Deno uses runtime flags like --allow-net, --deny-read to restrict access. For MCP, deny all then allow specific for agent tools. This prevents untrusted agents from accessing files or network.

### How does Fresh framework works alongside MCP?

Fresh handles routing to /mcp endpoints. Use islands for agent dashboards. Combine with Preact for reactive UIs serving MCP data.

### Can I bundle MCP server to a binary?

Yes, `deno compile --allow-net main.ts` creates a single executable. Distribute easily without Deno install.

### What Deno Deploy flags for production?

Use deployctl with --allow-net, --allow-env=DENO_KV. Deno Deploy provides global edge runtime.

### How to handle sessions in MCP?

Use Deno KV for persistent sessions. Store auth tokens by sessionId from headers.

## About Fast.io

Fast.io provides shared workspaces where people and AI agents work on the same files, with built-in semantic search and citation-backed chat over what they hold. Agents reach it through a remote MCP server at https://mcp.fast.io/mcp, a REST API at https://api.fast.io/current/, and a command line client published on npm as @vividengine/fastio-cli.
