October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk4 min

See Your MCP Server’s Tools With a Standard-Library Profiler

A standard-library Python profiler can inventory the tools an MCP server advertises over stdio, preserve their schemas, and report whether tool-list pagination completed.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To see what tools an MCP server advertises, send the MCP tools/list discovery request and record each returned definition. The Python script below uses only the standard library and supports stdio transport: it launches a server command, initializes an MCP session, follows tool-list pagination, and writes a JSON inventory. It describes the interface the server advertises; it does not test tool calls or establish that a tool is safe.

What an MCP tool profile tells you

MCP separates discovery from execution. tools/list returns the tools and their metadata; tools/call invokes a named tool. A profile made from discovery is a snapshot of the advertised surface, not a behavioral test. A declared input schema does not prove that the implementation accepts every declared input, and descriptions or annotations are server-provided metadata rather than verified guarantees.

As an Amazon Associate I earn from qualifying purchases.

A tool definition has a name and input schema. Depending on what the server supplies, it can also include a title, description, output schema, and annotations. The specification allows the list to be paginated, so an inventory should record whether it followed continuation cursors until no further page remained. See the MCP Tools specification and MCP schema reference.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

List MCP tools without installing the SDK

This minimal profiler uses Python 3 and standard-library modules only. It implements MCP over stdio, not Streamable HTTP or SSE. Pass the server’s normal launch command after --; for example, if a server is launched with python server.py, run the profiler as python mcp_profile.py -- python server.py. The command must start an MCP stdio server that reads newline-delimited JSON-RPC messages from stdin and writes protocol messages to stdout. Keep diagnostic output on stderr so it does not corrupt the protocol stream.

Save the following as mcp_profile.py. The default protocol version is 2025-06-18; override it with --protocol-version if your server requires a different version. The profile records the negotiated version returned during initialization when available.

#!/usr/bin/env python3
import argparse
import datetime as dt
import json
import subprocess
import sys


def read_message(proc):
    while True:
        line = proc.stdout.readline()
        if not line:
            raise RuntimeError("Server closed stdout before replying")
        try:
            message = json.loads(line)
        except json.JSONDecodeError:
            raise RuntimeError("Expected newline-delimited JSON on server stdout")
        if isinstance(message, dict) and "id" in message:
            return message


def request(proc, message_id, method, params=None):
    message = {"jsonrpc": "2.0", "id": message_id, "method": method}
    if params is not None:
        message["params"] = params
    proc.stdin.write(json.dumps(message, separators=(",", ":")) + "n")
    proc.stdin.flush()
    while True:
        reply = read_message(proc)
        if reply.get("id") == message_id:
            if "error" in reply:
                raise RuntimeError(f"{method} failed: {reply['error']}")
            return reply.get("result", {})


def main():
    parser = argparse.ArgumentParser(
        description="Profile tools advertised by an MCP stdio server"
    )
    parser.add_argument(
        "--protocol-version", default="2025-06-18",
        help="MCP protocol version to request during initialization"
    )
    parser.add_argument("command", nargs=argparse.REMAINDER,
                        help="server launch command, preceded by --")
    args = parser.parse_args()
    command = args.command[1:] if args.command[:1] == ["--"] else args.command
    if not command:
        parser.error("provide a server launch command after --")

    proc = subprocess.Popen(command, stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE, text=True, bufsize=1)
    try:
        init = request(proc, 1, "initialize", {
            "protocolVersion": args.protocol_version,
            "capabilities": {},
            "clientInfo": {"name": "stdlib-mcp-profiler", "version": "1.0"}
        })
        proc.stdin.write(json.dumps({
            "jsonrpc": "2.0", "method": "notifications/initialized"
        }, separators=(",", ":")) + "n")
        proc.stdin.flush()

        tools = []
        pages = 0
        cursor = None
        while True:
            params = {"cursor": cursor} if cursor is not None else {}
            result = request(proc, pages + 2, "tools/list", params)
            pages += 1
            tools.extend(result.get("tools", []))
            cursor = result.get("nextCursor")
            if cursor is None:
                break

        profile = {
            "profiled_at": dt.datetime.now(dt.timezone.utc).isoformat(),
            "transport": "stdio",
            "launch_command": command,
            "requested_protocol_version": args.protocol_version,
            "negotiated_protocol_version": init.get("protocolVersion"),
            "pages_received": pages,
            "continuation_cursor_present": cursor is not None,
            "pagination_complete": cursor is None,
            "tool_count": len(tools),
            "tools": tools
        }
        print(json.dumps(profile, indent=2, ensure_ascii=False))
    finally:
        proc.terminate()
        proc.wait(timeout=5)


if __name__ == "__main__":
    main()

Read and retain the inventory

Run the script with the launch command appropriate to your server. Its JSON output preserves each returned tool object, including the raw input schema and any output schema or other metadata supplied by the server. That makes the original declarations available for inspection even when a compact summary would omit schema constraints.

For a quick human-readable view, each input schema’s properties describes declared fields, and its required array identifies required fields. A field’s type is useful but not the whole contract: constraints such as enumerated values, bounds, nested properties, or string formats can matter to callers. Keep the raw schema rather than reducing it to field names and types alone.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The profile records the launch command, stdio transport, timestamp, requested and negotiated protocol versions, number of pages received, and whether pagination completed. It does not capture endpoint or authorization details for other transports; this script does not support those transports.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Compare profiles without mistaking them for compatibility tests

To make a before-and-after comparison meaningful, profile the same server version under the same credentials or authorization scope, transport, and protocol version. Record those conditions alongside the output. The specification permits the tool set to vary with authorization, so a difference between inventories may reflect access context rather than a deployment change.

Useful comparison points include tool count and names, changed required inputs, changed schemas, and whether both inventories completed pagination. A renamed tool or altered required field is a signal to investigate, not by itself proof of a breaking change: the MCP protocol does not promise that comparing these declarations establishes compatibility.

When to use an SDK instead

This script is intentionally narrow: it launches a stdio server and collects declarations. MCP also defines Streamable HTTP and SSE transports, which require their own transport handling; this code does not speak them. The official MCP Python SDK documentation lists those transports, and its client guide shows a client API whose list_tools() result exposes tool metadata. Use an SDK client when you need broader transport support or a fuller integration rather than this lightweight inventory.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.