Authenticated write MCP server for DSpace 7+ repositories (deposit, upload, edit)
Project description
dspace-mcp-write
An authenticated, write-capable MCP
server for DSpace 7+ repositories. It lets an AI
assistant deposit new items, upload files, edit metadata, and create
collections — on top of everything the read-only
dspace-mcp server already does
(search, fetch, browse, extract PDF text). All of dspace-mcp's read tools are
included here, now authenticated.
This is the sharp tool. If you only need to read a repository, run
dspace-mcpinstead — it holds no credentials and cannot change anything. Rundspace-mcp-writeonly when you actually want an assistant that can modify your repository, and read the Security section below first.
Security — read this before you run it
Unlike the read-only server, dspace-mcp-write holds credentials for a real
DSpace account and can modify your repository. Be deliberate about it:
confirmis a usability guardrail, not a security boundary. Every mutating tool defaults toconfirm=False, returning a preview of what it would do without doing it. That helps a well-behaved assistant show you a plan before acting — but it is set by the same model that calls the tool, and this server also ingests untrusted repository content (PDF text), a classic prompt-injection vector. Do not treatconfirmas a wall.- The real trust boundary is DSpace itself: the permissions of the technical account you configure, plus your MCP host's approval of each tool call.
- Recommended setup: use a narrowly-permissioned technical account (submit
rights only on the collections you intend, not an admin), and set
DSPACE_WRITE_COLLECTIONSto the specific collections you want writable. With that, the blast radius is bounded by DSpace, not by the model's goodwill.
Deposits are draft-first: creating an item and uploading a file leave it as a
workspace draft. Nothing becomes public until the separate, explicit
deposit_workspace_item tool submits it to the collection's workflow.
Install
With uv:
uvx dspace-mcp-write --base-url https://demo.dspace.org/server \
--username you@example.org --password '••••••'
Or with pip:
pip install dspace-mcp-write
Credentials are required — running this server is the opt-in to writing. Prefer environment variables over command-line flags so secrets don't land in your shell history or process list (see Configuration).
Configure your MCP client
Claude Code:
claude mcp add dspace-write \
--env DSPACE_BASE_URL=https://demo.dspace.org/server \
--env DSPACE_USERNAME=you@example.org \
--env DSPACE_PASSWORD=secret \
--env DSPACE_WRITE_COLLECTIONS=<collection-uuid>,<collection-uuid> \
-- uvx dspace-mcp-write
Claude Desktop / any client using mcp.json:
{
"mcpServers": {
"dspace-write": {
"command": "uvx",
"args": ["dspace-mcp-write"],
"env": {
"DSPACE_BASE_URL": "https://demo.dspace.org/server",
"DSPACE_USERNAME": "you@example.org",
"DSPACE_PASSWORD": "secret",
"DSPACE_WRITE_COLLECTIONS": "<collection-uuid>"
}
}
}
}
Tools
Every mutating tool takes a confirm flag: call it with confirm=false (the
default) to get a preview, confirm=true to actually perform the change.
Write tools
| Tool | What it does |
|---|---|
get_submission_form |
Show a collection's submission fields and which are required — check this before depositing. |
create_workspace_item |
Start a draft in a collection and fill its metadata (leaves it as a draft). |
update_workspace_item_metadata |
Fix or complete a draft's metadata after a validation error. |
upload_file_to_workspace_item |
Attach a file to a draft. |
deposit_workspace_item |
Submit a draft to the collection's workflow — the only tool that publishes. Requires grant_license=true when the collection needs the deposit licence accepted. |
discard_workspace_item |
Delete a draft you created. |
add_file_to_item |
Attach a file to an existing, archived item. |
update_item_metadata |
Edit an existing item's metadata. |
create_collection / create_community |
Create repository structure. |
Read tools
All nine tools from dspace-mcp are
registered here too (search_items, get_item, list_communities,
list_collections, list_bitstreams, get_bitstream_text,
list_facet_values, get_item_statistics, get_repository_info) — now
authenticated, so they can also see non-public content the account is allowed to
read.
Configuration
| Variable | Default | Meaning |
|---|---|---|
DSPACE_BASE_URL |
(required) | REST API root, e.g. https://demo.dspace.org/server |
DSPACE_USERNAME |
(required) | technical account e-mail |
DSPACE_PASSWORD |
(required) | account password |
DSPACE_WRITE_COLLECTIONS |
(empty = all) | comma-separated collection UUIDs the server may deposit into / attach files to |
DSPACE_UPLOAD_MAX_MB |
100 |
refuse to upload files larger than this |
DSPACE_TIMEOUT |
15 |
seconds per HTTP request |
DSPACE_MAX_RESULTS |
50 |
ceiling on records the read tools return |
Every variable has a matching flag (--base-url, --username, --password,
--write-collections, --upload-max-mb, …). DSPACE_WRITE_COLLECTIONS bounds
deposits and file uploads; it does not restrict create_collection /
create_community, which have no target collection — rely on the account's
permissions for those.
How it talks to DSpace
DSpace 7+ writes go over an authenticated REST surface: a CSRF handshake
(GET /api/security/csrf), a JWT login (POST /api/authn/login), and a
submission flow (/api/submission/workspaceitems → JSON-Patch metadata →
multipart file upload → /api/workflow/workflowitems). This server manages the
rotating CSRF token and the JWT for you, scopes those credentials strictly to
your DSpace host (never leaking them to redirect targets such as S3/CDN), and
discovers each collection's submission form at runtime rather than assuming a
fixed field layout. The design and its rationale — including the API quirks
verified against a live instance — live in docs/superpowers/specs/.
Development
git clone https://github.com/mpasternak/dspace-mcp-write
cd dspace-mcp-write
uv sync --dev
uv run pytest # unit tests, offline (respx)
uv run ruff check .
# Live contract tests hit a real DSpace and need a real account.
# demo.dspace.org has a public demo admin account:
export DSPACE_TEST_USER='dspacedemo+admin@gmail.com'
export DSPACE_TEST_PASSWORD='dspace'
uv run pytest -m live
The live round-trip creates a draft, uploads a small file, verifies it, and
discards the draft — it cleans up after itself. demo.dspace.org is a shared,
frequently-reset instance, so the live job is best-effort, not a release gate.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dspace_mcp_write-0.1.0.tar.gz.
File metadata
- Download URL: dspace_mcp_write-0.1.0.tar.gz
- Upload date:
- Size: 43.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e2a2529cb4e821d1f14748989d22f2ec09849f8a501b28f323a1d290d48bbba0
|
|
| MD5 |
2ea6ff0560e5c1a64a99c20eb030abee
|
|
| BLAKE2b-256 |
43596cfc0934ae5f4b9f0a0fdae9a65b74c2be9e883e42d2013ee4188160d337
|
Provenance
The following attestation bundles were made for dspace_mcp_write-0.1.0.tar.gz:
Publisher:
publish.yml on mpasternak/dspace-mcp-write
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dspace_mcp_write-0.1.0.tar.gz -
Subject digest:
e2a2529cb4e821d1f14748989d22f2ec09849f8a501b28f323a1d290d48bbba0 - Sigstore transparency entry: 2236501126
- Sigstore integration time:
-
Permalink:
mpasternak/dspace-mcp-write@fa510cfd3d5af0b79fc06bd78c7fb2fb6965745d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/mpasternak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fa510cfd3d5af0b79fc06bd78c7fb2fb6965745d -
Trigger Event:
release
-
Statement type:
File details
Details for the file dspace_mcp_write-0.1.0-py3-none-any.whl.
File metadata
- Download URL: dspace_mcp_write-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9bbe0aa2c287baaa04655955fbec34a267d291a8fbc39bed9a13982cee9d741
|
|
| MD5 |
49c3022262c6901960fb153bce029615
|
|
| BLAKE2b-256 |
ae8a80c22c6867f5920525f06e8498f651fad272fa90586e24f9eb21c0296622
|
Provenance
The following attestation bundles were made for dspace_mcp_write-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on mpasternak/dspace-mcp-write
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dspace_mcp_write-0.1.0-py3-none-any.whl -
Subject digest:
b9bbe0aa2c287baaa04655955fbec34a267d291a8fbc39bed9a13982cee9d741 - Sigstore transparency entry: 2236501297
- Sigstore integration time:
-
Permalink:
mpasternak/dspace-mcp-write@fa510cfd3d5af0b79fc06bd78c7fb2fb6965745d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/mpasternak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fa510cfd3d5af0b79fc06bd78c7fb2fb6965745d -
Trigger Event:
release
-
Statement type: