An entirely empty MCP server that passes protocol conformance.
This is a rhetorical artifact: a fully-valid Model Context Protocol server that advertises zero tools, zero resources, and zero prompts. It exists to demonstrate that "we have an MCP" is a valueless claim. MCP is a protocol, not a product. A server can be 100% conformant and do absolutely nothing.
Live instance: https://compliant-empty-mcp-production.up.railway.app/mcp
npx -y github:shinytoyrobots/compliant-empty-mcpOr clone and build:
git clone https://github.com/shinytoyrobots/compliant-empty-mcp
cd compliant-empty-mcp
npm install
npm run build
npm startThe server speaks JSON-RPC 2.0 over stdio. It responds to initialize, tools/list, resources/list, and prompts/list — the last three with empty arrays. Any other method returns JSON-RPC error -32601 ("Method not found").
npm run start:httpThis starts a Streamable HTTP transport on port 3000 (or $PORT). The MCP endpoint is POST /mcp.
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0.1"}}}'curl -X POST https://compliant-empty-mcp-production.up.railway.app/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'Response: {"result":{"tools":[]},"jsonrpc":"2.0","id":1}
npx @modelcontextprotocol/inspectorIn the Inspector UI, set Transport Type to "Streamable HTTP", Connection Type to "Direct", and URL to:
https://compliant-empty-mcp-production.up.railway.app/mcp
Add to ~/.claude.json (Claude Code) or ~/Library/Application Support/Claude/claude_desktop_config.json (Claude Desktop):
{
"mcpServers": {
"compliant-empty-mcp": {
"type": "url",
"url": "https://compliant-empty-mcp-production.up.railway.app/mcp"
}
}
}The server will appear as a connected MCP with zero tools. That's the point.
npm run build
npm run conformanceMCP conformance probe — compliant-empty-mcp
[PASS] AC-2: initialize returns valid InitializeResult with serverInfo.name
[PASS] AC-3: tools/list returns { tools: [] }
[PASS] AC-4: resources/list returns { resources: [] }
[PASS] AC-5: prompts/list returns { prompts: [] }
[PASS] AC-6: zero tools, zero resources, zero prompts at all times
[PASS] AC-7: unsupported method returns error -32601
[PASS] AC-9: stdio transport is the default and functional
[PASS] AC-1: server terminates cleanly after stdin close
8/8 checks passed.
The HTTP server runs on any platform that hosts Node.js. A multi-stage Dockerfile is included.
Railway: import from GitHub. Set the custom start command to npm run start:http (under Service → Settings → Deploy).
Render (free tier): connect this repo, set build command npm install && npm run build, start command npm run start:http.
Fly.io: fly launch auto-detects the Dockerfile.
The full implementation fits in one file:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListToolsRequestSchema,
ListResourcesRequestSchema,
ListPromptsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{ name: "compliant-empty-mcp", version: "0.1.0" },
{ capabilities: { tools: {}, resources: {}, prompts: {} } },
);
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [] }));
server.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: [] }));
server.setRequestHandler(ListPromptsRequestSchema, async () => ({ prompts: [] }));
await server.connect(new StdioServerTransport());That is the entire product. It is a valid MCP server. It does nothing.
Next time a vendor tells you they "have an MCP," ask what's in it.
MIT