Who manages plugins
Go to Command Center → Plugins. The page has an MCP tab, shown first, and an HTTP API tab. The MCP tab lists each plugin’s name, description, type, scope, state and creation time; the HTTP API tab lists each API’s name, location, scope, state and creation time. Open a row or select its arrow to reach the plugin’s page; the trash action deletes an unassigned plugin. The plugin page keeps scope, enabled state and Save Changes in its top bar. Its name, description, connection and authentication fields appear in one form.What each role can do
Only administrators change plugins; everyone else reads them:
On a hosted MCP server, an organization administrator gets a Turn off button, in a save that changes nothing else; once it is off, the details say that only a tenant-level administrator can change it or turn it back on, and no Delete is offered.
Scope
The Scope selector controls which organizations can use the plugin. Scoped to Organization, the default, associates it with the currently selected organization only, restricting it to that org’s agents. Scoped to Tenant makes it available to all organizations in the tenant. Selecting the tenant scope requires tenant-level access; without it the selector stays on Scoped to Organization. Changing an OAuth plugin’s scope disconnects its OAuth accounts and forgets its trusted provider. While an enabled OAuth plugin is assigned to agents, the scope change is refused unless the same save turns the plugin off.Enabled state
Switching a plugin off stops every agent from using it from the next turn, and keeps the assignments.Assign plugins to an agent
Open Agents, select the agent, and add or remove its plugins, MCP servers and HTTP APIs alike. Anyone who can edit the agent can do this, without being an administrator; an auditor can read the assignments but not change them. Each assignment shows the plugin kind and authentication method. When you create an agent in Command Center, the enabled plugins that need no account (anonymous plugins, hosted MCP servers, and Bearer or API-key plugins holding their credential) are added by default. This default belongs to the form: an agent created through the public API or the AI Assistant gets only the plugins the request names, and one created by a CSV or JSON import gets none. Through the API, save one assignment, replace the agent’s whole set, or passplugin_ids when creating the agent.
Remote MCP servers
Remote MCP server endpoints
Endpoint rules
The rules apply to the address a name resolves to, so a public address is refused even when the URL looks internal. No setting turns off cleartext HTTP to private addresses, so a new internal MCP server needs no deployment change. Storing an HTTP URL grants no permission by itself, and assigning it to an agent does not activate it. If the rules change, saved settings stay readable and deletable, and you can still edit the description or keep the plugin disabled; creating, replacing or enabling a connection must meet the current rules.
Through a proxy
An engine that sends its outbound traffic through a proxy (HTTP_PROXY, HTTPS_PROXY) sends MCP endpoints and OAuth providers through it too, except the hosts NO_PROXY names, so list internal MCP services there. The engine still resolves each destination and applies the rules above first, so it must be able to resolve those names itself. A hosted MCP server reaches no proxy unless its variables name one, such as HTTPS_PROXY.
MCP server detection
What the MCP URL field accepts when you add a remote MCP server, and how 2501 sets up the plugin from it.What the MCP URL field accepts
Only the URL is sent: headers, tokens and other values in a pasted configuration are neither sent nor saved. In a
docker run command, a variable whose name holds a secret word, such as GITHUB_TOKEN, API_KEY, PGPASSWORD, SSH_PASSPHRASE or accessToken, becomes a credential to choose, and its pasted value is not kept; a name where that word is only part of another, such as BASE_PATH or MAX_TOKENS, stays a plain value. Options 2501 does not grant a hosted MCP server, such as host folders (-v), published ports (-p) or network settings, are left out and named.
How detection picks the authentication
The engine connects to the URL the way a task would, over Streamable HTTP or, for an older server, HTTP+SSE, and lists its tools without calling any.
The form then shows how many tools it verified, or why it could not connect, such as
Not an MCP endpoint (HTTP 404), a refused connection, a host name that does not resolve, an untrusted TLS certificate, a failed TLS handshake or a timeout; Detect again repeats the check. Add MCP stays unavailable while the engine refuses the address, such as cleartext HTTP to a public address, but a server it could not reach can still be added. The name is the one a pasted configuration gives, else the one the server announces, else one taken from the URL’s host name without words such as mcp and server (none for an IP address or localhost); change it if it does not suit.
Add a remote MCP server
A plugin is either a remote MCP server, which 2501 connects to by its URL, or a hosted MCP server, which the engine runs itself from a container image.- Open Plugins and select Add MCP.
- Paste the server’s MCP URL, its README configuration or its command line. The form fills in what it finds and asks only for the rest. See What the MCP URL field accepts.
- Check the authentication 2501 detected, as How detection picks the authentication describes. For a server that answers without authentication, leave Anonymous / Agent managed selected, or select Change to pick another. An API key also needs a header name such as
X-Api-Key. - For Bearer token or API key, choose the Secret or Vault path credential the plugin sends: every agent assigned the plugin uses it.
- Enter the name and description, choose the scope and enabled state in the top bar, and save.
- Assign the plugin to an agent and check the connection from there: saving deploys and connects to nothing.
Connect an MCP endpoint through the API
Create a plugin through the public API with a custom name, an optional description, and an anonymous connection:enabled starts enabled. Set enabled: false when creating or updating a plugin to keep its assigned agents from using it, and enabled: true to let them again, from the next turn of a task already running. The Plugins page saves a new plugin enabled, and asks for the credential of a Bearer or API-key plugin before saving it. Saving a URL never connects to it, resolves a credential or deploys a server. These settings name the credential, never its value. API-key header names must be valid HTTP names and cannot replace transport or session headers such as Host, Content-Type, Mcp-Session-Id or Mcp-Protocol-Version. Custom headers such as X-API-Key and raw Authorization schemes are accepted. An assignment can be checked before enablement.
Updates can change the name or description, or replace the entire connection object. Omitting a field preserves it. A plugin without an endpoint can be given one in an update that also leaves it disabled; see Give a legacy plugin an endpoint. No other change of connection type is accepted. Each authentication method takes different fields, as Authentication methods lists.
Hosted MCP servers
Hosted MCP server lifecycle
The engine runs one container per hosted MCP server and organization next to itself, shared by that organization’s tasks; a hosted MCP server in use has no time limit. On Kubernetes its variables reach its pod through a Secret the pod owns and that is deleted with it, so the engine’s role needs to create secrets.What stops or replaces the container
When a start fails
Meanwhile a connection check shows when the next try is and why the last one failed, including the server’s last error output when it exited during startup. A task is told only that the plugin could not be reached, and the engine logs the full error (
MCP plugin is unavailable). Credential variable values are replaced with [REDACTED] in that output and in the logs.
Image pull logins
The login an image is pulled with depends on where it runs:Hosted MCP server limits
Only a tenant-level administrator adds or changes a hosted MCP server, and 2501 runs its image exactly as named, so trusting a tenant administrator with hosted MCP servers means trusting any image they name. The container gets no Linux capabilities and cannot gain privileges. It never runs as root, whatever user its image names: it runs as user 65532, or on OpenShift as the user the cluster assigns. The image must therefore work as any non-root user: its files readable by every user (readable by group 0, as OpenShift expects), and nothing written outside/tmp, which is its HOME unless it sets one. Serve an image that cannot through an HTTP wrapper instead.
Resource limits
Network
On Kubernetes its pods carry the labelapp.kubernetes.io/managed-by: 2501-mcp-hosted, and the mcp-hosted-isolation network policy the CLI generates with the other manifests holds those pods, and only those, to DNS and public addresses, with no traffic in. To let them reach an internal service, such as a vCenter, apply a policy of your own that selects the same label and allows its range; allow-mcp-hosted-internal in kubernetes-overlays/networkpolicy.example.yml is one to adapt. The pods get no Service environment variables. On Amazon EKS the policy applies a few seconds after a pod starts unless the VPC CNI runs with NETWORK_POLICY_ENFORCING_MODE=strict, which denies every new pod all traffic until its policies apply. On Docker, the firewall rules below do the same, and without them it reaches other containers’ published ports and the machine’s network.
Add a hosted MCP server
A hosted MCP server runs from a container image: paste itsdocker run command in the MCP URL field, and the hosted MCP server’s fields appear below it, to check or complete: the image, such as registry.example.com/team/mcp-server:1.2, its arguments one per line, and its environment variables. A variable holds either a plain value, which everyone who can read plugins sees, or a Secret or Vault path credential, which 2501 reads when the hosted MCP server starts and never shows. An existing plugin switches between a remote MCP server and a hosted MCP server only in a save that also disables it. Its first start may pull the image, so check the connection from an agent once after saving. If a proxy in front of Command Center gives up on the check first, the agent’s form says the server is still starting: check again a minute later. Only tenant-level administrators can add, change or delete a hosted MCP server; see Who manages plugins.
Run hosted MCP servers without internet access
Put the hosted MCP server’s image in a registry your cluster, or the engine’s machine on Docker, can pull from, and enter it by that reference. The engine pulls it with the login Image pull logins lists. On Docker, mount the file into the engine’s container and pointDOCKER_CONFIG at its directory, or pull or load the image on the engine’s machine first (docker pull, or docker load from a saved image): the engine uses an image the machine already has.
Build an image for an npm or PyPI server
A server published only on npm or PyPI needs an image built for it. Build it in your own pipeline, through your package mirror, and pin the version so that an installation does not change on its own:python:3.12-slim, pip install the pinned package and set its command as the ENTRYPOINT. A server that only reaches an online service, such as Context7, still needs that service: without internet access, choose servers that talk to your own systems.
Isolate hosted MCP servers on Docker
On Docker, including Docker Swarm, these firewall rules are a required step on every machine where the engine runs hosted MCP servers. Without them a hosted MCP server’s network keeps it away only from containers that publish no port. It still reaches every container that publishes a port, on that container’s own address and published port, even a port published on127.0.0.1 only, such as a database, and whatever the machine itself reaches: private ranges, the cloud metadata address and the machine’s own services. To hold hosted MCP servers to public addresses, drop their traffic to private ranges, the metadata address and the machine itself, as root on the engine’s machine, once the engine has started a first hosted MCP server and created the network:
DOCKER-USER covers traffic to other machines and to other containers, published ports included, since Docker gives containers addresses in private ranges, and INPUT covers the machine’s own services. If the Docker daemon gives networks addresses outside these ranges (default-address-pools), add those ranges to the loop. Name resolution keeps working, since Docker resolves names for the container from the machine itself. To let hosted MCP servers reach an internal service, insert (-I) an ACCEPT rule for its address after running these, so it comes first. The rules last until the machine restarts, and apply to the network as it is: save them with your firewall tooling, and run them again if the network is removed and created again. On Kubernetes, the network policy does this instead.
MCP credentials and OAuth
Plugin credentials
One plugin has one connection method and, for Bearer or API key, one credential, which every agent assigned the plugin sends. It must be a Secret or Vault path in the plugin’s organization or shared across the tenant; a tenant-wide plugin takes only a tenant-wide credential. No token value appears in the picker or in any response. Changing the credential or the URL of an enabled plugin needs no switch off: a running task’s next call is refused as changed, and its next turn connects with the new settings. A credential a plugin sends cannot be deleted, even while the plugin is disabled.Authentication methods
Eachauthentication.method takes different fields, and not all can start enabled:
Which plugins take placeholders
A placeholder the agent has no access to fails the call, and nothing is sent. The value is hidden in the tool result the agent reads, the task history and the ticket, and the recorded call keeps the placeholder. The MCP server writes the tool descriptions the agent reads, so it can ask for any credential the agent has: give that agent only the credentials the server may see.
OAuth accounts
How an OAuth plugin identifies itself, trusts its provider and keeps its accounts signed in. Authorize an OAuth account connects one.How 2501 identifies itself to the provider
- Automatic: when the provider reads Client ID Metadata Documents and BASE_URL is an HTTPS address that resolves to public addresses, the client ID is the document Command Center publishes at
/api/mcp-oauth/client, which the provider fetches. Otherwise 2501 registers dynamically. - Dynamic: 2501 registers a client with the exact callback, once per provider: a public client, or a confidential one when the provider takes no public client, whose secret 2501 keeps. It is reused until the provider’s expiry for it, and registered again once the provider no longer accepts it. A provider that offers neither automatic nor dynamic registration, or refuses it, needs a pre-registered client, and connecting says so.
- Client secret: sent as
client_secret_basicorclient_secret_post, as the provider advertises. - Private key: a PKCS #8 PEM key, RS256 by default or ES256, with the key ID (
kid) if the provider asks for one. Each token request carries a JWT signed with it, valid for a minute. - Service account: Connect service account gets a token with the client credentials grant, without opening the provider, and the provider must allow that grant for the client.
private_key_jwt is refused as unsupported. A sign-in with the metadata document that expires without returning suggests choosing dynamic registration. Registration names no scopes, so the provider gives its defaults and the plugin’s scopes are asked for at sign-in; on Keycloak each must be an Optional client scope, and a provider that limits a client to its registered scopes needs a pre-registered client. 2501 leaves out the resource parameter for Microsoft Entra ID, which refuses it.
Redirect URL
Register the redirect URL the plugin form shows under Redirect URL to register with your provider, with its copy button:
The host is the deployment’s
BASE_URL, which the engine and Command Center must share: the address users open Command Center with, HTTPS where you can. A plain-HTTP address, on an installation reachable only on its own network, is accepted, but some providers refuse to send the browser back to one; the code sign-in or pasting the return address then still complete the sign-in, and the plugin editor says when Command Center is served over plain HTTP. Only a missing BASE_URL stops the sign-in. The Client ID Metadata Document still needs an HTTPS address that resolves publicly.
Trusted provider
A plugin trusts one authorization server, and sends client secrets, codes and tokens to that server only. The editor shows it, for example “Trusts login.example.com”.
The provider’s addresses must be public HTTPS addresses. An installation whose identity provider sits on its own private network sets
MCP_OAUTH_ALLOW_PRIVATE_PROVIDERS=true on the engine; without it, detection and connecting both say the provider is on a private address and name that setting.
Provider requirements
The provider must meet these, or sign-in or renewal fails:
A return arriving at a provider’s own redirect URL was sent to that server’s address, so that is all; 2501 registers its clients there, and so do pre-registered clients set up in the plugin form. The address does not prove which client the return is for: at a provider with open client registration, anyone can register a client with that address and send a code there, and only the sign-in’s state and PKCE verifier keep that code from completing it. Access and refresh tokens remain private to the plugin authorization and are excluded from API serialization and agent CSV/JSON imports.
Token renewal
- A connection check, a task turn or a call finds less than a minute or a tenth of the token’s lifetime left, whichever is longer; before a turn the token must also outlast the turn, seven minutes at most. Or the MCP server answers
401: it processed nothing, so the token is renewed however long it has left, the call is sent again once, and a refused connection reconnects at the next turn. - A new token. Concurrent checks share one exchange and keep the same account, across engine processes too, and an open task session takes the token without reconnecting.
- The provider refuses or cannot be reached. The account is kept, and once its token has expired a check returns
authorization_required. - The next check or task, a minute later.
- The token expires while nobody uses the plugin, and the account holds a refresh token or is a service account: nothing renews in the background.
- The next check, task or call.
- The token expires and the account holds no refresh token.
- Reconnect account.
authorization.renewable in GET /api/v1/plugins/{id}/oauth says whether an account renews. A token without an expiry, or one the provider revoked early, stops only when the MCP server refuses it.
Renewal failures
The account panel says the last renewal failed and why. The account is kept meanwhile, since a provider that refuses and one that cannot be reached look the same, and a service account whose client secret or private key was fixed recovers by itself at the next renewal.
A missing scope the plugin’s own scope list leaves out is shown with a prompt to add it there, since reconnecting never asks beyond that list.
Missing scopes
If a server refuses a call because the connected account lacks a scope, the call fails with a message naming it and the account shows Reconnect needed with scopes followed by the scopes the server asks for. Reconnecting the account, a service account included, asks the provider for them as well; nothing asks for them on the server’s word alone. A plugin that lists its own scopes never asks beyond them, and when the provider or the server lists the scopes it knows, only those are asked for. A scope the provider refuses is no longer asked for: connect again.Advanced settings
Two optional fields of the OAuth connection, under Advanced in the plugin form, cover providers that need more:audience: the API the tokens are for, sent as theaudienceparameter on the sign-in page and on every token and device request, service accounts included. Auth0 needs it to issue a token for an API rather than refuse the service account (“No audience parameter was provided”).metadata_url: the HTTPS address of the authorization server’s metadata document, for a provider whose metadata does not live at its issuer. Azure AD B2C publishes it under a user flow, for examplehttps://<tenant>.b2clogin.com/<tenant>.onmicrosoft.com/<user flow>/v2.0/.well-known/openid-configuration, and names a tenant ID issuer. Sign-in and renewal then read that document instead of the server the MCP server names, and the plugin trusts the issuer the document names. The issuer and the endpoints the document lists must be on the document’s own origin.
Choose the credential a plugin sends
Choose it in the plugin’s form, when adding the plugin or editing it, or setcredential_id in its connection through the API; see Plugin credentials for which credentials it takes. To reach one service two ways, or with two accounts, create two plugins and assign each to the agents that need it.
Give each agent its own token
For an MCP server where each agent signs in with its own token:- Configure the plugin as anonymous.
- Give the agent the token as a credential in its accessible credentials.
- The agent passes it in the tool arguments as
{{secret:<name>}}, and 2501 puts in the value just before the call leaves, under the same rules as a placeholder in a command.
Authorize an OAuth account
On the Plugins page, select OAuth, choose how 2501 identifies itself to the provider, and leave Use the provider’s requested scopes selected or enter explicit scopes. Save the plugin, then connect an account as described below. Run Check connection from an assigned agent, then enable the plugin once every organization with a live assignment has connected its account; an enabled plugin only accepts new assignments in organizations that did. Reconnect account replaces the previous authorization and can select another account. The saved plugin page keeps these OAuth settings visible beside the connected account.Connect an account
Connect an account once per organization: every agent assigned there shares it, and a tenant-wide plugin connects in each organization that uses it.- In the plugin editor, select Connect account. Only someone who can edit the plugin can.
- Sign in at the provider, in the way Command Center offers:
- Sign-in page. Select Open the sign-in page, or Copy the link to open it elsewhere, then choose the account and consent. The provider sends your browser back to Command Center.
- A code. When the provider supports device sign-in, the editor shows a code and the provider’s address. Open the address on any device that can reach the provider, enter the code and sign in. A refused or expired code offers Start again.
- Paste the return address. If the page the provider sends you back to does not load, copy the whole address from the address bar into Paste the address your browser ended on, and select Complete.
- Command Center says the account is connected.
- A sign-in expires after ten minutes, or with the provider’s device code. Only the user who started it can complete it, once, and starting again replaces only your own attempt.
- The connected account keeps working until a new one is authorized, so closing or refusing the consent screen disconnects nothing. No token is returned.
- The sign-in page asks the provider to let you choose the account (
prompt=select_account, orprompt=loginwhen the provider lists its prompts without that one), so a session already open there does not connect its account unchosen. - A provider that does not let the client use device sign-in gets the sign-in page instead. A device check the provider fails to answer is asked again later; anything else ends the code and says why.
- If your Command Center session ended before you came back, sign in again and start the connection again.
- The account shows as “Connected as …”, also on a successful check: the
preferred_username, email or subject from the ID token when the scopes includeopenid, else from the provider’s user info endpoint, or the client ID for a service account.
Connect an account through the API
With a Command Center session that can edit the plugin; other sessions get403, and API keys cannot:
Connect Microsoft Entra ID
Entra ID does not register clients on its own, so create the client there first:- In the Entra admin center, open App registrations and select New registration. Under Redirect URI, choose Web and enter the redirect URL the plugin form shows for your tenant’s issuer,
https://your-command-center-host/api/internal/mcp-oauth/callback/<key>: start the plugin with the MCP server’s URL and copy it from there. - Under Certificates & secrets, create a client secret. Store its value in 2501 as a Secret credential and name it as the plugin’s client secret.
- Under API permissions, add the delegated permissions the MCP server expects, usually a scope of its own app registration such as
api://<application ID>/mcp.read, and grant admin consent if your tenant requires it. - To let people sign in with a code instead, under Authentication, turn on Allow public client flows. Connecting then shows a code first.
offline_access so 2501 receives a refresh token, and openid profile to show who signed in. Entra issues a token for one API at a time, so do not mix the MCP server’s scope with Microsoft Graph scopes. The trusted provider is your tenant’s issuer, https://login.microsoftonline.com/<tenant ID>/v2.0. An MCP server that names a multi-tenant endpoint (common or organizations) is trusted as that endpoint, for example https://login.microsoftonline.com/common/v2.0: people from any tenant can then sign in, and a service account is not available, since it needs a tenant.
For a service account, add an Application permission of the MCP server’s app registration instead, grant admin consent, select Sign in as a service account, and enter the single scope api://<application ID>/.default.
MCP servers in a task
MCP servers during a task
A failed call may have reached the server, so its outcome is unknown and the task never sends it again. Handling Permissions covers what this means for revoking access. Task details show each plugin the task could not use, with its reason, and each credential or OAuth account change; anyone who can read the task can read this history, and it does not enter the agent’s dialogue.Tool limits
When a change reaches a running task
Connection check results
What checking an assigned connection returns. The engine initializes the saved endpoint, lists tools and closes its test client. For Bearer and API-key authentication, it resolves only the plugin’s Secret or Vault path after checking that it is still in the agent’s organization or tenant-wide; a draft without one fails the check. Invalid secrets and unresolved Vault values block the check without falling back to anonymous access or another credential. It calls no tool, deploys nothing and leaves the shared service running. You can check a disabled assignment without enabling it, except a hosted MCP server: a check starts the hosted MCP server, so only a tenant-level administrator can check one while it is turned off, and anyone else gets403. The public agent plugin list contains enabled plugins by default; GET /api/v1/agents/{agentId}/plugins?include_disabled=true also returns disabled assignments.
The result is an instant snapshot. Success requires that the assignment, enablement, connection and credential access still match when the client closes. Bearer and API-key checks resolve the plugin’s credential again before returning success, so a changed Vault value also invalidates the result. The check does not prove access to individual operations or guarantee that a later task can connect. Checking is optional and does not change activation or runtime authorization.
The result displays the check time, tool count, negotiated transport and protocol version, or a failure reason. It is local to the open form, clears when assignments change, and is not continuous monitoring. To use the connection in a task, separately enable the plugin. Bearer and API-key connections need the plugin’s credential, described above. A successful check is optional and does not grant runtime access.
Check results
For a remote MCP server it names the HTTP status, a URL that does not look like an MCP endpoint (it answered HTTP 404 or 405, with a web page or other content that is not MCP messages, named by its media type, or with JSON that is not an MCP message, such as a REST API’s root), a host name that does not resolve, a TLS certificate the engine does not trust, a failed TLS handshake, a refused connection (with the address and port tried) or a closed one, or a timeout, and never repeats what the server answered. For a hosted MCP server it is the start error, its credential values redacted, such as an image that cannot be pulled, a namespace quota used up, a role that cannot create pods or secrets, a handshake that timed out or all 32 hosted MCP servers in use. The agent’s plugin list shows it after the failure.
Failure categories
Check an assigned connection
Open an agent’s detail page and select the plugin, including a disabled plugin. Save the agent, then select the flash icon beside the saved assignment; its tooltip reads Check connection. HTTP API assignments have no check here; check them on the plugin’s form instead. The result appears below the assigned plugins. To remove the assignment, select its X and save the agent. The form blocks saving if it cannot load assignments; use Retry before continuing. The equivalent API call isPOST /api/v1/agents/{agentId}/plugins/{pluginId}/check with no body. Connection check results lists what it returns. The caller needs permission to write the agent and read the plugin.
HTTP APIs
An HTTP API plugin connects agents to APIs no MCP server covers, such as your internal APIs or APIs that LLMs have no prior knowledge of.HTTP API requests
An agent assigned an HTTP API plugin gets three tools: one to send a request (method, relative path, query, body and content type), one to list the uploaded documentation files, and one to read a file incat -n-numbered pages. The request tool answers with the status, headers and body as JSON. A task in investigate mode is held to GET, whatever method the request names. Any other task can send GET, HEAD, OPTIONS, POST, PUT, PATCH or DELETE.
A request body holds at most 64 KiB. A request gets 10 seconds to answer, once its executor runs; one that must start an executor first waits up to 3 minutes for it. Redirects are not followed: the agent reads the 3xx answer itself. An error status, such as 404 or 500, reaches the agent like any other answer. A response body past 64 KiB is cut and marked truncated, set-cookie headers are removed, and the credential is replaced in the response wherever it appears.
A request refused before it left, by the destination rules, the outbound proxy or a failed connection, tells the agent that nothing reached the API. A request that was sent but got no complete answer tells the agent its outcome is unknown and, for any method but GET, HEAD or OPTIONS, to check its effect before sending it again. 2501 never sends a request again on its own.
Requests go through the same Blacklist check as a shell command.
HTTP API documentation files
Documentation is optional but highly recommended. OpenAPI or Swagger files work, and so does plain Markdown or text documentation. Each file keeps its path inside the folder it was uploaded from, such asapi/schemas/order.yaml.
File limits
- Hidden files and folders, such as
.git, andnode_modulesare skipped. - Minified JSON puts a whole file on one line and is refused, so pretty-print it before uploading.
- A path that leaves the folder, such as one with
.., or that holds an invisible character, such as a right-to-left override, is refused. - Files uploaded together are stored together: if one is refused, none are, and the message names every refused file with its reason.
- Uploading a file at the same path replaces the previous one for every agent.
Add an HTTP API
An HTTP API plugin calls a service directly, with structured requests instead of an MCP server in front of it. Open Plugins, select the HTTP API tab beside MCP, and choose Add HTTP API. Enter a name and a description. The description tells the agent what the API is for and when to use it. An HTTP API plugin has no tool descriptions of its own, so a save without a description is refused; without uploaded documentation, the description is all the agent has. Choose where requests run from, Main executor or a registered cluster, and enter the Base URL: every request goes to a relative path under it, so it cannot carry query parameters itself. The location is fixed once the plugin is saved; create a new plugin to run the same API from elsewhere. An HTTP API that runs on a cluster must belong to that cluster’s organization. On Main executor, requests use the engine’s outbound proxy; on a cluster, they connect directly from the cluster. Choose the authentication: Anonymous, Bearer token, or API key header with the header name, each with the Secret or Vault path credential to send; see Choose the credential a plugin sends. To confirm the API is reachable before saving, click Check connection below the authentication, when adding the plugin or on its page. An executor in the chosen location opens a connection to the base URL’s host and port, completes the TLS handshake for HTTPS, and closes it: no HTTP request is sent and no credential is used. The result is Connected, or the step that failed - the executor start, the host name lookup, the outbound proxy, the connection, the TLS handshake, or a destination 2501 refuses - and never anything from the API. Behind the engine’s outbound proxy, a Main executor check asks the proxy to open the connection, as a request does. A check on a cluster starts an executor with the cluster’s Executor placement and shows each step as it runs. A check does not prove that the credential works or that a request succeeds. Checking needs permission to edit the plugin. To give the agent documentation, pick files with Add files, or a whole folder with Add folder; see HTTP API documentation files for what is accepted.Connect an HTTP API through the API
Create an HTTP API plugin through the public API with its base URL, where it runs from, and anonymous authentication:location to { "kind": "satellite", "cluster_id": "<cluster ID>" } to send requests from a registered cluster instead of the Main executor. authentication also takes { "method": "bearer", "credential_id": "<credential ID>" } or { "method": "api-key", "header_name": "X-Api-Key", "credential_id": "<credential ID>" }.
Upload reference files with POST /api/v1/plugins/{id}/documents: a multipart/form-data body with one file part and one relative_path part per file, in the same order, sending its Content-Length. GET /api/v1/plugins/{id}/documents lists the stored files, and DELETE /api/v1/plugins/{id}/documents/{documentId} removes one. See HTTP API documentation files for the accepted file types and size limits.
Legacy plugins
Plugins without an endpoint
Without a URL connection, creation acceptsGitHub MCP Plugin, Notion MCP Plugin and vmware, and saves the plugin enabled unless the request sends enabled: false, like any new plugin. Records without an endpoint report Migration required and provide no tools. Creation compatibility does not start a built-in backend. Other existing legacy names remain readable and editable; creating a new custom name requires a URL connection.
Saving the endpoint preserves credential grants and task history. It does not copy engine secrets, deploy the new service or stop any service or executor. Invalid settings, lost access or concurrent re-enablement prevent the update. Once a plugin has an endpoint it cannot be taken back to having none, and returning to the removed runtime is unsupported.
Legacy VMware plugin settings
Where the settings of the VMware MCP that the removed runtime started go. Give a legacy plugin an endpoint moves the plugin.VMware settings
The removed runtime ran the image the engine settingVMWARE_MCP_IMAGE named (vmware-mcp:latest by default) and passed it every engine variable whose name starts with VMWARE_, unchanged. The VMware MCP reads the variables of govc, the vSphere command line it runs, instead. Each setting therefore moves to a variable of the new hosted MCP server:
VMware settings that move
GOVC variables
Other govc variables, such as
GOVC_DATACENTER, set its defaults as usual.
Give a legacy plugin an endpoint
Before upgrading, the deployment owner stops the old engine as Plugins from the legacy runtime describes. Deploy the replacement MCP service, or run the server as a hosted MCP server: a server shipped as a container image can be a hosted MCP server, which 2501 runs itself. Create it as a new plugin with that image, under a new name: the legacy plugin, such asvmware, keeps its name. Assign the new plugin to the agents that used the legacy one, then turn the legacy plugin off or delete it. The VMware MCP that the removed runtime started is such a server, published as 605134458542.dkr.ecr.eu-west-3.amazonaws.com/2501.ai/release/vmware-mcp:<version>: it takes no arguments, and Legacy VMware plugin settings lists its variables and where each old setting goes. On Kubernetes, allow the vCenter’s address range for hosted MCP server pods with a policy of your own, since they reach only public addresses by default.
- Open the unconfigured plugin’s editor on the Plugins page and choose Add an endpoint.
- Enter the deployed MCP URL and authentication method, turn the plugin off, then save.
- Reload and verify the saved connection. The plugin keeps its ID and agent assignments and remains disabled.
- For a Bearer or API-key endpoint, choose the credential the plugin sends; for OAuth, connect the account of each organization. Check each saved connection, then enable the plugin.

