AI & MCP
Testing an MCP server locally: six calls that settle the doubt
Test an MCP server with six calls: handshake, list, call, notification, unknown method and bad token. If they match the spec, a client can use it.
Key points
- Read the handshake on three fields: protocolVersion, capabilities and serverInfo.name.
- A notification, an unknown method and a bad token answer differently, so test all three.
- The EneUI endpoint answers 200 even when the body holds a JSON-RPC error.
You test an MCP server with six calls: initialize, tools/list, tools/call, a notification, an unknown method and a bad token. If the answers match the specification, the server is ready for a client.
Start with the handshake
curl -s https://ui.eneawork.it/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'
Check three fields: protocolVersion 2025-06-18, the capabilities object and serverInfo.name. If the server declares tools only, expect no prompts and no sampling: the empty list is consistent, not broken.
Then the list and one call
curl -s https://ui.eneawork.it/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
curl -s https://ui.eneawork.it/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"search_components","arguments":{"query":"data table","limit":2}}}'
The list must hold 9 tools with their input schema; the call returns text content with a URL and an install command. A query with no hits produces a message with isError: true, not a JSON-RPC error.
The answers nobody tests
| Probe | Expected | On the EneUI server |
|---|---|---|
| Notification without id | 202, empty body | 202, empty body |
| Unknown method | -32601 | -32601 |
| Invalid token | 401 and WWW-Authenticate | 401 with resource_metadata |
| Malformed JSON | JSON-RPC error | 400 with an HTML body |
The last row is the common defect: the Express parser answers before the dispatcher, so the error arrives as HTML and a client that reads JSON only treats it as a network fault.
Test the rate limit by counting
Anonymous traffic goes through a per-IP limit, RATE_MCP_PER_MIN, 120 per minute when the variable is unset; authenticated traffic has a per-plan quota. Past the limit you get 429 with Retry-After: 60 and code -32002.
for i in $(seq 1 3); do
curl -s -o /dev/null -w "%{http_code}\n" https://ui.eneawork.it/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"ping"}'
done
A local run without writing a client
Start the server with npm start, export RATE_MCP_PER_MIN=5 and repeat the loop: the 429 must arrive on the sixth call. If it does not, the counter is per account or not mounted on the right path.
The EneUI catalogue
The probes use real records: modals, heroes and the Aceternity animated modal, MIT licence and 290 stars declared upstream, read on 1 November 2026.
The limitation
The server answers 200 even when the body holds a JSON-RPC error: anyone checking the HTTP status alone counts a failed call as a success. The test must read error and isError, not the status code.
Where to continue
The OAuth flow and the 401 are in OAuth for MCP servers; the methods are in how to build an MCP server; the tool schema is in designing an MCP tool. Resources against tools is in resources and tools in MCP.
Frequently asked questions
Is curl enough to test an MCP server?
For most of it, yes. Six calls cover the handshake, the list, a call, a notification, a method error and authentication, with no client installed.
Why does a notification return nothing?
Because a notification has no id and the protocol forbids answering it. The server closes with 202 and an empty body: a body here would be a bug.
How do I test the rate limit locally?
Set RATE_MCP_PER_MIN to a low value such as 5, restart the server and repeat the same call: the 429 with Retry-After must arrive on the sixth.
What does -32601 mean?
Method not found: the server received a method it does not implement. On EneUI that happens with prompts/get and sampling/createMessage.
Does a 200 mean the call succeeded?
No. A JSON-RPC error travels inside a 200 response; you must read the error field or isError in the tool result.