The mode this server runs in is now its identity, not its state. Whether you configure an account picks one of two profiles, and the profile shapes the server's name, the description the assistant reads at startup, the tool list, and the tool signatures.
This started as a report from use: the assistant kept losing track of which mode it was in, and got it wrong in both directions — talking about "the logged-in account" on an installation that had none, and handing over embargoed material without mentioning it was not public.
Breaking
continue_anonymouslyis gone, along with the whole decision state machine behind it. It existed so a failed login could be negotiated mid-conversation, which turned out to be a question nobody could answer usefully — including the person who had configured the server.- A failed login now stops the process (exit code
3) instead of blocking every tool and asking. Fix the credentials and restart, or remove them to run the public profile deliberately. The choice belongs to configuration, not to a conversation. - The MCP server reports a new name:
dspace-mcp-publicordspace-mcp-account. Your client's own registration name is unaffected.
Two profiles
| public | account | |
|---|---|---|
| tools | 11 | 13 |
as_anonymous |
absent from every schema and description | present where it means something |
| extra tools | — | compare_access, get_download_link |
The server now sends instructions at startup, so the assistant knows whose eyes it is looking through before it calls anything. Previously that was discoverable only by calling get_repository_info and noticing.
In the public profile the as_anonymous argument is not merely unused — it is untrue, because it implies an account to contrast with. It is now absent from the schemas entirely, so an anonymous installation neither sees it nor pays tokens for it.
A new dspace-mcp-public command guarantees the public profile: given credentials through a flag or the environment, it refuses to start rather than ignore them. Register the server twice to have both views side by side — the README shows the configuration.
Getting a restricted file to a person
The server could already read restricted files. What did not work was the link it handed over: the bare /content address is refused in a browser even when you are logged into the website.
get_download_link fixes that, and measures before it acts:
- ask anonymously for the plain address — if it answers, the file is public and you get a clean, permanent link, with no token minted at all;
- only on refusal, try again with an authentication token in the URL;
- if that fails too, hand back the item's page instead.
Since most files in a repository are public, step 1 usually ends it and no credential ever leaves the process. When one does, the tool says plainly what it is: the URL carries a credential for the whole account, not for one file, and it expires.
Two limits stated in the README rather than hidden: the check reflects what the server can reach from its own network position, so an instance granting access by IP range may still refuse your browser; and httpx logs full URLs at INFO level, so a debug-logging MCP client will write the token to its log.
Also
- Files in listings now carry
item_url, and an item without a handle finally gets a/items/<uuid>address instead ofnull. - A URL never reaches an error message with its query string attached — it could be carrying that token.
- Fixed: the version-consistency test failed to collect on Python 3.10 (
tomllibis 3.11+), which had left CI red onmainfor several commits.