Connect an AI agent
Two ways in, both on the public API, so scopes, rate limits, credits and test mode apply as they do to any key:
Use a test-mode key while trying it: jobs run end to end, return fixture results and
charge nothing. Start with digitisation.read and digitisation.write: the agent
proposes candidates, and a person reviews and stages them in the Platform.
Only grant digitisation.review if the agent may make review decisions. Grant
catalogue.read and catalogue.write together for import_shades, which creates or
revises known colours. stage_candidate needs catalogue.write; find_variant
needs catalogue.read. measure_regions requires both digitisation.write and
digitisation.read, including with wait: false: its tool contract covers queuing
and polling. Scopes do not imply each other.
MCP server
Streamable HTTP at /mcp. Send your API key as a bearer token; without one the server
answers 401. It keeps no key and no state between calls.
Sign in instead of pasting a key
A client that connects through OAuth, such as a Claude.ai or Claude Desktop custom
connector, signs you in with your MorphiaOne Platform account instead. The server
publishes where to sign in at /.well-known/oauth-protected-resource, and its 401
names that document, so the client finds it alone: add the connector by its URL and
sign in when asked.
The agent then acts as you, within your role in the account:
- A viewer’s agent reads; a developer’s drafts; an owner’s or admin’s may also review.
- Approving and publishing a catalogue stay in the console, for a person, whatever the role.
- If your account requires a person to review, the agent’s decisions are refused as a key’s are; it gives you the candidate’s review link instead.
- Removing you from the account stops the agent’s next call.
From your own code, pass the token where you would pass a key: access_token= in
Python, accessToken in TypeScript (one or the other, never both).
Sign-in is being rolled out. Until the hosted endpoint offers it, use an API key.
The hosted MCP endpoint is not public yet. Until it is, ask for its URL when you
request access, and use it where the snippets say MCP_URL.
Claude Code
Cursor
VS Code
Create .mcp.json with literal environment references:
Set MCP_URL and MORPHIAONE_API_KEY in the environment that launches Claude Code.
The client expands these references when connecting. Do not expand the key in a
shell command or save its value in the configuration. In a real client session,
check /mcp to confirm the connection before starting a job.
See Claude Code’s environment-variable configuration.
Local server
morphiaone-mcp runs the same tools over stdio on your machine. It reads the key from
MORPHIAONE_API_KEY and can upload a local photo by path. It needs no hosted URL and
no OAuth, so Claude Desktop can use it too. Until the package is published, install it
from a checkout: pip install -e sdk/python -e mcp-server.
The CLI writes the entry for you, keeping your other servers and backing up the file it changes:
It runs morphiaone-mcp from your PATH if it finds it, otherwise uvx morphiaone-mcp.
These are the entries it writes:
Claude Code (local)
Cursor (local)
Claude Desktop (local)
.mcp.json:
MORPHIAONE_BASE_URL defaults to https://api.morphiaone.ai.
Tools
retain_evidence takes exactly one of path, asset_id or url. Only a
local server reads path, and only a .jpg, .png or .webp file
whose bytes are that image; anything else is refused before it leaves your machine. A
deployment that fetches no links answers a url with 400 INVALID_REQUEST and
remote_input_disabled.
With a hosted server the agent never holds the photo, so it asks the person for it:
start_upload answers an upload_url to send them. They open it to choose the photo,
or run curl -T photo.jpg "<upload_url>"; it needs no API key, works once and expires
after 15 minutes. The agent reads get_upload until it is stored, then passes its
asset_id to retain_evidence. The link is shown only when the session starts, so
start a new one rather than retrying. The account’s key network allowlist does not
apply to the person’s send: the link itself is the permission. You can also upload
the photo yourself with the SDK or morphiaone digitisation retain --file and hand
the agent its evidence or asset id.
tools/list shows only tools for which your key has every required scope. A key
with both read scopes sees four read tools. If the key cannot be checked, discovery
fails instead of advertising unrestricted tools. Each tool call checks scopes again,
so a client cannot bypass this check by calling a hidden tool and scope changes take
effect on the next call. The gateway still authorizes each API operation.
GET /v1/api-key (client.whoami(), morphiaone whoami) answers the key’s scopes.
Each tool answers the fields a reviewer needs and the digest the next call takes. Pass
raw: true for the full response with its audit digests. Writes derive their
Idempotency-Key from their arguments, so an agent’s retry replays the first answer,
including a failed assessment. To measure the same regions again on purpose, pass
attempt: 1 (then 2, and so on) to measure_regions.
The server tells the agent to show the user each measured colour and to accept only on an explicit yes. That is guidance to the agent, not proof that a person approved.
Every decision records who made it: a candidate’s reviewed_by and a stage’s
reviewed_by and staged_by are {"type": "user"} for a member in the Platform or
{"type": "api_key"} for a key. When the review must be a person’s, an owner or admin
turns on Settings → Review policy in the Platform. Then the server enforces it for
every key of the account, whatever its scopes:
acceptandrejectanswer403HUMAN_REVIEW_REQUIRED.stageanswers the same unless a member accepted the candidate.- The candidate’s
review_urlopens it in the Platform. The agent gives that link to the user and waits; once a member accepts, the agent may stage it.
Each key decision and each refusal is a row in the account’s audit log. A key without
digitisation.review and catalogue.write is still the narrowest grant: it can retain,
measure and propose candidates and nothing more. The policy does not cover generic
import_shades, which copies a known hex into a draft with catalogue.write and no
candidate; do not grant that scope to an agent whose colours a person must approve.
Staging is not publishing: a staged draft renders nothing until someone approves and
publishes it in the Platform.
Skill
For agents that run shell commands (Claude Code, Claude Agent SDK), the
morphiaone-digitisation skill ships in the SDK repository under
sdk/skills/morphiaone-digitisation/. Copy that folder into .claude/skills/ (one
project) or ~/.claude/skills/ (every project). It drives pip install morphiaone and
reads the key only from MORPHIAONE_API_KEY.
The agent commands (whoami, --compact) need the current SDK; upgrade an older install.
Qualify locally before hosting
Claude Code and Cursor can connect to the local Streamable HTTP service; a public
hostname is not required for a real-client test. Use a test-mode key, retain a local
photo with morphiaone digitisation retain --file, and give its evidence id to the
agent. Verify measurement, candidate creation, human Platform review and staging.
Check retries, missing scopes and revocation with separate test keys. Record client
and package versions and request ids, never credential values.
Public hosting needs a separate authentication review: the current static API-key adapter forwards the caller’s key to the public API. It is not an OAuth deployment. OAuth must validate tokens issued for the MCP endpoint and use separately authorized upstream credentials. Keep URL fetching disabled until its deployment gates pass; local-file retention works without arbitrary URL fetching.
Building your own agent on the SDK? Name it with app_info="my-agent/1.0" (appInfo in
TypeScript): it goes first in the User-Agent the SDK sends.
The order of calls
Both follow Digitise and import shades: retain, measure, make a candidate, review, stage.