Quickstart
- Open the probe and paste the URL of a server that speaks MCP over Streamable HTTP, for example
https://mcp.deepwiki.com/mcp. Thehttps://prefix is added if you leave it out. - Press Probe. Moonpeak detects the protocol era (2026-07-28 or an older handshake revision), lists everything the server exposes and shows two scores, protocol and security, with the reason behind each point lost.
- Open a tool to get a form generated from its input schema. Press Run to call it. If the tool links an MCP App, its UI renders under the result.
- Export the report as Markdown or JSON, or copy its share link.
Deep links
Any probe can be opened directly. The page starts probing as soon as it loads:
https://moonpeak.dev/?url=https%3A%2F%2Fmcp.deepwiki.com%2Fmcp
Servers behind a token
Choose Add a bearer token under the URL field. The token is sent as Authorization: Bearer … to the server you named, on each request, and is never stored. Full OAuth sign-in flows are not supported yet.
Connect the Moonpeak server
Moonpeak's own server is public, stateless and read-only. Its endpoint is:
https://moonpeak.dev/api/mcp
- Open Claude's settings and go to Connectors.
- Choose Add custom connector, name it Moonpeak and paste the endpoint above. No authentication is needed.
- In a chat, enable the connector and ask: "Look up the token 0x39dbed3a2bd333467115de45665cc57f813c4571 with Moonpeak." Claude calls
token_lookupand shows the token card.
- In ChatGPT's settings, open Apps & Connectors and turn on developer mode in the advanced settings.
- Create a connector with the endpoint above and no authentication.
- Start a chat with the connector selected and ask for the current mainnet block. ChatGPT calls
chain_status.
Menu names change between releases; look for the connector or developer mode settings if these labels differ.
Any client that supports remote MCP servers over Streamable HTTP can use the endpoint directly. A typical configuration entry:
{
"mcpServers": {
"moonpeak": {
"type": "http",
"url": "https://moonpeak.dev/api/mcp"
}
}
}Tool reference
All three tools are read-only and declare readOnlyHint: true. Each returns a short text summary and the same data as structuredContent, described by an output schema.
chain_status
Latest block, block age, gas price and chain ID of mainnet Chain 4663, read live from a public node. Takes no arguments.
{
"chainId": 4663,
"block": 108349031,
"blockTime": "2026-11-07T10:46:41.000Z",
"blockAgeSeconds": 1,
"gasPriceGwei": "0.020054"
}token_lookup
Reads an ERC-20 contract: name, symbol, decimals and total supply, plus one holder balance if asked. Links the ui://moonpeak/token-card.html MCP App.
| Argument | Type | Description |
|---|---|---|
| address required | string | Token contract, 0x followed by 40 hex characters. |
| holder | string | Wallet whose balance to read, same format. |
{
"address": "0x39dbed3a2bd333467115de45665cc57f813c4571",
"name": "Pons",
"symbol": "PONS",
"decimals": 18,
"totalSupply": "1,000,000,000",
"holderBalance": "0",
"block": 108349031
}Errors come back as a normal result with isError: true, for example "No contract at 0x…0001 on Chain 4663." or "… is a contract but does not answer as an ERC-20 token."
moon_phase
Approximate moon phase and illumination for a UTC date. Defaults to today. Invalid dates such as 2026-02-30 are rejected.
| Argument | Type | Description |
|---|---|---|
| date | string | UTC date, YYYY-MM-DD. |
{
"date": "2026-11-24",
"phase": "Full moon",
"illumination": 1,
"ageDays": 14.6,
"nextFullMoon": "2026-12-24"
}Raw protocol
The Moonpeak server speaks both protocol eras. In MCP 2026-07-28 there is no handshake: every request carries its version and client details in _meta, and the method in an Mcp-Method header that must match the body.
1. Discover the server (2026-07-28)
curl -s https://moonpeak.dev/api/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: server/discover' \
-d '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"curl","version":"1"},"io.modelcontextprotocol/clientCapabilities":{}}}}'2. Call a tool (2026-07-28)
tools/call, resources/read and prompts/get also need an Mcp-Name header.
curl -s https://moonpeak.dev/api/mcp \
-H 'content-type: application/json' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: tools/call' \
-H 'Mcp-Name: moon_phase' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"moon_phase","arguments":{"date":"2026-11-24"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"curl","version":"1"},"io.modelcontextprotocol/clientCapabilities":{}}}}'Every result carries resultType; discovery, lists and reads add ttlMs and cacheScope. A header that contradicts the body gets 400 with error -32020, an unknown version gets 400 with -32022 and the supported list, an unknown method gets 404 with -32601.
3. Legacy clients
Clients that start with initialize (2025-11-25 and earlier) still work, without sessions:
curl -s https://moonpeak.dev/api/mcp \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'Score API and badges
GET /api/score runs the full probe from Moonpeak's servers, with the same engine as the site, and returns the report as JSON.
| Parameter | Description |
|---|---|
| url required | The server's MCP endpoint, URL-encoded. https:// only. |
| min | Lowest acceptable protocol score, 0 to 100. |
| securityMin | Lowest acceptable security score, 0 to 100. |
| pin | Expected tool fingerprint: the first 8 to 64 hex characters shown in a report. Any change fails. |
It answers 200 when every threshold passes and 422 when one fails, with the reasons in failures. Unreachable servers get 502 with an error. An Authorization header is forwarded to the probed server only, and such responses are never cached.
curl -sS --fail-with-body \ "https://moonpeak.dev/api/score?url=https%3A%2F%2Fmoonpeak.dev%2Fapi%2Fmcp&min=85&securityMin=85"
{
"ok": true,
"pass": true,
"failures": [],
"era": "modern",
"protocolVersion": "2026-07-28",
"score": 100,
"securityScore": 100,
"fingerprint": "755ffb801c321249e475f6d4ebb9b2f0aec23ff066ecb9ea6f97b45f1d8f313b",
"checks": [ … ],
"security": [ … ],
"report": "https://moonpeak.dev/?url=…#probe"
}Badges
GET /api/badge?url=… returns an SVG badge with the protocol score; add &type=security for the security score. Badges are cached for an hour.
[](https://moonpeak.dev/?url=https%3A%2F%2Fmcp.example.com%2Fmcp)
MCP Apps host
When a tool's _meta.ui.resourceUri (or openai/outputTemplate) points to a resource, Moonpeak reads it with resources/read, checks that it is HTML and renders it in an iframe sandboxed with allow-scripts allow-forms only. The preview host supports:
| Message | Direction | What Moonpeak does |
|---|---|---|
| ui/initialize | app → host | Answers with host info, capabilities and a context of dark theme, inline display, locale and web platform. |
| ui/notifications/initialized | app → host | Sends the tool input, then the tool result. |
| ui/notifications/tool-input | host → app | The arguments from the form. |
| ui/notifications/tool-result | host → app | The full CallToolResult. |
| tools/call | app → host | Proxied to the server through the relay, logged in the handshake log. |
| resources/read | app → host | Proxied to the server. |
| ui/notifications/size-changed | app → host | Resizes the preview, between 60 and 1200 px. |
| ui/open-link | app → host | Opens http(s) links in a new tab. |
| ui/message | app → host | Shows the message the app asked to send. |
Apps that never send initialized still receive their data 1.5 s after loading. Apps built for the Apps SDK get a window.openai object with toolInput, toolOutput, callTool, openExternal and sendFollowUpMessage.
Relay API
POST /api/relay forwards one JSON-RPC message to a public MCP server and returns what came back. It is what the probe uses, and you can call it too.
| Request field | Description |
|---|---|
| url required | Target server, https:// only. |
| message required | One JSON-RPC 2.0 object, up to 200 KB. |
| headers | MCP headers to forward: MCP-Protocol-Version, Mcp-Method, Mcp-Name, Mcp-Param-* and, for legacy servers, Mcp-Session-Id. Anything else is dropped. |
| auth | Bearer token, sent as Authorization. |
| Response field | Description |
|---|---|
| ok | true when the server answered 2xx. |
| status · ms | Server HTTP status and round-trip time through the relay. |
| transport | json, sse, none or other. |
| messages | Every JSON-RPC message received. For SSE, reading stops once the answer to your id arrives. |
| sessionId · wwwAuthenticate · location | Matching response headers, when present. |
| error | Why the request could not complete. |
curl -s https://moonpeak.dev/api/relay \
-H 'content-type: application/json' \
-d '{"url":"https://mcp.deepwiki.com/mcp","message":{"jsonrpc":"2.0","id":1,"method":"ping"}}'Limits and errors
| You see | Meaning | What to do |
|---|---|---|
| Requires authorization (401) | The server wants credentials. | Add a bearer token. OAuth-only servers are not supported yet. |
| Does not accept POST (405) | The URL is not a Streamable HTTP endpoint. | Use the server's MCP route, which often ends in /mcp. |
| Redirects to … | The server answered 3xx. | Probe the URL it points to. |
| Local hosts / private addresses | The target resolves to a non-public address. | Expose it through a public HTTPS tunnel. |
| Did not answer within 20 s | Timeout on the server side. | Check the server's cold start and logs. |
| Response larger than 3 MB | One answer exceeded the cap. | Paginate long lists with nextCursor. |
| Did not answer with JSON-RPC | The body was HTML or plain text. | Check that the URL is the MCP endpoint, not a web page. |