Developers
321GoCheck MCP server for UK background checks
Add UK background checks to your HR system, ATS or AI agent. Our remote MCP server lets any Model Context Protocol client price, order and track checks for a 321GoCheck client account. Start with a free test key: the sandbox prices real orders but never places them.
https://api.321gocheck.com/mcpAt a glance
- Transport: Streamable HTTP, JSON responses, stateless (no session id). Protocol versions 2025-11-25, 2025-06-18, 2025-03-26.
- Auth for assistants: OAuth 2.1 with PKCE (S256) and dynamic client registration. Discovery from the 401 challenge via
https://api.321gocheck.com/.well-known/oauth-protected-resource. - Auth for your own systems: the client's API key as
Authorization: Bearer GC_live_….GC_test_…keys are a sandbox. - Scopes:
orders:read(packages, quotes, orders, status) andorders:write(place, cancel, resend). - Limits: 60 tool calls a minute per account; up to 10 candidates per order; quotes last 30 minutes.
- Data: candidates' names, emails and progress only. Documents, report contents and referee answers are never returned; completed checks return a link to the report in the client app.
How an order works
list_packagesreturns package ids such asfixed:4(our packages) andsaved:12(the client's own), with prices.quote_ordervalidates the candidates and returns the exact price and aquote_id. Nothing is ordered.Show the quote to the user. Only after they confirm, call
create_orderwith thequote_idandconfirm: true. It is idempotent: the same quote never orders twice.Each candidate gets an email invitation and completes their part on their phone. Follow progress with
list_ordersandget_order_status.
Tools
list_packages read
The background check packages the client can order: 321GoCheck's fixed packages and the client's own saved packages, with the checks in each, the price per candidate and the optional criminal record check levels.
client_type | "employer" | "landlord" | Only packages for employers (staff) or landlords (tenants) |
quote_order read
Check and price an order before placing it: a package, optionally a basic criminal record check, and one or more candidates. Nothing is ordered and nobody is contacted. Returns a quote_id that create_order needs; quotes last 30 minutes.
package_id * | string | From list_packages, e.g. 'fixed:4' or 'saved:12' |
candidates * | array of object | Each: first_name, last_name, email, phone_code, phone_number |
criminal_check | "E & W - Basic" | "Scotland - Basic" | "NI - Basic" | Optional basic criminal record check (England & Wales, Scotland or Northern Ireland) |
note | string | Optional note on the order, e.g. the role or a reference |
create_order write
Place an order from a quote. Only call this after showing the quote (package, candidates, total including VAT) to the user and getting their explicit confirmation. The order is invoiced to the client's account and each candidate is emailed an invitation. Calling it again with the same quote_id does not order twice.
quote_id * | string | |
confirm * | boolean | true: the user has confirmed this quote |
list_orders read
The client's orders, newest first, with each candidate's stage.
status | "all" | "in progress" | "completed" | "cancelled" | |
limit | integer |
get_order_status read
One order in detail: for each candidate and each check, the stage (with the candidate, waiting for referees, being checked, completed), the expected completion date, whether it is overdue, and a link to the report in the client app once completed.
order_id * | integer |
resend_invite write
Email (and text, if a phone number was given) a candidate their invitation again, for a candidate who hasn't started yet.
order_id * | integer | |
candidate_email * | string |
cancel_order destructive
Cancel an order: checks stop and the candidates' links stop working. Only call this after the user has explicitly confirmed. It cannot be undone.
order_id * | integer | |
reason * | string | Why the order is cancelled |
* required. Tool errors come back as a normal result with isError: true and a message you can show the user.
Examples
VS Code / GitHub Copilot (.vscode/mcp.json)
{
"servers": {
"321gocheck": { "type": "http", "url": "https://api.321gocheck.com/mcp" }
}
}List the tools with curl
curl -s https://api.321gocheck.com/mcp \
-H "Authorization: Bearer GC_test_YOUR_TEST_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Price an order
curl -s https://api.321gocheck.com/mcp \
-H "Authorization: Bearer GC_test_YOUR_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{
"name":"quote_order",
"arguments":{"package_id":"fixed:4","criminal_check":"E & W - Basic",
"candidates":[{"first_name":"Jane","last_name":"Smith","email":"[email protected]"}]}}}'Python (official MCP SDK)
# pip install mcp
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import create_mcp_http_client, streamable_http_client
async def main():
headers = {"Authorization": "Bearer GC_test_YOUR_TEST_KEY"}
async with create_mcp_http_client(headers=headers) as http, \
streamable_http_client("https://api.321gocheck.com/mcp", http_client=http) as (read, write, *_):
async with ClientSession(read, write) as session:
await session.initialize()
packages = await session.call_tool("list_packages", {"client_type": "employer"})
print(packages.content[0].text)
asyncio.run(main())REST API (without MCP)
The same steps as plain HTTPS calls with the API key as Authorization: Bearer GC_live_… (or GC_test_… for the sandbox).
GET https://api.321gocheck.com/packages?client_type=employer: packages and prices.POST https://api.321gocheck.com/background-check/quotewithpackage_id,candidates(first_name, last_name, email), optionalcriminal_checkandnote: the price and aquote_id.POST https://api.321gocheck.com/background-checkwithquote_id: places the order once the user agrees. The same quote never orders twice.GET https://api.321gocheck.com/background-check/{order_id}: each candidate's progress.
Webhooks
Instead of polling, your system is told when something changes. Add an endpoint on the API dashboard or with POST https://api.321gocheck.com/webhooks (a live key): url and the events you want.
order.placed,order.completed,order.cancelled: the order.candidate.updated: a candidate moves from invited to filling in, being checked, completed.check.completed: one check of a candidate is done.report.ready: all of them are, with the report link.
Every delivery is signed: X-GoCheck-Signature is the SHA-256 HMAC of timestamp.body with the endpoint's secret, and X-GoCheck-Timestamp lets you reject old requests. Answer 2xx within 10 seconds; otherwise we retry for 12 hours. Payloads carry names, emails and stages only, never documents or results.
OAuth endpoints
- Authorisation server metadata:
https://api.321gocheck.com/.well-known/oauth-authorization-server - Registration (public clients,
token_endpoint_auth_method: none):https://api.321gocheck.com/oauth/register - Authorise:
https://api.321gocheck.com/oauth/authorize. The user signs in to 321GoCheck and approves your app. - Token (authorisation code with PKCE, refresh token rotation):
https://api.321gocheck.com/oauth/token - Revoke:
https://api.321gocheck.com/oauth/revoke. Clients can also disconnect apps on their API dashboard.
Building an integration for many 321GoCheck clients, or need help? Email [email protected].