Skip to content
Anlyon
Esc
↑↓navigate↵open⌘Jpreview

Adopt tools as governed actions

Answers 404 where the mcp-upstreams feature is off. Adopts tools from the last listing. Each becomes a governed action named <upstream>-<tool> whose version pins the tool’s definition hash; a tool adopted before whose definition changed is re-adopted as a new version. The suggested class is never applied by itself: approval and impact are what the request chooses (ADR 0020). A tool that cannot be adopted is reported in skipped without stopping the others. From an API key, a CLI login or an MCP session this answers 202 with a sign-off link, for a first adoption and a re-adoption alike: only a workspace admin, as a person, can approve it. If the named tools’ definitions change before they decide, the request fails as SIGN_OFF_STALE and nothing is adopted.

POST/api/v2/mcp-upstreams/{id}/adopt
Authorization
AuthorizationBearer token (Anlyon API key) · headerrequired

Workspace API key sent as Authorization: Bearer <key>.

or
better-auth.session_tokenAPI key · cookierequired

Browser session used by dashboard-only operations.

Path parameters
idstringrequired

The upstream's id (mcpu_...).

matches ^mcpu_[A-Za-z0-9_-]+$
Header parameters
X-Request-Idstring

Optional caller correlation ID. Unsafe or oversized values are replaced.

max length 128
Request body
requiredapplication/json
toolsobjectrequired

Tool name to the operator's choices. 1 to 100 tools.

Responses
200

Only re-adoptions, or nothing adopted.

successbooleanrequired
dataMcpAdoptResultrequired
Show properties
adoptedobject[]required
Show properties
Array of object
toolstringrequired
actionActionrequired
Show properties
idstringrequired
environmentIdstring<uuid>required

The environment this action lives in. An action belongs to exactly one.

namestringrequired
descriptionstring | nullrequired
methodstringrequired
Allowed:GETPOSTPUTPATCHDELETE
urlTemplatestringrequired
headersobjectrequired
bodyTemplateobject | nullrequired
inputSchemaobjectrequired
requiresApprovalbooleanrequired
enabledbooleanrequired
secretsstring[]required

Referenced secret names only; values are never returned.

currentVersionIdstring | nullrequired

The immutable version this definition currently is. An agent version pins a version id, so this is what to pin to hold an action at its present definition. Null only for actions that predate versioning and have not been edited since.

adapterActionAdapter | nullrequired

The governed-effect adapter, or null for a template action.

Show properties
Any of:
ActionAdapter
typestringrequired
Allowed:stripe.refundgithub.file_updateresend.email_send
configobjectrequired
credentialSecretstringrequired
matches ^[A-Z0-9_]+$
null
null
governedbooleanrequired

True when every invocation creates a governed effect. The action has an adapter, or it carries a declaration.

impactActionImpact | nullrequired

The declared impact, or null when the action declares none.

Show properties
Any of:
ActionImpact
dimensionstringrequired

money, resource_mutations, or a workspace-declared unit such as emails, messages or rows.

matches ^[a-z][a-z0-9_]{0,31}$
unitstring

The currency for money (lowercase ISO 4217, required). For every other dimension the unit is the dimension name and may be left out.

min length 1 · max length 32
amountstringrequired
min length 1 · max length 200
boundstringrequired
Allowed:exactupper_bound
null
null
verifyActionVerify | nullrequired

The declared read-back, or null when the action declares none.

Show properties
Any of:
ActionVerify
urlstringrequired
min length 1 · max length 2048
statusintegerrequired

The status the read-back must answer with.

min 100 · max 599
matchobject[]

JSON path equality checks on the read-back body. Every one must hold.

max items 10
Show properties
Array of object
pathstringrequired

A dotted path into the read-back body. A numeric segment indexes an array; a * segment stands for any item of one (labels.*.name).

min length 1 · max length 200
equalsany | nullrequired

A string, number, boolean or null. A string may be exactly one {{input.field}} or {{response.field}}.

absentboolean

True when the check holds only if no value at the path equals equals: how a removal is read back. Left out, the check holds when one does.

graphqlobject

A GraphQL read-back: Anlyon POSTs { query, variables } to url instead of a GET. The query is fixed text: no placeholder, and no mutation or subscription anywhere in it, so a read-back cannot write. Only the variables come from the call.

Show properties
querystringrequired
min length 1 · max length 10000
variablesobject

Each a string, number, boolean or null; a string may be exactly one {{input.field}} or {{response.field}}.

null
null
createdAtstring<date-time>required
updatedAtstring<date-time>required
readoptedbooleanrequired
skippedobject[]required
Show properties
Array of object
toolstringrequired
reasonstringrequired
201

At least one tool was adopted as a new action.

successbooleanrequired
dataMcpAdoptResultrequired
Show properties
adoptedobject[]required
Show properties
Array of object
toolstringrequired
actionActionrequired
Show properties
idstringrequired
environmentIdstring<uuid>required

The environment this action lives in. An action belongs to exactly one.

namestringrequired
descriptionstring | nullrequired
methodstringrequired
Allowed:GETPOSTPUTPATCHDELETE
urlTemplatestringrequired
headersobjectrequired
bodyTemplateobject | nullrequired
inputSchemaobjectrequired
requiresApprovalbooleanrequired
enabledbooleanrequired
secretsstring[]required

Referenced secret names only; values are never returned.

currentVersionIdstring | nullrequired

The immutable version this definition currently is. An agent version pins a version id, so this is what to pin to hold an action at its present definition. Null only for actions that predate versioning and have not been edited since.

adapterActionAdapter | nullrequired

The governed-effect adapter, or null for a template action.

Show properties
Any of:
ActionAdapter
typestringrequired
Allowed:stripe.refundgithub.file_updateresend.email_send
configobjectrequired
credentialSecretstringrequired
matches ^[A-Z0-9_]+$
null
null
governedbooleanrequired

True when every invocation creates a governed effect. The action has an adapter, or it carries a declaration.

impactActionImpact | nullrequired

The declared impact, or null when the action declares none.

Show properties
Any of:
ActionImpact
dimensionstringrequired

money, resource_mutations, or a workspace-declared unit such as emails, messages or rows.

matches ^[a-z][a-z0-9_]{0,31}$
unitstring

The currency for money (lowercase ISO 4217, required). For every other dimension the unit is the dimension name and may be left out.

min length 1 · max length 32
amountstringrequired
min length 1 · max length 200
boundstringrequired
Allowed:exactupper_bound
null
null
verifyActionVerify | nullrequired

The declared read-back, or null when the action declares none.

Show properties
Any of:
ActionVerify
urlstringrequired
min length 1 · max length 2048
statusintegerrequired

The status the read-back must answer with.

min 100 · max 599
matchobject[]

JSON path equality checks on the read-back body. Every one must hold.

max items 10
Show properties
Array of object
pathstringrequired

A dotted path into the read-back body. A numeric segment indexes an array; a * segment stands for any item of one (labels.*.name).

min length 1 · max length 200
equalsany | nullrequired

A string, number, boolean or null. A string may be exactly one {{input.field}} or {{response.field}}.

absentboolean

True when the check holds only if no value at the path equals equals: how a removal is read back. Left out, the check holds when one does.

graphqlobject

A GraphQL read-back: Anlyon POSTs { query, variables } to url instead of a GET. The query is fixed text: no placeholder, and no mutation or subscription anywhere in it, so a read-back cannot write. Only the variables come from the call.

Show properties
querystringrequired
min length 1 · max length 10000
variablesobject

Each a string, number, boolean or null; a string may be exactly one {{input.field}} or {{response.field}}.

null
null
createdAtstring<date-time>required
updatedAtstring<date-time>required
readoptedbooleanrequired
skippedobject[]required
Show properties
Array of object
toolstringrequired
reasonstringrequired
202

Accepted, not applied: the change loosens a guardrail, so a workspace admin has to approve it. Location is the request to poll.

successbooleanrequired
Allowed:true
signOffRequiredbooleanrequired
Allowed:true
dataSignOffRequestrequired

A governance change that loosens a guardrail, asked for by an API key, a CLI login or an MCP session, waiting for a workspace admin. Give signOffUrl to a person; poll pollUrl.

Show properties
objectstringrequired
Allowed:sign_off_request
idstringrequired
statusstringrequired

pending until a workspace admin decides. applied: approved and in effect. rejected, expired (after 24 hours), cancelled (withdrawn by the credential) and failed (approved but could not be applied, see error): nothing changed.

Allowed:pendingappliedrejectedexpiredcancelledfailed
operationstringrequired
Allowed:policy.createpolicy.updatepolicy.deletepolicy_file.applyimpact_limit.updateimpact_limit.archivebudget.putbudget.deleteenvironment.resumeaction.createaction.updateaction.importsecret.putsecret_store.createsecret_store.updatesecret_store_settings.updateoauth_app.put
environmentIdstring<uuid>required
resourceobject | nullrequired
Show properties
typestringrequired
idstringrequired
namestring
summarystringrequired
changesSignOffChange[]required
Show properties
Array of SignOffChange
fieldstringrequired
fromany | nullrequired

The value before. Never a secret value.

toany | nullrequired

The value after. Never a secret value.

directionstringrequired
Allowed:tighteninglooseningneutral
reasonstringrequired
diffstringrequired

The changes as plain text

signOffUrlstring<uri>required

The console page where a workspace admin approves or rejects it. Give this to a person.

pollUrlstringrequired
pollAfterSecondsintegerrequired
requestedByobjectrequired
Show properties
typestringrequired
Allowed:api_keyoauth_clientsystem
idstring | nullrequired
onBehalfOfstring | null

For a CLI login or an MCP session

createdAtstring<date-time>required
expiresAtstring<date-time>required
decidedAtstring<date-time> | nullrequired
decidedByobject | nullrequired
Show properties
typestringrequired
Allowed:user
idstringrequired
viastringrequired
Allowed:consoleemail_link
decisionNotestring | nullrequired
resultany | nullrequired

When applied, what the original request would have returned: the limit, budget, policy or action as it now is.

errorobject | nullrequired
Show properties
codestringrequired
messagestringrequired
400

Bad Request - Invalid input data

successbooleanrequired
requestIdstringrequired

Correlation ID matching the X-Request-Id response header.

errorobjectrequired
Show properties
codestring
messagestring
detailsobject
fixErrorFix

How to get past this error, for a person or an agent. Present on refusals with a known next step, such as a missing scope or role, a plan or billing limit, a halted environment, or a missing secret, connected account, OAuth app or end-user header. Absent when there is no fix to give. Kept in production responses, unlike details.

Show properties
summarystringrequired

One sentence that says what to do.

commandstring

An exact anlyon CLI command that fixes it. Absent when no command does.

urlstring<uri>

An absolute console link where a person fixes it.

docsstring<uri>

A docs page that explains it.

401

Unauthorized - Invalid or missing API key

successbooleanrequired
requestIdstringrequired

Correlation ID matching the X-Request-Id response header.

errorobjectrequired
Show properties
codestring
messagestring
detailsobject
fixErrorFix

How to get past this error, for a person or an agent. Present on refusals with a known next step, such as a missing scope or role, a plan or billing limit, a halted environment, or a missing secret, connected account, OAuth app or end-user header. Absent when there is no fix to give. Kept in production responses, unlike details.

Show properties
summarystringrequired

One sentence that says what to do.

commandstring

An exact anlyon CLI command that fixes it. Absent when no command does.

urlstring<uri>

An absolute console link where a person fixes it.

docsstring<uri>

A docs page that explains it.

403

Authenticated credential lacks the required scope or workspace access.

successbooleanrequired
requestIdstringrequired

Correlation ID matching the X-Request-Id response header.

errorobjectrequired
Show properties
codestring
messagestring
detailsobject
fixErrorFix

How to get past this error, for a person or an agent. Present on refusals with a known next step, such as a missing scope or role, a plan or billing limit, a halted environment, or a missing secret, connected account, OAuth app or end-user header. Absent when there is no fix to give. Kept in production responses, unlike details.

Show properties
summarystringrequired

One sentence that says what to do.

commandstring

An exact anlyon CLI command that fixes it. Absent when no command does.

urlstring<uri>

An absolute console link where a person fixes it.

docsstring<uri>

A docs page that explains it.

404

Not Found - Resource does not exist

successbooleanrequired
requestIdstringrequired

Correlation ID matching the X-Request-Id response header.

errorobjectrequired
Show properties
codestring
messagestring
detailsobject
fixErrorFix

How to get past this error, for a person or an agent. Present on refusals with a known next step, such as a missing scope or role, a plan or billing limit, a halted environment, or a missing secret, connected account, OAuth app or end-user header. Absent when there is no fix to give. Kept in production responses, unlike details.

Show properties
summarystringrequired

One sentence that says what to do.

commandstring

An exact anlyon CLI command that fixes it. Absent when no command does.

urlstring<uri>

An absolute console link where a person fixes it.

docsstring<uri>

A docs page that explains it.

429

Too Many Requests - Rate limit exceeded. A workspace's API requests are limited per minute and per UTC clock hour by plan; Retry-After says when to try again, and an hourly refusal names the limit and when the count resets. Successful responses carry the same limits in X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (the minute) and X-RateLimit-Limit-Hour, X-RateLimit-Remaining-Hour, X-RateLimit-Reset-Hour (the hour).

successbooleanrequired
requestIdstringrequired

Correlation ID matching the X-Request-Id response header.

errorobjectrequired
Show properties
codestring
messagestring
detailsobject
fixErrorFix

How to get past this error, for a person or an agent. Present on refusals with a known next step, such as a missing scope or role, a plan or billing limit, a halted environment, or a missing secret, connected account, OAuth app or end-user header. Absent when there is no fix to give. Kept in production responses, unlike details.

Show properties
summarystringrequired

One sentence that says what to do.

commandstring

An exact anlyon CLI command that fixes it. Absent when no command does.

urlstring<uri>

An absolute console link where a person fixes it.

docsstring<uri>

A docs page that explains it.

Try it
Server
Authorization
Parameters
Bodyapplication/json
Request
curl -X POST 'https://api.anlyon.com/api/v2/mcp-upstreams/string/adopt' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "tools": {
    "property1": {
      "requiresApproval": true,
      "description": "string",
      "toolHash": "string",
      "impact": {
        "dimension": "string",
        "unit": "string",
        "amount": "string",
        "bound": "exact"
      }
    },
    "property2": {
      "requiresApproval": true,
      "description": "string",
      "toolHash": "string",
      "impact": {
        "dimension": "string",
        "unit": "string",
        "amount": "string",
        "bound": "exact"
      }
    }
  }
}'
Response
{
  "success": true,
  "data": {
    "adopted": [
      {
        "tool": "string",
        "action": {
          "id": "act_01JABCDEF",
          "environmentId": "19f5cc2e-7657-437a-9268-83cd3d563563",
          "name": "create-ticket",
          "description": "string",
          "method": "GET",
          "urlTemplate": "string",
          "headers": {},
          "bodyTemplate": {},
          "inputSchema": {},
          "requiresApproval": true,
          "enabled": true,
          "secrets": [
            "string"
          ],
          "currentVersionId": "acv_01JABCDEF",
          "adapter": {
            "type": "stripe.refund",
            "config": {
              "account": "acct_123",
              "mode": "test",
              "currency": "usd"
            },
            "credentialSecret": "STRIPE_TEST_KEY"
          },
          "governed": true,
          "impact": {
            "dimension": "emails",
            "unit": "emails",
            "amount": "count(input.to)",
            "bound": "exact"
          },
          "verify": {
            "url": "https://api.example.com/v1/messages/{{response.id}}",
            "status": 200,
            "match": [
              {
                "path": "status",
                "equals": "sent",
                "absent": true
              }
            ],
            "graphql": {
              "query": "query($id: String!) { issue(id: $id) { title } }",
              "variables": {
                "property1": null,
                "property2": null
              }
            }
          },
          "createdAt": "2019-08-24T14:15:22Z",
          "updatedAt": "2019-08-24T14:15:22Z"
        },
        "readopted": true
      }
    ],
    "skipped": [
      {
        "tool": "string",
        "reason": "string"
      }
    ]
  }
}

Was this page helpful?