MCP instrumentation
Record tool execution inside your own MCP server with @doclight/mcp 0.1.0, automatically or manually, and shut down cleanly.
@doclight/mcp records tool execution inside an MCP server you run. Version covered: npm 0.1.0. Source:
sdk-mcp · npm.
Not the Doclight MCP server
This package instruments a customer's MCP server. The Doclight MCP server is a separate, local program that
exposes your Doclight visibility data to AI clients. Installing @doclight/mcp does not install it.
Install
pnpm add @doclight/[email protected] @modelcontextprotocol/[email protected]@modelcontextprotocol/sdk is a peer dependency (>=1.0.0). 1.29.0 is the version the examples were written against.
Configure credentials as described on the Express page.
Automatic instrumentation
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { withDoclight } from "@doclight/mcp";
const server = new McpServer({ name: "example", version: "1.0.0" });
withDoclight(server, {
apiKey: process.env.DOCLIGHT_API_KEY,
projectId: process.env.DOCLIGHT_PROJECT_ID,
endpoint: process.env.DOCLIGHT_ENDPOINT,
});
server.registerTool("health", { description: "Return a safe test result" }, async () => ({
content: [{ type: "text", text: "ok" }],
}));
await server.connect(new StdioServerTransport());- Use
McpServer, not the low-levelServer. The wrapper patchestool()andregisterTool()and wraps handlers registered before or after the call. It relies on MCP SDK internals, so test it with your pinned MCP version. - Each invocation creates its own session, records
tool_calledwith duration and status, then completes the session. - Tool arguments and return payloads are not recorded. Internal reasoning and other MCP protocol operations are not observed.
Limits of 0.1.0
A thrown exception counts as failure. A resolved result with isError: true is not treated as a failure. Call
withDoclight once per server; repeated wrapping is not guarded and duplicates events. getDoclightMcp() is not
exported, and automatic wrapping gives no handle for a final flush.
Manual instrumentation and shutdown
Use the manual context when you need to own the lifecycle:
import { createDoclightMcp } from "@doclight/mcp";
const mcp = createDoclightMcp({
apiKey: process.env.DOCLIGHT_API_KEY,
projectId: process.env.DOCLIGHT_PROJECT_ID,
endpoint: process.env.DOCLIGHT_ENDPOINT,
});
const sessionId = mcp.startSession("safe-tool-test");
try {
const result = await mcp.trackTool("health", sessionId, async () => ({ ok: true }));
mcp.endSession(sessionId, "success");
console.error(result);
} catch (error) {
mcp.endSession(sessionId, "failed");
throw error;
} finally {
await mcp.shutdown();
}createDoclightMcp returns client, startSession, endSession, trackTool, flush and shutdown. Lifecycle hooks are
off by default so your server owns shutdown.
- Stdio servers: stdout carries MCP protocol messages only. Log to stderr (
console.error), neverconsole.log. - In a long-running server, shut down the shared context once when the server exits, not after each tool call.
- Do not wrap the same call both manually and automatically.
Evidence strength
Tool timing and thrown errors measured inside your server are stronger execution evidence than website request logs. Even so, a successful tool call does not show the agent completed its whole task.