Skip to main content
Glama
shinytoyrobots

compliant-empty-mcp

README.md
# compliant-empty-mcp

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

## Run it (stdio)

```bash
npx -y github:shinytoyrobots/compliant-empty-mcp
```

Or clone and build:

```bash
git clone https://github.com/shinytoyrobots/compliant-empty-mcp
cd compliant-empty-mcp
npm install
npm run build
npm start
```

The 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").

## Run it (HTTP)

```bash
npm run start:http
```

This starts a Streamable HTTP transport on port 3000 (or `$PORT`). The MCP endpoint is `POST /mcp`.

```bash
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"}}}'
```

## Test it

### Against the live instance

```bash
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}`

### MCP Inspector

```bash
npx @modelcontextprotocol/inspector
```

In 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
```

### Connect as an MCP client

Add to `~/.claude.json` (Claude Code) or `~/Library/Application Support/Claude/claude_desktop_config.json` (Claude Desktop):

```json
{
  "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.

### Conformance probe (local)

```bash
npm run build
npm run conformance
```

```
MCP 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.
```

## Deploy your own

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.

## How empty is it?

The full implementation fits in one file:

```ts
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.

## The point

Next time a vendor tells you they "have an MCP," ask what's in it.

## License

MIT

Maintenance

ActivityInactive
ResponsivenessNo issues