Serve a reachable MCP transport endpoint
What we checked
We tried to connect to the transport your listing declares and complete a live MCP handshake against it. The outcome decides the signal:
Why it matters
A remote MCP server is only useful if a client can actually open a connection and speak the protocol to it. If we can’t reach the endpoint, get bounced to a different host, or get something back that isn’t MCP, then neither can the agents your users run. Verifying a live handshake is the difference between “this server claims to exist” and “this server works.” It’s also the gate for every other endpoint check: if we can’t complete the handshake, there’s nothing else to assess.
stdio is a different model entirely. It’s how a local or packaged server
talks to a client over standard input/output on the same machine; there’s no
network endpoint to dial, so it can’t be a remote server. If your server is
meant to be hosted, it needs an HTTP transport.
How to fix it
Serve a Streamable HTTP MCP endpoint at the URL you declare. It must:
- stay on the same host: a same-origin redirect (a trailing slash, or an
http://→https://upgrade) is followed and fine, but a redirect to a different host or a downgrade to plaintext fails; - respond to the MCP handshake (don’t return a generic web page or an HTTP error);
- present a valid TLS certificate (see TLS).
The official SDKs provide the Streamable HTTP transport. The snippets below are deliberately minimal and conceptual; check your SDK version’s docs for the exact handler wiring, as the transport API has evolved across releases.
// @modelcontextprotocol/sdk - Streamable HTTP transport
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
const server = new McpServer({ name: "my-server", version: "1.0.0" });
// register your tools/resources here, e.g. server.registerTool(...)
const app = express();
app.use(express.json());
// Serve MCP at the SAME path you declare in your listing.
app.post("/mcp", async (req, res) => {
// A stateless transport is the simplest correct starting point - and as of
// MCP 2026-07-28 it is the only shape: that revision removed protocol-level
// sessions and the Mcp-Session-Id header entirely.
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
res.on("close", () => transport.close());
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
});
app.listen(3000); # Official 'mcp' SDK - Streamable HTTP transport
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-server")
@mcp.tool()
def ping() -> str:
return "pong"
if __name__ == "__main__":
# Exposes a Streamable HTTP app you serve behind your TLS reverse proxy.
# The default mount path is /mcp - declare that same path in your listing.
mcp.run(transport="streamable-http") How we re-check
We re-probe the declared endpoint on our next crawl of your listing. Once we can reach it (following at most one same-origin redirect) and complete an MCP handshake over valid TLS, the check records a verified transport on the following score refresh.
Give this to your AI
Paste this into Claude Code (or any coding agent) from inside your server's repository. It states the failing signal, the outcome we re-check for, and the format the fix has to take.
Context: this repository/infra runs a remote MCP server that should answer a live MCP handshake over Streamable HTTP at an HTTPS endpoint. VerifyMCP's transport check failed (the URL was unreachable, redirected away, answered with something other than MCP, returned an HTTP error, declared no remote transport, or declared only stdio), which means we could not reach the declared URL and complete the handshake there. Goal: the declared URL answers a live MCP `initialize` handshake directly (following at most one same-host redirect) over valid TLS, so the next crawl records the transport as verified. Do this: 1. Confirm the URL declared in your listing is the exact path your server serves Streamable HTTP on (e.g. `/mcp`), not a redirect target or a different host. 2. If the endpoint returns a generic web page, a 4xx/5xx, or redirects to a different host or downgrades to plaintext, fix the routing so the handshake path answers directly on the declared host. 3. If the server currently only exposes `stdio`, that is a local transport with no network endpoint; adding a real Streamable HTTP transport is a genuine architecture change, so confirm with the human before standing up a new public endpoint. 4. Re-serve TLS correctly on that endpoint (see the TLS guide) so the handshake completes over a trusted connection. Rules: - Never point the declared URL at a health-check or landing page that merely returns HTTP 200; the handshake itself has to complete. - Do not silently drop an existing transport that current clients rely on (e.g. legacy HTTP+SSE) while adding Streamable HTTP; keep it available until you've confirmed no active client still needs it, and ask the human before removing it. Report back: the URL you verified, and the raw `initialize` response (or the `curl`/handshake transcript) proving it answers directly. Reference: https://verifymcp.io/docs/remote/transport