Skip to main content

ojs-mcp

tests PyPI License: MIT

An MCP server for the authenticated REST API of Open Journal Systems (OJS 3.5/3.6). Connected to an MCP client (Claude Desktop, Claude Code, and others), it gives the model access to a journal's submissions, reviews, issues, and editorial statistics — and, with writes explicitly enabled, also to making editorial decisions, publishing, and editing metadata.

Verified against a live OJS 3.5

Every tool has been exercised end-to-end against a real OJS 3.5.0-5 instance — the sixteen read tools, the ojs_request escape hatch, and all five write tools. The write tools were checked by reading back the state OJS actually ended up in, not by trusting the status code: an announcement created, publication metadata edited, a submission carried from the submission stage to production by two editorial decisions, then published and unpublished again.

That instance is reproducible. demo/ holds the Docker stack, the fictional seed content, and the two scripts that drive this server against it as a real MCP client — check_api.py for the read tools, check_writes.py for the write tools.

Three things have not been exercised against a live server, and still rest on what the PKP source (pkp-lib, pkp/ojs) says rather than on observed behavior: login/password authentication (OJS_USERNAME/OJS_PASSWORD), network mode (OJS_MCP_TRANSPORT=http), and OJS 3.6 — only 3.5 has been tested. The unit test suite likewise runs entirely against stubbed HTTP responses (via respx).

Writes change real journal data, which is why OJS_ALLOW_WRITES=1 is off by default. Verify each tool's effect on a test journal before pointing it at production.

Quick start

OJS_BASE_URL=https://journals.your-university.edu OJS_API_TOKEN=your-token uvx ojs-mcp

No separate install step needed — uv downloads and runs the package on first launch. In practice your MCP client calls this command for you, using the configuration format from the section below.

Before you start — this won't work without two things

The OJS REST API has no anonymous read access. For the server to be able to connect at all, both of these must be true on the OJS instance side:

  1. api_key_secret set in config.inc.php — without it, API tokens don't work at all (OJS responds with a 500 error to every request that carries a token). This must be done by the OJS server administrator; it can't be worked around from the outside.
  2. An account with a role in the specific journal — merely having an OJS account is not enough. Almost every API endpoint requires some role (manager, editor, reviewer...); an account with no role in the given journal gets denied (401) on almost every call.

A third condition applies to instances served by Apache — including the official pkpofficial/ojs Docker images: the web server must forward the Authorization header to PHP. Apache does not do that on its own, and when it doesn't, OJS answers 401 to every request carrying a token, with a response indistinguishable from an anonymous one. The one-line fix, and how to tell this case apart from a genuine permission problem, are in the authentication documentation.

Without these conditions the server will start, but every tool that reaches into OJS will return an authentication error. Details, including the login/password alternative and its limitations, are in docs/authentication.md.

Getting a token

A logged-in user generates an API token in their own OJS profile: User Profile → API Key (only available once the instance administrator has set api_key_secret — see above). The token acts with that account's permissions, so its scope is whatever roles that account holds in the given journal.

Example MCP client configuration

{
  "mcpServers": {
    "ojs": {
      "command": "uvx",
      "args": ["ojs-mcp"],
      "env": {
        "OJS_BASE_URL": "https://journals.your-university.edu",
        "OJS_JOURNAL": "my-journal",
        "OJS_API_TOKEN": "paste-your-ojs-profile-token-here"
      }
    }
  }
}

OJS_JOURNAL is optional — leave it out if the instance serves several journals and you'd rather pick one with the journal parameter on each call.

Where to actually paste this configuration

In Claude Desktop: Settings → Developer → Edit Config opens (and, on first use, creates) the claude_desktop_config.json file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Paste the snippet above under the mcpServers key — if the file already has other servers configured, add the "ojs" key alongside them, don't overwrite the whole file — save and restart Claude Desktop. Other desktop MCP clients have their own place for this configuration (e.g. Claude Code reads it via claude mcp add or from an .mcp.json file) — check their documentation; the shape of the env section above is the same across all of them.

This step disappears entirely when installing from the MCPB bundle (see below) — there, the instance address, journal, and token are filled in through a form in the client's UI, with no manual JSON editing at all. That's a good reason to reach for the bundle instead of uvx if editing a configuration file by hand isn't your thing.

Environment variables (summary)

Variable Required Description
OJS_BASE_URL yes The OJS instance address, exactly as it works in the browser.
OJS_JOURNAL no The journal shortcut — skips the journal parameter on every call.
OJS_API_TOKEN no* The token from a user's profile. Takes precedence over login/password.
OJS_USERNAME / OJS_PASSWORD no* Form-based login — won't work with reCAPTCHA/ALTCHA.
OJS_ALLOW_WRITES no 1 exposes the tools that modify journal data (hidden by default).

* — either OJS_API_TOKEN or the OJS_USERNAME/OJS_PASSWORD pair is required (in stdio mode). The full list, including the network-mode variables (OJS_MCP_TRANSPORT and others), is in docs/configuration.md.

Alternative to uvx: the MCPB bundle

For desktop MCP clients that support the MCP Bundle (.mcpb) format — the installer file is attached to every release under Releases. Installation happens through the client's UI, configuration through a form instead of manual JSON editing; no Python or uv installation required — the bundle pulls its own dependencies on first run.

Documentation

Full documentation (installation, configuration, authentication, tool list, multi-tenant hosting): https://mpasternak.github.io/ojs-mcp/

License

MIT. See LICENSE.

Metadata

Release files for ojs-mcp 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ojs-mcp 0.2.1
File Size Uploaded Provenance Actions
ojs_mcp-0.2.1.tar.gz 107.0 kB With provenance Details for ojs_mcp-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ojs-mcp 0.2.1
File Interpreter ABI Platform Actions
ojs_mcp-0.2.1-py3-none-any.whl Python 3 none any Details for ojs_mcp-0.2.1-py3-none-any.whl

Total release size: 183.0 kB

Release files / ojs_mcp-0.2.1.tar.gz

Download URL ojs_mcp-0.2.1.tar.gz
Size 107.0 kB
Tags Source
SHA-256 checksum
How to use checksums
1d5a702055d7e0452f452c1a53998a0cba0d745903219b227f01f981737c551b
BLAKE2b-256 checksum
How to use checksums
84e2f63dc0963f2200f73a156fefd257c618e158255400205ad1a1e939a61614
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / ojs_mcp-0.2.1-py3-none-any.whl

Download URL ojs_mcp-0.2.1-py3-none-any.whl
Size 76.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2d7a33a2861f1750cd998f1aa94b12254e6ea1a36a69e254d06cd6605ccddd92
BLAKE2b-256 checksum
How to use checksums
e764309f8b06a690b51828be60d72eaf6862997fa08ccbca57b6999808755f0e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Security for ojs-mcp 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ojs_mcp-0.2.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page