Verify the OpenSEO MCP server end-to-end on a local dev server — protocol-level correctness against real DataForSEO, then a headless-agent consumer probe that tests tool ergonomics (descriptions, schemas, output size, errors, async flows) without the maintainer manually driving an MCP client. Use after adding or changing MCP tools, or when asked to check that the MCP "works" or "is ergonomic".
Two layers, in order. The protocol layer proves the server and provider behave; the consumer layer proves an agent that has never seen the code can use the tools well. They catch different bugs — protocol testing found DataForSEO quirks (zoom-dependent empty SERPs), the consumer probe found ergonomics failures (9KB provider rows overflowing client token budgets, fractional inputs rejected upstream with raw provider errors). Do both.
.env.local needs AUTH_MODE=local_noauth and DATAFORSEO_API_KEY (base64 of login:password). Never print the key.pnpm dev:agents in the background. The server URL is branch-prefixed: http://<branch-suffix>.open-seo.localhost:1355 (the exact URL is printed on boot; logs tee to .logs/dev-server.log).local_noauth, /mcp needs no token. Vite hot-reloads server code, so fix → re-call without restarting.tools/list) or reconnect the MCP client before calling it again. Clients can cache validators from the previous tool list and reject valid results after the provider call has already incurred a charge.Raw JSON-RPC against /mcp — the layer for asserting exact shapes and driving edge cases (resume taskIds, empty results, invalid inputs):
curl -sS http://<url>/mcp \
-H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# tools/call: {"method":"tools/call","params":{"name":"<tool>","arguments":{...}}}list_projects, then create_project if empty — most tools need a projectId.taskId.local_noauth — billing needs unit tests, not this). Keep depths 10–20.Spawn a headless Claude subprocess connected as a real MCP client. Write a config:
{
"mcpServers": {
"openseo-local": { "type": "http", "url": "http://<url>/mcp" }
}
}Then run a NATURAL task — never name the tools; whether the model finds them from descriptions alone is the test:
claude -p "<natural task a customer would ask>. Keep spend minimal: depths 10-20, one 3x3 grid max, ~10 paid calls.
Deliver two sections: 1. FINDINGS — the task result. 2. MCP FEEDBACK — critique the MCP as a first-time consumer:
were descriptions enough to pick tools without trial and error? confusing schemas, surprising output shapes or sizes,
unclear errors, credit-cost surprises? Did async/taskId flows behave as described? List anything that made you hesitate or retry." \
--mcp-config mcp-local.json --strict-mcp-config \
--allowedTools "mcp__openseo-local,mcp__openseo-local__*" \
--model sonnet --max-turns 30Use --model sonnet as the typical-client proxy — if sonnet navigates it cold, weaker clients likely can too. Read FINDINGS for correctness (did it get real, sensible data?) and MCP FEEDBACK for the rubric below.
.describe() (units, whole-number requirements, defaults, what's ignored when). If the probe guessed-and-retried an input, encode the rule server-side (coerce/round) or document it — prefer coercing.popular_times/attribute trees/photo URLs must be trimmed to the fields the tool's job needs; point to the single-entity tool for the full shape.Fix findings → hot-reload picks them up → re-verify just the changed behavior via curl (cheap) → rerun the full consumer probe once per iteration round (it re-tests selection and flow, not just the fix). When done: stop the dev server background task, run the repo's tests/ci:check, and fold genuine provider quirks into code comments or tests so the next agent doesn't rediscover them.
7b9ee0e
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.