Resource Tools
A resource is what a plan unlocks: a place a connector gates, or a perk tracked by hand.
A resource is what a plan unlocks: a place a connector gates, or a perk tracked by hand. These tools register resources, link and unlink them, read their health and manage the standby and replacement flows Disaster Recovery relies on.
Tools
activate_resourceActivate ResourceDESTRUCTIVEcreate_resourceCreate Manual ResourceDESTRUCTIVEdeactivate_resourceDeactivate ResourceDESTRUCTIVEdelete_resourceDelete ResourceREADget_resourceGet ResourceREADlist_resourcesList ResourcesWRITErequest_resource_linkRequest Resource LinkDESTRUCTIVEunlink_resourceUnlink ResourceDESTRUCTIVEupdate_resourceUpdate Resourceactivate_resource
DESTRUCTIVESwitch a project resource on so the plans that link it grant it again. Emits project.resource.updated when the switch flips.
Turn a resource back on. The plans that link it never stopped linking it while it was off — switching off only stopped the bot offering and granting the channel or group — so switching on needs no re-linking: the plans grant it again from the next admission.
Runs the same Action the dashboard and the REST API use.
project.resource.updated emits once, carrying
changes.active from false to true, and only when the switch actually flips. Re-calling on a
resource that is already on is a no-op: the current row comes back and nothing emits.
Requires ability
The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.
Runs the same action as
The REST endpoint and this tool share one action, so validation, permissions and events are identical.
Fires one event
Delivered to every endpoint subscribed to it once the change is made.
Annotations
A client that honours annotations asks a person before running it. Sending the same arguments twice changes nothing the second time.
Arguments
resource_id*stringUUID of the resource to switch on.
What it returns
{ "data": { "id": "b73c5f21-9d80-4a6e-8215-4f70ce13a9d6", "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13", "kind": "telegram:channel", "connector": "telegram", "space": { "id": "3c1f7a58-2b6e-4d90-8f41-6a2e9c5d7b10", "external_id": "-1001234567890", "title": "Research Channel" }, "title": "Research Channel", "description": null, "active": true, "created_at": "2026-05-18T10:05:00+00:00", "updated_at": "2026-09-06T08:30:12+00:00" }}The full get_resource row, with active: true.
How it fails
VALIDATION_FAILEDthe caller is a team member whose role lacks the team's resource-update
RESOURCE_NOT_FOUNDunknown resource_id, a resource on another team's project, or one outside
AUTHENTICATION_REQUIREDno authenticated user on the request.
TOKEN_MISSING_ABILITYtoken lacks project-resource:update.
create_resource
DESTRUCTIVECreate a manual project resource (PDF link, token, URL placeholder) on a project with a connected connector. Gated places are linked through their connector.
Create a manual project resource. Delegates to an Action so policy checks and cache invalidation run identically to the dashboard, and a project.resource.created event fires.
Gated places (a channel, group or supergroup on Telegram, and whatever
another connector gates) cannot be created through this tool. Only the
connector can prove its installation administers the place, so a link starts
with request_resource_link and finishes
on the platform. Create manual perks here, and only once a connector on the
project is connected: a project with none answers CONNECTOR_NOT_INSTALLED.
Requires ability
The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.
Runs the same action as
The REST endpoint and this tool share one action, so validation, permissions and events are identical.
Fires one event
Delivered to every endpoint subscribed to it once the change is made.
Annotations
A client that honours annotations asks a person before running it. It reaches beyond Subscriby: a connector, a provider or a member.
Arguments
project_id*stringUUID of the parent project.
title*stringResource title (5..255 chars).
descriptionstringoptionalOptional resource description. Max 1000 chars, HTML is filtered.
activebooleanoptionalDefaults to true. Set false to create in inactive state.
What it returns
{ "data": { "id": "b73c5f21-9d80-4a6e-8215-4f70ce13a9d6", "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13", "kind": "manual", "connector": null, "space": null, "title": "Onboarding PDF", "description": "Link to the onboarding pack.", "active": true, "created_at": "2026-05-18T10:05:00Z", "updated_at": "2026-05-18T10:05:00Z" }}The full get_resource row: a manual perk is kind: "manual" with connector and space both null.
How it fails
VALIDATION_FAILEDtitle is outside the 5..255 character range.
CONNECTOR_NOT_INSTALLEDno connector on the project is connected, so nothing could deliver the resource; install and connect one first.
RESOURCE_NOT_FOUNDproject_id is unknown or out of the token's team scope.
TOKEN_MISSING_ABILITYtoken lacks project-resource:create.
deactivate_resource
DESTRUCTIVESwitch a project resource off without touching the plans that sell it. Reversible with activate_resource. Emits project.resource.updated when the switch flips.
Pause one channel or group without editing a single plan. While a resource is off the bot stops
offering and granting it, and the plans that link it keep selling everything else they include. The
link itself is untouched, which is what makes this reversible:
activate_resource brings it back exactly as it was.
The safe alternative to delete_resource
delete_resource removes the row for good and
every plan loses the link. Switching off keeps the row, the link and the
connector binding. Reach for it for maintenance, a channel being reorganised,
or anything you might want back.
Runs the same Action the dashboard and the REST API use.
project.resource.updated emits once, carrying
changes.active from true to false, and only when the switch actually flips. Re-calling on a
resource that is already off is a no-op: the current row comes back and nothing emits.
Requires ability
The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.
Runs the same action as
The REST endpoint and this tool share one action, so validation, permissions and events are identical.
Fires one event
Delivered to every endpoint subscribed to it once the change is made.
Annotations
A client that honours annotations asks a person before running it. Sending the same arguments twice changes nothing the second time.
Arguments
resource_id*stringUUID of the resource to switch off.
What it returns
{ "data": { "id": "b73c5f21-9d80-4a6e-8215-4f70ce13a9d6", "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13", "kind": "telegram:channel", "connector": "telegram", "space": { "id": "3c1f7a58-2b6e-4d90-8f41-6a2e9c5d7b10", "external_id": "-1001234567890", "title": "Research Channel" }, "title": "Research Channel", "description": null, "active": false, "created_at": "2026-05-18T10:05:00+00:00", "updated_at": "2026-09-06T08:30:12+00:00" }}The full get_resource row, with active: false. space is kept —
the binding survives the switch.
How it fails
VALIDATION_FAILEDthe caller is a team member whose role lacks the team's resource-update
RESOURCE_NOT_FOUNDunknown resource_id, a resource on another team's project, or one outside
AUTHENTICATION_REQUIREDno authenticated user on the request.
TOKEN_MISSING_ABILITYtoken lacks project-resource:update.
delete_resource
DESTRUCTIVEHard-delete a project resource. Emits project.resource.deleted before the row disappears so listeners see the snapshot.
Hard-delete a project resource by UUID. Delegates to an Action that emits project.resource.deleted with the row snapshot before the delete executes so downstream listeners capture the final state. Scoped to the caller's team.
Requires ability
The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.
Runs the same action as
The REST endpoint and this tool share one action, so validation, permissions and events are identical.
Fires one event
Delivered to every endpoint subscribed to it once the change is made.
Annotations
A client that honours annotations asks a person before running it. Sending the same arguments twice changes nothing the second time. It reaches beyond Subscriby: a connector, a provider or a member.
Arguments
resource_id*stringUUID of the resource to delete.
What it returns
{ "data": { "resource_id": "b73c5f21-9d80-4a6e-8215-4f70ce13a9d6", "deleted": true }}How it fails
RESOURCE_NOT_FOUNDunknown resource_id, or the parent project is outside the token's scope.
TOKEN_MISSING_ABILITYtoken lacks project-resource:delete.
get_resource
READFetch a single project resource by UUID. Returns its kind, connector, the place it is bound to, title, description, switch and timestamps.
Fetch full detail for one project resource. Results are scoped to the caller's team; unknown or out-of-scope IDs surface as RESOURCE_NOT_FOUND to prevent existence leaks.
Requires ability
The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.
Runs the same action as
The REST endpoint and this tool share one action, so validation, permissions and events are identical.
Annotations
It reads and never changes anything.
Arguments
resource_id*stringUUID of the project resource to fetch.
What it returns
{ "data": { "id": "b73c5f21-9d80-4a6e-8215-4f70ce13a9d6", "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13", "kind": "telegram:channel", "connector": "telegram", "space": { "id": "3c1f7a58-2b6e-4d90-8f41-6a2e9c5d7b10", "external_id": "-1001234567890", "title": "Research Channel" }, "title": "Research Channel", "description": null, "active": true, "created_at": "2026-05-18T10:05:00Z", "updated_at": "2026-05-18T10:05:00Z" }}kind is manual for a perk the creator hands over by hand, otherwise the connector's kind spelled connector:kind as list_connectors lists each connector's resource_kinds. connector and space are null for a manual perk; space is also null for a place-kind resource that was unlinked.
How it fails
RESOURCE_NOT_FOUNDunknown resource_id, or the parent project is outside the token's scope.
TOKEN_MISSING_ABILITYtoken lacks project-resource:view.
list_resources
READPaginated list of project resources (the places a connector gates plus manual perks) scoped to one project, narrowable by kind and by connector.
List every resource attached to a project — the places a connector gates, manual PDF / URL perks, and any other unit the creator has registered as gated content. Results are scoped to the caller's team and ordered newest-first. kind narrows the page to one kind of resource and connector to everything one connector gates; either alone or both together.
Requires ability
The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.
Runs the same action as
The REST endpoint and this tool share one action, so validation, permissions and events are identical.
Annotations
It reads and never changes anything.
Arguments
project_id*stringUUID of the parent project.
limitintegeroptionalMaximum resources to return per page (1..100).
1max100pageintegeroptional1-indexed page number.
1kindstringoptionalOnly resources of one kind: `manual`, or a connector's kind spelled `connector:kind` as `list_connectors` lists each connector's `resource_kinds`.
connectorstringoptionalOnly the resources one connector gates, by the key `list_connectors` lists it under.
What it returns
{ "data": [ { "id": "b73c5f21-9d80-4a6e-8215-4f70ce13a9d6", "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13", "kind": "telegram:channel", "connector": "telegram", "space": { "id": "3c1f7a58-2b6e-4d90-8f41-6a2e9c5d7b10", "external_id": "-1001234567890", "title": "Research Premium Lounge" }, "title": "Research Premium Lounge", "description": "Daily research notes.", "active": true, "created_at": "2026-05-18T10:05:00Z", "updated_at": "2026-05-18T10:05:00Z" }, { "id": "8c2f4a61-3d7e-4b90-a5c8-1e6f9d0b2c73", "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13", "kind": "manual", "connector": null, "space": null, "title": "Onboarding PDF", "description": "Link to the onboarding pack.", "active": true, "created_at": "2026-05-18T10:05:00Z", "updated_at": "2026-05-18T10:05:00Z" } ], "meta": { "page": 1, "limit": 25, "total": 2, "has_more": false }}space is the place the resource is bound to, null for a manual perk and for a place-kind resource that was unlinked. The row is the same object GET /v1/projects/{project}/resources returns.
How it fails
RESOURCE_NOT_FOUNDunknown project_id, or the project belongs to a team outside the token's scope.
VALIDATION_FAILEDkind is neither manual nor connector:kind, or connector is not a connector key.
TOKEN_MISSING_ABILITYtoken lacks project-resource:view-any.
Ask the creator, through the connector, to pick the place a new resource will be; it appears the moment they choose.
Linking a place a connector gates is a conversation with the creator on the connector: only the platform can prove the installation administers the place, so the connector messages the creator with a picker and the resource appears, announced by project.resource.linked, the moment they choose. Nothing is created by this call itself; a manual perk is created with create_resource. The REST twin is POST /v1/projects/{project}/resources/link-requests.
Requires ability
The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.
Runs the same action as
The REST endpoint and this tool share one action, so validation, permissions and events are identical.
Arguments
project_id*stringUUID of the project the linked place will belong to.
kind*stringThe kind of place to ask for, spelled `connector:kind`: a connector's key, a colon, and one of the `resource_kinds` that `list_connectors` lists for it.
What it returns
{ "data": { "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13", "kind": "telegram:channel", "status": "request_sent" }, "meta": {}}How it fails
CONNECTOR_NOT_INSTALLEDthe project runs no connected connector, so nothing could finish the link.
VALIDATION_FAILEDkind is manual, a bare word or otherwise not connector:kind; no connected connector on the project gates the kind; or the creator cannot be reached on the connector.
RESOURCE_NOT_FOUNDproject_id is not a project the token can see.
AUTHENTICATION_REQUIREDno authenticated user on the request.
TOKEN_MISSING_ABILITYtoken lacks project-resource:create.
unlink_resource
DESTRUCTIVEClear the connector place from a resource, reverting it to an unlinked placeholder the creator can relink through the connector.
Clear the connector place (space) from a resource, reverting it to an unlinked placeholder row the creator can relink through the connector with request_resource_link. Delegates to an Action so a project.resource.unlinked event fires. No-op if the resource is already unlinked.
Requires ability
The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.
Runs the same action as
The REST endpoint and this tool share one action, so validation, permissions and events are identical.
Fires one event
Delivered to every endpoint subscribed to it once the change is made.
Annotations
A client that honours annotations asks a person before running it. Sending the same arguments twice changes nothing the second time. It reaches beyond Subscriby: a connector, a provider or a member.
Arguments
resource_id*stringUUID of the resource to unlink.
What it returns
{ "data": { "id": "b73c5f21-9d80-4a6e-8215-4f70ce13a9d6", "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13", "kind": "telegram:channel", "connector": "telegram", "space": null, "title": "Research Channel", "description": null, "active": true, "created_at": "2026-05-18T10:05:00Z", "updated_at": "2026-09-06T08:30:12Z" }}The full get_resource row with space cleared. The resource keeps its kind and connector: it is still a Telegram channel resource, only one bound to no place until the creator links another.
How it fails
RESOURCE_NOT_FOUNDunknown resource_id, or the parent project is outside the token's scope.
TOKEN_MISSING_ABILITYtoken lacks project-resource:update.
update_resource
DESTRUCTIVERetitle, describe or switch a project resource. Partial by design — anything omitted keeps its stored value; the kind and the place are fixed.
Change what the dashboard's resource editor lets a creator change: the title, the description
and the active switch. Only the arguments present are written; anything omitted is filled from the
stored row, so a title-only change never touches the description and is never logged as a
description edit.
Emits project.resource.updated with the fields that
actually moved. A call whose arguments change nothing returns the current row and emits nothing.
`kind`, `connector` and `space` are silently ignored
The resource kind is its identity and the connector place (space) is its
binding; neither can be set here. Sending them is not an error — they are
simply not read. A place is linked through the connector with
request_resource_link, and cleared with
unlink_resource.
`active` here, or the dedicated switches
active is accepted alongside the other fields. When the switch is the only
thing changing, activate_resource and
deactivate_resource do the same thing with
a one-argument call.
Requires ability
The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.
Runs the same action as
The REST endpoint and this tool share one action, so validation, permissions and events are identical.
Fires one event
Delivered to every endpoint subscribed to it once the change is made.
Annotations
A client that honours annotations asks a person before running it. Sending the same arguments twice changes nothing the second time. It reaches beyond Subscriby: a connector, a provider or a member.
Arguments
resource_id*stringUUID of the resource to change.
titlestringoptionalNew title, 5 to 255 characters.
descriptionstringoptionalNew description, up to 1000 characters of well-formed HTML. Pass null or an empty string to clear it.
activebooleanoptionaltrue offers the resource on the plans that link it, false switches it off without touching those plans.
What it returns
{ "data": { "id": "b73c5f21-9d80-4a6e-8215-4f70ce13a9d6", "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13", "kind": "telegram:channel", "connector": "telegram", "space": { "id": "3c1f7a58-2b6e-4d90-8f41-6a2e9c5d7b10", "external_id": "-1001234567890", "title": "Members lounge" }, "title": "Members lounge (VIP)", "description": "Where the regulars hang out.", "active": true, "created_at": "2026-05-18T10:05:00+00:00", "updated_at": "2026-09-06T08:30:12+00:00" }}The full get_resource row. description comes back purified, so the
HTML you read may be tidier than the HTML you sent. space is null on a manual perk and on a resource not yet linked
to a place on its connector.
How it fails
VALIDATION_FAILEDtitle outside 5–255 characters (error.context.title); description
RESOURCE_NOT_FOUNDunknown resource_id, a resource on another team's project, or one outside
AUTHENTICATION_REQUIREDno authenticated user on the request.
TOKEN_MISSING_ABILITYtoken lacks project-resource:update.
How is this guide?