Skip to main content
Glama
DavidOsipov

nplg-dspace-mcp

by DavidOsipov

NPLG DSpace MCP

Upstream-read-only Streamable HTTP MCP server for the National Parliamentary Library of Georgia's Iverieli repository (dspace.nplg.gov.ge). Its public Alpic profile exposes archive search and returns metadata plus public bitstream URLs. search_documents fails closed with UPSTREAM_FAILURE when NPLG's search route is unavailable; it does not use an unapproved fallback scraper. The separate private profile can download validated PDFs and render historical Georgian newspapers as full-page JPEGs plus overlapping crop-only tiles.

What is implemented

  • The direct/private application endpoint is sessionless MCP 2026-07-28 over POST /mcp and uses server/discover. Alpic's hosted gateway separately owns the public legacy initialize lifecycle, currently negotiates 2025-11-25, requires notifications/initialized, and may issue an Mcp-Session-Id that must be reused; a passing candidate-bound hosted verification proves that lifecycle is terminated or translated at the gateway rather than forwarded to the modern-only application process.

  • NPLG-specific current JSPUI, legacy DSpace 5.5 XMLUI/Manakin, and OAI-PMH adapters; this is intentionally not a generic DSpace scraper.

  • Exact-origin, canonical-handle, DNS/IP, redirect, MIME, signature, streaming-size, and path controls.

  • Rich Dublin Core metadata with OAI-DIM preference and bounded JSPUI/XMLUI repository-HTML fallback.

  • Content-addressed public PDF storage, signed expiring asset URLs, and canonical MCP resource reads for authorized PDFs, manifests, page JPEGs, and tiles in the private profile.

  • Conservative PDFium-based page classification:

    • byte-identical extraction for eligible single embedded JPEG pages;

    • native embedded-scan pixel-grid rendering where defensible;

    • explicitly labelled fallback_400_dpi for vector or mixed pages.

  • JPEG pages with no post-render resize.

  • Default 2048×2048 crop-only tiles with 128-pixel overlap.

  • Shared upstream request pacing plus fail-fast MCP, asset-stream, server-wide, and PDF-job concurrency bounds.

  • The public alpic-metadata profile is anonymous and exposes only three metadata tools; static bearer/API-key configuration remains forbidden in production.

  • Docker Compose + Caddy deployment assets and post-deploy verification scripts.

The server performs no OCR. The public profile exposes the companion workflow as a static MCP resource; it tells resource-capable agents to retrieve an explicitly public PDF URL and preserve evidence while inspecting the document locally. MCP does not require every client to discover or execute that workflow. No MCP tool mutates the upstream NPLG archive and render deletion remains operator-only. The three private tools that populate the local download/render cache are accurately marked as cache-writing in their MCP annotations.

Related MCP server: ANNO MCP Server

MCP tools

alpic-metadata exposes exactly the first three tools. The five PDF and render tools are available only in private-full.

Tool

Purpose

search_documents

Search Iverieli, optionally within a collection handle.

get_document_metadata

Read rich metadata for a canonical handle.

list_document_files

List public and restricted bitstreams attached to an item.

download_document_file

Download a discovered public PDF only.

inspect_pdf

Classify pages and report scan geometry and text overlays.

render_pdf_pages

Create full-page JPEGs on the native scan grid or labelled fallback grid.

render_pdf_page_tiles

Create overlapping crop-only tiles without resize.

get_render_manifest

Refresh structured render metadata and signed links.

MCP resources

The public alpic-metadata profile advertises exactly one non-templated, read-only text/markdown resource:

  • nplg://skills/georgian-newspaper-visual-analysis contains bounded instructions for selecting a public bitstream and performing PDF inspection in the client environment. It performs no server-side download, parsing, rendering, caching, or deletion.

The private-full profile advertises one fixed resource and two canonical templates:

  • nplg://about describes the server's read-only scope and provenance rules.

  • nplg://artifact/{artifact_id} reads an authorized content-addressed PDF, rendered JPEG, or tile manifest. A concrete artifact identifier is doc_ followed by exactly 64 lowercase hexadecimal SHA-256 characters.

  • nplg://render/{render_id}/manifest reads an authorized bounded render manifest. A concrete render identifier is rnd_ followed by exactly 32 lowercase hexadecimal characters.

Clients resolve those canonical URIs through resources/read. Successful tool calls put their strictly validated Pydantic result in structuredContent; the SDK content array carries one bounded human summary. Expected tool execution errors set isError: true, return one sanitized text message, and omit structuredContent so clients do not validate an error against the advertised success schema. Tool result resource_uri fields identify resources that may be read through the protocol after the same authorization and expiry checks. The alpic-metadata profile does not register resource templates or advertise local storage, PDF processing, or asset routes.

Local development

The supported Python range is >=3.12,<3.15. The reviewed bootstrap lock is for uv 0.12.5, Node 24.19.0, npm 11.18.0, and the x86_64 Linux target; runtime downloads only immutable direct artifacts and authenticates them with the repository-pinned SHA-256 after accepted upstream-evidence review. Runtime and development dependencies are hash-pinned.

requirements-security.in is intentionally separate from requirements-dev.in: Semgrep 1.175.0 hard-pins mcp==1.29.0, which is incompatible with the required official mcp==2.1.1. Combining those inputs would produce an unsatisfiable lock rather than a stricter environment.

set -euo pipefail

# Choose an absolute path outside this checkout. The caller creates and owns it.
TOOL_ROOT=/absolute/external/path/nplg-toolchain
mkdir -m 0700 "$TOOL_ROOT"

python3 scripts/bootstrap_toolchain.py \
  --lock security/bootstrap-toolchain-lock.json \
  --tool uv \
  --target x86_64-unknown-linux-gnu \
  --destination "$TOOL_ROOT/uv"
python3 scripts/bootstrap_toolchain.py \
  --lock security/bootstrap-toolchain-lock.json \
  --tool node \
  --target x86_64-unknown-linux-gnu \
  --destination "$TOOL_ROOT/node"
python3 scripts/bootstrap_toolchain.py \
  --lock security/bootstrap-toolchain-lock.json \
  --tool npm \
  --target x86_64-unknown-linux-gnu \
  --destination "$TOOL_ROOT/npm" \
  --dependency "node=$TOOL_ROOT/node"

UV_BIN="$TOOL_ROOT/uv/uv-0.12.5.data/scripts"
NODE_BIN="$TOOL_ROOT/node/node-v24.19.0-linux-x64/bin"
NPM_BIN="$TOOL_ROOT/npm/bin"
export PATH="$UV_BIN:$NPM_BIN:$NODE_BIN:/usr/bin:/bin"

test "$(uv --version)" = "uv 0.12.5 (x86_64-unknown-linux-gnu)"
test "$(node --version)" = "v24.19.0"
test "$(npm --version)" = "11.18.0"

uv venv --python "$(uv python find 3.13.15)" .venv
uv pip sync --python .venv/bin/python --require-hashes requirements-dev.lock
npm ci --ignore-scripts
test "$(.venv/bin/python -c 'import platform; print(platform.python_version())')" = "3.13.15"
test "$(npm exec --offline -- pyright --version)" = "pyright 1.1.413"

The exact Python 3.13.15 claim is established only after the checks above pass. Do not substitute an ambient package installer or editable checkout.

Start the local service from the synchronized environment:

set -euo pipefail

export NODE_ENV=development
export DEPLOYMENT_PROFILE=private-full
export CURSOR_SIGNING_SECRET="$(.venv/bin/python -c 'import secrets; print(secrets.token_hex(32))')"
export ASSET_SIGNING_SECRET="$(.venv/bin/python -c 'import secrets; print(secrets.token_hex(32))')"
export ALLOW_ANONYMOUS=true
export PUBLIC_BASE_URL=http://127.0.0.1:8000
.venv/bin/python -m nplg_mcp

In another shell:

.venv/bin/python scripts/verify_deploy.py \
  --base-url http://127.0.0.1:8000 \
  --profile private-full

From the shell where the reviewed toolchain variables above were set, run tests:

NPLG_REVIEWED_NODE="$NODE_BIN/node" .venv/bin/python -m pytest -q
.venv/bin/python -m compileall -q src scripts

Offline tests use pinned HTML/OAI fixtures and a synthetic PDF corpus. Live NPLG checks are deliberately opt-in.

The phase 0–1 capability records under contracts/ are negative evidence, not OAuth support: dynamic operation-scope 403, exact Alpic detector replay, route compatibility, provider selection, DCR issuer semantics, and the witnessed end-to-end flow remain deferred work. The public alpic-metadata profile does not consume that verdict; it still refuses all static bearer/API-key fallback.

Production deployment

The current candidate remains do_not_release until its candidate and protected release gates are complete. The public alpic-metadata profile does not require OAuth, but Alpic's serverless runtime, 30-second tool limit, and static /assets/ handling do not provide a full-fidelity target for the current multi-call rendering workflow. See deploy/ALPIC.md for the restricted metadata deployment.

The checked-in Docker Compose path selects private-full; it is not a Docker/VPS substitute for the anonymous metadata deployment and correctly fails closed with the metadata profile's anonymous settings. Follow deploy/ALPIC.md for the restricted alpic-metadata deployment. A future authenticated full-profile deployment requires its own approved runtime and release contract.

When reviewing that deferred Compose configuration, validate it without printing the rendered environment, which can contain secrets:

docker compose --env-file .env config --quiet

Design, review, and agent workflow

  • Approved design: docs/superpowers/specs/2026-08-14-nplg-dspace-mcp-design.md

  • Implementation plan: docs/superpowers/plans/2026-08-14-nplg-dspace-mcp-implementation.md

  • Critical review: docs/reviews/2026-08-14-critical-review.md

  • Georgian visual-analysis skill: skills/georgian-newspaper-visual-analysis/SKILL.md

  • Current security-repair verification: docs/verification/2026-08-14-security-repair-report.md

  • Historical verification snapshot: docs/verification/2026-08-14-verification-report.md

Explicit limitations

  • Live JSPUI/XMLUI/OAI compatibility must be rechecked after deployment because upstream HTML can change.

  • The server uses the official MCP Python SDK behind project-owned HTTP admission and bounded JSON preflight controls; those controls cover only this server's supported profiles.

  • Hosted SDK interoperability and Inspector checks remain part of the separately governed post-deploy evidence, not local release authority.

  • PDF work is bounded inside a hardened container but not inside a separately verified nested sandbox.

  • The cache is single-node filesystem storage and is not horizontally coordinated or automatically pruned. A process-local logical-byte quota rejects new cache writes at CACHE_MAX_BYTES; retain a filesystem/inode limit and disk alerts as independent controls.

  • Process-local admission limits bound work inside one server process; they are not per-client rate limits. Internet deployments still need a trusted edge policy for client-aware abuse controls.

  • Public download access does not establish public-domain status; rights metadata remains part of the evidence record.

License

The project-authored source is MIT. Runtime and development dependencies retain their own licenses; see THIRD_PARTY_NOTICES.md. The production image uses permissively licensed pypdfium2/PDFium, and synthetic fixtures use permissively licensed ReportLab and pypdf.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    MCP server for searching and accessing historical Austrian newspapers from ANNO, providing full-text search, snippet extraction, and OCR text download.
    3
    Apache 2.0
  • A
    license
    A
    quality
    B
    maintenance
    MCP server and CLI for full-text search of the Deutsches Zeitungsportal (German newspaper collection), enabling querying ~33.8 million digitized pages with Solr syntax, date/title/place filters, and snippet highlights.
    3
    Apache 2.0
  • A
    license
    A
    quality
    B
    maintenance
    MCP server for searching and retrieving full-text pages from the Library of Congress, including newspapers, books, and manuscripts, via the loc.gov API.
    3
    Apache 2.0

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DavidOsipov/nplg-dspace-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server