Testing and Shipping

Advanced

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:

Open
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.

Read Testing Your Server

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.ts reaches the server only through the frontmcp command (frontmcp dev and the builds). Started any other way, it answers at / until you set http.entryPath, so a client pointed at /mcp gets 404.
  • FrontMCP hides the message of any plain Error a tool throws. Fail with PublicMcpError for anything the model should read.
  • Clients before MCP 2026-07-28 need MCP_SESSION_SECRET. Without it their initialize gets a 500 that names the secret (the code is SESSION_SECRET_REQUIRED), while clients on MCP 2026-07-28 and /healthz still 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 Server

Running 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 Instances

Auth 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.