Testing and Shipping
A server that works in the Playground has two more jobs before anyone relies on it: it has to keep working as you change it, and it has to run somewhere clients can reach. This chapter covers both: testing the server end to end, deploying it, and running several copies of it.
In this chapter
Testing your server
@frontmcp/testing starts your server, connects a real MCP client to it, and gives each test that client as mcp. You check what a model would see: which tools are listed, what a call returns, what an error looks like. Open the Tests tab:
import { test, expect } from "@frontmcp/testing";
test("lists get_ticket", async ({ mcp }) => {
expect(await mcp.tools.list()).toContainTool("get_ticket");
});
test("returns a ticket by id", async ({ mcp }) => {
const result = await mcp.tools.call("get_ticket", { id: "T-1" });
expect(result).toBeSuccessful();
expect(result.json()).toEqual({ id: "T-1", title: "Cannot log in", status: "open" });
});
test("fails with a readable message for an unknown ticket", async ({ mcp }) => {
const result = await mcp.tools.call("get_ticket", { id: "T-9" });
expect(result).toBeError();
expect(result).toHaveTextContent("There's no ticket T-9");
});Starting FrontMCP in your browser…
FrontMCP starts when this example comes into view.
The same file runs in your project with npx frontmcp test.
Ready to learn this topic?
Learn the mcp fixture and the MCP matchers, what result.json() really returns, how to tell tool errors from protocol errors, how to test resources, prompts and tools that ask the user, and how to run tests in a project.
Building and deploying
frontmcp build packages your server for a target: a Node bundle, Vercel, AWS Lambda or a Cloudflare Worker. A deployed server runs in production mode, and a few things change there:
- The MCP path in
frontmcp.config.tsreaches the server only through thefrontmcpcommand (frontmcp devand the builds). Started any other way, it answers at/until you sethttp.entryPath, so a client pointed at/mcpgets404. - FrontMCP hides the message of any plain
Errora tool throws. Fail withPublicMcpErrorfor anything the model should read. - Clients before MCP 2026-07-28 need
MCP_SESSION_SECRET. Without it theirinitializegets a500that names the secret (the code isSESSION_SECRET_REQUIRED), while clients on MCP 2026-07-28 and/healthzstill work, so a health check won't notice.
Ready to learn this topic?
Learn how to choose a target, set the endpoint path, give production mode the secrets it needs, run the build in a container, check a deployed server and point a client at it.
Read Deploying Your ServerRunning several instances
Behind a load balancer, each request goes to whichever instance it likes, and each instance has its own memory. Clients on MCP 2026-07-28 keep no session, so they need only the same secrets on every instance. Anything a provider keeps belongs in a store every instance reaches, and older clients' sessions and rate limits are shared through Redis.
Ready to learn this topic?
Learn what instances must share, which secrets every instance needs, how to share sessions and rate limits through Redis, what happens when Redis can't be reached, and the traps in FrontMCP 1.9.3.
Read Running Several InstancesAuth in production has the full checklist, and Deployment has every target's options.
What's next?
Start the chapter with Testing Your Server. After it, Escape Hatches covers what to do when FrontMCP's usual path isn't enough: reading the raw request, calling other services, and running FrontMCP outside a Node server.