dist/codex/nlweb-protocol/skills/nlweb-mcp-server/SKILL.md
Expose NLWeb as an MCP (Model Context Protocol) server — JSON-RPC 2.0 endpoint at /mcp, the `ask` / `list_sites` / `who` tools, MCP protocol version 2024-11-05, and integration with ChatGPT, Claude, Gemini, and other agent clients. Use when wiring NLWeb to an AI agent via MCP or building an MCP client that consumes an NLWeb site.
npx skillsauth add orcaqubits/agentic-commerce-claude-plugins nlweb-mcp-serverInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Fetch live spec:
/mcp route alongside /ask).AskAgent/python/webserver/mcp_wrapper.py in the live repo for the exact JSON-RPC method list and tool schemas — these change between releases.NLWeb is already an MCP server out of the box — same code, second binding. The /mcp route in webserver/routes/mcp.py accepts JSON-RPC 2.0 requests and re-uses the same NLWebHandler pipeline as /ask. No separate process, no extra config.
| Route | Method | Purpose |
|-------|--------|---------|
| /mcp | POST, GET | Main JSON-RPC endpoint |
| /mcp/{path} | POST, GET | Path-scoped variant |
| /mcp/health | GET | Liveness check |
NLWeb identifies itself with MCP protocol version 2024-11-05 and server name nlweb-mcp-server. Pin to this protocol version in clients until you verify a newer one is supported.
| Method | Direction | Notes |
|--------|-----------|-------|
| initialize | client → server | Handshake; returns server capabilities |
| initialized | client → server | Notification; no response |
| tools/list | client → server | Returns the tool definitions |
| tools/call | client → server | Invoke a tool |
| notifications/cancelled | client → server | Cancel an in-flight tool call |
(prompts/list and prompts/get appear in some docs but are not in mcp_wrapper.py at the time of writing — verify.)
Three tools are advertised via tools/list:
ask — the primary NL query{
"name": "ask",
"description": "Ask a natural-language question grounded in the site's Schema.org content.",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" },
"site": { "type": "array", "items": { "type": "string" } },
"generate_mode": { "type": "string", "enum": ["list", "summarize", "generate"] }
},
"required": ["query"]
}
}
Note that the MCP ask tool takes site as an array (where the REST /ask takes a single string). Map accordingly in clients.
list_sites — enumeration{ "name": "list_sites", "description": "List all sites the agent can query.", "inputSchema": { "type": "object", "properties": {} } }
who — federated discovery (conditional)Only present when who_endpoint_enabled: true in config_nlweb.yaml. Takes {query}, returns the best NLWeb site(s) for that query — used for federated search across sites.
JSON-RPC 2.0 itself is request/response — no streaming. NLWeb's /mcp is NOT SSE by default. SSE only activates when the inner ask tool is called with streaming: true in its args. Most MCP clients don't expect that, so for cross-agent compatibility leave streaming off in MCP and turn it on only for clients you control.
JSON-RPC 2.0 errors:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "Internal error",
"data": { "errors": [...] }
}
}
Common codes: -32700 parse error, -32600 invalid request, -32601 method not found, -32602 invalid params, -32603 internal error.
NLWeb actually ships two MCP integrations:
| Wrapper | Path | Purpose |
|---------|------|---------|
| webserver/mcp_wrapper.py | /mcp on the aiohttp server (port 8000) | The canonical Python MCP server |
| openai-apps-sdk-integration/nlweb_server_node/ | Separate Node.js/TypeScript process | Adds a React widget for ChatGPT Apps SDK — registers a nlweb-list tool and serves ui://widget/nlweb-list.html |
There's also an A2A wrapper (webserver/a2a_wrapper.py, route a2a.py) for Google's Agent-to-Agent protocol, and an AppSDK adapter on port 8100 (appsdk_adapter_server.py) that translates NLWeb's message list to OpenAI Apps SDK envelopes for existing clients.
You don't typically write an MCP server for NLWeb — it's already there. What you might do:
tools/list matches your needs by hitting it from your agent client.mcp_wrapper.py::handle_tools_list carefully (you'll re-merge on upgrade).webserver/middleware/) — MCP has no built-in auth; bring your own (bearer token, OAuth proxy, etc.).who for offline / single-site deployments by setting who_endpoint_enabled: false.# Sketch — verify against latest MCP client SDK
import httpx, json
async def mcp_call(url, method, params=None):
payload = {"jsonrpc": "2.0", "id": 1, "method": method, "params": params or {}}
async with httpx.AsyncClient() as c:
r = await c.post(url, json=payload, timeout=60)
return r.json()
# Handshake
await mcp_call("http://localhost:8000/mcp", "initialize", {"protocolVersion": "2024-11-05"})
# Discover tools
tools = await mcp_call("http://localhost:8000/mcp", "tools/list")
# Ask
result = await mcp_call("http://localhost:8000/mcp", "tools/call", {
"name": "ask",
"arguments": {"query": "what's new this week?", "site": ["news"], "generate_mode": "summarize"}
})
Add an entry in ~/.claude.json mcpServers:
{
"mcpServers": {
"my-nlweb-site": {
"url": "http://localhost:8000/mcp",
"transport": "http"
}
}
}
(Verify the exact Claude Code MCP config schema in current docs — it changes.)
ChatGPT Apps SDK requires the separate Node.js MCP server in openai-apps-sdk-integration/nlweb_server_node/. It bundles a React widget that renders the nlweb-list tool's results. Follow docs/nlweb-chatgpt-integration.md for the exact registration steps — ChatGPT's MCP app store rules change.
Gemini's tool-calling supports MCP via the Vertex AI Agent SDK. Point it at http://your-nlweb-host:8000/mcp and call tools/list → tools/call.
tools/list on every upgrade.site arg differs between /ask (string) and /mcp::ask (array). Don't confuse them./mcp is not SSE by default. Don't wire your client expecting EventSource./mcp.Always re-fetch mcp_wrapper.py and the chatgpt-integration doc before generating final code.
development
Build with Spree's headless Next.js storefront — the official `spree/storefront` repo (Next.js 16 App Router with Server Actions and Turbopack, React 19 Server Components, Tailwind CSS 4, TypeScript 5, `@spree/sdk`, Sentry), server-only auth (httpOnly JWT cookies + publishable key), MeiliSearch faceted catalog, one-page checkout with Apple/Google Pay/Klarna/Affirm/SEPA, multi-region market routing, GA4 + JSON-LD SEO, and Vercel/Docker deployment. Use when forking or customizing the storefront, or evaluating headless adoption.
tools
Build Spree extensions as Rails engines — gem scaffolding, `bin/rails g spree:extension`, mounting routes/migrations/assets, the modern `prepend` decorator pattern (`*_decorator.rb` with `self.prepended(base)`), generators (`spree:model_decorator`, `spree:controller_decorator`), the four customization surfaces in preference order (Events > Webhooks > Dependencies > Decorators), Spree::Dependencies for swapping service objects, gem release/versioning, and the deprecated Deface engine. Use when building a reusable Spree extension or adding non-trivial customization to an app.
development
Build with Spree's event bus and Webhooks 2.0 — `Spree::Events` publication, `Spree::Subscriber` DSL with `subscribes_to` and `on`, wildcard matching, lifecycle events (`{model}.created/.updated/.deleted` via `publishes_lifecycle_events`), the canonical event catalog (order.*, payment.*, shipment.*, product.*), Webhooks 2.0 endpoints, HMAC-SHA256 signing (`X-Spree-Webhook-Signature`), exponential-backoff retries, and Sidekiq job orchestration. Use when wiring event-driven business logic, building webhook consumers, or replacing ActiveSupport callback chains.
tools
Cross-cutting Spree development patterns — the customization preference hierarchy (Events > Webhooks > Dependencies > Decorators), `Spree::Dependencies` service-object swapping, the `_decorator.rb` + `prepend` + `self.prepended` idiom, idempotent subscribers and webhook receivers, multi-store scoping discipline, prefixed IDs, calculator polymorphism (shipping/promotion/tax share the base), service-object composition with `dry-monads` or simple results, why to avoid `class_eval` reopening and Deface, and Spree-on-Rails idioms (Hotwire/Turbo Stimulus, ActiveStorage, Action Cable, Sidekiq). Use when designing the architecture of a Spree extension or solving cross-cutting concerns.