Skip to content

The MCP server

Reference for M1rror's MCP server, covering Streamable HTTP transport, OAuth 2.1 and agent tokens, scopes, effective permissions, limits and errors.

On this page

Endpoint and transport

URLhttps://mcp.m1rror.com/mcp (self-hosted deployments show theirs in Connect your agent)
TransportStreamable HTTP, stateless: each POST /mcp carries its own Authorization: Bearer header
HealthGET /healthz
Server namem1rror

A local stdio mode also exists for development (--stdio, with the token in M1RROR_TOKEN).

Authentication

The server accepts two kinds of token. Anything else gets 401 invalid_token.

M1rror follows the MCP authorization specification:

  • Protected resource metadata at /.well-known/oauth-protected-resource/mcp points clients at the authorization server, https://m1rror.com/api/auth.
  • Clients register dynamically (RFC 7591) as public clients and must use PKCE with S256. Tokens are bound to the MCP server with resource indicators (RFC 8707).
  • On the consent screen the person chooses the workspace and the permissions.
  • Access tokens last 1 hour; refresh tokens rotate and last 30 days. An OAuth grant lasts 90 days.

Agent tokens

Personal agent tokens are created in Connect your agent or Agent access. They're shown once, stored only as a hash, can be limited to one project and expire after at most 90 days.

Scopes

ScopePermissions
m1rror:readRead projects, references, designs, releases, build plans and runs.
m1rror:draftWrite references and draft designs, ask for a review, submit evidence and prepare build plans.

Effective permissions

On every request, an agent's authority is the intersection of its grant, its token's scopes and the current permissions of the person who connected it. If that person loses a role, the agent loses it too.

Agents never receive approval, billing, membership, ownership, policy or integration permissions, can't open pull requests and never see actions that require explicit human confirmation.

Tool profiles

Every grant also has a tool profile, which decides which tools the agent sees and may call. A profile never adds permissions: the scopes and the connecting person's permissions still apply on top.

ProfileToolsDefault for
implementer14 tools for building an approved release and reporting back (listed below)OAuth connections, tokens from Connect your agent, and new tokens in Agent access
fullEvery tool the grant's permissions allow (223 tools in all)Grants made before profiles existed, or a token created with Tools › Full (every permitted tool)

The implementer tools are:

  • What to build: taste_get_implementation_brief, taste_get_project_context, taste_list_releases, taste_get_release, taste_diff_releases, taste_list_implementation_contracts, taste_get_implementation_contract.
  • Reporting back: taste_link_pull_request, taste_submit_implementation_progress, taste_submit_evidence.
  • Where it stands: taste_get_ship_ledger, taste_list_pr_checks, taste_get_pr_check, taste_start_ci_check (check a commit from CI).

Coding agents work better with a short tool list: the implementer listing is about 11 KB, against about 181 KB for every tool.

Choose a profile

  • Agent access › new agent token › Tools: Implementer (14 tools) or Full (every permitted tool).
  • Connect your agent creates an implementer token in one click.
  • OAuth connections get the implementer profile.

Narrow a connection

Add ?profile=implementer to the server URL to use only the implementer tools on that connection, even with a token that has the full set:

Code
https://mcp.m1rror.com/mcp?profile=implementer

In local stdio mode, set M1RROR_TOOL_PROFILE=implementer instead. A profile on the URL can only narrow a grant, never widen it: an implementer token stays implementer with ?profile=full.

Calling a tool outside the profile fails with forbidden and the reason outside_tool_profile.

Resources

Besides tools, the server offers read-only resources: context a coding agent can load without calling a tool. Each one is JSON (application/json).

ResourceURIWhat it holds
Design systemm1rror://projects/{project_id}/systemThe token document with resolved values, contrast checks and diagnostics, and the component registry with binding status
Screen specm1rror://projects/{project_id}/screens/{screen_id}The screen's component tree, its states and any agent draft waiting for review
Screen flowm1rror://projects/{project_id}/flowLinks between screens, broken links and the named flows
Releasem1rror://projects/{project_id}/releases/{release_id}An immutable design release: payload, digest and content
Implementation contractm1rror://projects/{project_id}/contracts/{contract_id}Digest, scope, budget and authorization status
Surface brandm1rror://projects/{project_id}/surfaces/{surface_id}/brandThe brand a surface uses and its resolved tokens, with the layer each value comes from
Audit findingsm1rror://projects/{project_id}/findings{?repository_id}Findings from the newest design audit, with file and line
  • resources/templates/list returns the URI templates above. resources/list returns concrete URIs for your projects, 10 projects per page.
  • Reading a resource runs the same governed read as the matching tool, so the same permissions and tool profile apply. You only see the resources your connection can read. With the implementer profile, that is releases and implementation contracts.
  • An unknown id, or an id from another workspace, fails with "Resource not found" (-32002).
  • Subscriptions are not offered. The server is stateless, so it can't notify you when a resource changes. Read it again instead.

Prompts

Prompts are ready-made instructions that pull in the right resources. Your client lists them with prompts/list and shows them as slash commands or templates.

PromptArgumentsEmbeds
implement_screenproject_id, screen_id, optional surface_id and contract_idThe screen spec, the design system (or the surface brand), and the contract if given
implement_releaseproject_id, release_id, optional contract_idThe release, and the contract if given
fix_design_driftproject_id, optional repository_idThe latest audit findings and the design system
build_flowproject_id, optional flow (a flow name)The screen flow and the design system

If your connection can't read an extra resource, such as the design system, the prompt leaves it out and says so. If it can't read the main one, the prompt fails.

Waiting for a run

Scans, captures and other long jobs return a run id. Call taste_wait_for_run with the run id and a timeout_s of up to 50 seconds. It returns as soon as the run finishes (done: true), or with the current status and done: false when the time runs out. Call it again to keep waiting.

Limits

  • 120 requests per minute per token.
  • Request bodies up to 40 MB.
  • Browser requests from other origins are refused.

Retries

Every tool that changes something accepts an optional idempotency_key: a string of 8 to 128 characters, such as a UUID. If a call times out and you retry it with the same key and the same arguments, M1rror returns the first result. Nothing is created or charged twice.

  • The same key with different arguments fails with idempotency_mismatch.
  • If the first call is still running, the retry fails with conflict. Wait and try again.
  • If the first call failed, the retry runs again.

Keys belong to your connection and to one tool. Use a new key for each new change.

Work that runs later

Scans, captures, generations and previews run in the background. Before one starts, M1rror checks again that your connection and the person who created it still have access. If access was removed in the meantime, the run stops with forbidden: access changed after this was queued, and nothing is charged.

Errors

Tool errors use M1rror's error codes, for example forbidden, not_found, validation_failed, stale_revision (someone changed it first: re-read and retry), conflict, idempotency_mismatch (an idempotency_key reused with different arguments), budget_exhausted, gated_capability (not set up on this deployment) and rate_limited. Each error says whether it's safe to retry.

Two you are likely to meet with the implementer tools:

  • forbidden with outside_tool_profile: the tool isn't in this connection's profile. Use a token with the full profile, or a tool from the list above.
  • conflict with release_not_approved: the release isn't approved, so there is nothing to implement or link yet.

Last updated

Edit this page on GitHub