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.
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 production MCP server at mcp.fast.io with multiple tools 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, Fastio Collaboration, and Fastio 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.
Ready for Agentic Workspaces?
Build custom MCP tools or use Fastio's hosted MCP server with 251 tools, 50GB free storage, no credit card. Perfect for Deno developers. Built for building mcp servers deno workflows.
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:
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:
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:
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:
{
"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.
Related Resources
Ready for Agentic Workspaces?
Build custom MCP tools or use Fastio's hosted MCP server with 251 tools, 50GB free storage, no credit card. Perfect for Deno developers. Built for building mcp servers deno workflows.