Tool API plugins¶
content_deployment_tools exposes the main module's operations as
Tool API plugins, for the chat project,
MCP Server, ECA and anything else that runs tools. It is experimental while
Tool API is in beta, and was tested against Tool API 1.0.0-beta11.
Nothing is configured for MCP Server: exposing the tools over MCP is each site's choice, made in MCP Server's own configuration.
The tools¶
Each tool calls the service its Drush command calls, and its one output,
result, holds what the command prints. Tool API's operation kinds say what
each does; destructive asks callers to confirm first.
| Tool | Operation | Destructive | Drush command |
|---|---|---|---|
content_spec_model |
explain | no | content-spec:model |
content_spec_query |
read | no | content-spec:query |
content_spec_read |
read | no | content-spec:read |
content_spec_pending |
read | no | content-spec:pending |
content_spec_create |
write | no | content-spec:create |
content_spec_apply |
write | no | content-spec:apply |
content_spec_media_ingest |
write | no | content-spec:media-ingest |
content_spec_publish |
write | no | content-spec:publish |
content_spec_unpublish |
write | yes | content-spec:unpublish |
Inputs are the commands' options, in snake case:
| Tool | Inputs |
|---|---|
content_spec_model |
entity_type, bundle |
content_spec_query |
entity_type (default node), bundle, search, where (a list of conditions), published, unpublished, sort, limit, offset, with (a list of field names), count_only |
content_spec_read |
entity (id or uuid), entity_type (default node), no_text, published, portable, structure_only |
content_spec_pending |
conflicts |
content_spec_create, content_spec_apply |
spec (the content spec, as an object), dry_run, publish |
content_spec_media_ingest |
file (a file entity's uuid), alt, name, bundle |
content_spec_publish |
entity, entity_type, langcode |
content_spec_unpublish |
entity, entity_type |
tool.plugin.<id> config schema covers each tool's inputs, for a site that
stores them. A spec is free-form there; create and apply validate it when they
run.
Who writes¶
Drush commands and changesets write as the robot account. A tool writes as the account invoking it: that account owns what it creates and authors each revision.
Access¶
Each tool checks access in access(), as Tool API asks, and again when it
runs, since a caller can run a tool without asking. A refusal at run time is a
failed result of category Access, and nothing is written.
| Tool | Allowed when the account |
|---|---|
content_spec_model |
may create content of some bundle a spec can describe, or administer some entity type's fields |
content_spec_query |
may run it; rows and the count are of what it may view, and a field asked for is reported where it may view the field. Accounts take administer users. |
content_spec_read |
may view the entity; the newest revision, when it is a pending draft in any language, takes update access. Accounts take administer users. |
content_spec_pending |
may run it; the list holds the drafts of entities it may update |
content_spec_create, content_spec_apply |
has create access to the bundle, or update access to the entity; edit access to each field the write changes; use access to every text format the spec writes, a value without a format taking the field's default; update access to each entity a paragraph is claimed from; and, with publish, the review flow's access to publish. Accounts take administer users, since a spec can carry roles. |
content_spec_media_ingest |
uploaded the file; has create access to the media type, or, when the bytes are already a media item, view access to it, and update access when the ingest would change its alt text |
content_spec_publish |
may publish the draft: the workflow's transition to its published state, or update access and edit access to the published flag without moderation |
content_spec_unpublish |
may take it offline: the workflow's transition to the archived state, or update access and edit access to the published flag; administer users to block an account |
A field the write leaves as it is needs no edit access, so a spec read and applied back unchanged does not need access to its author or dates. A configurable field the spec omits is emptied, and so changed.
Media¶
The media ingest tool reads no paths: a path from a remote caller would let it read any file the web server can. Upload the bytes first, through an authenticated route that makes a file entity, such as core's JSON:API or REST file upload, then pass the file's uuid. The file is left as it is; the media item gets a file of its own.
Running a tool from Drush¶
drush tool:run content_spec_read --uid=2 --input='{"entity":"0a8ba38b-c932-40ca-bd7f-f28a87686ac8"}' --json
{
"success": true,
"message": "Read node \"Opening hours\".",
"outputs": {
"result": {
"$schema": "https://project.pages.drupalcode.org/content_deployment/schema/content-spec/v3",
"entity_type": "node",
"bundle": "landing",
"uuid": "0a8ba38b-c932-40ca-bd7f-f28a87686ac8",
"title": "Opening hours"
}
}
}
--uid names the invoking account; without it the tool runs as anonymous.