ctx.log, which sends MCP log notifications to the
connected client. This page covers framework logs only.
Default output
FastMCP chooses a log format on its own. You do not need to configure it. When stderr is a terminal (a TTY) and theNO_COLOR environment variable
is unset, FastMCP writes styled lines. Each line starts with a colored
symbol that marks its level. On startup, FastMCP also prints a banner:
the server name, version, transport, and, for HTTP, the URL it listens
on.
When stderr is not a terminal, or NO_COLOR is set, FastMCP writes plain
lines instead. Each line has this form:
LEVEL is one of DEBUG, INFO, WARN, or ERROR, in uppercase. The
JSON object at the end is optional. It appears only when the log call
carries metadata.
All framework logs go to stderr. FastMCP never writes a framework log to
stdout. On the stdio transport, stdout carries the protocol stream, so a
framework log there would corrupt it.
Log level
UselogLevel to set the lowest severity FastMCP logs. There are five
levels, from most to least verbose: debug, info, warn, error, and
silent. Setting a level logs that level and every level after it. For
example, warn logs warnings and errors, but not debug or info messages.
silent logs nothing at all, including the startup banner and the
listening line.
- The
logLeveloption, if you set it. - The
FASTMCP_LOG_LEVELenvironment variable, if you set it. The value is case-insensitive. info, the default, when neither is set.
new FastMCP(...). This applies to both logLevel and FASTMCP_LOG_LEVEL.
A misconfigured deployment fails immediately, instead of logging too
much or too little in silence.
The TypeScript type for this option is FrameworkLogLevel. It is a
separate type from LogLevel, which is the eight-level type ctx.log
uses. See Framework logs and client logging
below.
Custom loggers
FastMCP does not require a specific logging library. Thelogger option
accepts any object with four methods: debug, info, warn, and
error. Each method takes a message string and an optional metadata
object.
console satisfies this shape directly.
logger: console with the stdio transport. console.info and
console.debug write to stdout, and stdout carries the JSON-RPC protocol
stream on stdio. This corrupts the protocol. Use a logger that writes every
level to stderr instead, for example the Winston example below, which routes
info and debug to stderr via stderrLevels.
Winston also satisfies this shape directly. Winston’s info(message, meta) signature matches FastMCP’s.
[fastmcp] prefix before it calls your logger. The message is
plain text, and the metadata is a structured object, not a formatted
string.
Most metadata objects carry a component field. This field names the
part of the framework that produced the log, for example tool, http,
cors, openapi, proxy, auth, context, or routes.
Framework logs and client logging
FastMCP has two separate logging systems. Do not confuse them.
These two systems never mix. A framework log never reaches the client.
A
ctx.log call never reaches your injected logger. See
context for ctx.log.
LoggingMiddleware
LoggingMiddleware logs every request: its method, its outcome, and how
long it took. See middleware for the full
middleware system.
LoggingMiddleware takes an optional emit function, and its behavior
depends on whether you supply one.
With no emit function, LoggingMiddleware writes through the
framework logger. Its output goes to stderr, gated by logLevel like
any other framework log. This is the default, and it changed in this
release: earlier versions wrote to stdout through console.log. On the
stdio transport, that corrupted the JSON-RPC protocol stream. If
something in your setup reads LoggingMiddleware output from stdout,
point it at stderr instead.
With an explicit emit function, LoggingMiddleware calls it directly
with a [fastmcp]-prefixed string. This keeps the previous format, and
you control where the string goes.
Proxy servers
createProxy and buildProxyFromClient accept logger and logLevel
options. FastMCP forwards them to the internal FastMCP instance that
backs the proxy, so the proxy’s own lifecycle and warning logs (for
example a failed capability probe against the upstream server) follow
the same configuration as any other server.