For the complete documentation index, see llms.txt. This page is also available as Markdown.

🤖AI Agent (MCP)

Connect an AI coding assistant to your Obsidian License account over the Model Context Protocol, at https://license.ohalee.com/mcp.

Our Model Context Protocol endpoint lets an AI coding assistant (Claude Code, or any MCP client) work with your licensing directly. It gives the agent two things:

  1. A way in. Manage products, issue and revoke license keys, promote and roll back versions, and read activation logs, as the account behind your API key.

  2. The knowledge to use it. Ten implementation guides plus a project scaffolder covering both modes end to end: the one-call license check for an ordinary jar, and the full protected-module route with the ProtectedModule contract, the Obsidian-Module manifest attribute, the classloader rules, tiers and entitlements, the loader, publishing, and the wire protocol.

The knowledge half needs no credentials, so the agent can learn the whole mechanism before it touches your account.

Setup

Nothing to install. We serve MCP at https://license.ohalee.com/mcp, and there are two ways to authenticate.

Add the endpoint with no credentials. Your client opens a browser, you sign in, and it keeps itself authenticated from there.

claude mcp add --transport http obsidian-license https://license.ohalee.com/mcp

We implement the MCP authorization spec end to end: protected-resource and authorization-server discovery, dynamic client registration, and an authorization-code flow with PKCE. Your client handles the whole dance, so all you do is approve the request in the browser. Access tokens last 12 hours and are refreshed automatically, so you are not pasting anything again tomorrow.

If your client reports "Dynamic Client Registration rejected" or "Cannot POST /register", it is talking to a build from before OAuth support landed. Update the server (self-hosters) or reconnect, and make sure the URL is exactly https://license.ohalee.com/mcp with no trailing path.

Or use an API key

Better for CI, headless machines, and anywhere a browser is not available. Create one on the API Keys page and send it as a bearer token:

claude mcp add --transport http obsidian-license https://license.ohalee.com/mcp \
  --header "Authorization: Bearer obl_your_key"

Or in a client that reads a JSON config:

However you authenticate, the endpoint acts as your account, with the same permissions, plan limits and audit trail as the dashboard. It is stateless: each request gets its own server scoped to the token it carried, so nothing is kept between calls and nothing is shared between accounts. Send JSON-RPC with POST; a GET returns 405, because there is no session to stream into.

The local option

The platform also ships a stdio MCP server in the mcp-server/ package, which runs on your own machine. It has the same license tools and the same guides, plus the three things the hosted endpoint cannot do, since that one runs on our servers and cannot see your disk:

  • Upload a built jar from a local path, with a check that the jar really carries its Obsidian-Module manifest attribute.

  • Write a generated starter project straight into a folder.

  • Sign in with your email and password instead of carrying an API key. The agent calls obsidian_login and asks you for a TOTP code when two-factor is on; the password is used once and never stored, and the 12 hour token is cached with 0600 permissions.

Variable
Meaning

OBSIDIAN_URL

Your license server, https://license.ohalee.com for the hosted service

OBSIDIAN_API_KEY

Personal API key (obl_...), optional

OBSIDIAN_MCP_NO_CACHE

1 keeps a login token in memory only

OBSIDIAN_MCP_STATE_DIR

Where that token is cached (default ~/.obsidian-license/)

There is deliberately no default server URL: leaving it unset is safer than guessing one and sending your password somewhere you did not choose.

What the agent can do

Session: obsidian_login, obsidian_logout, obsidian_whoami, obsidian_set_server, obsidian_create_api_key, obsidian_list_api_keys, obsidian_revoke_api_key

Products: obsidian_list_products, obsidian_create_product, obsidian_update_product, obsidian_upload_payload, obsidian_list_versions, obsidian_promote_version, obsidian_set_product_trial, obsidian_delete_product, obsidian_server_key

Licenses: obsidian_list_licenses, obsidian_create_license, obsidian_bulk_create_licenses, obsidian_update_license, obsidian_revoke_license, obsidian_reactivate_license, obsidian_reset_license_activations, obsidian_delete_license

Diagnostics: obsidian_activation_logs, obsidian_stats

Knowledge: obsidian_guide, obsidian_scaffold_java

The hosted endpoint carries all of these except the ones that need your filesystem or an interactive login: obsidian_login, obsidian_logout, obsidian_set_server and obsidian_upload_payload are stdio only, and obsidian_scaffold_java returns the files as text rather than writing them.

obsidian_upload_payload checks the jar's Obsidian-Module manifest attribute before uploading anything: a jar without it uploads happily and then fails on every customer's server.

The guides

obsidian_guide returns the topic below as markdown. They are also exposed as resources at obsidian://guide/<slug>, and there are two prompts, protect-java-plugin and diagnose-activation.

Topic
Covers

overview

The moving parts and what happens on a customer's server

license-check

Licensing an ordinary jar with one call: the client, seats, entitlements

java-integration

Gradle setup, the entry class, the manifest attribute, classloader rules

migrating-plugin

Translating an existing JavaPlugin, and the state that breaks reloads

entitlements

Selling several SKUs from one build with the signed entitlement block

loader-config

Building the loader and what customers install

publishing

Products, uploads, version channels, CI

licensing

Seats, revocation, marketplaces, trials, spotting abuse

protocol

The wire format, the signed envelope, every denial code

troubleshooting

What each failure actually means

Things to ask it

  • "Convert this plugin to a protected module and publish it as my-plugin."

  • "A customer says the plugin will not start. Their key is OBS-... Work out why."

  • "Issue 50 keys for my-plugin with 2 seats each and give me the CSV."

  • "Put this build on the beta channel and move my three testers onto it."

  • "Add a premium tier to my-plugin with a max_homes entitlement, and show me the code that reads it."

The agent is acting on your live account. Ask it to confirm before it revokes, deletes, or promotes anything, and check what it proposes on destructive calls.

Last updated