Short answer
An MCP server exposes a business system’s tools and data to any Model Context Protocol client, such as Claude, ChatGPT or an in-house agent, through one standard JSON-RPC interface. Under the current 2026-07-28 specification, servers are stateless, authorise with OAuth, and can pause a tool call to ask the user for confirmation. For New Zealand businesses, Xero and HubSpot already publish remote MCP servers.
- MCP 2026-07-28 removed sessions and the initialize handshake; every request is self-describing.
- Gateways can authorise per tool using the required Mcp-Method and Mcp-Name headers.
- Token passthrough is forbidden: validate audience and use the server’s own downstream credentials.
- Xero’s remote MCP tools do not ask for confirmation before writes, per its FAQ.
- Expose narrow tools with minimal scopes; keep approvals in your own layer.
When a business system needs an MCP server
An MCP server is worth building when more than one AI client needs governed access to the same system. The Model Context Protocol defines hosts (AI applications), clients (connectors inside them) and servers (services offering tools, resources and prompts), all speaking JSON-RPC 2.0. Build the server once, and Claude, ChatGPT, Copilot and your own agents can all use it under the same scopes and logs.
If one application owns its tools, skip MCP and use native function calling; the contract rules in our guide to AI tool calling in production apply either way. If a vendor already publishes a server, start there:
| Vendor server (as documented on 19 October 2026) | Status | What matters for design |
|---|---|---|
| Xero Remote MCP | Available to developer apps; real organisations need the Core plan or above | OAuth 2.0 with PKCE; each call runs against one organisation; V1 tools do not ask the user to confirm writes; only API calls are logged, not prompts or tool calls; 1,000 calls per day per organisation on Starter, 5,000 on Core and above |
| HubSpot remote MCP server | Generally available since 13 April 2026 | OAuth 2.1 with PKCE; reads and writes CRM records and activities; respects existing user permissions; activity objects blocked when sensitive data is turned on |
| Microsoft MCP Server for Enterprise | Public preview | Read-only Microsoft Graph queries over Entra identity and directory data, honouring user roles and granted scopes |
The Xero FAQ is explicit that its server does not confirm before changing data and that you must log the agent’s reasoning yourself. That gap is the usual reason NZ firms put their own server or approval layer in front. Our Xero integration guide and HubSpot integration guide cover the vendor options in more depth.
What changed in the 2026-07-28 specification
The 2026-07-28 revision turned MCP into a stateless request and response protocol, which makes servers ordinary HTTP workloads. These are the changes that affect a business-system server most:
| Change | What it means for your server |
|---|---|
No initialize handshake and no Mcp-Session-Id; version and client capabilities travel in each request’s _meta |
Run several instances behind a plain round-robin load balancer; no sticky sessions or shared session store |
server/discover is a mandatory RPC |
Use it for version negotiation and health checks |
Mcp-Method and Mcp-Name headers required on Streamable HTTP POSTs |
Your gateway can authorise, rate-limit and meter per tool without parsing bodies |
| Cross-call state uses explicit handles passed as tool arguments | Check the caller’s authorisation against the handle on every call |
Multi Round-Trip Requests: a tool can return resultType: "input_required" |
Ask the user to confirm a write mid-call without holding a stream open |
List results carry ttlMs and cacheScope; tools/list SHOULD be in deterministic order |
Stable tool catalogues keep clients’ prompt caches warm |
| Roots, Sampling and Logging deprecated (twelve-month minimum window) | Pass paths as parameters, call model APIs directly, log to stderr or OpenTelemetry |
Dynamic Client Registration deprecated in favour of Client ID Metadata Documents; clients MUST validate the iss parameter (RFC 9207) |
Plan client registration on CIMD; closes authorisation-server mix-up attacks |
A reference integration
Illustrative example: a Christchurch trades business runs jobs in a field-service system and accounts in Xero. Staff want to ask Claude or ChatGPT about jobs, log notes, prepare quotes and raise draft invoices. The design puts one MCP server in front of both systems:
- Identity. Staff sign in through the firm’s identity provider. The MCP server accepts only tokens whose audience is the MCP server itself.
- Gateway. A gateway reads
Mcp-Name, checks the token’s scopes against that tool, applies per-user and per-tool rate limits, and forwards to any stateless server instance. - Server. Each tool is a narrow verb with a strict
inputSchema. The server calls the downstream APIs with its own credentials, scoped to what the tool needs. - Confirmation. Tools with external effects return
input_requiredwith a plain summary (recipient, amount, line items) and a signedrequestState, then execute only on an accepted retry. - Audit. Every call records user, client, tool, argument hash, decision and the downstream request ID, so you can answer “who did this, through which AI app” later.
The permission model is the part to agree with the business owner first:
| Tool | Scope | Side-effect class | Approval |
|---|---|---|---|
search_jobs, get_job |
jobs:read |
Read | None |
add_job_note |
jobs:notes.write |
Reversible write | None; logged |
draft_quote |
quotes:draft |
Reversible write | None; stays a draft |
create_draft_invoice |
invoices:draft |
Reversible write | None; stays a draft in Xero |
send_quote_to_customer |
quotes:send |
External effect | User confirms each send |
| Approve or pay invoices | Not exposed | Irreversible | Stays in Xero, done by a person |
Not exposing a capability is the strongest control you have. The MCP security guidance lists the common scope mistakes: publishing every scope in scopes_supported, wildcard scopes such as files:*, and bundling unrelated privileges up front.
A tool handler with scope checks and confirmation
The sketch below is framework-neutral. Field names follow the 2026-07-28 tools specification; error code -32020 is the specification’s HeaderMismatch code.
import hmac, hashlib, json
def handle_tools_call(req, principal, tools, secret: bytes):
params = req.json["params"]
tool = tools.get(params["name"])
if tool is None or req.headers.get("Mcp-Name") != params["name"]:
return rpc_error(req, -32020, "Mcp-Name header does not match the tool name")
if tool.scope not in principal.scopes:
return tool_error(f"Missing scope {tool.scope}. Ask an administrator.")
args = tool.validate(params["arguments"]) # strict inputSchema, raises on failure
for handle in tool.handles(args): # e.g. quote_id minted earlier
if not owns(principal, handle):
return tool_error("Unknown or inaccessible handle.")
if tool.side_effect == "external":
digest = hashlib.sha256(json.dumps(args, sort_keys=True).encode()).hexdigest()
expected = hmac.new(secret, f"{principal.sub}|{tool.name}|{digest}".encode(),
hashlib.sha256).hexdigest()
reply = (params.get("inputResponses") or {}).get("confirm")
if not reply or params.get("requestState") != expected or reply["action"] != "accept":
return {"resultType": "input_required",
"inputRequests": {"confirm": {"method": "elicitation/create", "params": {
"mode": "form", "message": tool.summary(args),
"requestedSchema": {"type": "object", "properties": {},
"additionalProperties": False}}}},
"requestState": expected}
result = tool.run(args, credentials=tool.downstream_credentials())
audit(principal, req, tool, args, result)
return {"resultType": "complete", "content": result.content,
"structuredContent": result.data, "isError": False}
Binding requestState to the user, tool and exact arguments means a confirmation for one quote cannot be replayed to send a different one. Confirmation through elicitation only works when a person is at the client; for headless agents, route the same summary to an approval queue instead, as described in our guide to agent permissions and approvals.
Security rules that are easy to get wrong
Most MCP security problems are OAuth and authorisation problems, not model problems. The specification’s security best practices call out these, among others:
- Token passthrough is forbidden. Accepting a token issued for another service and forwarding it downstream breaks audience validation and audit trails. Validate the audience, then use the server’s own credentials.
- State handle hijacking. A handle is a name, not a capability. Validate authorisation against it on every call; for unauthenticated servers, use high-entropy handles with a bounded lifetime.
- Annotations are untrusted. Clients MUST treat hints such as
readOnlyHintanddestructiveHintas untrusted unless the server is trusted, so never let a third-party server’s annotation decide whether a write needs confirmation. - Tool results carry injected instructions. A customer email returned by
get_jobcan contain text aimed at the model. Test this deliberately with the cases in our prompt injection testing guide. - Confused deputy. Proxy servers that use a static client ID with a third-party authorisation server need per-client consent, or an attacker can obtain codes without the user’s agreement.
Where MCP integrations go wrong
The protocol is now stable enough that failures come from design choices:
- Wrapping the whole API. A server that exposes every endpoint as a tool gives the model too much choice and too much authority. Expose the ten verbs the workflow needs.
- Trusting vendor defaults for writes. Xero’s FAQ says its V1 tools do not elicit confirmation. If your process needs a check, it has to live in your client, server or approval layer.
- Missing the reasoning in the log. Vendor logs record API calls, not the prompt or the tool call that caused them. Keep your own AI audit log joined on request IDs.
- Session-era code. Servers that stored state against
Mcp-Session-Idneed migrating to explicit handles; the old HTTP+SSE transport is deprecated. - Unstable tool lists. Reordering or rewording tool definitions on every deploy breaks client prompt caches and changes model behaviour. Version tool definitions and test changes against an evaluation set.
For teams starting out, our lesson on connecting AI to your CRM covers the non-technical decisions, and our AI integration service builds and runs servers like the one above.
- The server targets protocol version 2026-07-28 and implements
server/discover - No state depends on sessions; handles are checked against the caller on every call
- The gateway authorises and rate-limits on
Mcp-Namebefore the request reaches a server - Tokens are audience-validated; nothing is passed through to downstream APIs
- Scopes are per tool, with no wildcards and no unused scopes advertised
- External-effect tools require confirmation bound to user, tool and arguments
- Irreversible actions are not exposed at all unless a person approves each one
- Tool lists are deterministic and versioned, with
ttlMsandcacheScopeset - Annotations from third-party servers never decide whether a write is confirmed
- Every call is logged with user, client, tool, argument hash and downstream request ID
- Injection tests run against tools that return customer or third-party text
Sources
- Model Context Protocol specification, version 2026-07-28, Model Context Protocol (LF Projects), 28 July 2026
- Key changes in 2026-07-28, Model Context Protocol (LF Projects), 28 July 2026
- Tools (server features), Model Context Protocol (LF Projects), 28 July 2026
- Security Best Practices, Model Context Protocol (LF Projects), accessed 19 October 2026
- The 2026-07-28 Specification, Model Context Protocol Blog, 28 July 2026
- MCP joins the Agentic AI Foundation, Model Context Protocol Blog, 9 December 2025
- Remote MCP FAQs, Xero Developer, accessed 19 October 2026
- Remote HubSpot MCP server is now generally available, HubSpot Developer Changelog, 13 April 2026
- Overview of Microsoft MCP Server for Enterprise, Microsoft Learn, 27 June 2026
Written by the Levy Street team in Wellington. Last updated 19 October 2026.