Use the ZajLibrary MCP
Learn · guide · Library MCP
Point an MCP client at https://library.zajapps.com/api/mcp, then run list_contents → search_library → get_document. Anonymous callers read public docs and may submit_feedback; a Bearer admin token or signed-in session unlocks private docs and admin feedback tools.
What you’ll learn
Section titled “What you’ll learn”- Production vs local URLs and port rules
- Cursor, Claude Code, and admin Bearer wiring
- All six tools — arguments, enums, and example payloads
- A search → read → verify → feedback workflow
- Operator index/embeddings maintenance and troubleshooting
Before you start
Section titled “Before you start”| Requirement | Notes |
|---|---|
| MCP-capable client | Cursor, Claude Code, or any Streamable HTTP MCP host |
| Time | ~10 min connect · ~2 min smoke-test |
| Local dev | app/.env.local with dev DATABASE_URL if testing feedback storage locally |
| Optional admin | MCP_ADMIN_TOKEN in app/.env.local + same value sent as Bearer for private docs / admin tools |
Endpoints
Section titled “Endpoints”| Environment | MCP URL |
|---|---|
| Production | https://library.zajapps.com/api/mcp |
| Local dev | http://localhost:4321/api/mcp |
Local dev is locked to port 4321 (app/dev-port.mjs). From app/:
cd appnpm run devWhen to use local vs production MCP
Section titled “When to use local vs production MCP”Prod default — use zajlibrary for real deploys and stable citations. Local sometimes — use zajlibrary-local for doc authoring, first-time setup-new QA, unreleased dev content, or testing submit_feedback on the dev queue.
Quick comparison:
| Situation | Server |
|---|---|
| Real CodeCanyon deploy; stable handoff | zajlibrary (prod) |
| First walkthrough, WIP docs, local feedback QA | zajlibrary-local (:4321, dev running) |
The MCP index is build-time — after doc edits: npm run build:index then restart dev. Details: Use local ZajLibrary MCP.
Connect your client
Section titled “Connect your client”This repo pins production + local MCP in .mcp.json — see Use local ZajLibrary MCP for when to enable each server.
Restart Cursor or reload MCP servers after editing.
Add the remote server (user scope survives across projects):
claude mcp add --transport http zajlibrary https://library.zajapps.com/api/mcp -s userLocal dev:
claude mcp add --transport http zajlibrary-local http://localhost:4321/api/mcp -s userVerify:
claude mcp listSend on every MCP HTTP request:
Authorization: Bearer <MCP_ADMIN_TOKEN>| Credential | What you get |
|---|---|
| (none) | Public docs + submit_feedback |
MCP_ADMIN_TOKEN (matches server env) | Private docs + feedback submit + list_feedback + review_feedback |
| Signed-in Better Auth session on same origin | Private docs + feedback submit; allowlisted admin email also gets list/review |
Local server token in app/.env.local:
MCP_ADMIN_TOKEN=your-long-random-tokenProduction / Preview: set the same variable in Vercel (Preview uses the development Neon branch — same as local).
If your MCP host supports custom headers on HTTP transports, attach the Bearer token there. The smoke script sends Bearer when MCP_ADMIN_TOKEN is set in the environment.
How it fits together
Section titled “How it fits together”graph LR Client["MCP client"] -->|"Streamable HTTP"| Endpoint["/api/mcp"] Endpoint --> Search["search_library"] Endpoint --> Get["get_document"] Endpoint --> List["list_contents"] Endpoint --> FB["submit_feedback"] Endpoint --> LFB["list_feedback"] Endpoint --> RFB["review_feedback"] Search --> Index[("docs.json + vectors.json")] Get --> Index List --> Index FB --> DB[("Neon feedback queue")] LFB --> DB RFB --> DBThe site is static except this route. Search reads a build-time index regenerated on every npm run dev / npm run build — not live filesystem reads at request time.
Tools reference
Section titled “Tools reference”Read tools (public*)
Section titled “Read tools (public*)”list_contents
Section titled “list_contents”No arguments. Returns JSON (and text) with:
| Field | Meaning |
|---|---|
totalDocs | Indexed public doc count (private excluded unless scoped) |
semanticEnabled | Whether vectors.json has embeddings |
commitSha / commitShaShort / indexBuiltAt | Index provenance — compare to prod deploy |
categories / subcategories / topics | Topic-first taxonomy counts |
shelves / collections / topTags | Shelf/register/tag rollups |
search_library
Section titled “search_library”| Argument | Default | Notes |
|---|---|---|
query | (required) | Natural language or keywords |
mode | hybrid | keyword · semantic · hybrid (RRF). Falls back to keyword if embeddings empty |
limit | 8 | Max 25 |
Returns ranked hits with title, URL, topic crumb (category/subcategory/topic), shelf/kind, snippet, and structuredContent.hits for programmatic clients. Provenance footer on every response.
get_document
Section titled “get_document”| Argument | Notes |
|---|---|
ref | Topic-first id, slug path, or full library.zajapps.com URL — e.g. tech-stack/laravel/codecanyon/build/playbooks/setup-new/ |
Returns full Markdown body plus metadata header. Private docs return not-found unless caller has read-private.
Write tool (public)
Section titled “Write tool (public)”submit_feedback
Section titled “submit_feedback”Files to the same DB queue as the site feedback form (source: mcp).
| Argument | Required | Values / notes |
|---|---|---|
type | yes | bug · suggestion · missing · update · question |
title | yes | Concise summary (min 3 chars; long titles normalized — detail goes in body) |
body | no | Full description, repro, expected/actual |
pageUrl | no | Relative path or https:// URL for the page |
docId | no | Topic-first document id |
category | no | docs · admin-ui · mcp · feedback-system · content-intake · deploy · auth · database · agent-rules · other |
subcategory | no | Finer area label |
topic | no | Product/content family |
section | no | Heading or UI section |
severity | no | low · med · high · critical |
accuracyState | no | unreviewed · confirmed · partially_correct · incorrect · insufficient_detail |
evidenceSummary | no | Command output, screenshot note, source citation |
externalId | no | External id e.g. FB-13 |
dedupeKey | no | Stable idempotency key for agents/importers |
metadata | no | JSON bag: expected, actual, reproSteps, environment, agent, model, etc. |
Example:
{ "type": "missing", "title": "Phase 3 env template path not documented", "body": "Step references Admin-Local/Templates/.env.example but playbook links elsewhere.", "pageUrl": "/tech-stack/laravel/codecanyon/build/playbooks/setup-new/03-local-dev/", "category": "docs", "severity": "med", "dedupeKey": "setup-new/03-local-dev/env-template"}Admin tools
Section titled “Admin tools”Require list-feedback scope (admin token or allowlisted session).
list_feedback
Section titled “list_feedback”| Argument | Notes |
|---|---|
status | new · triaged · planned · done · wontfix |
reviewDecision | pending · approved · rejected · needs_info · duplicate |
implementationState | not_started · in_progress · implemented · verified · wontfix · not_applicable |
category / severity | Same enums as submit |
search | Case-insensitive match in title, body, docId, pageUrl, evidence |
limit | Default 50, max 200 |
Submitter emails are redacted (hasEmail: true/false only).
review_feedback
Section titled “review_feedback”| Argument | Notes |
|---|---|
id | Row id (required) |
reviewDecision / implementationState | Workflow fields (see enums above) |
category / severity / accuracyState | Optional reclassification |
duplicateOf | Link duplicate to another id |
reviewNotes / implementationNotes / evidenceSummary | Triage notes |
Recommended agent workflow
Section titled “Recommended agent workflow”list_contents— readcommitShaShortandsemanticEnabled.search_library—mode: hybrid,limit5–8; read snippets before fetching bodies.get_document— one or two best hits; cite the returned URL in your answer.submit_feedback— wrong, missing, or stale content (always includepageUrlordocIdwhen known).
Verify before you declare (coverage + gates)
Section titled “Verify before you declare (coverage + gates)”When checking whether a playbook step, feedback item, or gate is done, missing, or pending:
| Bad | Good |
|---|---|
grep for one string → declare ❌ pending | get_document the Part document → find the ## / #### section → match substance |
search_library returns no hit → assume gap | Broaden query · try keyword mode · read parent phase page |
| Checklist box unchecked from memory | Run the verify command; if grep fails, read the prose block it references |
For Phase 1 infra gates specifically, 7 · Verify & gate pairs grep smoke checks with substance checks on CLAUDE.local.md and project_context.md — grep alone is never enough.
Verify with the smoke script
Section titled “Verify with the smoke script”From repo root (dev server running for local):
cd app && npm run test:mcpnode app/scripts/test-mcp-client.ts http://localhost:4321node app/scripts/test-mcp-client.ts https://library.zajapps.comExpected: connects, asserts all six tool names are registered, runs list_contents, searches, fetches one document, prints MCP smoke test passed.
The script exercises read tools by default. Set MCP_ADMIN_TOKEN in the environment to also call list_feedback. Test submit_feedback and review_feedback through your MCP client or the admin dashboard at /admin.
Index and embeddings (operators)
Section titled “Index and embeddings (operators)”| Artifact | When it updates |
|---|---|
src/mcp/generated/docs.json | Every predev / prebuild (gitignored locally) |
src/mcp/generated/vectors.json | npm run embed with MCP_EMBED=1 + AI_GATEWAY_API_KEY — committed for Vercel |
cd appnpm run embed # needs AI_GATEWAY_API_KEY in .env.localgit add src/mcp/generated/vectors.jsonRe-embed after large content changes, commit vectors.json, redeploy. Without vectors, semantic and hybrid degrade to keyword search automatically.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause | Fix |
|---|---|---|
Connection refused on :4321 | Dev server not running or wrong port | cd app && npm run dev — port 4321 only |
No document found for "…" | Bad ref or private doc without auth | Copy url from search_library hit; add Bearer token for private shelf |
No matches for "…" | Query too narrow or index stale | Broaden query; try mode: keyword; npm run build:index then restart dev |
| New page missing from MCP | Index not refreshed after edit | cd app && npm run build:index then restart dev — index is imported at server start |
| Local MCP connection refused | Dev not running | cd app && npm run dev on port 4321 only; disable zajlibrary-local when dev is off |
| Semantic seems weak | Empty or stale vectors.json | Run npm run embed, commit, redeploy |
| Admin tools return “Admin scope required” | Missing or wrong MCP_ADMIN_TOKEN | Match client Bearer to server env; restart dev after .env.local change |
| Feedback insert fails locally | DB env points at wrong Neon branch | Use development branch DATABASE_URL in app/.env.local |
Key source files
Section titled “Key source files”Directoryapp/
Directorysrc/
- pages/api/[transport].ts
- mcp/search.ts
- mcp/embed.ts
- lib/feedback.ts
- tenant.config.mjs
Directoryscripts/
- build-mcp-index.ts
- test-mcp-client.ts
Checklist
Section titled “Checklist”- MCP URL reachable (prod or
:4321local) - Client lists all six tools
- Smoke script passes
- Agent cites library URLs from tool results, not memory
- Gaps filed with
submit_feedback(pageUrl+dedupeKeywhen possible)