MCP server
Connect any MCP-compatible agent to Apier's hosted Norwegian compliance tools — per-client config, a five-minute quickstart, and the full 26-tool reference.
[Cite this as: Apier.no Docs v0.1.0 — last updated 2026-07-19]
Apier ships a hosted Model Context Protocol (MCP) server so an AI agent can answer Norwegian compliance questions — what a company must file, who may act for it, and when obligations are due — without you teaching it Norwegian law or rebuilding the Altinn / Maskinporten / Brønnøysund integration. The agent discovers a set of deterministic tools and calls them; every answer is the same shape it would get over REST, plus a justification an agent can cite back to a user.
| Endpoint | https://www.apier.no/api/mcp |
| Transport | Streamable HTTP |
| Registry | no.apier/mcp (the official MCP registry) |
| npm package | @apier-no/mcp (a thin local proxy for stdio-only clients) |
| Auth | Bearer API key (discovery is keyless — see below) |
The same tool verdicts are available over plain REST — see the endpoint reference. MCP is the fastest path for an agent runtime; REST is the fallback for any HTTP client.
One-click install
The quickest way in: register the Apier MCP server with your client in a single click. Cursor uses a real install deep link; Claude Desktop has no install scheme yet, so the button copies a ready-to-paste config block. Both point at the same hosted endpoint — the detailed per-client configuration below is the manual alternative, and the place to add your API key.
MCP client install is available on desktop. See the connection guide
What you connect with
There are two ways to reach the server, and which one you use depends on your client:
- Direct streamable HTTP. Clients that speak remote MCP natively
(VS Code, the OpenAI Agents SDK, Azure AI Foundry, and recent
Cursor builds) connect straight to
https://www.apier.no/api/mcpand send the API key in anAuthorization: Bearerheader. - The
@apier-no/mcpstdio proxy. Clients that only speak stdio (Claude Desktop, older Cursor) launch the published npm package vianpx. It readsAPIER_API_KEYfrom the environment, scrubs it from the child process, and forwards it as the bearer header to the same hosted endpoint. No tool logic runs locally — everything resolves server-side.
Per-client configuration
Each block below is copy-paste ready. Replace the placeholder key with a real one from your dashboard — see getting a key — and keep it out of source control.
Claude Desktop
Edit claude_desktop_config.json (Settings → Developer → Edit Config):
{
"mcpServers": {
"apier": {
"command": "npx",
"args": ["-y", "@apier-no/mcp"],
"env": { "APIER_API_KEY": "apr_live_<your_key_here>" }
}
}
}Restart Claude Desktop; the Apier tools appear in the tool menu.
Windows: if Claude Desktop reports
spawn npx ENOENT, wrap the launcher — set"command": "cmd"and"args": ["/c", "npx", "-y", "@apier-no/mcp"], keeping the sameenv. The same applies to any stdio/npx-based client on Windows.
Cursor
Add the same server to ~/.cursor/mcp.json (global) or
.cursor/mcp.json (per-project):
{
"mcpServers": {
"apier": {
"command": "npx",
"args": ["-y", "@apier-no/mcp"],
"env": { "APIER_API_KEY": "apr_live_<your_key_here>" }
}
}
}VS Code
VS Code (Copilot agent mode) speaks remote MCP natively, so it
connects to the endpoint directly. Add .vscode/mcp.json:
{
"servers": {
"apier": {
"type": "http",
"url": "https://www.apier.no/api/mcp",
"headers": { "Authorization": "Bearer apr_live_<your_key_here>" }
}
}
}OpenAI Agents SDK
Wire the endpoint as a MCPServerStreamableHttp server and hand it to
an Agent (Python):
import asyncio
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
async def main():
async with MCPServerStreamableHttp(
name="apier",
params={
"url": "https://www.apier.no/api/mcp",
"headers": {"Authorization": "Bearer apr_live_<your_key_here>"},
},
) as apier:
agent = Agent(
name="Compliance assistant",
instructions="Use Apier's tools for Norwegian compliance questions.",
mcp_servers=[apier],
)
result = await Runner.run(agent, "What does org 999999999 owe?")
print(result.final_output)
asyncio.run(main())Azure AI Foundry
Register the endpoint as an MCP tool on a Foundry agent. Auth headers are passed per run and are not persisted by Foundry (Python):
from azure.ai.agents.models import McpTool
apier = McpTool(
server_label="apier",
server_url="https://www.apier.no/api/mcp",
)
apier.update_headers("Authorization", "Bearer apr_live_<your_key_here>")
agent = project_client.agents.create_agent(
model="gpt-4o",
name="compliance-assistant",
instructions="Use Apier's tools for Norwegian compliance questions.",
tools=apier.definitions,
)Getting a key
Sign up and open your dashboard to
create a key. It is shown in full exactly once — store it
securely. Issued keys are prefixed apr_test_ (synthetic data) or
apr_live_ (production). See Authentication
for the full key model, tiers, and rate limits.
Try it without a key
tools/call also accepts the synthetic sandbox bearer — no signup, no
key provisioning:
Authorization: Bearer apier_sandbox_test_<suffix>Always append a unique random <suffix> (for example a fresh UUID) so
your session never collides with another agent's. With a sandbox
bearer, the read tools get_company_summary, get_company_context,
get_company_obligations, get_company_deadlines, and
explain_compliance_error answer from deterministic synthetic
fixtures (every response carries _meta.is_sandbox: true), and
submit_vat_return runs its usual sandbox flow. Use the reserved
sandbox org numbers from GET /api/v1/sandbox/fixtures — the magic
scenario pool there covers a plain active AS, a bankrupt company, an
ENK, and more. Tools without a sandbox route return a deterministic
SANDBOX_TOOL_UNAVAILABLE error; no sandbox call ever reaches
production data or a government system.
How bearer auth works
The MCP server splits a keyless discovery surface from an authenticated call surface:
- Keyless (no key needed) — the whole handshake and discovery
surface:
initialize,notifications/initialized,tools/list,ping,prompts/list,prompts/get,resources/list,resources/templates/list,resources/read(public rulebook resources only), andcompletion/complete. A client can complete the MCP handshake and read the full catalogue before presenting any credential; the discovery response is byte-identical for every caller. - Authenticated (key + scope) —
tools/call(except the five keyless public read tools —get_public_obligations,get_public_deadlines,explain_compliance_error,get_exchange_rate,get_pricing— which execute with no credential at all, andredeem_issuance_token, which needs no API key but DOES require a credential: the one-time owner-issued issuance token in its arguments), andresources/readfor company-specific resources. Otherwise a missing or invalid key returns a JSON-RPC-32001error with aWWW-Authenticate: Bearerchallenge, never a result. Each tool's required scope is in the tool reference below.
Every response also carries the negotiated MCP-Protocol-Version
header — see Supported protocol versions
for the full list.
The @apier-no/mcp proxy injects the bearer header for you from
APIER_API_KEY; the direct-HTTP clients above set it themselves.
OAuth is coming. Today authentication is a bearer API key. An OAuth 2.1 authorization-code flow — so an agent can obtain and refresh a key without copy-pasting one — is planned for a later release. The bearer key will keep working.
Supported protocol versions
Apier negotiates the MCP protocol version during initialize and echoes
the agreed value on the MCP-Protocol-Version response header. The server
supports, newest first:
2025-11-25(latest) — structured tool output, truthful tool annotations, per-tool icons, andverb_nountool naming.2025-06-182025-03-262024-11-05
A client that requests any of these gets it back verbatim; a client that requests an unknown version is offered the server's highest. Every newer field — title, annotations, output schema, icons — is additive, so an older client simply ignores what it does not understand.
Roadmap — not implemented. The
2026-07-28release candidate (the Tasks extension and MCP Apps) is not supported. Its design is still changing, so Apier has deliberately not built against it; this page will be updated when that work lands.
Five-minute quickstart
- Add the config for your client from the section above, using a
real key. (No key yet? You can still explore the tool catalogue —
tools/listis keyless — but calling a tool needs one.) - Restart the client so it picks up the new server.
- Ask a compliance question in natural language. The agent reads the tool catalogue, picks the right tool, and calls it:
You: What does org 999999999 owe?
Agent: (calls get_company_obligations with org_number "999999999")
Org 999999999 has these active obligations:
• MVA (VAT) return — filed per term — Merverdiavgiftsloven § 15-1
• A-melding — monthly employer/payroll report — A-opplysningsloven § 3
• Årsregnskap — annual accounts — Regnskapsloven § 8-2
Source: Brønnøysund + Apier Universal Rulebook. Each verdict
carries its legal_reference, so I can show you exactly which
rule applies.Under the hood the agent issued a single tools/call:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "get_company_obligations",
"arguments": { "org_number": "999999999" }
},
"id": 1
}Apier resolves it against the live Rulebook and returns the structured
obligation set. 999999999 is the documentation example org; to
rehearse the full authenticated surface — per-company context, dry-run
filings, receipts — with zero risk and no signup, point your agent at
the sandbox (it never calls a government system and tags
every response _meta.is_sandbox: true).
The response envelope
tools/call returns the MCP spec CallToolResult: the tool's answer is
serialized into a text content block and mirrored on
structuredContent, with isError flagging failures — so the official
MCP SDK client parses it without special handling:
{
"content": [{ "type": "text", "text": "{ …the envelope below, as JSON… }" }],
"structuredContent": {
"result": { "...": "the normalised tool payload" },
"justification": {
"rules_applied": ["MVA_FILING_BIMONTHLY"],
"source_data": ["brreg", "rulebook"],
"valid_until": "2026-07-01T00:00:00Z"
},
"metadata": {
"query_id": "…",
"resolved_at": "2026-06-05T08:00:00Z",
"data_sources": ["brreg", "rulebook"],
"schema_version": "2026.6.0",
"tool_name": "get_company_obligations"
}
},
"isError": false
}structuredContent is the same three-part envelope every tool returns, so
an agent parses results uniformly. justification is the audit signal —
which rules and upstream sources produced the answer, and when it goes
stale. On failure, isError is true, result is null, and metadata
carries a stable error_code from a closed
vocabulary plus a safe error_message (never a stack trace or raw
upstream body), a retryable boolean (true = repeating the same
call after a short backoff can plausibly succeed; false = change the
input or credential first — an identical retry fails identically), and
a one-sentence remediation hint. When an upstream code had to be
collapsed or renamed to keep the vocabulary closed (for example an
undocumented code surfacing as UPSTREAM_UNMAPPED, or a revoked
delegation surfacing as DELEGATION_REVOKED), the raw code is
preserved on metadata.upstream_code.
Tool reference
26 tools are live. Names are verb_noun, so an agent can read
the intent from the name alone. 22 are read-only; four model
writes — submit_vat_return (a VAT return, locked to the sandbox),
the two Fullmakt Rails delegation tools request_fullmakt and
revoke_fullmakt (AGT-02), which broker and revoke an agent's scoped
authority to act for a company through an Altinn systembruker, and
redeem_issuance_token, which converts an owner-minted one-time
issuance token into the agent's own API key (a write against Apier's
own account state only — no government system is touched). "Live"
here means the route is callable: the Fullmakt Rails writes are
mock-adapter-backed pending live partner validation and make no live
Altinn PDP or execution call yet.
submit_vat_return is deliberately not listed in tools/list
discovery — an agent enumerating the server sees 25 tools (22 reads
plus the two Fullmakt Rails delegation writes plus the keyless
issuance-token redemption), and calls submit_vat_return by name when
it needs the sandbox VAT flow (it stays fully callable over
tools/call). The other 25 each ship a longer description, a
structured output schema, truthful behaviour hints, and worked
examples in their tools/list entry — clients surface these
automatically.
Company intelligence
| Tool | Title | What it does | Scope |
|---|---|---|---|
search_companies | Search companies by name | Resolve a company name to its org number — up to 10 candidates (name, org_number, org_form, municipality, status). Start here when you have a name but not a number, then call the tools below with the chosen org number. | read:brreg |
get_company_summary | Company compliance summary | One-shot identity and compliance verdict for an org number — the broadest single call. | read:brreg |
get_company_verification | Company verification verdict | One verdict for an org, keyed on two facts: actively registered + signing authority visible (signaturrett, prokura, or the ENK innehaver). Not binary: unknown is returned when the status is indeterminate or no signing authority is visible — never inferred as fail. Bankruptcy (konkurs), liquidation (avvikling), dissolution (oppløst), filed accounts and MVA are surfaced alongside as transparency-only signals — they never change the verdict (a distressed company already reports a non-active status and fails on that). | read:brreg |
get_company_context | Company registry facts | Brønnøysund identity slice only (name, form, NACE, addresses, role codes) — no compliance verdict. | read:brreg |
get_company_profile | Company profile (Brønnøysund) | Structured Enhetsregisteret profile: name, form, NACE, addresses, status, MVA flag, role codes. | read:brreg |
get_company_obligations | Company regulatory obligations | Every applicable obligation with its current state and legal reference, evaluated against the live Rulebook. | read:brreg |
get_company_deadlines | Company filing calendar | Upcoming filing dates per obligation and period — Europe/Oslo, DST- and holiday-aware — over a horizon you choose. | read:brreg |
get_company_authority | Company signing-authority resolver | Who can legally sign for the company, and how — sole / joint / by_role / prokura_only / no_authority / unknown, normalised from Brønnøysund's Fullmakttjenesten combined with the registered role holders. No legal citation asserted. | read:brreg |
get_company_accounts | Company annual accounts snapshot | Current-snapshot årsregnskap from the open Regnskapsregisteret: filed-status (tri-state), most-recent accounts year, and that year's key figures (currency always surfaced). | read:brreg |
get_company_filing_history | Company filing history (Altinn) | The company's Altinn 3 filing instances, each paired with the Apier audit-log entry that produced it (filed_via_apier) — the accountant/auditor reconciliation wedge. Offset-paginated. Mock-gated until the live Altinn scope is approved. | read:altinn |
Three details of these tools are worth knowing before you wire them up:
get_company_summarypayload equivalence. Itsobligations[]array is byte-identical to whatget_company_obligationsreturns (same rule evaluation, shared cache), and itsdeadlines[]array matchesget_company_deadlinesover the same horizon for Tier 1 companies — on Tier 2 the summary'sdeadlines[]additionally carry a definitivefiling_status(filed/overdue) from compliance state. Because the summary tool takes only{ org_number }, callget_company_deadlineswhen you need to controlhorizon_months, orget_company_obligationsfor per-obligation drill-down.- MOD-11 validation. For
get_company_summary,get_company_context,get_company_obligations, andget_company_deadlines, a 9-digitorg_numberthat fails the MOD-11 control-digit check is rejected up-front asVALIDATION_FAILEDbefore any request is sent.get_company_profileis the exception: it does not run MOD-11 in its input schema, so a MOD-11 failure surfaces from the backing route asORG_NUMBER_INVALID_CHECKSUM(HTTP 400). Either way, correct the number rather than retrying the same one. get_company_profileuses POST. Its backing REST route isPOST /api/v1/brreg/company-profile(the org number goes in the JSON body), whereas the sibling company tools areGET /api/v1/company/{org}/…. This is a known method inconsistency — do not assumeGETwhen falling back to raw HTTP.
Public lookups (no org number required)
| Tool | Title | What it does | Scope |
|---|---|---|---|
get_public_obligations | Obligations by entity type | Baseline obligations an entity owes by being that form (AS, ENK, NUF, …), before per-company data. | read:rulebook |
get_public_deadlines | Norwegian filing calendar | The universal filing calendar for a year — MVA, A-melding, årsregnskap. | read:rulebook |
get_exchange_rate | Norges Bank exchange rate | The latest Norges Bank NOK reference rate for an ISO-4217 currency (NOK-anchored — exactly one of base/quote must be NOK; optional date). | read:norgesbank |
get_altinn_migration_guidance | Altinn 2 → 3 migration guidance | The Altinn 3 equivalent of an Altinn 2 service or role code, plus the Oslo-computed post-cutoff status of the 19 June 2026 Altinn 2 deprecation (now passed — deadline_passed is true, days_remaining is 0). Gate production migration actions on verified === true. Backing route is zero-auth; the MCP tool gates on read:digdir. | read:digdir |
Change archive
| Tool | Title | What it does | Scope |
|---|---|---|---|
list_changes | Query the cross-source change archive | Paginated, filterable read over every detected created / updated / deleted event across Apier's upstreams (Brønnøysund, Altinn schemas, DigDir policies, Norges Bank rates). Drive an incremental sync instead of re-fetching whole entities. HMAC-signed keyset cursors. | read:changes |
Authorisation
| Tool | Title | What it does | Scope |
|---|---|---|---|
check_authorization | Authorisation snapshot | Your delegation status on an org: granted vs missing scopes and the delegation chain. | read:altinn |
list_acting_capacity | Acting capacity for a person | The actions a person may take for an org, derived from their Altinn roles, each with a legal citation. | read:altinn |
Delegation (Fullmakt Rails)
| Tool | Title | What it does | Scope |
|---|---|---|---|
request_fullmakt | Request a fullmakt (broker a systembruker delegation) | Write. Brokers an Altinn systembruker delegation for a company and binds the returned system_user_id onto your agent principal (write-once; a pending principal becomes active). Altinn returns a delegation_url the company's signing authority must approve before the delegation is usable. Mock-adapter-backed pending live partner validation. Supports Idempotency-Key. | read:altinn |
check_fullmakt | Check your fullmakt state for a company | Read. Which of your agent principals hold live delegated authority for the org — overall_status is full / partial / none, with fix_steps naming any blocker. Reports the delegation state Apier recorded when it brokered the fullmakt, not a live Altinn PDP decision. none is a valid 200, never a 404. | read:altinn |
revoke_fullmakt | Revoke a fullmakt (retire a delegation + its principal) | Write. Withdraws the delegation (append-only: a status='revoked' marker row supersedes the original) and flips the principal to terminal revoked. Idempotent — revoking an already-revoked principal is a 200 no-op. Named warning tokens distinguish partial outcomes. Supports Idempotency-Key. | read:altinn |
Actions
| Tool | Title | What it does | Scope |
|---|---|---|---|
validate_action | Validate a regulatory action (dry-run) | Run a proposed filing through the five prerequisite checks with zero upstream side effects. | read:actions |
submit_vat_return | Submit VAT return (sandbox) | Sandbox-only MVA filing — preview without an approval token, or file a mock receipt with one. Never contacts a real government system. Not advertised in tools/list — call it by name. | read:actions |
Billing & credits
| Tool | Title | What it does | Scope |
|---|---|---|---|
get_pricing | Apier price list (keyless) | The machine-readable price list: per-call cost in whole øre for every metered endpoint/tool, whether credit enforcement is live, the 402 recovery-contract shape, top-up bounds, and the how-to-pay guide URL. Keyless — executes without an API key, so an agent can price a workflow before it holds any credential. Call it before metered work. | read:pricing |
get_credit_balance | Own prepaid credit balance | The calling key's own remaining prepaid balance in whole øre, with updated_at and the top_up_url a human uses to fund the key. Takes no input — it can only ever return the authenticated key's own balance. Call it before a batch of metered calls to confirm the balance covers it. The backing REST route is deliberately scope-exempt; the MCP tool's read:credits is satisfied by the default read:* grant. | read:credits |
Onboarding
| Tool | Title | What it does | Scope |
|---|---|---|---|
redeem_issuance_token | Redeem an owner-issued key-issuance token (keyless) | Convert a one-time issuance token the account owner minted in the dashboard into the agent's own read:*-scoped API key. Keyless — the presented token IS the credential. Single-use and atomic; the plaintext_key is returned exactly once and never logged. Minting and revoking issuance tokens are deliberately dashboard-only (owner-issued security model) — there is no mint tool to look for. | read:onboarding |
The full headless onboarding journey for an agent that arrives over
MCP with no credential: the account owner mints a one-time issuance
token in the dashboard and hands it to the agent out-of-band → the
agent calls redeem_issuance_token (keyless) and receives its own
read:*-scoped API key exactly once → every subsequent call
authenticates with Authorization: Bearer <plaintext_key> — starting
with, say, get_credit_balance to confirm the account's balance
before metered work (get_pricing needs no key at all).
Errors
| Tool | Title | What it does | Scope |
|---|---|---|---|
explain_compliance_error | Explain a compliance error | Turn any Apier error_code into a Norwegian-bokmål explanation with fix steps and, where applicable, a legal basis. | read:rulebook |
Keys carry a scopes array (default read:*, which grants any
read: action). A call whose key lacks the required scope returns
SCOPE_INSUFFICIENT. Reserved prefixes (write:, act:, delegate:)
are not assignable — which is why submit_vat_return needs only
read:actions: the human approval gate, not the agent's key,
authorises the mock filing.
REST-only surfaces
The MCP server exposes the read and dry-run tools an agent needs to reason about Norwegian compliance. Some Apier products are deliberately REST-only — they have no MCP tool, by design. The two surfaces are not meant to be identical: everything an agent should call autonomously is an MCP tool; everything that needs an operator, a human decision, or a financial/legal side effect stays on REST.
- Account management — creating and managing your own consumer account is an operator task behind a session, not an agent tool keyed on an API key.
- Admin / key management — minting and revoking API keys is gated by an operator secret, a different trust tier from an agent's key.
- Billing — subscription and usage endpoints are account-owner operations with financial side effects, kept off the agent surface.
- Privacy / data-subject requests — GDPR erasure and export are identity-verified human workflows, never an autonomous agent action.
- Sandbox rehearsal — the guided write-loop rehearsal is a stateful REST flow; agents reach the sandbox through the same read tools with a sandbox bearer instead.
- Human-in-the-loop approval — approving or rejecting a pending binding
action is the human gate that must sit outside the agent's own credentials
(the reserved
act:scope is never agent-assignable).
Next steps
Authentication
The full key model — formats, tiers, scopes, and rate limits.
Quick start
Zero-auth REST calls in under five minutes — no key required.
Endpoint reference
Every tool verdict is also a REST endpoint, backed by the OpenAPI spec.
SDKs
Official Python and MCP packages, plus spec-driven client generation.
Quick start
Your first Apier.no call in under five minutes — no signup, no API key.
Fullmakt Rails
Brokered, scoped, revocable authority (fullmakt) that lets a Norwegian company delegate a specific mandate to an AI agent through an Altinn systembruker — designed for machine-to-machine acting. Live over REST and MCP, mock-adapter-backed pending live partner validation.