Agent authentication
MCP server https://mcp.mdiv.pl/api/mcp accepts two authentication methods:
- OAuth 2.1 + PKCE, preferred for AI agents acting on behalf of the user (Claude Desktop, Cursor, ChatGPT with MCP). Requires
code_challenge_method=S256; the valueplainis rejected per RFC. Authorization endpoint:https://moje.mdiv.pl/oauth/authorize. Dynamic Client Registration:https://moje.mdiv.pl/api/oauth/register(RFC 7591). - Personal API Token, format
mpt_<64hex>(96 bits of entropy). Issued manually by the customer at https://moje.mdiv.pl/account/api-tokens. Passed in the headerAuthorization: Bearer mpt_….
Tokens are stored on the server as a bcrypt hash, never in plaintext. The token value is shown once, at the moment of issuance. The customer can revoke a token at any time via the panel.
Granular scopes (33)
Every token (OAuth or PAT) has an assigned subset of 33 scopes. List of domains: websites, domains, databases, email, dns, ssl, apps, jobs, packages, files, backups, commerce, profile, offline_access. Each domain has the splits :read / :write / :delete.
Implication rules:
:writeimplies:read, a token withdatabases:writecan also read.:deleteis NOT implied by:write. To delete a resource, the agent must hold a separate:deletescope.- All scopes are opt-in, by default an empty token allows nothing.
Full list and tool→scope mapping: see /en/for-ai-agents and /.well-known/mcp.json.
Tier system
Independently of token scopes, each customer account has the flag ai_deploy set by an mDiv administrator:
| Tier | What's allowed |
|---|---|
none | Default. All AI Deploy operations → 403 AI_DEPLOY_NOT_ENABLED. |
sandbox | Read-only tools only. install_*, delete_*, set_dns_records → 403 AI_DEPLOY_TIER_TOO_LOW. |
beta | Full ops range. Limit of 500 mutating calls per account per day. |
full | No restrictions beyond the physical limits of the plan. |
The customer starts on sandbox. Promotion after 1 to 2 weeks of testing happens after the customer's written consent and a log review. The global kill switch (AI_DEPLOY_GLOBALLY_DISABLED) allows AI Deploy to be disabled for all accounts in case of an incident on mDiv's side.
Two-step delete pattern
Every destructive operation (delete_*, in phase 1 covers only delete_domain; further resource types are added gradually) requires two calls:
preview_delete_domain({ domain_id })→{ preview_token, impact: { subdomains, ssl_certs, email_domains, warning }, expires_at }. The agent MUST show the user theimpactfield and wait for confirmation.delete_domain({ domain_id, preview_token, confirm: true})→{ deleted: true }.
The preview token has three safeguards:
- Bound to (user_id, resource_type, resource_id). The agent CANNOT slip the user a token issued for a different resource or account, the server rejects with
PREVIEW_TOKEN_OWNERSHIP_MISMATCH/PREVIEW_TOKEN_RESOURCE_MISMATCH. - Single-use, after the first use the token is invalidated.
- TTL 10 minutes. After expiry:
PREVIEW_TOKEN_EXPIRED.
Missing preview_token in a destructive call returns PREVIEW_TOKEN_MISSING; missing confirm: true → CONFIRMATION_REQUIRED. The pattern is being progressively rolled out to further resource types.
Idempotency-Key
All mutating endpoints (POST, PUT, PATCH, DELETE) honour the header Idempotency-Key with a UUID v4 supplied by the client.
- Replay with the same body within a 24h window → cached response with the header
Idempotent-Replay: true. - Replay with a different body →
409 IDEMPOTENCY_KEY_REUSED. - Invalid key format →
400 IDEMPOTENCY_KEY_INVALID. - Endpoints that return one-time secrets (
create_database, PAT issuance, OAuth token issuance) do not cache the response body. Replay re-executes the handler, the secret is not leaked via the cache.
Rate limit
Per-token sliding window of 60 seconds. Limits are more restrictive for operations with high infrastructure cost:
- Default: 60 req/min per token.
- Install ops (
install_wordpress,request_ssl): 5 req/min. Each such operation kicks off an install / certification pipeline, so aggressive polling has no use.
When exhausted: 429 RATE_LIMITED with headers X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After. The agent should respect Retry-After, ignoring it results in the token being paused.
Audit log
Every MCP call (read and write) is written to an immutable audit log on mDiv's side. Each entry contains:
- token_id (sha256 hash; never plaintext token)
- user_id, oauth_client_id (if OAuth)
- tool name, required scope, request body (PII redacted)
- resource_type, resource_id
- response status, error code
- IP, user-agent, timestamp with millisecond precision
- idempotency_key, preview_token (if used)
The customer is entitled to inspect the log for their account via the panel moje.mdiv.pl/account/audit-log. Retention: 12 months. Higher-risk logs (delete, install, token issuance), 24 months. After retention, entries are anonymised (token_id and IP zeroed), the rest is kept for statistics.
Anomaly detection
The audit log is analysed in near real time. Detected anomalies (sample thresholds):
- A series of
delete_*in a short window (≥3 in 60s), the token is paused pending administrator confirmation. set_dns_recordsoverwriting existing critical records (MX, SPF, DKIM), requires email confirmation from the customer.- A sudden change in the geographical origin of requests (IP geo), an email to the customer with a link "I don't recognise this activity → block the token".
- An attempt to enumerate other customers' resources (e.g. using somebody else's UUIDs), immediate token block and alert to the administrator.
The policy is evolutionary: new signals are added without API changes. Rules currently in production are described in the AI Deploy changelog.
Weekly summary email
Every customer with ai_deploy ≠ none receives a summary of the previous week on Monday morning:
- call count aggregated per scope and per tool
- list of write changes (domains, databases, installs, SSL created)
- list of destructive changes (delete_*) with timestamps
- active tokens and the dates of their most recent use
- flagged anomalies (if any)
- link to the panel for disabling AI Deploy or narrowing token scopes
The subscription can be turned off in the panel, but security alerts (anomalies, token blocks) are always sent, they cannot be silenced.
Data isolation between customers
Every MCP call is filtered by the user_id context extracted from the token. The backend performs authorisation at the SQL query level, even knowing another customer's domain / database / website UUID does not allow it to be retrieved.
The audit log validates that resource.user_id == token.user_id on every operation. An attempt to use somebody else's UUID ends with 404 NOT_FOUND (not 403, we don't disclose the resource's existence) and an entry in the anomaly detection log (section 8).
Customer databases live in separate MariaDB / PostgreSQL instances with dedicated users. Files on shared hosting are protected by open_basedir + per-user chroot.
Encryption and transport
In transit: all MCP, OAuth and customer panel endpoints enforce HTTPS (HSTS, TLS 1.3, Let's Encrypt certificates with auto-renew). HTTP connections are 301 redirected and do not serve any application endpoints.
At rest: user password hashes in argon2id; tokens (PAT, OAuth access/refresh) in bcrypt; preview tokens in memory with TTL 10 min (Redis with encryption at rest on the volume).
Backups: daily, encrypted (AES-256) before being written to remote storage. The key is never on the backed-up machine.
Secrets in response body (e.g. DB password from create_database): returned once, over Streamable HTTP, not written to logs or audit (audit records only the fact of the call, not the response content).
Incident response & disclosure
Vulnerability reports: security@…. We accept encrypted reports (PGP key available at /.well-known/security.txt). First-response time: up to 24h on business days.
Disclosure: 90-day coordinated disclosure from the date the vulnerability is confirmed. The reporter receives credit (unless they request anonymity). Hall of fame for researchers on a dedicated page after public launch (Q3 2026).
Data breach notifications: in the event of a personal-data incident (GDPR), customers are notified by email and in the panel within 72h of confirmation. The incident communication plan also includes: a detailed post-mortem on the mDiv blog, the list of affected accounts, remediation steps and recommendations for customers.
AI Deploy operational contact: ai-deploy@… or contact form.