Skip to main content
Glama
inspire-mcp
by karuboniru
README.md
# inspire-mcp-more

An extensible Model Context Protocol server for the public
[INSPIRE REST API](https://github.com/inspirehep/rest-api-doc).

It provides structured tools for literature, authors, DOI/arXiv/ORCID resolution,
citation export, and the INSPIRE bibliography generator. Responses offer bounded detail
levels so an MCP client can trade metadata completeness for model context size.

## Requirements

- Python 3.11 or newer
- [uv](https://docs.astral.sh/uv/)

## Install

Install globally from a checkout:

```bash
uv tool install .
```

Install from Git:

```bash
uv tool install git+https://github.com/karuboniru/inspire-mcp
```

Run without a persistent install:

```bash
uvx --from git+https://github.com/karuboniru/inspire-mcp inspire-mcp
```

## Run

The default transport is stdio:

```bash
inspire-mcp
```

For a local Streamable HTTP endpoint:

```bash
inspire-mcp --transport streamable-http --host 127.0.0.1 --port 8000
```

The endpoint is `http://127.0.0.1:8000/mcp` by default. Binding to a non-loopback
address requires Bearer or OAuth2/OIDC authentication (below) or `--allow-public-http`. Production
deployments should terminate TLS at a reverse proxy.

### Simple Bearer authentication for HTTP

Set a shared key in the environment to enable local token checking:

```bash
export INSPIRE_MCP_BEARER_TOKEN='your-secret-key'
inspire-mcp --transport streamable-http --host 0.0.0.0 --port 8000
```

Configure your MCP client to send `Authorization: Bearer your-secret-key` on every
HTTP request. Missing or incorrect tokens receive HTTP 401. Use a long, randomly
generated key and HTTPS for remote connections. This mode needs no identity provider
or public URL and does not provide OAuth discovery or login; the client must support
a configured Authorization header. Restart the server after changing the key.

The key must be nonempty and contain only letters, digits, `-`, `.`, `_`, `~`, `+`,
`/`, and optional trailing `=` characters. Do not combine `INSPIRE_MCP_BEARER_TOKEN`
with the OAuth/OIDC issuer, public URL, or JWKS settings below. Invalid or conflicting
settings stop startup. Authentication applies to HTTP; stdio is unchanged.

### OAuth2 / OIDC authentication for HTTP

This project is an **OAuth resource server**, not an OAuth login client or an
authorization server. The MCP client opens the authorization flow, receives the
callback, and exchanges the authorization code for an access token at the external
authorization server. This service validates that access token on MCP requests;
it does not receive login callbacks, issue tokens, or refresh them.

For an external OAuth2 authorization server issuing signed JWT access tokens:

```bash
export INSPIRE_MCP_OAUTH_ISSUER=https://auth.example.com/tenant
export INSPIRE_MCP_PUBLIC_URL=https://inspire.example.com/mcp
inspire-mcp --transport streamable-http --host 0.0.0.0 --port 8000
```

This uses RFC 8414 authorization server metadata. For the example above, discovery
uses `https://auth.example.com/.well-known/oauth-authorization-server/tenant`.

For an OIDC provider, use `INSPIRE_MCP_OIDC_ISSUER` instead of
`INSPIRE_MCP_OAUTH_ISSUER`. Existing OIDC configurations continue to work and use
`<issuer>/.well-known/openid-configuration`. Set exactly one issuer variable;
setting both is an error. Discovery modes do not automatically fall back to one another.

Optionally set `INSPIRE_MCP_JWKS_URI=https://auth.example.com/keys` to load trusted
public signing keys directly, bypassing server-side discovery. This works with
either issuer variable and still requires the issuer and public URL. It does not
replace the authorization metadata the MCP client needs to initiate login.

Use the exact issuer URL (including any path or trailing slash), and the externally
visible MCP endpoint URL. Both must use HTTPS. Configure the identity provider to
issue access tokens with `aud` containing `INSPIRE_MCP_PUBLIC_URL`. Its access
tokens must include `iss`, `aud`, `exp`, and `sub`, and use RS256/384/512 or
ES256/384/512 signatures. Opaque tokens and encrypted JWTs are not supported.

The server obtains the issuer's public signing keys from discovery or the configured
JWKS URI, caches them, and verifies tokens. **No JWT secret or private key is needed**:
the identity provider signs tokens; this server only verifies them. JWKS and, when
used, discovery endpoints must be reachable from the server.

Unauthenticated HTTP requests receive a 401 with an OAuth resource metadata URL.
Proxy `/.well-known/oauth-protected-resource` and its subpaths to this service as
well as `/mcp`, preserving the `Authorization` and `WWW-Authenticate` headers.
Clients discover the external authorization server and authenticate there. Configure
a client registration mechanism supported by your MCP client and provider (such as
CIMD), along with appropriate client/resource access policies at that provider; this
server does not implement client registration or an authorization server itself.
Any valid access token for this resource grants access to all tools; there is no
additional per-user or per-scope policy in this minimal integration.

Only leaving all authentication variables unset permits unauthenticated HTTP behavior.
Incomplete, conflicting, or empty authentication settings stop startup,
even with `--allow-public-http`. Stdio does not require tokens or contact the issuer.

Example MCP host configuration:

```json
{
  "mcpServers": {
    "inspire": {
      "command": "inspire-mcp"
    }
  }
}
```

## Container deployment

Build a minimal runtime image with Podman (Python dependencies are installed by
`uv sync --locked --no-dev --no-editable`):

```bash
podman build -t localhost/inspire-mcp:local .
podman run -d --name inspire-mcp --restart unless-stopped \
  -p 127.0.0.1:8000:8000 localhost/inspire-mcp:local
```

Docker can run the same image. The container defaults to a single process serving
Streamable HTTP on `0.0.0.0:8000/mcp`, as UID/GID 10001. The runtime contains no uv,
source checkout, development dependencies, or build cache. No persistent volume is
required. Pass application configuration using `-e INSPIRE_...=...` as listed below.

Connect your TLS reverse proxy to port 8000 and configure clients with
`https://<your-domain>/mcp`. Enable the Bearer or OAuth2/OIDC configuration above or use authentication
at the proxy.
The loopback port mapping above is suitable for a proxy on the same host; for a
containerized proxy, put both containers on a private network and proxy to
`http://inspire-mcp:8000/mcp` without publishing the backend port. Preserve streaming
responses (disable proxy buffering) and allow sufficient upstream response time.
Configure allowed public hosts/origins at your proxy, and keep the backend private.

Keep one replica for personal/small-team use: caches and upstream rate limits are
local to each process. Container arguments replace the default command; when
overriding them, include all required HTTP flags:

```bash
podman run --rm -p 127.0.0.1:8001:8001 localhost/inspire-mcp:local \
  --transport streamable-http --host 0.0.0.0 --port 8001 --allow-public-http
```

The container workflow builds and smoke-tests Linux amd64 and arm64 images on native
GitHub runners. Pull requests build only; pushes to `main`, release tags `v*`, and
manual runs publish to `ghcr.io/<owner>/<repository>`. `latest` follows `main`;
`sha-<full-commit-sha>` identifies a commit. Release tags are also published.
After the workflow has published an image, deploy it by replacing
`localhost/inspire-mcp:local` above with your GHCR image reference. Private GHCR
packages require `podman login ghcr.io` before pulling.

## Tools

| Tool | Purpose |
| --- | --- |
| `search_literature` | Search literature with INSPIRE query syntax |
| `get_literature` | Read a paper by recid, DOI, or arXiv ID |
| `list_literature_authors` | Page through embedded paper authors |
| `list_literature_references` | Page through a paper's references |
| `export_literature` | Export BibTeX, LaTeX, or CV HTML |
| `search_authors` | Search public author records |
| `get_author` | Read an author by recid or ORCID |
| `resolve_external_identifier` | Resolve DOI, arXiv, or ORCID to an INSPIRE recid |
| `generate_bibliography` | Generate a bibliography from TeX citation commands |

The `inspire://capabilities` resource describes supported values and limits.

## Detail levels

- `compact`: identity and discovery fields, optimized for model context.
- `standard`: research-oriented metadata with bounded author arrays.
- `detailed`: broad public metadata with explicit `truncated_fields` markers.

Large arrays are never byte-truncated. Use `list_literature_authors` and
`list_literature_references` to retrieve them in pages.

Author searches never expose email addresses. A single author record requires both
`detail="detailed"` and `include_email=true` before public email fields are included.

## Configuration

| Environment variable | Default |
| --- | --- |
| `INSPIRE_API_BASE_URL` | `https://inspirehep.net/api/` |
| `INSPIRE_TIMEOUT_SECONDS` | `30` |
| `INSPIRE_CONNECT_TIMEOUT_SECONDS` | `5` |
| `INSPIRE_RATE_LIMIT_REQUESTS` | `12` |
| `INSPIRE_RATE_LIMIT_WINDOW_SECONDS` | `5` |
| `INSPIRE_MAX_RETRIES` | `2` |
| `INSPIRE_MAX_TEX_BYTES` | `1000000` |
| `INSPIRE_MAX_EXPORT_CHARACTERS` | `1000000` |
| `INSPIRE_CACHE_TTL_SECONDS` | `300` |
| `INSPIRE_CACHE_MAX_ENTRIES` | `256` |
| `INSPIRE_DOWNLOAD_HOSTS` | `inspirehep.net,s3.cern.ch` |
| `INSPIRE_MCP_LOG_LEVEL` | `INFO` |
| `INSPIRE_MCP_BEARER_TOKEN` | Unset (shared HTTP Bearer key; mutually exclusive with OAuth/OIDC settings) |
| `INSPIRE_MCP_OAUTH_ISSUER` | Unset (RFC 8414 discovery; mutually exclusive with OIDC issuer) |
| `INSPIRE_MCP_OIDC_ISSUER` | Unset (OIDC discovery; existing configuration supported) |
| `INSPIRE_MCP_PUBLIC_URL` | Unset (required with either issuer; also the token audience) |
| `INSPIRE_MCP_JWKS_URI` | Unset (optional explicit HTTPS public key URL; skips server-side discovery) |

INSPIRE documents an upstream limit of 15 requests per 5 seconds per IP. This server
uses a lower default to preserve headroom and retries HTTP 429 responses conservatively.

Successful GET, search, and export responses are cached in each server process. Concurrent
identical requests share one upstream request. Set `INSPIRE_CACHE_TTL_SECONDS=0` to disable
the cache. Multi-process deployments maintain one independent cache per worker.

Generated bibliography content is currently served by INSPIRE through CERN object storage.
The default download allowlist therefore contains both `inspirehep.net` and the exact host
`s3.cern.ch`; arbitrary external download hosts remain blocked.

## Development

```bash
uv sync --all-groups
uv run ruff check .
uv run mypy
uv run pytest
uv build
```

The default tests use mocked HTTP responses. Live INSPIRE POST requests are not performed
by the test suite.

## INSPIRE terms

Use of the upstream API is governed by the
[INSPIRE terms of use](https://inspirehep.net/help/knowledge-base/terms-of-use/).
Bulk collection of email addresses is not allowed.

TDQS

A3.8/5.0

Scored across 9 tools

Disambiguation5/5

Each tool targets a distinct resource or action: literature search vs retrieval, listing authors vs references, exporting single papers, author search vs retrieval, external ID resolution, and bibliography generation. There is no meaningful overlap that would confuse an agent.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern (e.g., search_literature, get_author, list_literature_references). Naming is uniformly snake_case and predictable, making the tool set easy to navigate.

Tool Count5/5

Nine tools is well-scoped for an INSPIRE literature and author database interface. Each tool serves a clear purpose without redundancy, and the count is within the ideal range for a domain-specific server.

Completeness4/5

The set covers core workflows: searching and retrieving literature, exploring authors and references, exporting citations, resolving external identifiers, and generating bibliographies. Minor gaps exist, such as no batch citation counts or citation-of tracking, but these are not critical for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues