Why we made the MCP server a rule, not a feature

Every capability the panel has is a tool an agent can call. That is enforced as a shipping rule, and this is what it costs and what it buys.

Six glass sockets orbit a central hub, joined by one orange bridge

Most products that add an AI integration add a surface. A handful of endpoints get wrapped, the demo works, then the product moves on and the integration falls a year behind. The tell is the same: you can do a thing in the app that you cannot do through the API, and nobody can tell you which things those are.

The rule here runs the other way around. Every capability the panel has is a tool an agent can call. A feature ships on both surfaces or it does not ship, and a test fails when it does not.

The contract, in one table

EndpointPOST /mcp
Any other method405, JSON-RPC error -32000
TransportStreamable HTTP, stateless, JSON responses
AuthenticationAuthorization: Bearer pat_…, a personal access token
Unauthorized401, WWW-Authenticate header, JSON-RPC -32001
Authorized but refused200, with isError set on the result
Tools registered132

The last two rows are the ones that matter to anybody writing a client. A missing or bad credential is a transport-level failure and looks like one. Everything else, a ticket that does not exist, a role that is not allowed, a value that does not validate, comes back as a successful tool call carrying an error, so an agent can tell “I cannot reach this server” apart from “the server understood me and said no”. A known error keeps its own message; an unexpected one is replaced with Internal server error and the real type goes to the server log rather than to the client.

The rule is a test, not a promise

Parity is easy to claim and hard to keep, so it is checked. Every administrative capability the server knows about is required to carry both an HTTP route and an MCP tool. A capability missing either one fails the suite.

There is exactly one way out, and it is expensive on purpose: the capability has to be listed as a named exception with a reason attached, and the test asserts the reason is longer than 40 characters, because a label is not a decision. The suite also fails on a stale exception, meaning one written for a capability that is now fully served on both surfaces.

Three exceptions exist. Two of them are the same idea:

  • Creating a personal access token. A token is the credential an MCP client authenticates with. Minting one from inside an authenticated agent session would let a leaked token extend itself indefinitely.
  • Revoking one. The twin of the above: revocation stays on the surface that can also mint.
  • Accepting an invite. It is performed by the invited person against a token, not by an administrator acting on someone else’s behalf, so there is no agent-facing tool to expose.

A second test runs beside it and classifies every mutating tool as administrative or deliberately exempt, so a tool that changes something without writing an audit event cannot be added quietly.

One authorization module, two doors

The interesting part is not the MCP server. It is that the MCP tools and the panel’s HTTP routes call the same authorization module, which around 60 files in the server import. There is no second, looser path into your data.

That module also decides what a refusal reveals. No membership answers 404 rather than 403, because 403 confirms the project exists; an insufficient role answers 403. An agent gets the same two answers a browser does, for the same reasons.

So an agent holding your token is bound by exactly the roles you were granted. If someone removes you from a project, the agent loses that project at the same instant you do. And every change an agent makes lands on the ticket’s activity trail under your name, because it is not a separate integration acting on your behalf. It is you, with a different client.

What an agent gets that an API would not

An HTTP API assumes the reader already knows its shape. An agent does not, and guessing is where most tool use goes wrong.

So the server describes itself. The initialize handshake returns orientation instructions, and the get_documentation tool returns the whole manual, currently around 85 KiB of Markdown, as a single block of text. The same content is published as a resource. An agent can read the entire system without leaving the protocol, which is a better deal than hoping it inferred your pagination convention correctly.

The tool count is held to the same standard. It is asserted against a real tools/list response over an in-memory transport, so the number cannot drift from what the server registers, and a separate test pins every place the figure appears in prose. The manual, this site’s home page and the server itself have to agree, and they had already drifted to 19 and 122 against 132 before that test existed.

What it costs

Parity is a tax on every feature. Adding a settings toggle means adding the tool that sets it, and the tool has to enforce the same permission checks and produce the same audit event. A feature is not done when the screen works.

That tax is the point. The alternative, an API that covers the parts somebody remembered, is what makes agents useless for real work: the moment the model hits a gap, it has to hand the task back to you, and you are back to doing it by hand with extra steps.

Connecting

Create a personal access token in Personal settings → API & MCP, then:

claude mcp add -t http notarus https://<your-domain>/mcp \
  -H "Authorization: Bearer pat_…"

Ask it whoami on notarus to confirm the connection, then try something real: “list my tickets in Received and take the newest one.” That is list_tickets followed by assign_ticket("me"), and the ticket’s history will show that you did it. The full surface, with the transport and the error shapes a client has to handle, is on the developer reference.

Common questions

How many tools does the Notarus MCP server expose?

132, plus two canonical resources. The number is asserted against a real tools/list response over an in-memory transport, so it cannot drift from what the server actually registers, and a second test pins every place the figure is repeated in prose so the docs and the site cannot disagree with the code.

Is panel and MCP parity a convention or something the build enforces?

A test enforces it. Every administrative capability is required to have both an HTTP route and an MCP tool, and a capability missing either fails the suite unless it is listed as an exception with a written reason longer than 40 characters. Three exceptions exist today, each naming the decision behind it.

Can an agent do things through MCP that I cannot do myself?

No. The MCP tools and the panel's HTTP routes call the same authorization module, which around 60 files in the server import. An agent holding your token is bound by exactly the roles you were granted, and losing access to a project removes it from the agent at the same instant.

Why can an agent not create its own access token?

It is one of the three named parity exceptions. A personal access token is the credential an MCP client authenticates with, so minting one from inside an authenticated agent session would let a leaked token extend itself indefinitely. Revocation stays on the same surface, for the same reason.

What does an unauthorized MCP request return?

HTTP 401 with a WWW-Authenticate header naming the scheme, and a JSON-RPC error with code -32001. That is distinct from a tool call that is authorized but refused, which returns HTTP 200 with isError set on the result, so a client can tell a credential problem from a business one.

How does an agent learn what the Notarus MCP server can do?

The server documents itself. The initialize handshake returns orientation instructions, and the get_documentation tool returns the entire manual, currently about 85 KiB of Markdown, as one block of text. The same content is exposed as a resource, so an agent can learn the whole system without leaving MCP.

The Notarus team

The people who build Notarus. We write up the decisions behind the product when the reasoning is worth more than the changelog line.

Keep reading

Reports with the evidence attached.

Start free, one script tag.

<script src="…/widget.js" data-key="pb_pub_…">