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

Register an upstream MCP server

Answers 404 where the mcp-upstreams feature is off. Registers a remote MCP server (Streamable HTTP, https) and lists its tools: initialize and tools/list, reads only. Each tool is classified and hashed by the risk engine anlyon.dev runs. Nothing is adopted, so no agent can call anything yet. Headers carry credentials only as {{secret:NAME}} references, checked against the secret’s allowed hosts and placements, and naming one needs secrets:read. A server whose tools cannot be listed is not registered (400), and one that asks for an OAuth sign-in without OAuth settings is refused with that reason. From a credential it applies at once, except that a stored secret, or a server that signs people in with OAuth, answers 202 and waits for a person’s sign-off.

POST/api/v2/mcp-upstreams
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.

Header parameters
X-Request-Idstring

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

max length 128
Request body
requiredapplication/json
namestringrequired
matches ^[a-z][a-z0-9-]{0,31}$
urlstring<uri>required
max length 2048
headersobject
registryNamestring | null
max length 200
oauthobject | null

For a server that signs people in with OAuth (ADR 0026). With clientId, the client registered with the vendor, whose secret must have allowed hosts. Without it, this deployment's own client metadata document on a verified vendor's server whose authorization server accepts one, else a client registered with it dynamically (RFC 7591).

Show properties
clientIdstring | null
min length 1 · max length 512
clientSecretstring | null

A confidential client's secret as a secret reference. Omit for a public client (PKCE).

matches ^\{\{secret:[A-Z0-9_]+\}\}$
scopesstring[]
max items 50
redirectUristring<uri> | null

The redirect URI the client is registered with

max length 2048
authorizationServerstring<uri> | null

Which of the resource's authorization servers to use, when it names several. Default: the first.

max length 2048
Responses
201

Registered, with its tools listed.

successbooleanrequired
dataMcpUpstreamrequired
Show properties
idstringrequired
namestringrequired
urlstring<uri>required
headersobjectrequired

Sent on every request. Credentials appear only as secret references.

registryNamestring | nullrequired
protocolVersionstring | nullrequired
transportstring | nullrequired

How the server is reached, as the last listing found: Streamable HTTP, or the older HTTP+SSE transport (MCP 2024-11-05) Anlyon falls back to when the server answers 400, 404 or 405. Null until a listing has worked.

Allowed:streamable-httpssenull
serverInfoobject | nullrequired
toolsMcpToolSnapshot[]required
Show properties
Array of McpToolSnapshot
namestringrequired
hashstringrequired

sha256 of the tool's normalised definition

definitionobjectrequired
suggestedClassstringrequired
Allowed:readwriteirreversibledestructive
reasonsstring[]required
schemaCheckMcpSchemaCheckrequired

How a tool's arguments are checked. full: against its whole input schema (JSON Schema drafts 2020-12, 2019-09, 07 and 04). loose: the schema uses something Anlyon does not check, so only that the arguments are a JSON object of at most 256 KiB. A loose tool is still pinned by hash, and approval is always suggested for it.

Allowed:fullloose
schemaCheckReasonMcpSchemaCheckReason | nullrequired

Why a tool is loosely checked; null when it is checked in full. remote_ref: a $ref points outside the schema, and nothing is fetched. too_large: the schema is past a size, depth or reference limit. unsafe_pattern: a pattern could backtrack catastrophically or is too long. invalid_schema: the schema is not valid JSON Schema. unsupported_keyword: $dynamicRef or $recursiveRef. unknown_dialect: $schema names a dialect Anlyon does not know. ref_cycle: a $ref leads back to itself without moving into the value.

Allowed:remote_reftoo_largeunsafe_patterninvalid_schemaunsupported_keywordunknown_dialectref_cyclenull
toolsHashstring | nullrequired

The hash of the whole listing

listedAtstring<date-time> | nullrequired
lastErrorobject | nullrequired
listedWithstring | nullrequired

How the last listing was made: without a credential, with the headers, or with the operator's own OAuth grant.

Allowed:anonymousheadersoperatornull
checkobjectrequired

Whether Anlyon can re-list the server by itself, and when it last tried.

Show properties
statusstringrequired

failed: nothing is known since listedAt. needs_sign_in: it cannot be checked until someone connects their own account. An end user's sign-in is never used for it.

Allowed:okfailedneeds_sign_inpending
checkedAtstring<date-time> | nullrequired
nextCheckAtstring<date-time> | nullrequired
failuresintegerrequired

Failed checks in a row.

changesobject[]required

How the last listing differs from what was adopted. Finding a change adopts nothing and enables nothing. tool and before are the server's text, untrusted.

Show properties
Array of object
toolstringrequired
kindstringrequired

changed and removed are adopted tools, refused at dispatch until re-adopted. added is shown and never adopted.

Allowed:changedremovedadded
actionstring | nullrequired
actionIdstring | nullrequired
pinnedHashstring | nullrequired
currentHashstring | nullrequired
suggestedClassstring | nullrequired
Allowed:readwriteirreversibledestructivenull
beforeobject | nullrequired

The definition at the pin

detectedAtstring<date-time>required
oauthobject | nullrequired

Set for an upstream that signs people in with OAuth (ADR 0026). Never a token or a secret.

Show properties
resourcestring<uri>required
issuerstring<uri>required
authorizationServersstring[]required

Every authorization server the resource named; issuer is the one in use.

authorizationEndpointstring<uri>required
tokenEndpointstring<uri>required
scopesSupportedstring[]required
scopesstring[]required
clientIdstringrequired

The operator's client id

clientRegistrationstringrequired
Allowed:pre_registeredclient_metadata_documentdynamic
advertisedobjectrequired
Show properties
dynamicRegistrationbooleanrequired
clientIdMetadataDocumentsbooleanrequired
pkceS256booleanrequired
publicClientbooleanrequired
redirectUristring<uri>required
operatorConnectedbooleanrequired
adoptedobject[]required
Show properties
Array of object
toolstringrequired
actionstringrequired
actionIdstringrequired
enabledbooleanrequired
statestringrequired
Allowed:currentchangedmissing
toolHashstringrequired

The definition this action is pinned to.

requiresApprovalbooleanrequired
schemaCheckMcpSchemaCheckrequired

How a tool's arguments are checked. full: against its whole input schema (JSON Schema drafts 2020-12, 2019-09, 07 and 04). loose: the schema uses something Anlyon does not check, so only that the arguments are a JSON object of at most 256 KiB. A loose tool is still pinned by hash, and approval is always suggested for it.

Allowed:fullloose
schemaCheckReasonMcpSchemaCheckReason | nullrequired

Why a tool is loosely checked; null when it is checked in full. remote_ref: a $ref points outside the schema, and nothing is fetched. too_large: the schema is past a size, depth or reference limit. unsafe_pattern: a pattern could backtrack catastrophically or is too long. invalid_schema: the schema is not valid JSON Schema. unsupported_keyword: $dynamicRef or $recursiveRef. unknown_dialect: $schema names a dialect Anlyon does not know. ref_cycle: a $ref leads back to itself without moving into the value.

Allowed:remote_reftoo_largeunsafe_patterninvalid_schemaunsupported_keywordunknown_dialectref_cyclenull
archivedAtstring<date-time> | nullrequired
createdAtstring<date-time>required
updatedAtstring<date-time>required
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.

409

The request conflicts with current resource state or a concurrent decision.

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' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "string",
  "url": "http://example.com",
  "headers": {
    "property1": "string",
    "property2": "string"
  },
  "registryName": "string",
  "oauth": {
    "clientId": "string",
    "clientSecret": "{{secret:MCP_CLIENT_SECRET}}",
    "scopes": [
      "string"
    ],
    "redirectUri": "http://example.com",
    "authorizationServer": "http://example.com"
  }
}'
Response
{
  "success": true,
  "data": {
    "id": "mcpu_01JABCDEF",
    "name": "mailer",
    "url": "http://example.com",
    "headers": {
      "property1": "string",
      "property2": "string"
    },
    "registryName": "string",
    "protocolVersion": "string",
    "transport": "streamable-http",
    "serverInfo": {},
    "tools": [
      {
        "name": "string",
        "hash": "string",
        "definition": {},
        "suggestedClass": "read",
        "reasons": [
          "string"
        ],
        "schemaCheck": "full",
        "schemaCheckReason": "remote_ref"
      }
    ],
    "toolsHash": "string",
    "listedAt": "2019-08-24T14:15:22Z",
    "lastError": {},
    "listedWith": "anonymous",
    "check": {
      "status": "ok",
      "checkedAt": "2019-08-24T14:15:22Z",
      "nextCheckAt": "2019-08-24T14:15:22Z",
      "failures": 0
    },
    "changes": [
      {
        "tool": "string",
        "kind": "changed",
        "action": "string",
        "actionId": "string",
        "pinnedHash": "string",
        "currentHash": "string",
        "suggestedClass": "read",
        "before": {},
        "detectedAt": "2019-08-24T14:15:22Z"
      }
    ],
    "oauth": {
      "resource": "http://example.com",
      "issuer": "http://example.com",
      "authorizationServers": [
        "string"
      ],
      "authorizationEndpoint": "http://example.com",
      "tokenEndpoint": "http://example.com",
      "scopesSupported": [
        "string"
      ],
      "scopes": [
        "string"
      ],
      "clientId": "string",
      "clientRegistration": "pre_registered",
      "advertised": {
        "dynamicRegistration": true,
        "clientIdMetadataDocuments": true,
        "pkceS256": true
      },
      "publicClient": true,
      "redirectUri": "http://example.com",
      "operatorConnected": true
    },
    "adopted": [
      {
        "tool": "string",
        "action": "string",
        "actionId": "string",
        "enabled": true,
        "state": "current",
        "toolHash": "string",
        "requiresApproval": true,
        "schemaCheck": "full",
        "schemaCheckReason": "remote_ref"
      }
    ],
    "archivedAt": "2019-08-24T14:15:22Z",
    "createdAt": "2019-08-24T14:15:22Z",
    "updatedAt": "2019-08-24T14:15:22Z"
  }
}

Was this page helpful?