@mgcrea/mcp-cloudkit
A read-only-by-default MCP server for the CloudKit management API — browse containers, record types, and schemas, and preview a Development → Production deploy diff (mutations only when writes are enabled).
cloudkit_auth_status— check whether the management token works, whether writes are on, and exactly what config is missing.cloudkit_list_containers— list containers this team can manage, to find the container id other tools take.cloudkit_list_record_types— record types and fields forDEVELOPMENTorPRODUCTION; confirms a newCD_-prefixed field actually reached CloudKit.cloudkit_export_schema— dump an environment's full schema as.ckdbtext, or write it tooutputPath.cloudkit_diff_schema— pending Development → Production changes, one row per record type/field (ADD,CHANGE_INDEXES,RETYPE,MISSING_IN_DEVELOPMENT,OTHER); the read-only preview of a deploy.cloudkit_validate_schema— validate a local.ckdbagainst an environment without importing it.cloudkit_request— GET-only escape hatch for arbitrary routes (the Developmentresetroute is refused by path).With
CLOUDKIT_ALLOW_WRITES=1(andconfirm: true):cloudkit_deploy_schema— promote Development to Production, always computing the diff first and supportingdryRun; andcloudkit_import_schema— upload a.ckdbwholesale.Handles the two separate environment databases (Debug vs TestFlight/App Store) and stays entirely separate from App Store Connect credentials.
Provides tools for managing CloudKit schemas in an iCloud container, including listing containers and record types, exporting and validating schemas, diffing Development against Production, and deploying schema changes when writes are enabled.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@mgcrea/mcp-cloudkitshow me the schema diff between Development and Production"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@mgcrea/mcp-cloudkit
A Model Context Protocol server for the CloudKit
management API — the schema surface behind the CloudKit Console and xcrun cktool. Read a
container's schema, diff Development against Production, and deploy the way the Console's
Deploy Schema Changes button does, from an MCP client.
This is a separate service from App Store Connect, with its own host and its own credential — an App Store Connect API key gives no access to CloudKit, and this token gives no access to App Store Connect. See @mgcrea/mcp-appstore-connect for versions, builds, TestFlight, and the rest of a release.
The server is read-only by default. Mutating tools are not merely refused when writes are off — they are never registered, so an agent cannot call them at all.
Why this exists
NSPersistentCloudKitContainer (Core Data or SwiftData) creates new record types and fields in
the Development environment only. It cannot alter Production, and it does not report that it
did nothing — so a build that ships a new attribute before the schema is deployed saves it
locally, syncs everything else, and drops that one field on the floor. Nothing surfaces to the
user; the record just arrives on the other device with the field absent.
The fix is one Console click, but it is a click nobody can script safely without seeing the diff
first: the schema becomes additive-only the moment it is first pushed to Production, and stays
that way forever — a field can be added, never removed, renamed or retyped. This server exists
to make that click scriptable without losing the safety property that matters: cloudkit_deploy_schema
always fetches and returns the diff before promoting anything, exactly what the Console shows
you before you press the button.
Related MCP server: enterprise-mcp
The API is undocumented
Apple ships no public docs or OpenAPI spec for the CloudKit management API. The routes here were
read out of the cktool binary Xcode installs (strings $(xcrun -f cktool)), and the way it calls
them — headers, methods, bodies — out of a live cktool session under a debugger, because
strings alone gets that wrong:
A management token goes in
X-ACP-API-TOKEN.X-Apple-CloudKit-User-Token, the only header namestringsfinds, is for user tokens; a management token sent there gets401 Failed to validate user token.Containers are listed at
/teams/{teamId}/containers, the one route outside/v1/database.A
.ckdbgoes up as a multipart body with one part namedfile, nevertext/plain(415). Validate is aPOST; import is aPUT.The binary also names
…/recordTypes,…/containers/{id}and…/schema/diff. They exist, but refuse a management token (401 authentication-failed): they belong to the Console's signed-in session. So record types are read fromGET …/environments/{env}/schema, and the diff is computed here from the two environments' schemas — the same data, reachable with the token.
cktool's own CLI exposes export-schema, import-schema and validate-schema — but not a
diff or a deploy, which is why this server exists rather than just wrapping cktool.
Three consequences follow from that:
Every response shaper falls back to the raw payload when it does not recognise the envelope, rather than reporting an empty result. A wrong guess here must never read as "the field is not deployed yet" when the truth is "the shaper does not understand this response".
cloudkit_requestis a GET-by-default escape hatch, so one endpoint answering differently than expected cannot make the rest of the server useless.cloudkit_deploy_schemahas not yet been seen to work with a management token. Its…/schema/{uuid}/promoteroute comes from the binary like the rest, butcktoolnever calls it, and its Console-only neighbours refuse the token. If it is refused, the tool says so and returns the diff; deploy from the Console instead.
Features
cloudkit_diff_schemashows what a deploy would change, one row per record type or field:ADD,CHANGE_INDEXES,RETYPE,MISSING_IN_DEVELOPMENT(Production keeps it; a deploy cannot remove it), orOTHERwhen the schemas differ outside any field, such as permissions.cloudkit_deploy_schemaalways computes that diff first; it refuses when there is nothing to deploy, when a field is retyped, or when either schema cannot be read, and takesdryRunto stop before committing.cloudkit_list_record_typesanswers "did my new field actually reach CloudKit" in one call — Core Data and SwiftData prefix every record type and field withCD_, so a SwiftisHiddenonTrackshows up asCD_isHiddenonCD_Track.The container
resetroute (wipes all Development data) is not exposed as a tool, andcloudkit_requestrefuses to reach it by path, in any case and percent-encoded or not — omitting it as a tool would mean little if the escape hatch could still call it.
Security
Read-only by default.
CLOUDKIT_ALLOW_WRITES=1addscloudkit_deploy_schemaandcloudkit_import_schema; both then additionally require an explicitconfirm: trueon every call, andcloudkit_requestrequires it for any method other than GET.A management token can rewrite a container's schema, which is broader than reading one. Scope it to the team that needs it, keep it out of tracked files, and revoke it in the Console when you are done — there is no expiry on it otherwise.
No runtime dependencies beyond the MCP SDK and Zod — native
fetchthroughout.Your credentials stay in your environment or config file; nothing is sent anywhere but
api.icloud.apple.com.
Configure
Create a token at icloud.developer.apple.com/dashboard/account/tokens under CloudKit Management Tokens.
Variable | Required | Notes |
| yes | Apple's own variable name — |
| yes | Your 10-character Apple Developer team id. |
| no | Default container, e.g. |
| no |
|
| no | Retry budget for 429/5xx. Defaults to 3. |
| no |
|
cp .env.example .envConfig file
If you'd rather not put the token in your shell profile or every MCP client config:
// ~/.config/cloudkit/config.json (chmod 600)
{
"managementToken": "...",
"teamId": "75QE9PRT3V",
"containerId": "iCloud.io.mgcrea.Balise",
"allowWrites": false,
}The environment wins over the file, field by field — a one-off CLOUDKIT_ALLOW_WRITES=0 still
overrides a file that says true. Unknown keys are an error, not silently ignored. Location:
$CLOUDKIT_CONFIG, else $XDG_CONFIG_HOME/cloudkit/config.json, else ~/.config/cloudkit/config.json.
Quick start
pnpm install
pnpm buildThen copy .mcp.json.example to .mcp.json and fill it in.
Inspect the tools
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"cli","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| node dist/cli.js 2>/dev/null | jq -r '.result.tools[]?.name'Tools
Tool | What it does | Writes |
| Credential state and what to configure | no |
| Containers this team can manage | no |
| Record types and fields for an environment | no |
| An environment's full schema as | no |
| Pending Development → Production changes | no |
| Validate a local | no |
| Escape hatch for any other route | no (GET only) |
| Promote Development to Production | yes† |
| Upload a | yes† |
Italic tools need CLOUDKIT_ALLOW_WRITES=1. † additionally requires confirm: true.
Develop
pnpm dev # tsdown --watch
pnpm test # vitest
pnpm typecheck
pnpm lint
pnpm formatPublish
pnpm dlx release-it # bump, commit, tag
git push --follow-tags # CI publishes to npm + GHCR from the tagLicense
MIT
Available Tools
7 toolscloudkit_auth_statusCloudKit: Auth StatusARead-only
Report whether this server has a working CloudKit management token, whether writes are enabled, and — when something is missing — exactly what to set. Call this first when a tool you expected is not listed: an absent tool here means missing configuration rather than a bug.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and the description's 'Report' language is consistent. The description adds useful behavioral context: it explains what the report covers (token validity, write enabling, remediation instructions) and the diagnostic role of this tool. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, both information-dense and purposeful. The first sentence states the tool's core output; the second gives actionable usage guidance. No filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter diagnostic tool with readOnly annotation and no output schema, the description fully covers what the agent needs: what is reported, why to call it first, and how to interpret the absence of tools. Nothing important is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to add beyond the schema. Per the baseline for 0-parameter tools, a 4 is appropriate since no parameter ambiguity exists.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Report') and a precise resource ('CloudKit management token', 'whether writes are enabled'). It clearly distinguishes itself from sibling tools that list containers, record types, or export schemas by focusing on authentication and configuration status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance: 'Call this first when a tool you expected is not listed'. It also interprets the meaning of an absent tool as missing configuration rather than a bug, which directly helps an agent decide to call this tool before diagnosing further.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cloudkit_diff_schemaCloudKit: Diff SchemaARead-only
Show what deploying would change: the pending differences between the container's DEVELOPMENT and PRODUCTION schemas, one row per change: ADD, CHANGE_INDEXES, RETYPE, MISSING_IN_DEVELOPMENT (Production keeps it; a deploy cannot remove it) or OTHER (the schemas differ outside any field, e.g. permissions). Read this before cloudkit_deploy_schema. Production is additive-only and irreversible — a field can be added forever, but never removed, renamed or retyped — so a RETYPE is a reason to stop.
| Name | Required | Description | Default |
|---|---|---|---|
| containerId | No | The iCloud container id, e.g. "iCloud.com.acme.App". Get it from cloudkit_list_containers, or set CLOUDKIT_CONTAINER_ID to default it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, but the description adds substantial non-obvious domain behavior: production is additive-only and irreversible, fields can be added but never removed/renamed/retyped, and MISSING_IN_DEVELOPMENT cannot be cleaned up by a deploy. This is exactly the context an agent needs beyond the structured hint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose followed by the return-value enumeration and then the deploy caveat. Dense and mostly waste-free, though the parenthetical explanations make it slightly run-on.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-value burden and does so by enumerating every row type and defining the ambiguous ones (MISSING_IN_DEVELOPMENT, OTHER). Nothing an agent needs to interpret the result is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter, and its schema description already covers format, retrieval from cloudkit_list_containers, and the CLOUDKIT_CONTAINER_ID default (100% coverage). The description adds no parameter-level detail, so the baseline of 3 for a fully documented single param is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Show what deploying would change: the pending differences between the container's DEVELOPMENT and PRODUCTION schemas') and enumerates the exact change categories returned. An agent can distinguish it from cloudkit_validate_schema or cloudkit_export_schema without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit sequencing guidance: 'Read this before cloudkit_deploy_schema', plus a concrete stop condition ('a RETYPE is a reason to stop'). This routes the agent to the right point in the deploy workflow rather than leaving usage to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cloudkit_export_schemaCloudKit: Export SchemaARead-only
Export an environment's full schema as a .ckdb document. Returns the text, or writes it to outputPath and reports where it went. Exporting both environments and diffing them locally is one way to review a pending change; cloudkit_diff_schema is the direct one.
| Name | Required | Description | Default |
|---|---|---|---|
| outputPath | No | Write the schema here instead of returning it, e.g. "./dev.ckdb". | |
| containerId | No | The iCloud container id, e.g. "iCloud.com.acme.App". Get it from cloudkit_list_containers, or set CLOUDKIT_CONTAINER_ID to default it. | |
| environment | Yes | Which container environment. A Debug build's data and schema live in DEVELOPMENT; TestFlight and App Store builds use PRODUCTION. They are separate databases. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint=true already declared, the description adds useful behavioral detail: the tool can return the schema text or write it to outputPath and report the destination. This meaningfully explains the two execution modes without contradicting the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, front-loaded with the core purpose, and every sentence earns its place by adding behavioral or routing information. There is no redundant filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only export tool with fully documented parameters, the description covers the output behavior, the optional file-writing path, and the relevant sibling alternative. Nothing critical is missing for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the input schema already documents all parameters effectively. The description adds little parameter-specific meaning beyond what the schema provides, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: exporting an environment's full schema as a `.ckdb` document. It also differentiates the tool from cloudkit_diff_schema, making its role among siblings immediately clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides meaningful usage context by explaining that exporting both environments and diffing locally is one way to review a pending change, then names cloudkit_diff_schema as the more direct alternative. It stops short of giving explicit when-to-use/when-not-to-use rules, but the guidance is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cloudkit_list_containersCloudKit: List ContainersARead-only
List the CloudKit containers this team can manage, with their ids. Use this to find the container id the other cloudkit_* tools take.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already establishes safety, and the description adds meaningful scope by noting it lists only containers 'this team can manage' and that the ids are the tool's key output. It does not discuss return format or errors, but the tool is simple enough that this is acceptable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two succinct sentences with no filler. The primary action and result are front-loaded, and the stated purpose directly supports agent usage.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, read-only listing tool, the description fully conveys what it does, what it returns, and why an agent would call it. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With zero parameters and 100% schema description coverage, there is no parameter burden for the description to carry. The baseline of 4 applies, and the description adds no unnecessary parameter details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'List' and the resource 'CloudKit containers this team can manage', and identifies the output as ids. It is immediately distinguishable from sibling tools by describing its specific role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says to use this tool to find the container id that 'the other cloudkit_* tools take'. This directly tells an agent when this tool is needed and how it relates to all sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cloudkit_list_record_typesCloudKit: List Record TypesARead-only
List a container environment's record types and their fields. This is how you confirm a newly added field actually reached CloudKit: Core Data and SwiftData prefix everything with CD_, so a Swift property isHidden on Track appears here as CD_isHidden on CD_Track. A field missing from DEVELOPMENT has not been written by any client yet — there is nothing to deploy until one has.
| Name | Required | Description | Default |
|---|---|---|---|
| recordType | No | Return just this one record type, e.g. "CD_Track". Omit for all of them. | |
| containerId | No | The iCloud container id, e.g. "iCloud.com.acme.App". Get it from cloudkit_list_containers, or set CLOUDKIT_CONTAINER_ID to default it. | |
| environment | Yes | Which container environment. A Debug build's data and schema live in DEVELOPMENT; TestFlight and App Store builds use PRODUCTION. They are separate databases. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description adds meaningful behavioral context: Core Data and SwiftData prefix record types and fields with CD_, so names appear transformed. It also discloses that a field missing from DEVELOPMENT has not been written by any client yet, which is useful deployment-relevant behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences with the main action front-loaded. Every sentence earns its place: purpose, naming convention, and an important interpretation of absence. There is no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only listing tool, the description covers the key context: what is listed, how names are transformed, and what field absence means in DEVELOPMENT. It does not describe the output shape, but given the tool's simplicity and lack of output schema, this is a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The prose does not add much parameter-specific meaning beyond reinforcing environment separation, but the schema already documents environment, containerId, and recordType clearly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'List a container environment's record types and their fields.' It clearly states what the tool does and even frames it as how to confirm a newly added field reached CloudKit. However, it does not explicitly differentiate this tool from siblings like cloudkit_export_schema or cloudkit_diff_schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a concrete use case: 'This is how you confirm a newly added field actually reached CloudKit.' It also explains the meaning of a missing DEVELOPMENT field, which helps the agent decide when this tool is useful. It does not mention when not to use it or name alternative tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cloudkit_requestCloudKit: Raw RequestARead-only
Escape hatch: issue an arbitrary CloudKit management API request. The other cloudkit_* tools cover the documented-by-observation routes; this exists because the API is undocumented, so one endpoint being shaped differently than expected should not make the rest unreachable. Prefer a specific tool when one fits. Only GET is available while writes are disabled.
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | JSON request body. | |
| path | Yes | Absolute API path, e.g. "/v1/database/teams/{teamId}/containers/{containerId}/environments/DEVELOPMENT/schema". | |
| method | No | HTTP method. | GET |
| confirm | No | Required for any method other than GET. Explicit acknowledgement of a write. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description adds meaningful context beyond that: writes are currently disabled and only GET is available. It also explains the rationale (undocumented API, need for a fallback). It stops short of describing response shape or failure behavior for arbitrary paths.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the tool's identity, then rationale, then the constraint and preference. Every sentence earns its place, though the rationale sentence is slightly long-winded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an escape-hatch tool with no output schema and full schema coverage, the description supplies the context an agent needs: what it is, why it exists, when to prefer siblings, and the current GET-only limitation. Return-value details are not needed here.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including an example path and an explanation of confirm, so the schema already carries parameter meaning. The description reinforces the GET-only constraint but adds no format or syntax detail beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('issue an arbitrary CloudKit management API request') and frames it as an escape hatch. It explicitly contrasts itself with the sibling cloudkit_* tools, so an agent can tell when this is the right pick without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Prefer a specific tool when one fits' gives a clear selection rule, and 'this exists because the API is undocumented, so one endpoint being shaped differently than expected should not make the rest unreachable' explains the fallback condition. It does not name which sibling covers which route, but the general guidance is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cloudkit_validate_schemaCloudKit: Validate SchemaARead-only
Validate a local .ckdb file against a container environment without importing it. Read-only: it reports whether the schema would be accepted, and changes nothing.
| Name | Required | Description | Default |
|---|---|---|---|
| filePath | Yes | Path to the `.ckdb` file, e.g. "./dev.ckdb". | |
| containerId | No | The iCloud container id, e.g. "iCloud.com.acme.App". Get it from cloudkit_list_containers, or set CLOUDKIT_CONTAINER_ID to default it. | |
| environment | Yes | Which container environment. A Debug build's data and schema live in DEVELOPMENT; TestFlight and App Store builds use PRODUCTION. They are separate databases. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description reinforces that with 'Read-only' and 'changes nothing.' It additionally clarifies that no import is performed, which is useful behavioral context beyond the structured annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no wasted words. The action and resource are front-loaded, and each clause adds meaningful information about scope and side effects.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only validation tool, the schema plus description cover required parameters and the high-level return meaning. The description could be slightly more explicit about output shape or authentication prerequisites, but nothing essential is missing for invoking the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already describes filePath, containerId, and environment with full coverage. The description adds no new parameter-level detail beyond restating the file and environment concepts, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('validate'), names the exact resource (local .ckdb file), and states the outcome: reports whether the schema would be accepted. It also contrasts with importing, which helps distinguish it from mutation-style operations even without naming sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'without importing it' implies this is a pre-import compatibility check, so some usage context is present. However, it does not explicitly say when to choose this over siblings like cloudkit_diff_schema or cloudkit_export_schema, nor does it provide exclusions or alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.2.0- Changed
cloudkit_request1 field changed- changed
Input schema / properties / path / descriptionPrevious value: -"Absolute API path, e.g. \"/v1/database/teams/{teamId}/containers/{containerId}/environments/DEVELOPMENT/recordTypes\"."New value: +"Absolute API path, e.g. \"/v1/database/teams/{teamId}/containers/{containerId}/environments/DEVELOPMENT/schema\"."
7 tool updates
v0.1.0- First observed
cloudkit_auth_status - First observed
cloudkit_diff_schema - First observed
cloudkit_export_schema - First observed
cloudkit_list_containers - First observed
cloudkit_list_record_types - First observed
cloudkit_request - First observed
cloudkit_validate_schema
TDQS
Scored across 7 tools
Each specific tool targets a distinct schema operation (list containers, diff, export, validate, list record types), and the descriptions explicitly steer agents away from overlaps (diff vs export, validate vs import). The only real ambiguity is cloudkit_request, a catch-all escape hatch that technically subsumes every other tool, though its description mitigates this by telling agents to prefer specific tools.
All seven tools use the same cloudkit_ prefix followed by a clear snake_case noun/verb label (list_containers, diff_schema, export_schema, validate_schema, auth_status). The pattern is predictable and readable throughout, with no mixed conventions.
Seven tools is well-scoped for a CloudKit schema-management server, with each tool covering a distinct step (auth, discover containers, inspect record types, diff, export, validate, raw request). Nothing feels padded or missing in terms of quantity.
The surface covers inspection, diffing, exporting and validating, but there is no deploy/apply tool — and the descriptions explicitly reference cloudkit_deploy_schema, which is absent here, creating a dead end for the primary write workflow (presumably config-gated by the auth token). Union/import of a .ckdb is also absent, so an agent cannot complete the add-field lifecycle end to end.
Maintenance
Related MCP Connectors
Build multi-tenant apps over MCP. Schemas, CRUD, deploys — access control enforced server-side.
Hosted MCP server for AI-driven data ops. Create apps, manage schemas, and CRUD structured data.
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
An MCP server that provides access to Agility CMS. See https://mcp.agilitycms.com for more details.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceThis MCP server provides access to Apple's App Store Connect API. It allows users to inspect apps, versions, builds, TestFlight groups, sales, users, and optionally edit metadata and manage testers.345 npm2MIT
- AlicenseNot gradedqualityAmaintenanceAn MCP server exposing scoped, read-only enterprise operations tools with fail-closed credential handling. It returns opaque approval IDs for mutations and requires a separate operator approval command to release one-time capabilities.MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants and automation to inspect, compare, and manage FileMaker schema artifacts via MCP, including exploring objects, tracing references, generating diffs between versions, and automating schema tasks through jobs.1Apache 2.0
- FlicenseCqualityCmaintenanceEnables managing Harness configuration and content through MCP, including querying capabilities, reading and previewing documents, applying host changes, restoring backups, and relocating projects.44-