Skip to main content

Python SDK and MCP server for self-hosted PageIndex RAG service

Project description

pageserve

Python SDK and MCP server for PageIndex self-hosted RAG service.

PageIndex is a reasoning-based RAG engine that navigates document structure rather than doing vector similarity search — it reads the table of contents, picks the right sections, and synthesizes answers with page-level citations.

Installation

pip install pageserve              # SDK only (sync + async)
pip install "pageserve[mcp]"       # + MCP server for agent frameworks
pip install "pageserve[cli]"       # + CLI commands
pip install "pageserve[all]"       # everything

Quick start

from pageserve import PageServeClient

client = PageServeClient(
    base_url   = "https://pageindex.company.com",
    public_key = "<your-public-key>",
    secret_key = "<your-secret-key>",
)

# List indexed documents
docs = client.list_documents()

# Ask a question
result = client.query(docs[0].doc_id, "What are the probation terms?")
print(result.answer)
print(result.citation)   # "Employment Contract p.5, 6"
print(result.page_refs)  # [5, 6]

# Upload and wait for indexing to complete
upload = client.upload("./contract.pdf", wait=True)

# Read specific pages (no LLM, instant)
pages = client.get_pages(docs[0].doc_id, "22-24")

Async usage

import asyncio
from pageserve import AsyncPageServeClient

async def main():
    async with AsyncPageServeClient(
        base_url   = "https://pageindex.company.com",
        public_key = "<your-public-key>",
        secret_key = "<your-secret-key>",
    ) as client:
        docs = await client.list_documents()

        # Query multiple documents concurrently
        results = await client.query_many([
            (docs[0].doc_id, "What are the probation terms?"),
            (docs[1].doc_id, "What does the law say about probation?"),
        ])
        for r in results:
            print(r.answer)

asyncio.run(main())

Streaming

for event in client.query_stream(doc_id, "What are the key clauses?"):
    if event.type == "token":
        print(event.content, end="", flush=True)
    elif event.type == "sources":
        for src in event.sources:
            print(f"\nSource: {src.citation}")
    elif event.type == "done":
        break

MCP server (Claude Desktop / Cursor)

Run the MCP server so Claude or any MCP-compatible agent can query your documents:

{
  "mcpServers": {
    "pageindex": {
      "command": "pageserve",
      "args": ["mcp"],
      "env": {
        "PAGESERVE_URL":        "https://pageindex.company.com",
        "PAGESERVE_PUBLIC_KEY": "<your-public-key>",
        "PAGESERVE_SECRET_KEY": "<your-secret-key>"
      }
    }
  }
}

The MCP server exposes five tools:

  • list_documents — see what documents are available
  • query_document — ask a question against one document
  • query_multiple_documents — cross-reference multiple documents
  • get_page_content — read raw page text (no LLM, instant)
  • get_document_structure — browse the table of contents

Keys live in env vars and never appear in tool arguments or the model's context window.

CLI

export PAGESERVE_URL=https://pageindex.company.com
export PAGESERVE_PUBLIC_KEY=<your-public-key>
export PAGESERVE_SECRET_KEY=<your-secret-key>

pageserve list                                      # list documents
pageserve query <doc_id> "question"                 # ask a question
pageserve query <doc_id> "question" --stream        # streaming output
pageserve upload ./report.pdf --watch               # upload + progress bar
pageserve health                                    # service status
pageserve keys list                                 # list API keys
pageserve keys create "My App"                      # create a key
pageserve mcp                                       # run MCP server (stdio)
pageserve mcp --transport sse --port 3000           # MCP over SSE

Error handling

from pageserve import (
    AuthError,
    NotFoundError,
    DocumentNotReadyError,
    FileTooLargeError,
    RateLimitError,
    ServiceUnavailableError,
    ServiceError,
)

try:
    result = client.query(doc_id, "question")
except AuthError:
    print("Invalid or expired API key")
except NotFoundError:
    print("Document not found")
except RateLimitError as e:
    import time; time.sleep(e.retry_after)
except ServiceError as e:
    print(f"Server error [{e.status_code}]")

Documentation

Related

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pageserve-0.1.0.tar.gz (19.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pageserve-0.1.0-py3-none-any.whl (23.9 kB view details)

Uploaded Python 3

File details

Details for the file pageserve-0.1.0.tar.gz.

File metadata

  • Download URL: pageserve-0.1.0.tar.gz
  • Upload date:
  • Size: 19.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pageserve-0.1.0.tar.gz
Algorithm Hash digest
SHA256 339da305d11a50adf4868241719393350a47c1183b164292d5ca30470546cc88
MD5 cb57818ade074521359a1cdd2e9fa7de
BLAKE2b-256 302964949ecf0a414ebc5d64f08ca05cdbe07baf62accf52a4710e1a38628c8a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pageserve-0.1.0.tar.gz:

Publisher: publish.yml on pageserve/pageserve

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pageserve-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pageserve-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 23.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pageserve-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cbd6940ac56f7c2d0cb9d050361e6d867105e5690f7b962ff8ab35cdb3c86305
MD5 3acae87d542867730823d2c4bdaf436b
BLAKE2b-256 4c37a8d58348096a38d3d89831e3ca7f2f839e2129df893bb8652ac02cc33c60

See more details on using hashes here.

Provenance

The following attestation bundles were made for pageserve-0.1.0-py3-none-any.whl:

Publisher: publish.yml on pageserve/pageserve

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page