MCP Authentication

API keys, agent scoping, and sandbox mode for MCP

🔐 MCP Authentication

MCP agents authenticate using Bearer tokens — long-lived API keys created per agent. Each key is scoped to a specific entity (payroll company or employer) and optionally locked to sandbox mode.


API Key Format

mcp_<64 hexadecimal characters>

Example:

mcp_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

Keys are 256-bit random values, SHA-256 hashed before storage. The raw key is shown once at creation and cannot be retrieved again.


Getting Your API Key

MCP API keys are created by your Audit1 account manager or via the admin REST API. Contact [email protected] to request credentials for your agent.

You'll need to provide:

FieldDescription
Agent nameA human-readable label (e.g., "ADP Payroll Agent")
Entity typepayroll_company (multi-employer) or employer (single)
Entity IDThe Audit1 ObjectId for your payroll company or employer
Sandboxtrue for testing (forces dry-run on all submissions)
⚠️

Save your API key immediately — it's only shown once. If you lose it, request a new key and revoke the old one.


Request Format

All MCP calls go to a single endpoint using JSON-RPC 2.0:

curl -X POST https://payroll-mcp-server-902057957000.us-central1.run.app/mcp \
  -H "Authorization: Bearer mcp_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "initialize",
    "id": 1
  }'
📘

Single endpoint — Unlike the REST API which has many routes, MCP uses one endpoint (POST /mcp) for all operations. The method field determines the action.


Agent Scoping

Your API key determines what data you can access:

Agent TypeEntity TypeScope
Providerpayroll_companyAll employers where payroll_company_ids includes your company
EmployeremployerOnly this specific employer

Scope is resolved fresh on every request. If an employer is unlinked from your payroll company, your agent loses access immediately — no stale permissions.

Provider Agent Example

A payroll company with 100 employer clients:

Agent → list_employer_policies(employer_id: "abc") → ✅ (employer linked)
Agent → list_employer_policies(employer_id: "xyz") → ✅ (employer linked)
Agent → list_employer_policies(employer_id: "999") → ❌ SCOPE_ERROR (not linked)

Employer Agent Example

A single-employer agent:

Agent → list_employer_policies(employer_id: "abc") → ✅ (matches agent scope)
Agent → list_employer_policies(employer_id: "xyz") → ❌ SCOPE_ERROR (wrong employer)

Sandbox Mode

Sandbox agents work identically to production agents — they can discover fields, list policies, and validate data. The only difference: submit_payroll_data automatically forces dry_run: true, so no data enters the real processing pipeline.

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "submit_payroll_data",
    "arguments": {
      "employer_id": "681abc123def456789012345",
      "policy_id": "680def456ghi789012345678",
      "rows": [{ "employee_first_name": "Test", "gross_wages": 2500 }],
      "dry_run": false
    }
  },
  "id": 5
}
⚠️

Even though dry_run: false was set, a sandbox agent's submission will still be dry-run only. The response will indicate "dry_run": true.

Use sandbox mode for:

  • 🧪 Development and testing
  • 📋 Onboarding new agents
  • ✅ Validating data formats before going live

Credential Management

Create an Agent

curl -X POST https://payroll-mcp-server-902057957000.us-central1.run.app/api/v1/agents \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "ADP Payroll Agent",
    "entity_type": "payroll_company",
    "entity_id": "68c4c0535d5a5576362a9499",
    "sandbox": false,
    "created_by": "[email protected]"
  }'

Response (201 Created):

{
  "credential_id": "682abc123def456789012345",
  "agent_name": "ADP Payroll Agent",
  "entity_type": "payroll_company",
  "entity_id": "68c4c0535d5a5576362a9499",
  "sandbox": false,
  "api_key": "mcp_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
  "api_key_prefix": "mcp_a1b2",
  "message": "Store this API key securely — it cannot be retrieved again."
}

List Agents

curl "https://payroll-mcp-server-902057957000.us-central1.run.app/api/v1/agents?entity_type=payroll_company&entity_id=68c4c0535d5a5576362a9499"

Response (200 OK):

{
  "agents": [
    {
      "credential_id": "682abc123def456789012345",
      "agent_name": "ADP Payroll Agent",
      "entity_type": "payroll_company",
      "entity_id": "68c4c0535d5a5576362a9499",
      "api_key_prefix": "mcp_a1b2...",
      "status": "active",
      "sandbox": false,
      "created_at": "2026-03-15T10:30:00Z",
      "last_used_at": "2026-03-31T14:22:00Z"
    }
  ],
  "count": 1
}

Revoke an Agent

curl -X POST https://payroll-mcp-server-902057957000.us-central1.run.app/api/v1/agents/682abc123def456789012345/revoke

Response (200 OK):

{
  "credential_id": "682abc123def456789012345",
  "agent_name": "ADP Payroll Agent",
  "status": "revoked"
}

Key Management Best Practices

✅ Do❌ Don't
Store keys in environment variables or secret managersHardcode keys in source code
Use sandbox agents for developmentTest with production agents
Revoke unused or compromised keys immediatelyShare keys across multiple agents
Use one key per agent with descriptive namesReuse keys between environments
Log the key prefix (mcp_a1b2...) for debuggingLog the full API key

Error Responses

CodeErrorMeaning
-32001AUTH_ERRORMissing, invalid, or revoked API key
-32002SCOPE_ERRORAgent not authorized for this employer
-32003SANDBOX_ONLYSandbox agent attempted real submission (auto-forced to dry-run)

Example error:

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32001,
    "message": "Invalid or revoked API key"
  },
  "id": 1
}

📧 Need Help?

Email [email protected] to request new agent credentials or report authentication issues.