Sign in
Docs
0%

Transports

MCP

The API as tools for an assistant, over the Model Context Protocol.

The gateway serves https://api.inorbit.hr/mcp (streamable HTTP, stateless, MCP 2025-11-25): a fixed allowlist of operations as tools, named <backend>_<method> and described by the contract's own comments. The caller is whoever the token names, as on every other surface: the same rights, the same budget, the same record.

Scopes

A token reaches /mcp when it holds an MCP scope, and each tool needs its own:

ScopeTools
mcp:readthe tools that only read: the models and your budget, the sandbox's languages, the EVM lab's reads
mcp:generatethe tools that run a model: llm_generate, llm_embed, counted against your budget
mcp:writethe tools that change something: connection actions a grant gives the token (with connections:use), drafts, comments and reviews in your spaces (with decisions:write)
decisions:readbeside mcp:read, Decisions' reads: your spaces, their documents, versions, comments, reviews and diagrams
decisions:writebeside mcp:write, Decisions' writes (see Decisions)

tools/list lists only the tools the token may call. A call to a tool whose scope it lacks is 403 with WWW-Authenticate: Bearer error="insufficient_scope", scope="..." naming what the tool needs. A full API token (iohr.api) meets every scope.

Every tool says what it does through MCP's annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), so a client can ask you before it runs one that changes something.

Connecting an assistant

Give the assistant the address https://api.inorbit.hr/mcp and nothing else. It finds our sign-in, registers itself, and sends you to a page that names the app, where your browser goes back to afterwards, and what it may do in plain words. Allow it there; it then acts as you, under the scopes you allowed, until you revoke it under Sign-in and security → Connected apps in the console. The page does not ask again for 30 days. The app's access token lasts 15 minutes and is renewed with a refresh token that changes on every use.

  • claude.ai (and Claude Desktop): Customize → Connectors → Add custom connector, the address above, then Connect.
  • ChatGPT: Settings → Apps & Connectors → Advanced settings → turn on Developer mode, then Create, the address above, OAuth as the authentication.
  • Claude Code: claude mcp add --transport http inorbit https://api.inorbit.hr/mcp, then /mcp in a session and choose to authenticate.
  • Cursor: in ~/.cursor/mcp.json, {"mcpServers": {"inorbit": {"url": "https://api.inorbit.hr/mcp"}}}, then Connect in Settings → MCP.
  • VS Code: in .vscode/mcp.json, {"servers": {"inorbit": {"type": "http", "url": "https://api.inorbit.hr/mcp"}}}, then Start on the server.
  • Gemini CLI: gemini mcp add --transport http inorbit https://api.inorbit.hr/mcp, then /mcp auth inorbit.

An app that registers itself gets a public client (no secret, PKCE with S256) that may send you back to an https address or to a loopback address on your own computer, and nothing else; its tokens open /mcp and no other route. A client that only returns to your own computer (a loopback address) gets a warning on the page: any program on your computer could claim to be it, so allow it only right after you started the connection yourself. Registration is open to anyone and limited per address; a client nobody signs in with within 30 days is removed.

With an API token instead

Make an API token in the console with mcp:read (and mcp:generate if the assistant may run the models; decisions:read, or mcp:write and decisions:write as well, for Decisions), then:

claude mcp add --transport http inorbit https://api.inorbit.hr/mcp \
  --header "Authorization: Bearer $IOHR_TOKEN"

Or, for everyone working in a repository, in its .mcp.json with the token taken from the environment:

{
  "mcpServers": {
    "inorbit": {
      "type": "http",
      "url": "https://api.inorbit.hr/mcp",
      "headers": { "Authorization": "Bearer ${INORBIT_TOKEN}" }
    }
  }
}

Other assistants

Any client that sends a bearer header works the same way, with a token that holds the MCP scopes it needs:

// ~/.cursor/mcp.json, or .cursor/mcp.json in a project
{
  "mcpServers": {
    "inorbit": {
      "url": "https://api.inorbit.hr/mcp",
      "headers": { "Authorization": "Bearer ${env:INORBIT_TOKEN}" },
    },
  },
}

Who you are

accounts_get_me (title "Who am I", with account:read) answers who is calling: the person or API key the gateway verified, their own account, the team accounts they belong to, and for a key the scopes it carries. Call it first to learn which account_id the other tools take. Your model budget left today is llm_get_budget, and an account's spaces are decisions_list_spaces. It reads your own row only, never anyone else's.

Monitors

With connections:read, an assistant reads your monitors as evidence, under your rights in each account, and changes nothing:

  • connections_list_monitors: the account's monitors with their state (up, down, unknown, paused), narrowed by connection, agent, category or tags.
  • connections_get_monitor: one monitor, what it checks, from where and how often.
  • connections_list_monitor_runs: its check runs, newest first: when, from where, pass or fail, the latency and the kind of error. Never a response body.
  • connections_get_monitor_summary: uptime over 24 hours, 7 and 30 days, latency percentiles and the last failure.
  • connections_get_monitor_series: a time range in buckets, with the failures by kind.

Creating, changing, pausing and deleting a monitor stay in the console and the API.

Decisions

With decisions:read, an assistant works with your spaces as you do in Decisions, under your rights in each account:

  • Read. decisions_list_spaces (your spaces; space_id is a space's id), decisions_get_space, decisions_list_documents (with compact: true, each document as only its id, kind, number, title, status and access, to find one by), decisions_get_document (the text of a version and its findings; document_id takes the id, or what people call the document: RFC 0102.1, prd-12, adr 55, study 13, or its repository path docs/rfcs/0102.1-slug.md), decisions_list_versions, decisions_list_timeline, decisions_list_comments, decisions_list_reviews, decisions_list_review_queue (reviews asked of you), decisions_get_waiting (everything waiting on you across an account's spaces), decisions_list_questions, decisions_get_settings (a space's approval rules, including what assistants may approve), decisions_list_diagrams and decisions_get_diagram.
  • Write, with mcp:write and decisions:write. decisions_create_document starts a PRD, an ADR, an RFC or a study, decisions_save_document saves a draft as a new version, decisions_add_comment and decisions_resolve_comment take part in a thread, decisions_request_review asks people to review, decisions_submit_review asks for changes, decisions_set_status moves a document along its statuses, decisions_ask_question asks a person to settle something, and decisions_create_diagram and decisions_save_diagram draw. None of them removes anything, and each says so in its annotations.
  • Saving. A save names the base_version it was made from. If someone saved since, the tool answers an error with code: "conflict" and the current version's number; nothing is overwritten and nothing is retried. The assistant reads the document again, applies its change there and saves on that version.
  • Left to you. Approving a version, deciding or publishing a document, the spaces themselves and their settings, deleting a diagram and the export stay in the console. decisions_submit_review takes decision: "changes" only; an approval is refused before it reaches the service.
  • Names. These are the only names: the rfcs_* and labs_* tools and the rfc:* and lab:* scopes were replaced on 2026-10-08 (see the changelog).

A document is also a resource, inorbit://spaces/{space}/documents/{document}, read as Markdown with resources/read under the same scopes as decisions_get_document. resources/templates/list names the template; resources/list is empty, because documents are found with the tools.

Every tool

MCP tools lists each tool with its scopes, its arguments and an example call. It is generated from the server's own list on every build, so it never falls behind tools/list.

Discovery

/mcp is an OAuth protected resource. A request without a valid token is 401 with:

WWW-Authenticate: Bearer scope="mcp:read", resource_metadata="https://api.inorbit.hr/.well-known/oauth-protected-resource/mcp"

The metadata (RFC 9728) is public, at /.well-known/oauth-protected-resource/mcp and at the root address:

{
  "resource": "https://api.inorbit.hr/mcp",
  "authorization_servers": ["https://auth.inorbit.hr"],
  "scopes_supported": [
    "mcp:read",
    "mcp:write",
    "mcp:generate",
    "decisions:write",
    "decisions:read",
    "connections:use"
  ],
  "bearer_methods_supported": ["header"],
  "resource_name": "InOrbit",
  "resource_documentation": "https://developers.inorbit.hr/docs/transports/mcp"
}

A token is accepted when its audience is the API's (iohr-api) or this server's (https://api.inorbit.hr/mcp). A token minted for this server opens /mcp and no other route.

The sign-in's metadata is at https://auth.inorbit.hr/.well-known/oauth-authorization-server (RFC 8414). Besides the sign-in's own endpoints it names the registration endpoint (https://auth.inorbit.hr/oauth2/register, RFC 7591), S256 as the PKCE method and none among the token endpoint's authentication methods.