The Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context and tools to LLMs. Think of it as a USB-C for AI — a universal interface that lets any LLM client talk to any tool server without custom integrations.
In this post, we build and deploy a full MCP server — entirely on Gcore FastEdge. No containers, no VMs, no infrastructure. Just Rust compiled to WebAssembly, running on 160+ edge PoPs worldwide.
What is MCP?
MCP defines how clients (like Claude Desktop, VS Code extensions, or custom AI apps) discover and invoke tools on a server. The protocol uses JSON-RPC over HTTP with two transport modes:
- stdio — for local subprocess communication (CLI tools, editor plugins)
- Streamable HTTP — for remote servers via HTTP POST and Server-Sent Events
The Streamable HTTP transport is a great fit for edge compute because:
- MCP tools are stateless request-response — no persistent connections needed
- JSON-RPC over HTTP POST maps directly to FastEdge's request handler
- Sub-millisecond cold starts mean no latency penalty for infrequent calls
- Requests are handled at the geographically nearest edge PoP
The Architecture
Our MCP server exposes a single endpoint (/mcp) that accepts both GET and POST:
| Method | Path | Purpose |
|---|---|---|
| GET | /mcp | SSE stream (server events / handshake) |
| POST | /mcp | JSON-RPC message handler |
For this example, we implement three MCP tools:
- hello — greets the caller with an edge-generated message
- echo — echoes back whatever input you send
- info — returns metadata about the MCP server
Implementation in Rust
The full source is about 200 lines. Here's the core structure:
use fastedge::{
body::Body,
http::{Error, Request, Response, StatusCode},
};
use serde_json;
#[fastedge::http]
fn main(req: Request<Body>) -> Result<Response<Body>, Error> {
let method = req.method().clone();
let path = req.uri().path().to_string();
match (method.as_str(), path.as_str()) {
("GET", "/mcp") => {
// SSE endpoint — sends an "endpoint" event so the client
// knows where to send JSON-RPC messages
sse_reply("event: endpoint\ndata: /\n\n")
}
("POST", "/mcp") => {
// Parse JSON-RPC, dispatch to handler, return response
let body_str = String::from_utf8_lossy(req.body().as_ref());
let response = dispatch_jsonrpc(&body_str);
json_reply(StatusCode::OK, &response)
}
_ => not_found(),
}
}
The JSON-RPC dispatching follows the MCP spec exactly:
fn dispatch_jsonrpc(body_str: &str) -> String {
let msg: serde_json::Value = serde_json::from_str(body_str).unwrap_or_default();
let method = msg.get("method").and_then(|v| v.as_str()).unwrap_or("");
match method {
"initialize" => handle_initialize(msg.get("id")),
"tools/list" => handle_tools_list(msg.get("id")),
"tools/call" => handle_tools_call(
msg.get("id"),
msg.pointer("/params/name"),
msg.pointer("/params/arguments"),
),
"notifications/initialized" => String::new(), // 202 Accepted
_ => method_not_found(msg.get("id"), method),
}
}
Deploying to FastEdge
Deployment is a two-step process: upload the Wasm binary, then update the app.
# Build
cargo build --target wasm32-wasip1 --release
# Upload binary
curl -X POST https://api.gcore.com/fastedge/v1/binaries/raw \
-H "Authorization: APIKey YOUR_API_KEY" \
-H "Content-Type: application/octet-stream" \
--data-binary @target/wasm32-wasip1/release/mcp_server.wasm
# Create app
curl -X POST https://api.gcore.com/fastedge/v1/apps \
-H "Authorization: APIKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"binary": BINARY_ID, "name": "fastedge-mcp", "status": 1}'
Once the app is created, it's immediately live at https://fastedge-mcp-NNNN.fastedge.app. The MCP server is now running on 160+ edge PoPs worldwide.
Testing the MCP Server
Any MCP-compatible client can connect. You can also test with curl:
# Initialize session
curl -X POST https://fastedge-mcp-1476.fastedge.app/mcp \
-H "content-type: application/json" \
-H "accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-06-18","capabilities":{}}}'
# List available tools
curl -X POST https://fastedge-mcp-1476.fastedge.app/mcp \
-H "content-type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# Call the hello tool
curl -X POST https://fastedge-mcp-1476.fastedge.app/mcp \
-H "content-type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"hello","arguments":{"name":"FastEdge"}}}'
Performance
The Wasm binary is ~254KB (mostly serde_json for JSON-RPC parsing). FastEdge cold starts in under 1ms, so even infrequent MCP tool invocations see no startup penalty. A simple tool call completes in under 10ms including network transit from the nearest edge PoP.
For comparison, running the same server on a container platform would add 200-800ms of cold start latency per invocation. The edge eliminates that entirely.
What's Next?
This is a minimal example, but it demonstrates the core idea: MCP servers don't need to run on traditional infrastructure. The edge is a natural home for tool servers because:
- Global distribution — tools run closest to the client
- Zero infrastructure — no containers, no VMs, no load balancers
- Sub-millisecond cold starts — Wasm startup is faster than any container
- Built-in auth — add JWT validation at the edge (see our JWT Auth Gateway post)
Ready to build on this? Add more tools, connect to databases via HTTP client, or integrate with the FastEdge KV store for stateful operations. The edge is your platform.