> For the complete documentation index, see [llms.txt](https://developer.celigo.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.celigo.com/api/api-reference/mcp-servers.md).

# MCP Servers

MCP servers expose integration tools and builder-mode APIs as MCP-compatible endpoints consumed by AI agents and MCP clients.

Each server has a unique `relativeURI`, a collection of tools and APIs (each individually enable/disable), optional prompt templates, optional file resources from Celigo Storage, and optional OAuth configuration. Tools support MCP annotations (read-only, idempotent, destructive, open-world) and per-server overrides for connections, exports, imports, and routing. Permission sets ("Capability Sets" in the UI) bundle a server's tools and APIs into named grants for end users, and the server-scoped access endpoints bulk-assign capabilities to end users and groups and report compiled effective access. Optional traffic limits (`policies`) — a server-level rate limit, a per-user rate limit, and a usage quota — reject calls over the limit with HTTP 429 and `Retry-After` before any tool runs.

### MCP server schema

## The MCPServer object

```json
{"openapi":"3.2.0","info":{"title":"MCP Servers","version":"1.0.0"},"components":{"schemas":{"MCPServer":{"type":"object","required":["_id","name","relativeURI","disabled","createdAt","lastModified"],"description":"MCP server object as returned by the API.","allOf":[{"$ref":"#/components/schemas/MCPServerBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"Owning user ID."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"When this draft MCP server expires and will be automatically deleted. Only present\non servers created as drafts by the AI-assisted builder that have not yet been\nconfirmed. Unlike other resource types, MCP server drafts carry no `draft` boolean —\nthe presence of this field is what marks the draft state."}}}]},"MCPServerBase":{"type":"object","description":"Writable MCP server fields shared by the request and response schemas.","properties":{"name":{"type":"string","minLength":1,"maxLength":150,"description":"Display name for the MCP server."},"relativeURI":{"type":"string","maxLength":131072,"pattern":"^\\/[a-zA-Z0-9_\\-]+$","description":"URI path segment for the MCP server endpoint. Must be unique per account —\nduplicates are rejected with 422 `mcp_server_duplicate_relative_uri`. Only letters,\nnumbers, dashes, and underscores after the leading slash (the server's error message\nalso claims colons and dots are allowed, but they are rejected in practice). Creation\nalso requires the account to have an account alias set (422\n`mcp_server_account_alias_required` otherwise)."},"description":{"type":"string","maxLength":1000,"description":"Description of the MCP server's purpose."},"disabled":{"type":"boolean","default":true,"description":"Whether the MCP server is disabled. Defaults to `true` on creation.\nTo serve requests, at least one tool, API, resource, or prompt must\nalso be enabled."},"tools":{"type":"array","description":"Tool entries referencing Celigo Tool resources. Duplicate `_toolId`\nvalues are rejected. Names must be unique across both `tools` and `apis`.","items":{"$ref":"#/components/schemas/IOTool"}},"apis":{"type":"array","description":"API entries referencing Celigo builder-mode API resources. Only\nbuilder-type APIs are supported. Names must be unique across both\n`tools` and `apis`.","items":{"$ref":"#/components/schemas/ApiTool"}},"resources":{"type":"array","description":"Files from Celigo Storage exposed to MCP clients as MCP resources.\nEach entry references a storage file by `_fileId`; the same file can\nappear only once. Always returned in responses — servers created\nbefore resource support return an empty array. Not supported on\nsandbox servers.","items":{"$ref":"#/components/schemas/McpResource"}},"prompts":{"type":"array","description":"Prompt templates exposed to MCP clients. Each prompt has a unique\n`name` and may declare `arguments` that clients supply via\n`prompts/get`.","items":{"$ref":"#/components/schemas/Prompt"}},"permissionSets":{"type":"array","description":"Named bundles of this server's tools and APIs — shown as \"Capability\nSets\" in the UI — granted to end users as a unit via `pset:<_id>`\ncapability strings. Omitting the field on PUT resets it to an empty\narray, erasing every set and rewriting the grants that reference\nthem — always send the complete array back. Absent from responses for\nservers not saved since permission sets were introduced (unlike\n`resources`, the field is not normalized to an empty array).","items":{"$ref":"#/components/schemas/PermissionSet"}},"policies":{"type":"array","description":"Traffic limits enforced on this server before a tool runs — a\nserver-level rate limit, a per-user rate limit, and a usage quota, each\noptional and independent. An empty array (the default) means unlimited.\nAlways returned; servers saved before traffic limits existed return an\nempty array. Omitting the field on PUT clears every limit — send the\ncomplete array back, or edit it with PATCH.","items":{"$ref":"#/components/schemas/Policy"}},"oauth":{"$ref":"#/components/schemas/OAuthConfig"}}},"IOTool":{"type":"object","description":"A tool entry that maps a Celigo Tool resource to an MCP tool endpoint.\nThe referenced tool's input schema must have `type: \"object\"`.","properties":{"_toolId":{"type":"string","format":"objectId","description":"Tool resource ID. The referenced tool must exist and have an\ninput schema with `type: \"object\"`."},"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP tool name exposed to clients. Must be unique across all tools\nand APIs within this server."},"disabled":{"type":"boolean","default":true,"description":"When true, this tool is disabled and will not be exposed to MCP clients."},"annotations":{"$ref":"#/components/schemas/Annotations"},"overrides":{"$ref":"#/components/schemas/Overrides"}},"required":["_toolId","name"]},"Annotations":{"type":"object","description":"MCP-standard annotations that hint at the behavior of a tool.\n\nThese annotations follow the Model Context Protocol specification and help\nAI agents and MCP clients understand how a tool behaves without executing it.\nAll fields are optional hints — they are not enforced by the server.\n","properties":{"title":{"type":"string","maxLength":300,"description":"Human-readable title for the tool, displayed in MCP client UIs.\n\nIf not provided, the tool's `name` field is used instead.\n"},"destructiveHint":{"type":"boolean","description":"Hints that the tool may perform destructive operations such as\ndeleting or permanently modifying data.\n"},"idempotentHint":{"type":"boolean","description":"Hints that calling the tool multiple times with the same input\nproduces the same result without additional side effects.\n"},"openWorldHint":{"type":"boolean","description":"Hints that the tool interacts with an open-world environment\n(e.g., external APIs) where results may vary between calls.\n"},"readOnlyHint":{"type":"boolean","description":"Hints that the tool only reads data and does not modify any state.\n"}}},"Overrides":{"type":"object","description":"Per-server overrides for a tool's internal resources.\n\nWhen a tool is added to an MCP server, its connections, exports, imports,\nand routers can be customized for this specific server context without\nmodifying the underlying tool definition. This enables reusing the same\ntool across multiple MCP servers with different configurations.\n","properties":{"connections":{"type":"array","description":"Connection overrides. Each entry maps an abstract connection reference\nin the tool to a concrete connection resource for this server.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"The abstract connection identifier from the tool definition.\nThis is the connection reference that will be replaced.\n"},"_id":{"type":"string","format":"objectId","description":"The concrete connection resource to use in place of the abstract reference.\n"},"_borrowConcurrencyFromConnectionId":{"type":"string","description":"Optional connection from which to borrow concurrency limits.\n"}},"required":["_abstractId"]}},"exports":{"type":"array","description":"Export (lookup) overrides. Customize export resources used within the tool,\nincluding connection bindings, scheduling, response mappings, and\nadaptor-specific settings.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract export identifier from the tool definition"},"_id":{"type":"string","format":"objectId","description":"Concrete export resource to use"},"_connectionId":{"type":"string","format":"objectId","description":"Override the connection used by this export"},"type":{"type":"string","enum":["webhook","distributed","test","delta","once","tranlinedelta","simple","blob","all"],"description":"Override the export type"},"pageSize":{"type":"number","description":"Override the page size for pagination"},"skipRetries":{"type":"boolean","description":"When true, skips retries on failure."},"proceedOnFailure":{"type":"boolean","description":"When true, continues processing subsequent records after a failure."},"responseMapping":{"type":"object","description":"Override the response field mappings","properties":{"fields":{"type":"array","description":"Field-level mappings that copy individual values from the response back onto the record.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path in the response to extract the value from. Uses dot notation to navigate nested objects."},"generate":{"type":"string","description":"Target field path on the record where the extracted value is stored."}}}},"lists":{"type":"array","description":"Array-level mappings for one-to-many data in the response.","items":{"type":"object","properties":{"generate":{"type":"string","description":"Target array field on the record where the mapped list items are stored."},"fields":{"type":"array","description":"Field mappings applied to each item in the response array.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within each response list item to extract the value from."},"generate":{"type":"string","description":"Target field path within each mapped list item."}}}}}}}}}},"required":["_abstractId"]}},"imports":{"type":"array","description":"Import overrides. Customize import resources used within the tool,\nincluding connection bindings, hooks, response mappings, and\nadaptor-specific settings.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract import identifier from the tool definition"},"_connectionId":{"type":"string","format":"objectId","description":"Override the connection used by this import"},"proceedOnFailure":{"type":"boolean","description":"When true, continues processing subsequent records after a failure."},"responseMapping":{"type":"object","description":"Override the response field mappings","properties":{"fields":{"type":"array","description":"Field-level mappings that copy individual values from the response back onto the record.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path in the response to extract the value from. Uses dot notation to navigate nested objects."},"generate":{"type":"string","description":"Target field path on the record where the extracted value is stored."}}}},"lists":{"type":"array","description":"Array-level mappings for one-to-many data in the response.","items":{"type":"object","properties":{"generate":{"type":"string","description":"Target array field on the record where the mapped list items are stored."},"fields":{"type":"array","description":"Field mappings applied to each item in the response array.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within each response list item to extract the value from."},"generate":{"type":"string","description":"Target field path within each mapped list item."}}}}}}}}},"hooks":{"type":"object","description":"Override script hooks","properties":{"preMap":{"type":"object","description":"Hook that runs on each page of records before the import's mappings are applied.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}},"postMap":{"type":"object","description":"Hook that runs after the import's mappings are applied but before records\nare sent to the destination system.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}}}}},"required":["_abstractId"]}},"routers":{"type":"array","description":"Router overrides. Customize routing behavior for specific branches\nwithin the tool, including branch filters and routing strategies.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract router identifier from the tool definition"},"name":{"type":"string","description":"Override the router name"},"routeRecordsTo":{"type":"string","enum":["first_matching_branch","all_matching_branches"],"description":"Override the routing strategy"},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"Override the routing evaluation method"},"script":{"type":"object","description":"Override the router script","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Script containing the routing function named in `function`."},"function":{"type":"string","description":"Function within the referenced script that returns the name of the branch to route to."}}},"branches":{"type":"array","description":"Override specific branch configurations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract branch identifier"},"name":{"type":"string","description":"Override the branch name"},"description":{"type":"string","description":"Override the branch description"},"inputFilter":{"type":"object","description":"Override the branch filter criteria","properties":{"version":{"type":"string","enum":["1"],"description":"Filter format version."},"rules":{"type":"array","description":"Filter rules in Celigo expression-based filter format. Array-based DSL where\nthe first element is an operator (e.g. \"equals\", \"and\", \"or\"), followed by\noperands which can be nested expressions.","items":{}}}}}}}},"required":["_abstractId"]}}}},"ApiTool":{"type":"object","description":"An API entry that maps a Celigo builder-mode API resource to an MCP\ntool endpoint. Script-type APIs are not supported.","properties":{"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP tool name exposed to clients. Must be unique across all tools\nand APIs within this server."},"_apiId":{"type":"string","format":"objectId","description":"API resource ID. Must reference a builder-type API (not script-type)."},"disabled":{"type":"boolean","default":true,"description":"When true, this API tool is disabled and will not be exposed to MCP clients."}},"required":["name","_apiId"]},"McpResource":{"type":"object","description":"A resource entry that exposes a Celigo Storage file to MCP clients.\nClients discover resources via `resources/list` and fetch file content\nvia `resources/read`. Resources are not supported on sandbox servers —\nsetting `resources` together with `sandbox: true` returns 422\n`mcp_server_resources_not_allowed_in_sandbox`.","properties":{"title":{"type":"string","maxLength":250,"description":"Human-readable display title shown to MCP clients alongside the\nfile. Free text, unlike tool and API names (which are\nregex-constrained MCP identifiers)."},"_fileId":{"type":"string","format":"objectId","description":"Celigo Storage file exposed by this resource. Must reference an\nactive file (not a folder) owned by the account — invalid references\nreturn 422 `mcp_server_file_not_found`. Each file can be referenced\nonly once per server; duplicates return 422\n`mcp_server_duplicate_file_not_allowed`. Manage files via\n`GET /v1/storage/items`."},"disabled":{"type":"boolean","default":true,"description":"When true, the resource is hidden from MCP clients and its file is\nnot served. Resources are disabled by default; set to false to\nexpose the file."}},"required":["_fileId"]},"Prompt":{"type":"object","description":"A prompt template entry on an MCP server.\n\nPrompts are inline, reusable templates that MCP-compatible clients (Claude,\nCursor, Celigo AI Agents, etc.) discover via `prompts/list` and fetch via\n`prompts/get`. Each `{{placeholder}}` inside a message template becomes a\ndeclared argument that the client supplies at invocation time; the\nbackend performs Handlebars substitution before returning the rendered\nmessages.\n\nUnlike `tools[]` and `apis[]` — which reference other Celigo resources by\nID — a prompt is stored inline on the MCP server document. There is no\nseparate \"Prompt\" resource type.\n\n`prompts/get` returns rendered messages of shape\n`[{role, content: {type, text | data, mimeType?}}]` — `text` for `text`\ncontent, or `data` (base64) + `mimeType` for `image`/`audio`. This schema\ncaptures the stored template; the rendered output is not part of the\npersisted document.\n","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Server-generated identifier for the prompt — the grant handle\nreferenced as `tool:<_id>` in end-user, group, and role resource\ngrants. Identity is preserved across updates by matching on `name`,\nso renaming a prompt assigns a new `_id` and breaks grants that\nreference the old one.\n"},"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP prompt name exposed to clients via `prompts/list`.\n\nMust be unique within `prompts[]` on this server. Only alphanumeric\ncharacters, underscores, hyphens, and dots are allowed. Prompts have\ntheir own namespace — a prompt named `summarize_meeting` does not\ncollide with a tool or API of the same name.\n\nMaximum length: 128 characters. Duplicate names return 422\n`mcp_server_duplicate_prompt_name`.\n"},"title":{"type":"string","maxLength":1000,"description":"Human-readable display title shown alongside `name` in MCP clients.\n\nUnlike `name` (the MCP identifier, regex-constrained), `title` is\nfree text. Optional — clients fall back to `name` when omitted.\n"},"description":{"type":"string","maxLength":1000,"description":"Optional description of what the prompt does. Shown to MCP clients\nduring discovery so users and LLMs can choose the right prompt.\n"},"arguments":{"type":"array","description":"Declared arguments for the prompt. Every `{{placeholder}}` referenced\nin `messagesTemplate[*].template` should appear here so MCP clients\nknow what to supply when invoking the prompt.\n","items":{"$ref":"#/components/schemas/PromptArgument"}},"messagesTemplate":{"type":"array","description":"Ordered list of message templates forming the prompt body. At least\none entry is required. Each entry renders to a single message after\nHandlebars substitution.\n","minItems":1,"items":{"$ref":"#/components/schemas/PromptMessage"}},"mockInput":{"type":"object","description":"Sample argument values used to preview / test-run the prompt in the\nauthoring UI — a plain object mapping argument names to sample values\n(e.g. `{\"username\": \"John Doe\"}`). Keys usually mirror `arguments[].name`\nbut this is not enforced. Has no effect on `prompts/get` rendering for\nMCP clients.\n"},"disabled":{"type":"boolean","default":true,"description":"When true, the prompt is hidden from MCP clients — omitted from\n`prompts/list` and not fetchable via `prompts/get`. New prompts\ndefault to disabled; set to false to expose the prompt. An enabled\nprompt also satisfies the server-level enablement rule on its own.\nPrompts saved before this field existed are reported as\n`disabled: false`."}},"required":["name","messagesTemplate"]},"PromptArgument":{"type":"object","description":"A single declared argument for a prompt. Argument names appear as\n`{{name}}` placeholders inside `messagesTemplate[*].template` and are\nsubstituted with client-supplied values at invocation time.\n","properties":{"name":{"type":"string","maxLength":256,"pattern":"^\\w+$","description":"Argument name. Must match `^\\\\w+$` (letters, digits, and underscores\nonly) so it can be referenced as a Handlebars `{{placeholder}}` in the\nmessage template. Hyphens, dots, and other characters are not allowed\nhere (even though prompt `name` permits them) — they would break the\ntemplate parser.\n"},"description":{"type":"string","maxLength":1000,"description":"Optional human-readable description of the argument. Shown to MCP\nclients during discovery; useful for guiding LLMs that supply values.\n"},"required":{"type":"boolean","default":true,"description":"Whether the client must supply this argument. Defaults to `true`.\nWhen `false`, the client may omit the argument and the\n`{{placeholder}}` is left empty after substitution.\n"}},"required":["name"]},"PromptMessage":{"type":"object","description":"A single message entry inside a prompt's `messagesTemplate[]`. Renders to\na `{role, content: {type, text|data, mimeType?}}` object in the\n`prompts/get` response after Handlebars substitution.\n","properties":{"role":{"type":"string","enum":["user","assistant"],"description":"Message role exposed to MCP clients.\n\nOnly `user` and `assistant` are supported. `system` role messages are\nnot allowed at this layer — express system-level intent inside the\nfirst user or assistant template.\n"},"contentType":{"type":"string","enum":["text","image","audio","resource"],"default":"text","description":"Type of content this message carries.\n\n- `text` — `template` holds the Handlebars-templated text body.\n- `image` / `audio` — `data` (base64) and `mimeType` are required\n  (omitting `mimeType` returns 422 `mcp_server_prompt_mimetype_required`);\n  `template` is not used.\n- `resource` — reserved for future use; the authoring UI does not\n  currently expose this option.\n"},"template":{"type":"string","maxLength":4096,"description":"Handlebars-templated text body. Use `{{argumentName}}` to reference\ndeclared arguments — they are substituted server-side before the\nmessage is returned to the client.\n\nUp to 4 KB inline. Templates larger than 4 KB are automatically\noffloaded to S3 (up to a 1 MB hard limit) and rehydrated on read.\n\nOnly relevant when `contentType` is `text` (the default).\n"},"data":{"type":"string","description":"Base64-encoded binary content for image / audio messages. Only allowed\nwhen `contentType` is `image` or `audio`.\n\nUp to 10 MB via S3 offload.\n"},"mimeType":{"type":"string","maxLength":100,"description":"MIME type for the binary `data`. Required when `contentType` is `image`\nor `audio` (e.g. `image/png`, `audio/wav`).\n"}},"required":["role"]},"PermissionSet":{"type":"object","description":"A named bundle of this server's tools and APIs — shown as a \"Capability\nSet\" in the integrator.io UI — granted to end users as one unit through\nthe `pset:<_id>` capability string on end-user, group, and role resource\ngrants. There is no standalone permission-set resource: sets live only\ninside the MCP server document, and each set's `_id` is the stable handle\nthat grants reference.\n\nDeleting a set — or resubmitting it without its `_id` — rewrites every\ngrant that references it: the `pset:` capability is replaced with the\nset's constituent `tool:`/`api:` capabilities at removal time.","properties":{"_id":{"type":"string","format":"objectId","description":"Server-generated identifier for the set — the grant handle referenced\nas `pset:<_id>` in resource grants. Send it back unchanged on PUT to\npreserve the set's identity; a set submitted without its `_id` is\ntreated as a brand-new set and assigned a fresh one."},"name":{"type":"string","maxLength":300,"description":"Display name for the set. Must be unique per server,\ncase-insensitively — duplicates are rejected with 422."},"description":{"type":"string","maxLength":1000,"description":"Description of what the set grants and who it is for."},"accessLevel":{"type":"string","enum":["read","write"],"description":"OAuth-aligned access level the set pins for everyone it is granted to."},"_toolIds":{"type":"array","description":"Tool resources included in the set. Every entry must reference a tool\nalready attached to this server through `tools[]._toolId` —\nreferencing one that is not attached is rejected with 422.","items":{"type":"string","format":"objectId"}},"_apiIds":{"type":"array","description":"Builder-mode API resources included in the set. Every entry must\nreference an API already attached to this server through\n`apis[]._apiId` — referencing one that is not attached is rejected\nwith 422.","items":{"type":"string","format":"objectId"}}},"required":["name","accessLevel"]},"Policy":{"type":"object","description":"One traffic limit the server enforces before a tool runs — shown under\n**Access > Governance** in the UI. A `rate-limit` caps calls per MINUTE,\nHOUR, or DAY with a continuously refilling allowance, either for the whole\nserver (`keyResolver` `endpoint`) or separately for each OAuth end user\n(`keyResolver` `consumer`); a `quota` caps cumulative calls over a UTC\ncalendar DAY, WEEK, or MONTH across every consumer. A call must pass every\nenabled policy. A rejected call is not executed and receives HTTP 429 with\na `Retry-After` header (seconds until the allowance refills or the quota\nperiod resets), an `X-RateLimit-Limit` header, and a JSON-RPC error\n(code -32004) whose message names the policy: `Rate limit exceeded: <name>`\nor `Usage quota exceeded: <name>`.","required":["type","name","config"],"properties":{"type":{"type":"string","enum":["rate-limit","quota"],"description":"Kind of limit. Use rate-limit to protect downstream systems from bursts\nand, with `keyResolver` `consumer`, to keep one end user from consuming\nthe whole server; use quota to cap total consumption for cost control."},"name":{"type":"string","maxLength":100,"description":"Label for the limit, echoed verbatim in the 429 error message that\nrejected clients receive — name it the way consumers should read it."},"enabled":{"type":"boolean","default":true,"description":"When true, the policy is enforced. Set to false to keep the\nconfiguration in place without enforcing it."},"config":{"type":"object","additionalProperties":false,"description":"Limit value and period. The maximum `limit` depends on the unit and\nequals the platform ceiling of 300 calls per second over one period.","required":["limit","periodTime","periodTimeUnit"],"properties":{"limit":{"type":"integer","minimum":1,"description":"Maximum number of counted calls in one period. Ceilings per unit:\n18000 per MINUTE, 1080000 per HOUR, 25920000 per DAY, 181440000 per\nWEEK, 777600000 per MONTH — higher values are rejected with 422\n`policy_config_invalid`."},"periodTime":{"type":"integer","const":1,"default":1,"description":"Number of `periodTimeUnit` units in one period. Only a single unit\nis supported; any other value is rejected with 422."},"periodTimeUnit":{"type":"string","enum":["MINUTE","HOUR","DAY","WEEK","MONTH"],"description":"Length of one period. Rate limits take MINUTE, HOUR, or DAY; quotas\ntake DAY, WEEK, or MONTH — any other pairing, or a lowercase value,\nis rejected with 422 `policy_config_invalid`."},"keyResolver":{"type":"string","enum":["endpoint","consumer"],"default":"endpoint","description":"Whose allowance the limit tracks. Omit it (or send endpoint) for a\nserver-level limit and send consumer for a per-user rate limit;\nquotas accept endpoint only."}},"if":{"properties":{"periodTimeUnit":{"const":"MINUTE"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":18000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"HOUR"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":1080000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"DAY"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":25920000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"WEEK"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":181440000}}},"else":{"properties":{"limit":{"maximum":777600000}}}}}}}},"if":{"properties":{"type":{"const":"rate-limit"}},"required":["type"]},"then":{"properties":{"config":{"properties":{"periodTimeUnit":{"enum":["MINUTE","HOUR","DAY"]}}}}},"else":{"properties":{"config":{"properties":{"periodTimeUnit":{"enum":["DAY","WEEK","MONTH"]},"keyResolver":{"enum":["endpoint"]}}}}}},"OAuthConfig":{"type":"object","description":"OAuth 2.0 configuration for the MCP server. Three modes are supported:\n\n**Celigo-managed OAuth** — set `useCeligoOauth: true`. No issuer or\naudience configuration needed; Celigo handles token validation.\n\n**OAuth provider reference** — set `_mcpOAuthProviderId` to the ID of\na shared MCP OAuth provider resource (see `/v1/mcpoauthproviders`).\nThe provider holds the issuer, audience, and introspection settings.\n\n**Inline custom OAuth** — set `issuerURL` and `audience` directly.\nTokens are validated against the issuer's JWKS. Optionally enable\n`useIntrospection` for opaque tokens via RFC 7662.\n\nOmit `oauth` entirely (or send `{}`) to disable OAuth on the server.\nIn responses, `oauth` is absent when no OAuth mode is configured.\nThe three modes are mutually exclusive. When using inline custom\nOAuth, both `issuerURL` and `audience` are required. When\n`useIntrospection` is `true`, `clientId` is also required.","properties":{"useCeligoOauth":{"type":"boolean","description":"When `true`, enables Celigo-managed OAuth. No external issuer\nconfiguration is needed. Mutually exclusive with\n`_mcpOAuthProviderId` and inline OAuth fields."},"_mcpOAuthProviderId":{"type":"string","format":"objectId","description":"References a shared MCP OAuth provider resource that holds the\nissuer, audience, scopes, and introspection settings. Mutually\nexclusive with `useCeligoOauth` and inline OAuth fields.\n\nUse `GET /v1/mcpoauthproviders` to list available providers."},"issuerURL":{"type":"string","format":"uri","description":"OAuth 2.0 issuer URL for inline custom OAuth.\n\nMust be a well-formed URL with an explicit scheme — bare hostnames\nand protocol-less values are rejected with 422 `invalid_uri`.\nUse `https://` for production issuers."},"audience":{"type":"string","description":"Expected `aud` claim on incoming access tokens. Required when\nusing inline custom OAuth — omitting it returns\n`missing_required_field` on `oauth.audience`."},"useIntrospection":{"type":"boolean","default":false,"description":"When `true`, opaque access tokens are validated by calling the\nissuer's RFC 7662 introspection endpoint using `clientId` /\n`clientSecret`. When `false`, only JWT access tokens are accepted."},"scopes":{"type":"array","description":"Required OAuth scopes. Incoming tokens must carry every listed scope.\n\nRejected values return `enum` / `invalid_field_value` on\n`oauth.scopes.<index>`.","items":{"type":"string","enum":["mcp:read","mcp:write"]}},"clientId":{"type":["string","null"],"description":"OAuth client ID used when introspecting opaque tokens. Required\nwhen `useIntrospection` is `true`."},"clientSecret":{"type":["string","null"],"description":"OAuth client secret used with `clientId` for introspection. Masked\nas `\"******\"` in response payloads; sending the masked value on\nPUT is treated as \"leave unchanged\"."}},"dependentRequired":{"issuerURL":["audience"],"audience":["issuerURL"]},"if":{"properties":{"useIntrospection":{"const":true}},"required":["useIntrospection"]},"then":{"required":["clientId"]}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]}}}}
```

## List MCP servers

> Returns all MCP servers in the account.

```json
{"openapi":"3.2.0","info":{"title":"MCP Servers","version":"1.0.0"},"tags":[{"name":"MCP Servers","description":"MCP servers expose integration tools and builder-mode APIs as\nMCP-compatible endpoints consumed by AI agents and MCP clients.\n\nEach server has a unique `relativeURI`, a collection of tools and APIs\n(each individually enable/disable), optional prompt templates, optional\nfile resources from Celigo Storage, and optional OAuth configuration.\nTools support MCP annotations (read-only, idempotent, destructive,\nopen-world) and per-server overrides for connections, exports, imports,\nand routing. Permission sets (\"Capability Sets\" in the UI) bundle a\nserver's tools and APIs into named grants for end users, and the\nserver-scoped access endpoints bulk-assign capabilities to end users\nand groups and report compiled effective access. Optional traffic\nlimits (`policies`) — a server-level rate limit, a per-user rate\nlimit, and a usage quota — reject calls over the limit with HTTP 429\nand `Retry-After` before any tool runs.\n\n## MCP server schema\n\n{% openapi-schemas spec=\"mcp-server\" schemas=\"MCPServer\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"parameters":{"Include":{"name":"include","in":"query","required":false,"description":"Comma-separated list of fields to project into each returned record.\nTriggers summary projection: the response contains a minimal identity\nset (`_id`, `name`, plus resource-specific fields) with the requested\nfields added on top. Supports dot notation for nested fields.\nMutually exclusive with `exclude`.","schema":{"type":"string"}},"Exclude":{"name":"exclude","in":"query","required":false,"description":"Comma-separated list of fields to strip from the default response.\nUnlike `include`, does not trigger summary projection — returns the\nfull record with the named fields removed. Protected identity fields\n(e.g. `name`) cannot be stripped. Mutually exclusive with `include`.","schema":{"type":"string"}}},"schemas":{"MCPServer":{"type":"object","required":["_id","name","relativeURI","disabled","createdAt","lastModified"],"description":"MCP server object as returned by the API.","allOf":[{"$ref":"#/components/schemas/MCPServerBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"Owning user ID."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"When this draft MCP server expires and will be automatically deleted. Only present\non servers created as drafts by the AI-assisted builder that have not yet been\nconfirmed. Unlike other resource types, MCP server drafts carry no `draft` boolean —\nthe presence of this field is what marks the draft state."}}}]},"MCPServerBase":{"type":"object","description":"Writable MCP server fields shared by the request and response schemas.","properties":{"name":{"type":"string","minLength":1,"maxLength":150,"description":"Display name for the MCP server."},"relativeURI":{"type":"string","maxLength":131072,"pattern":"^\\/[a-zA-Z0-9_\\-]+$","description":"URI path segment for the MCP server endpoint. Must be unique per account —\nduplicates are rejected with 422 `mcp_server_duplicate_relative_uri`. Only letters,\nnumbers, dashes, and underscores after the leading slash (the server's error message\nalso claims colons and dots are allowed, but they are rejected in practice). Creation\nalso requires the account to have an account alias set (422\n`mcp_server_account_alias_required` otherwise)."},"description":{"type":"string","maxLength":1000,"description":"Description of the MCP server's purpose."},"disabled":{"type":"boolean","default":true,"description":"Whether the MCP server is disabled. Defaults to `true` on creation.\nTo serve requests, at least one tool, API, resource, or prompt must\nalso be enabled."},"tools":{"type":"array","description":"Tool entries referencing Celigo Tool resources. Duplicate `_toolId`\nvalues are rejected. Names must be unique across both `tools` and `apis`.","items":{"$ref":"#/components/schemas/IOTool"}},"apis":{"type":"array","description":"API entries referencing Celigo builder-mode API resources. Only\nbuilder-type APIs are supported. Names must be unique across both\n`tools` and `apis`.","items":{"$ref":"#/components/schemas/ApiTool"}},"resources":{"type":"array","description":"Files from Celigo Storage exposed to MCP clients as MCP resources.\nEach entry references a storage file by `_fileId`; the same file can\nappear only once. Always returned in responses — servers created\nbefore resource support return an empty array. Not supported on\nsandbox servers.","items":{"$ref":"#/components/schemas/McpResource"}},"prompts":{"type":"array","description":"Prompt templates exposed to MCP clients. Each prompt has a unique\n`name` and may declare `arguments` that clients supply via\n`prompts/get`.","items":{"$ref":"#/components/schemas/Prompt"}},"permissionSets":{"type":"array","description":"Named bundles of this server's tools and APIs — shown as \"Capability\nSets\" in the UI — granted to end users as a unit via `pset:<_id>`\ncapability strings. Omitting the field on PUT resets it to an empty\narray, erasing every set and rewriting the grants that reference\nthem — always send the complete array back. Absent from responses for\nservers not saved since permission sets were introduced (unlike\n`resources`, the field is not normalized to an empty array).","items":{"$ref":"#/components/schemas/PermissionSet"}},"policies":{"type":"array","description":"Traffic limits enforced on this server before a tool runs — a\nserver-level rate limit, a per-user rate limit, and a usage quota, each\noptional and independent. An empty array (the default) means unlimited.\nAlways returned; servers saved before traffic limits existed return an\nempty array. Omitting the field on PUT clears every limit — send the\ncomplete array back, or edit it with PATCH.","items":{"$ref":"#/components/schemas/Policy"}},"oauth":{"$ref":"#/components/schemas/OAuthConfig"}}},"IOTool":{"type":"object","description":"A tool entry that maps a Celigo Tool resource to an MCP tool endpoint.\nThe referenced tool's input schema must have `type: \"object\"`.","properties":{"_toolId":{"type":"string","format":"objectId","description":"Tool resource ID. The referenced tool must exist and have an\ninput schema with `type: \"object\"`."},"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP tool name exposed to clients. Must be unique across all tools\nand APIs within this server."},"disabled":{"type":"boolean","default":true,"description":"When true, this tool is disabled and will not be exposed to MCP clients."},"annotations":{"$ref":"#/components/schemas/Annotations"},"overrides":{"$ref":"#/components/schemas/Overrides"}},"required":["_toolId","name"]},"Annotations":{"type":"object","description":"MCP-standard annotations that hint at the behavior of a tool.\n\nThese annotations follow the Model Context Protocol specification and help\nAI agents and MCP clients understand how a tool behaves without executing it.\nAll fields are optional hints — they are not enforced by the server.\n","properties":{"title":{"type":"string","maxLength":300,"description":"Human-readable title for the tool, displayed in MCP client UIs.\n\nIf not provided, the tool's `name` field is used instead.\n"},"destructiveHint":{"type":"boolean","description":"Hints that the tool may perform destructive operations such as\ndeleting or permanently modifying data.\n"},"idempotentHint":{"type":"boolean","description":"Hints that calling the tool multiple times with the same input\nproduces the same result without additional side effects.\n"},"openWorldHint":{"type":"boolean","description":"Hints that the tool interacts with an open-world environment\n(e.g., external APIs) where results may vary between calls.\n"},"readOnlyHint":{"type":"boolean","description":"Hints that the tool only reads data and does not modify any state.\n"}}},"Overrides":{"type":"object","description":"Per-server overrides for a tool's internal resources.\n\nWhen a tool is added to an MCP server, its connections, exports, imports,\nand routers can be customized for this specific server context without\nmodifying the underlying tool definition. This enables reusing the same\ntool across multiple MCP servers with different configurations.\n","properties":{"connections":{"type":"array","description":"Connection overrides. Each entry maps an abstract connection reference\nin the tool to a concrete connection resource for this server.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"The abstract connection identifier from the tool definition.\nThis is the connection reference that will be replaced.\n"},"_id":{"type":"string","format":"objectId","description":"The concrete connection resource to use in place of the abstract reference.\n"},"_borrowConcurrencyFromConnectionId":{"type":"string","description":"Optional connection from which to borrow concurrency limits.\n"}},"required":["_abstractId"]}},"exports":{"type":"array","description":"Export (lookup) overrides. Customize export resources used within the tool,\nincluding connection bindings, scheduling, response mappings, and\nadaptor-specific settings.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract export identifier from the tool definition"},"_id":{"type":"string","format":"objectId","description":"Concrete export resource to use"},"_connectionId":{"type":"string","format":"objectId","description":"Override the connection used by this export"},"type":{"type":"string","enum":["webhook","distributed","test","delta","once","tranlinedelta","simple","blob","all"],"description":"Override the export type"},"pageSize":{"type":"number","description":"Override the page size for pagination"},"skipRetries":{"type":"boolean","description":"When true, skips retries on failure."},"proceedOnFailure":{"type":"boolean","description":"When true, continues processing subsequent records after a failure."},"responseMapping":{"type":"object","description":"Override the response field mappings","properties":{"fields":{"type":"array","description":"Field-level mappings that copy individual values from the response back onto the record.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path in the response to extract the value from. Uses dot notation to navigate nested objects."},"generate":{"type":"string","description":"Target field path on the record where the extracted value is stored."}}}},"lists":{"type":"array","description":"Array-level mappings for one-to-many data in the response.","items":{"type":"object","properties":{"generate":{"type":"string","description":"Target array field on the record where the mapped list items are stored."},"fields":{"type":"array","description":"Field mappings applied to each item in the response array.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within each response list item to extract the value from."},"generate":{"type":"string","description":"Target field path within each mapped list item."}}}}}}}}}},"required":["_abstractId"]}},"imports":{"type":"array","description":"Import overrides. Customize import resources used within the tool,\nincluding connection bindings, hooks, response mappings, and\nadaptor-specific settings.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract import identifier from the tool definition"},"_connectionId":{"type":"string","format":"objectId","description":"Override the connection used by this import"},"proceedOnFailure":{"type":"boolean","description":"When true, continues processing subsequent records after a failure."},"responseMapping":{"type":"object","description":"Override the response field mappings","properties":{"fields":{"type":"array","description":"Field-level mappings that copy individual values from the response back onto the record.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path in the response to extract the value from. Uses dot notation to navigate nested objects."},"generate":{"type":"string","description":"Target field path on the record where the extracted value is stored."}}}},"lists":{"type":"array","description":"Array-level mappings for one-to-many data in the response.","items":{"type":"object","properties":{"generate":{"type":"string","description":"Target array field on the record where the mapped list items are stored."},"fields":{"type":"array","description":"Field mappings applied to each item in the response array.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within each response list item to extract the value from."},"generate":{"type":"string","description":"Target field path within each mapped list item."}}}}}}}}},"hooks":{"type":"object","description":"Override script hooks","properties":{"preMap":{"type":"object","description":"Hook that runs on each page of records before the import's mappings are applied.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}},"postMap":{"type":"object","description":"Hook that runs after the import's mappings are applied but before records\nare sent to the destination system.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}}}}},"required":["_abstractId"]}},"routers":{"type":"array","description":"Router overrides. Customize routing behavior for specific branches\nwithin the tool, including branch filters and routing strategies.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract router identifier from the tool definition"},"name":{"type":"string","description":"Override the router name"},"routeRecordsTo":{"type":"string","enum":["first_matching_branch","all_matching_branches"],"description":"Override the routing strategy"},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"Override the routing evaluation method"},"script":{"type":"object","description":"Override the router script","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Script containing the routing function named in `function`."},"function":{"type":"string","description":"Function within the referenced script that returns the name of the branch to route to."}}},"branches":{"type":"array","description":"Override specific branch configurations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract branch identifier"},"name":{"type":"string","description":"Override the branch name"},"description":{"type":"string","description":"Override the branch description"},"inputFilter":{"type":"object","description":"Override the branch filter criteria","properties":{"version":{"type":"string","enum":["1"],"description":"Filter format version."},"rules":{"type":"array","description":"Filter rules in Celigo expression-based filter format. Array-based DSL where\nthe first element is an operator (e.g. \"equals\", \"and\", \"or\"), followed by\noperands which can be nested expressions.","items":{}}}}}}}},"required":["_abstractId"]}}}},"ApiTool":{"type":"object","description":"An API entry that maps a Celigo builder-mode API resource to an MCP\ntool endpoint. Script-type APIs are not supported.","properties":{"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP tool name exposed to clients. Must be unique across all tools\nand APIs within this server."},"_apiId":{"type":"string","format":"objectId","description":"API resource ID. Must reference a builder-type API (not script-type)."},"disabled":{"type":"boolean","default":true,"description":"When true, this API tool is disabled and will not be exposed to MCP clients."}},"required":["name","_apiId"]},"McpResource":{"type":"object","description":"A resource entry that exposes a Celigo Storage file to MCP clients.\nClients discover resources via `resources/list` and fetch file content\nvia `resources/read`. Resources are not supported on sandbox servers —\nsetting `resources` together with `sandbox: true` returns 422\n`mcp_server_resources_not_allowed_in_sandbox`.","properties":{"title":{"type":"string","maxLength":250,"description":"Human-readable display title shown to MCP clients alongside the\nfile. Free text, unlike tool and API names (which are\nregex-constrained MCP identifiers)."},"_fileId":{"type":"string","format":"objectId","description":"Celigo Storage file exposed by this resource. Must reference an\nactive file (not a folder) owned by the account — invalid references\nreturn 422 `mcp_server_file_not_found`. Each file can be referenced\nonly once per server; duplicates return 422\n`mcp_server_duplicate_file_not_allowed`. Manage files via\n`GET /v1/storage/items`."},"disabled":{"type":"boolean","default":true,"description":"When true, the resource is hidden from MCP clients and its file is\nnot served. Resources are disabled by default; set to false to\nexpose the file."}},"required":["_fileId"]},"Prompt":{"type":"object","description":"A prompt template entry on an MCP server.\n\nPrompts are inline, reusable templates that MCP-compatible clients (Claude,\nCursor, Celigo AI Agents, etc.) discover via `prompts/list` and fetch via\n`prompts/get`. Each `{{placeholder}}` inside a message template becomes a\ndeclared argument that the client supplies at invocation time; the\nbackend performs Handlebars substitution before returning the rendered\nmessages.\n\nUnlike `tools[]` and `apis[]` — which reference other Celigo resources by\nID — a prompt is stored inline on the MCP server document. There is no\nseparate \"Prompt\" resource type.\n\n`prompts/get` returns rendered messages of shape\n`[{role, content: {type, text | data, mimeType?}}]` — `text` for `text`\ncontent, or `data` (base64) + `mimeType` for `image`/`audio`. This schema\ncaptures the stored template; the rendered output is not part of the\npersisted document.\n","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Server-generated identifier for the prompt — the grant handle\nreferenced as `tool:<_id>` in end-user, group, and role resource\ngrants. Identity is preserved across updates by matching on `name`,\nso renaming a prompt assigns a new `_id` and breaks grants that\nreference the old one.\n"},"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP prompt name exposed to clients via `prompts/list`.\n\nMust be unique within `prompts[]` on this server. Only alphanumeric\ncharacters, underscores, hyphens, and dots are allowed. Prompts have\ntheir own namespace — a prompt named `summarize_meeting` does not\ncollide with a tool or API of the same name.\n\nMaximum length: 128 characters. Duplicate names return 422\n`mcp_server_duplicate_prompt_name`.\n"},"title":{"type":"string","maxLength":1000,"description":"Human-readable display title shown alongside `name` in MCP clients.\n\nUnlike `name` (the MCP identifier, regex-constrained), `title` is\nfree text. Optional — clients fall back to `name` when omitted.\n"},"description":{"type":"string","maxLength":1000,"description":"Optional description of what the prompt does. Shown to MCP clients\nduring discovery so users and LLMs can choose the right prompt.\n"},"arguments":{"type":"array","description":"Declared arguments for the prompt. Every `{{placeholder}}` referenced\nin `messagesTemplate[*].template` should appear here so MCP clients\nknow what to supply when invoking the prompt.\n","items":{"$ref":"#/components/schemas/PromptArgument"}},"messagesTemplate":{"type":"array","description":"Ordered list of message templates forming the prompt body. At least\none entry is required. Each entry renders to a single message after\nHandlebars substitution.\n","minItems":1,"items":{"$ref":"#/components/schemas/PromptMessage"}},"mockInput":{"type":"object","description":"Sample argument values used to preview / test-run the prompt in the\nauthoring UI — a plain object mapping argument names to sample values\n(e.g. `{\"username\": \"John Doe\"}`). Keys usually mirror `arguments[].name`\nbut this is not enforced. Has no effect on `prompts/get` rendering for\nMCP clients.\n"},"disabled":{"type":"boolean","default":true,"description":"When true, the prompt is hidden from MCP clients — omitted from\n`prompts/list` and not fetchable via `prompts/get`. New prompts\ndefault to disabled; set to false to expose the prompt. An enabled\nprompt also satisfies the server-level enablement rule on its own.\nPrompts saved before this field existed are reported as\n`disabled: false`."}},"required":["name","messagesTemplate"]},"PromptArgument":{"type":"object","description":"A single declared argument for a prompt. Argument names appear as\n`{{name}}` placeholders inside `messagesTemplate[*].template` and are\nsubstituted with client-supplied values at invocation time.\n","properties":{"name":{"type":"string","maxLength":256,"pattern":"^\\w+$","description":"Argument name. Must match `^\\\\w+$` (letters, digits, and underscores\nonly) so it can be referenced as a Handlebars `{{placeholder}}` in the\nmessage template. Hyphens, dots, and other characters are not allowed\nhere (even though prompt `name` permits them) — they would break the\ntemplate parser.\n"},"description":{"type":"string","maxLength":1000,"description":"Optional human-readable description of the argument. Shown to MCP\nclients during discovery; useful for guiding LLMs that supply values.\n"},"required":{"type":"boolean","default":true,"description":"Whether the client must supply this argument. Defaults to `true`.\nWhen `false`, the client may omit the argument and the\n`{{placeholder}}` is left empty after substitution.\n"}},"required":["name"]},"PromptMessage":{"type":"object","description":"A single message entry inside a prompt's `messagesTemplate[]`. Renders to\na `{role, content: {type, text|data, mimeType?}}` object in the\n`prompts/get` response after Handlebars substitution.\n","properties":{"role":{"type":"string","enum":["user","assistant"],"description":"Message role exposed to MCP clients.\n\nOnly `user` and `assistant` are supported. `system` role messages are\nnot allowed at this layer — express system-level intent inside the\nfirst user or assistant template.\n"},"contentType":{"type":"string","enum":["text","image","audio","resource"],"default":"text","description":"Type of content this message carries.\n\n- `text` — `template` holds the Handlebars-templated text body.\n- `image` / `audio` — `data` (base64) and `mimeType` are required\n  (omitting `mimeType` returns 422 `mcp_server_prompt_mimetype_required`);\n  `template` is not used.\n- `resource` — reserved for future use; the authoring UI does not\n  currently expose this option.\n"},"template":{"type":"string","maxLength":4096,"description":"Handlebars-templated text body. Use `{{argumentName}}` to reference\ndeclared arguments — they are substituted server-side before the\nmessage is returned to the client.\n\nUp to 4 KB inline. Templates larger than 4 KB are automatically\noffloaded to S3 (up to a 1 MB hard limit) and rehydrated on read.\n\nOnly relevant when `contentType` is `text` (the default).\n"},"data":{"type":"string","description":"Base64-encoded binary content for image / audio messages. Only allowed\nwhen `contentType` is `image` or `audio`.\n\nUp to 10 MB via S3 offload.\n"},"mimeType":{"type":"string","maxLength":100,"description":"MIME type for the binary `data`. Required when `contentType` is `image`\nor `audio` (e.g. `image/png`, `audio/wav`).\n"}},"required":["role"]},"PermissionSet":{"type":"object","description":"A named bundle of this server's tools and APIs — shown as a \"Capability\nSet\" in the integrator.io UI — granted to end users as one unit through\nthe `pset:<_id>` capability string on end-user, group, and role resource\ngrants. There is no standalone permission-set resource: sets live only\ninside the MCP server document, and each set's `_id` is the stable handle\nthat grants reference.\n\nDeleting a set — or resubmitting it without its `_id` — rewrites every\ngrant that references it: the `pset:` capability is replaced with the\nset's constituent `tool:`/`api:` capabilities at removal time.","properties":{"_id":{"type":"string","format":"objectId","description":"Server-generated identifier for the set — the grant handle referenced\nas `pset:<_id>` in resource grants. Send it back unchanged on PUT to\npreserve the set's identity; a set submitted without its `_id` is\ntreated as a brand-new set and assigned a fresh one."},"name":{"type":"string","maxLength":300,"description":"Display name for the set. Must be unique per server,\ncase-insensitively — duplicates are rejected with 422."},"description":{"type":"string","maxLength":1000,"description":"Description of what the set grants and who it is for."},"accessLevel":{"type":"string","enum":["read","write"],"description":"OAuth-aligned access level the set pins for everyone it is granted to."},"_toolIds":{"type":"array","description":"Tool resources included in the set. Every entry must reference a tool\nalready attached to this server through `tools[]._toolId` —\nreferencing one that is not attached is rejected with 422.","items":{"type":"string","format":"objectId"}},"_apiIds":{"type":"array","description":"Builder-mode API resources included in the set. Every entry must\nreference an API already attached to this server through\n`apis[]._apiId` — referencing one that is not attached is rejected\nwith 422.","items":{"type":"string","format":"objectId"}}},"required":["name","accessLevel"]},"Policy":{"type":"object","description":"One traffic limit the server enforces before a tool runs — shown under\n**Access > Governance** in the UI. A `rate-limit` caps calls per MINUTE,\nHOUR, or DAY with a continuously refilling allowance, either for the whole\nserver (`keyResolver` `endpoint`) or separately for each OAuth end user\n(`keyResolver` `consumer`); a `quota` caps cumulative calls over a UTC\ncalendar DAY, WEEK, or MONTH across every consumer. A call must pass every\nenabled policy. A rejected call is not executed and receives HTTP 429 with\na `Retry-After` header (seconds until the allowance refills or the quota\nperiod resets), an `X-RateLimit-Limit` header, and a JSON-RPC error\n(code -32004) whose message names the policy: `Rate limit exceeded: <name>`\nor `Usage quota exceeded: <name>`.","required":["type","name","config"],"properties":{"type":{"type":"string","enum":["rate-limit","quota"],"description":"Kind of limit. Use rate-limit to protect downstream systems from bursts\nand, with `keyResolver` `consumer`, to keep one end user from consuming\nthe whole server; use quota to cap total consumption for cost control."},"name":{"type":"string","maxLength":100,"description":"Label for the limit, echoed verbatim in the 429 error message that\nrejected clients receive — name it the way consumers should read it."},"enabled":{"type":"boolean","default":true,"description":"When true, the policy is enforced. Set to false to keep the\nconfiguration in place without enforcing it."},"config":{"type":"object","additionalProperties":false,"description":"Limit value and period. The maximum `limit` depends on the unit and\nequals the platform ceiling of 300 calls per second over one period.","required":["limit","periodTime","periodTimeUnit"],"properties":{"limit":{"type":"integer","minimum":1,"description":"Maximum number of counted calls in one period. Ceilings per unit:\n18000 per MINUTE, 1080000 per HOUR, 25920000 per DAY, 181440000 per\nWEEK, 777600000 per MONTH — higher values are rejected with 422\n`policy_config_invalid`."},"periodTime":{"type":"integer","const":1,"default":1,"description":"Number of `periodTimeUnit` units in one period. Only a single unit\nis supported; any other value is rejected with 422."},"periodTimeUnit":{"type":"string","enum":["MINUTE","HOUR","DAY","WEEK","MONTH"],"description":"Length of one period. Rate limits take MINUTE, HOUR, or DAY; quotas\ntake DAY, WEEK, or MONTH — any other pairing, or a lowercase value,\nis rejected with 422 `policy_config_invalid`."},"keyResolver":{"type":"string","enum":["endpoint","consumer"],"default":"endpoint","description":"Whose allowance the limit tracks. Omit it (or send endpoint) for a\nserver-level limit and send consumer for a per-user rate limit;\nquotas accept endpoint only."}},"if":{"properties":{"periodTimeUnit":{"const":"MINUTE"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":18000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"HOUR"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":1080000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"DAY"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":25920000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"WEEK"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":181440000}}},"else":{"properties":{"limit":{"maximum":777600000}}}}}}}},"if":{"properties":{"type":{"const":"rate-limit"}},"required":["type"]},"then":{"properties":{"config":{"properties":{"periodTimeUnit":{"enum":["MINUTE","HOUR","DAY"]}}}}},"else":{"properties":{"config":{"properties":{"periodTimeUnit":{"enum":["DAY","WEEK","MONTH"]},"keyResolver":{"enum":["endpoint"]}}}}}},"OAuthConfig":{"type":"object","description":"OAuth 2.0 configuration for the MCP server. Three modes are supported:\n\n**Celigo-managed OAuth** — set `useCeligoOauth: true`. No issuer or\naudience configuration needed; Celigo handles token validation.\n\n**OAuth provider reference** — set `_mcpOAuthProviderId` to the ID of\na shared MCP OAuth provider resource (see `/v1/mcpoauthproviders`).\nThe provider holds the issuer, audience, and introspection settings.\n\n**Inline custom OAuth** — set `issuerURL` and `audience` directly.\nTokens are validated against the issuer's JWKS. Optionally enable\n`useIntrospection` for opaque tokens via RFC 7662.\n\nOmit `oauth` entirely (or send `{}`) to disable OAuth on the server.\nIn responses, `oauth` is absent when no OAuth mode is configured.\nThe three modes are mutually exclusive. When using inline custom\nOAuth, both `issuerURL` and `audience` are required. When\n`useIntrospection` is `true`, `clientId` is also required.","properties":{"useCeligoOauth":{"type":"boolean","description":"When `true`, enables Celigo-managed OAuth. No external issuer\nconfiguration is needed. Mutually exclusive with\n`_mcpOAuthProviderId` and inline OAuth fields."},"_mcpOAuthProviderId":{"type":"string","format":"objectId","description":"References a shared MCP OAuth provider resource that holds the\nissuer, audience, scopes, and introspection settings. Mutually\nexclusive with `useCeligoOauth` and inline OAuth fields.\n\nUse `GET /v1/mcpoauthproviders` to list available providers."},"issuerURL":{"type":"string","format":"uri","description":"OAuth 2.0 issuer URL for inline custom OAuth.\n\nMust be a well-formed URL with an explicit scheme — bare hostnames\nand protocol-less values are rejected with 422 `invalid_uri`.\nUse `https://` for production issuers."},"audience":{"type":"string","description":"Expected `aud` claim on incoming access tokens. Required when\nusing inline custom OAuth — omitting it returns\n`missing_required_field` on `oauth.audience`."},"useIntrospection":{"type":"boolean","default":false,"description":"When `true`, opaque access tokens are validated by calling the\nissuer's RFC 7662 introspection endpoint using `clientId` /\n`clientSecret`. When `false`, only JWT access tokens are accepted."},"scopes":{"type":"array","description":"Required OAuth scopes. Incoming tokens must carry every listed scope.\n\nRejected values return `enum` / `invalid_field_value` on\n`oauth.scopes.<index>`.","items":{"type":"string","enum":["mcp:read","mcp:write"]}},"clientId":{"type":["string","null"],"description":"OAuth client ID used when introspecting opaque tokens. Required\nwhen `useIntrospection` is `true`."},"clientSecret":{"type":["string","null"],"description":"OAuth client secret used with `clientId` for introspection. Masked\nas `\"******\"` in response payloads; sending the masked value on\nPUT is treated as \"leave unchanged\"."}},"dependentRequired":{"issuerURL":["audience"],"audience":["issuerURL"]},"if":{"properties":{"useIntrospection":{"const":true}},"required":["useIntrospection"]},"then":{"required":["clientId"]}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/mcpservers":{"get":{"summary":"List MCP servers","description":"Returns all MCP servers in the account.","operationId":"listMcpServers","tags":["MCP Servers"],"parameters":[{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/Exclude"}],"responses":{"200":{"description":"MCP server list.","headers":{"Link":{"description":"RFC 5988 pagination links. Contains `<...>; rel=\"next\"` when\nmore pages remain; absent on the final page.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MCPServer"}}}}},"204":{"description":"No MCP servers exist in the account."},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```

## Create an MCP server

> Creates an MCP server. The server is created disabled by default.\
> \`name\` and \`relativeURI\` are the only required fields;\
> \`relativeURI\` must be unique per account.

```json
{"openapi":"3.2.0","info":{"title":"MCP Servers","version":"1.0.0"},"tags":[{"name":"MCP Servers","description":"MCP servers expose integration tools and builder-mode APIs as\nMCP-compatible endpoints consumed by AI agents and MCP clients.\n\nEach server has a unique `relativeURI`, a collection of tools and APIs\n(each individually enable/disable), optional prompt templates, optional\nfile resources from Celigo Storage, and optional OAuth configuration.\nTools support MCP annotations (read-only, idempotent, destructive,\nopen-world) and per-server overrides for connections, exports, imports,\nand routing. Permission sets (\"Capability Sets\" in the UI) bundle a\nserver's tools and APIs into named grants for end users, and the\nserver-scoped access endpoints bulk-assign capabilities to end users\nand groups and report compiled effective access. Optional traffic\nlimits (`policies`) — a server-level rate limit, a per-user rate\nlimit, and a usage quota — reject calls over the limit with HTTP 429\nand `Retry-After` before any tool runs.\n\n## MCP server schema\n\n{% openapi-schemas spec=\"mcp-server\" schemas=\"MCPServer\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Request":{"type":"object","description":"Request body for creating or updating an MCP server. On PUT, include\nthe full `tools`, `apis`, `prompts`, `resources`, `permissionSets`, and\n`policies` arrays because omitted arrays are cleared. Use PATCH to update individual\nfields without affecting these arrays.","required":["name","relativeURI"],"allOf":[{"$ref":"#/components/schemas/MCPServerBase"}]},"MCPServerBase":{"type":"object","description":"Writable MCP server fields shared by the request and response schemas.","properties":{"name":{"type":"string","minLength":1,"maxLength":150,"description":"Display name for the MCP server."},"relativeURI":{"type":"string","maxLength":131072,"pattern":"^\\/[a-zA-Z0-9_\\-]+$","description":"URI path segment for the MCP server endpoint. Must be unique per account —\nduplicates are rejected with 422 `mcp_server_duplicate_relative_uri`. Only letters,\nnumbers, dashes, and underscores after the leading slash (the server's error message\nalso claims colons and dots are allowed, but they are rejected in practice). Creation\nalso requires the account to have an account alias set (422\n`mcp_server_account_alias_required` otherwise)."},"description":{"type":"string","maxLength":1000,"description":"Description of the MCP server's purpose."},"disabled":{"type":"boolean","default":true,"description":"Whether the MCP server is disabled. Defaults to `true` on creation.\nTo serve requests, at least one tool, API, resource, or prompt must\nalso be enabled."},"tools":{"type":"array","description":"Tool entries referencing Celigo Tool resources. Duplicate `_toolId`\nvalues are rejected. Names must be unique across both `tools` and `apis`.","items":{"$ref":"#/components/schemas/IOTool"}},"apis":{"type":"array","description":"API entries referencing Celigo builder-mode API resources. Only\nbuilder-type APIs are supported. Names must be unique across both\n`tools` and `apis`.","items":{"$ref":"#/components/schemas/ApiTool"}},"resources":{"type":"array","description":"Files from Celigo Storage exposed to MCP clients as MCP resources.\nEach entry references a storage file by `_fileId`; the same file can\nappear only once. Always returned in responses — servers created\nbefore resource support return an empty array. Not supported on\nsandbox servers.","items":{"$ref":"#/components/schemas/McpResource"}},"prompts":{"type":"array","description":"Prompt templates exposed to MCP clients. Each prompt has a unique\n`name` and may declare `arguments` that clients supply via\n`prompts/get`.","items":{"$ref":"#/components/schemas/Prompt"}},"permissionSets":{"type":"array","description":"Named bundles of this server's tools and APIs — shown as \"Capability\nSets\" in the UI — granted to end users as a unit via `pset:<_id>`\ncapability strings. Omitting the field on PUT resets it to an empty\narray, erasing every set and rewriting the grants that reference\nthem — always send the complete array back. Absent from responses for\nservers not saved since permission sets were introduced (unlike\n`resources`, the field is not normalized to an empty array).","items":{"$ref":"#/components/schemas/PermissionSet"}},"policies":{"type":"array","description":"Traffic limits enforced on this server before a tool runs — a\nserver-level rate limit, a per-user rate limit, and a usage quota, each\noptional and independent. An empty array (the default) means unlimited.\nAlways returned; servers saved before traffic limits existed return an\nempty array. Omitting the field on PUT clears every limit — send the\ncomplete array back, or edit it with PATCH.","items":{"$ref":"#/components/schemas/Policy"}},"oauth":{"$ref":"#/components/schemas/OAuthConfig"}}},"IOTool":{"type":"object","description":"A tool entry that maps a Celigo Tool resource to an MCP tool endpoint.\nThe referenced tool's input schema must have `type: \"object\"`.","properties":{"_toolId":{"type":"string","format":"objectId","description":"Tool resource ID. The referenced tool must exist and have an\ninput schema with `type: \"object\"`."},"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP tool name exposed to clients. Must be unique across all tools\nand APIs within this server."},"disabled":{"type":"boolean","default":true,"description":"When true, this tool is disabled and will not be exposed to MCP clients."},"annotations":{"$ref":"#/components/schemas/Annotations"},"overrides":{"$ref":"#/components/schemas/Overrides"}},"required":["_toolId","name"]},"Annotations":{"type":"object","description":"MCP-standard annotations that hint at the behavior of a tool.\n\nThese annotations follow the Model Context Protocol specification and help\nAI agents and MCP clients understand how a tool behaves without executing it.\nAll fields are optional hints — they are not enforced by the server.\n","properties":{"title":{"type":"string","maxLength":300,"description":"Human-readable title for the tool, displayed in MCP client UIs.\n\nIf not provided, the tool's `name` field is used instead.\n"},"destructiveHint":{"type":"boolean","description":"Hints that the tool may perform destructive operations such as\ndeleting or permanently modifying data.\n"},"idempotentHint":{"type":"boolean","description":"Hints that calling the tool multiple times with the same input\nproduces the same result without additional side effects.\n"},"openWorldHint":{"type":"boolean","description":"Hints that the tool interacts with an open-world environment\n(e.g., external APIs) where results may vary between calls.\n"},"readOnlyHint":{"type":"boolean","description":"Hints that the tool only reads data and does not modify any state.\n"}}},"Overrides":{"type":"object","description":"Per-server overrides for a tool's internal resources.\n\nWhen a tool is added to an MCP server, its connections, exports, imports,\nand routers can be customized for this specific server context without\nmodifying the underlying tool definition. This enables reusing the same\ntool across multiple MCP servers with different configurations.\n","properties":{"connections":{"type":"array","description":"Connection overrides. Each entry maps an abstract connection reference\nin the tool to a concrete connection resource for this server.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"The abstract connection identifier from the tool definition.\nThis is the connection reference that will be replaced.\n"},"_id":{"type":"string","format":"objectId","description":"The concrete connection resource to use in place of the abstract reference.\n"},"_borrowConcurrencyFromConnectionId":{"type":"string","description":"Optional connection from which to borrow concurrency limits.\n"}},"required":["_abstractId"]}},"exports":{"type":"array","description":"Export (lookup) overrides. Customize export resources used within the tool,\nincluding connection bindings, scheduling, response mappings, and\nadaptor-specific settings.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract export identifier from the tool definition"},"_id":{"type":"string","format":"objectId","description":"Concrete export resource to use"},"_connectionId":{"type":"string","format":"objectId","description":"Override the connection used by this export"},"type":{"type":"string","enum":["webhook","distributed","test","delta","once","tranlinedelta","simple","blob","all"],"description":"Override the export type"},"pageSize":{"type":"number","description":"Override the page size for pagination"},"skipRetries":{"type":"boolean","description":"When true, skips retries on failure."},"proceedOnFailure":{"type":"boolean","description":"When true, continues processing subsequent records after a failure."},"responseMapping":{"type":"object","description":"Override the response field mappings","properties":{"fields":{"type":"array","description":"Field-level mappings that copy individual values from the response back onto the record.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path in the response to extract the value from. Uses dot notation to navigate nested objects."},"generate":{"type":"string","description":"Target field path on the record where the extracted value is stored."}}}},"lists":{"type":"array","description":"Array-level mappings for one-to-many data in the response.","items":{"type":"object","properties":{"generate":{"type":"string","description":"Target array field on the record where the mapped list items are stored."},"fields":{"type":"array","description":"Field mappings applied to each item in the response array.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within each response list item to extract the value from."},"generate":{"type":"string","description":"Target field path within each mapped list item."}}}}}}}}}},"required":["_abstractId"]}},"imports":{"type":"array","description":"Import overrides. Customize import resources used within the tool,\nincluding connection bindings, hooks, response mappings, and\nadaptor-specific settings.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract import identifier from the tool definition"},"_connectionId":{"type":"string","format":"objectId","description":"Override the connection used by this import"},"proceedOnFailure":{"type":"boolean","description":"When true, continues processing subsequent records after a failure."},"responseMapping":{"type":"object","description":"Override the response field mappings","properties":{"fields":{"type":"array","description":"Field-level mappings that copy individual values from the response back onto the record.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path in the response to extract the value from. Uses dot notation to navigate nested objects."},"generate":{"type":"string","description":"Target field path on the record where the extracted value is stored."}}}},"lists":{"type":"array","description":"Array-level mappings for one-to-many data in the response.","items":{"type":"object","properties":{"generate":{"type":"string","description":"Target array field on the record where the mapped list items are stored."},"fields":{"type":"array","description":"Field mappings applied to each item in the response array.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within each response list item to extract the value from."},"generate":{"type":"string","description":"Target field path within each mapped list item."}}}}}}}}},"hooks":{"type":"object","description":"Override script hooks","properties":{"preMap":{"type":"object","description":"Hook that runs on each page of records before the import's mappings are applied.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}},"postMap":{"type":"object","description":"Hook that runs after the import's mappings are applied but before records\nare sent to the destination system.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}}}}},"required":["_abstractId"]}},"routers":{"type":"array","description":"Router overrides. Customize routing behavior for specific branches\nwithin the tool, including branch filters and routing strategies.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract router identifier from the tool definition"},"name":{"type":"string","description":"Override the router name"},"routeRecordsTo":{"type":"string","enum":["first_matching_branch","all_matching_branches"],"description":"Override the routing strategy"},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"Override the routing evaluation method"},"script":{"type":"object","description":"Override the router script","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Script containing the routing function named in `function`."},"function":{"type":"string","description":"Function within the referenced script that returns the name of the branch to route to."}}},"branches":{"type":"array","description":"Override specific branch configurations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract branch identifier"},"name":{"type":"string","description":"Override the branch name"},"description":{"type":"string","description":"Override the branch description"},"inputFilter":{"type":"object","description":"Override the branch filter criteria","properties":{"version":{"type":"string","enum":["1"],"description":"Filter format version."},"rules":{"type":"array","description":"Filter rules in Celigo expression-based filter format. Array-based DSL where\nthe first element is an operator (e.g. \"equals\", \"and\", \"or\"), followed by\noperands which can be nested expressions.","items":{}}}}}}}},"required":["_abstractId"]}}}},"ApiTool":{"type":"object","description":"An API entry that maps a Celigo builder-mode API resource to an MCP\ntool endpoint. Script-type APIs are not supported.","properties":{"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP tool name exposed to clients. Must be unique across all tools\nand APIs within this server."},"_apiId":{"type":"string","format":"objectId","description":"API resource ID. Must reference a builder-type API (not script-type)."},"disabled":{"type":"boolean","default":true,"description":"When true, this API tool is disabled and will not be exposed to MCP clients."}},"required":["name","_apiId"]},"McpResource":{"type":"object","description":"A resource entry that exposes a Celigo Storage file to MCP clients.\nClients discover resources via `resources/list` and fetch file content\nvia `resources/read`. Resources are not supported on sandbox servers —\nsetting `resources` together with `sandbox: true` returns 422\n`mcp_server_resources_not_allowed_in_sandbox`.","properties":{"title":{"type":"string","maxLength":250,"description":"Human-readable display title shown to MCP clients alongside the\nfile. Free text, unlike tool and API names (which are\nregex-constrained MCP identifiers)."},"_fileId":{"type":"string","format":"objectId","description":"Celigo Storage file exposed by this resource. Must reference an\nactive file (not a folder) owned by the account — invalid references\nreturn 422 `mcp_server_file_not_found`. Each file can be referenced\nonly once per server; duplicates return 422\n`mcp_server_duplicate_file_not_allowed`. Manage files via\n`GET /v1/storage/items`."},"disabled":{"type":"boolean","default":true,"description":"When true, the resource is hidden from MCP clients and its file is\nnot served. Resources are disabled by default; set to false to\nexpose the file."}},"required":["_fileId"]},"Prompt":{"type":"object","description":"A prompt template entry on an MCP server.\n\nPrompts are inline, reusable templates that MCP-compatible clients (Claude,\nCursor, Celigo AI Agents, etc.) discover via `prompts/list` and fetch via\n`prompts/get`. Each `{{placeholder}}` inside a message template becomes a\ndeclared argument that the client supplies at invocation time; the\nbackend performs Handlebars substitution before returning the rendered\nmessages.\n\nUnlike `tools[]` and `apis[]` — which reference other Celigo resources by\nID — a prompt is stored inline on the MCP server document. There is no\nseparate \"Prompt\" resource type.\n\n`prompts/get` returns rendered messages of shape\n`[{role, content: {type, text | data, mimeType?}}]` — `text` for `text`\ncontent, or `data` (base64) + `mimeType` for `image`/`audio`. This schema\ncaptures the stored template; the rendered output is not part of the\npersisted document.\n","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Server-generated identifier for the prompt — the grant handle\nreferenced as `tool:<_id>` in end-user, group, and role resource\ngrants. Identity is preserved across updates by matching on `name`,\nso renaming a prompt assigns a new `_id` and breaks grants that\nreference the old one.\n"},"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP prompt name exposed to clients via `prompts/list`.\n\nMust be unique within `prompts[]` on this server. Only alphanumeric\ncharacters, underscores, hyphens, and dots are allowed. Prompts have\ntheir own namespace — a prompt named `summarize_meeting` does not\ncollide with a tool or API of the same name.\n\nMaximum length: 128 characters. Duplicate names return 422\n`mcp_server_duplicate_prompt_name`.\n"},"title":{"type":"string","maxLength":1000,"description":"Human-readable display title shown alongside `name` in MCP clients.\n\nUnlike `name` (the MCP identifier, regex-constrained), `title` is\nfree text. Optional — clients fall back to `name` when omitted.\n"},"description":{"type":"string","maxLength":1000,"description":"Optional description of what the prompt does. Shown to MCP clients\nduring discovery so users and LLMs can choose the right prompt.\n"},"arguments":{"type":"array","description":"Declared arguments for the prompt. Every `{{placeholder}}` referenced\nin `messagesTemplate[*].template` should appear here so MCP clients\nknow what to supply when invoking the prompt.\n","items":{"$ref":"#/components/schemas/PromptArgument"}},"messagesTemplate":{"type":"array","description":"Ordered list of message templates forming the prompt body. At least\none entry is required. Each entry renders to a single message after\nHandlebars substitution.\n","minItems":1,"items":{"$ref":"#/components/schemas/PromptMessage"}},"mockInput":{"type":"object","description":"Sample argument values used to preview / test-run the prompt in the\nauthoring UI — a plain object mapping argument names to sample values\n(e.g. `{\"username\": \"John Doe\"}`). Keys usually mirror `arguments[].name`\nbut this is not enforced. Has no effect on `prompts/get` rendering for\nMCP clients.\n"},"disabled":{"type":"boolean","default":true,"description":"When true, the prompt is hidden from MCP clients — omitted from\n`prompts/list` and not fetchable via `prompts/get`. New prompts\ndefault to disabled; set to false to expose the prompt. An enabled\nprompt also satisfies the server-level enablement rule on its own.\nPrompts saved before this field existed are reported as\n`disabled: false`."}},"required":["name","messagesTemplate"]},"PromptArgument":{"type":"object","description":"A single declared argument for a prompt. Argument names appear as\n`{{name}}` placeholders inside `messagesTemplate[*].template` and are\nsubstituted with client-supplied values at invocation time.\n","properties":{"name":{"type":"string","maxLength":256,"pattern":"^\\w+$","description":"Argument name. Must match `^\\\\w+$` (letters, digits, and underscores\nonly) so it can be referenced as a Handlebars `{{placeholder}}` in the\nmessage template. Hyphens, dots, and other characters are not allowed\nhere (even though prompt `name` permits them) — they would break the\ntemplate parser.\n"},"description":{"type":"string","maxLength":1000,"description":"Optional human-readable description of the argument. Shown to MCP\nclients during discovery; useful for guiding LLMs that supply values.\n"},"required":{"type":"boolean","default":true,"description":"Whether the client must supply this argument. Defaults to `true`.\nWhen `false`, the client may omit the argument and the\n`{{placeholder}}` is left empty after substitution.\n"}},"required":["name"]},"PromptMessage":{"type":"object","description":"A single message entry inside a prompt's `messagesTemplate[]`. Renders to\na `{role, content: {type, text|data, mimeType?}}` object in the\n`prompts/get` response after Handlebars substitution.\n","properties":{"role":{"type":"string","enum":["user","assistant"],"description":"Message role exposed to MCP clients.\n\nOnly `user` and `assistant` are supported. `system` role messages are\nnot allowed at this layer — express system-level intent inside the\nfirst user or assistant template.\n"},"contentType":{"type":"string","enum":["text","image","audio","resource"],"default":"text","description":"Type of content this message carries.\n\n- `text` — `template` holds the Handlebars-templated text body.\n- `image` / `audio` — `data` (base64) and `mimeType` are required\n  (omitting `mimeType` returns 422 `mcp_server_prompt_mimetype_required`);\n  `template` is not used.\n- `resource` — reserved for future use; the authoring UI does not\n  currently expose this option.\n"},"template":{"type":"string","maxLength":4096,"description":"Handlebars-templated text body. Use `{{argumentName}}` to reference\ndeclared arguments — they are substituted server-side before the\nmessage is returned to the client.\n\nUp to 4 KB inline. Templates larger than 4 KB are automatically\noffloaded to S3 (up to a 1 MB hard limit) and rehydrated on read.\n\nOnly relevant when `contentType` is `text` (the default).\n"},"data":{"type":"string","description":"Base64-encoded binary content for image / audio messages. Only allowed\nwhen `contentType` is `image` or `audio`.\n\nUp to 10 MB via S3 offload.\n"},"mimeType":{"type":"string","maxLength":100,"description":"MIME type for the binary `data`. Required when `contentType` is `image`\nor `audio` (e.g. `image/png`, `audio/wav`).\n"}},"required":["role"]},"PermissionSet":{"type":"object","description":"A named bundle of this server's tools and APIs — shown as a \"Capability\nSet\" in the integrator.io UI — granted to end users as one unit through\nthe `pset:<_id>` capability string on end-user, group, and role resource\ngrants. There is no standalone permission-set resource: sets live only\ninside the MCP server document, and each set's `_id` is the stable handle\nthat grants reference.\n\nDeleting a set — or resubmitting it without its `_id` — rewrites every\ngrant that references it: the `pset:` capability is replaced with the\nset's constituent `tool:`/`api:` capabilities at removal time.","properties":{"_id":{"type":"string","format":"objectId","description":"Server-generated identifier for the set — the grant handle referenced\nas `pset:<_id>` in resource grants. Send it back unchanged on PUT to\npreserve the set's identity; a set submitted without its `_id` is\ntreated as a brand-new set and assigned a fresh one."},"name":{"type":"string","maxLength":300,"description":"Display name for the set. Must be unique per server,\ncase-insensitively — duplicates are rejected with 422."},"description":{"type":"string","maxLength":1000,"description":"Description of what the set grants and who it is for."},"accessLevel":{"type":"string","enum":["read","write"],"description":"OAuth-aligned access level the set pins for everyone it is granted to."},"_toolIds":{"type":"array","description":"Tool resources included in the set. Every entry must reference a tool\nalready attached to this server through `tools[]._toolId` —\nreferencing one that is not attached is rejected with 422.","items":{"type":"string","format":"objectId"}},"_apiIds":{"type":"array","description":"Builder-mode API resources included in the set. Every entry must\nreference an API already attached to this server through\n`apis[]._apiId` — referencing one that is not attached is rejected\nwith 422.","items":{"type":"string","format":"objectId"}}},"required":["name","accessLevel"]},"Policy":{"type":"object","description":"One traffic limit the server enforces before a tool runs — shown under\n**Access > Governance** in the UI. A `rate-limit` caps calls per MINUTE,\nHOUR, or DAY with a continuously refilling allowance, either for the whole\nserver (`keyResolver` `endpoint`) or separately for each OAuth end user\n(`keyResolver` `consumer`); a `quota` caps cumulative calls over a UTC\ncalendar DAY, WEEK, or MONTH across every consumer. A call must pass every\nenabled policy. A rejected call is not executed and receives HTTP 429 with\na `Retry-After` header (seconds until the allowance refills or the quota\nperiod resets), an `X-RateLimit-Limit` header, and a JSON-RPC error\n(code -32004) whose message names the policy: `Rate limit exceeded: <name>`\nor `Usage quota exceeded: <name>`.","required":["type","name","config"],"properties":{"type":{"type":"string","enum":["rate-limit","quota"],"description":"Kind of limit. Use rate-limit to protect downstream systems from bursts\nand, with `keyResolver` `consumer`, to keep one end user from consuming\nthe whole server; use quota to cap total consumption for cost control."},"name":{"type":"string","maxLength":100,"description":"Label for the limit, echoed verbatim in the 429 error message that\nrejected clients receive — name it the way consumers should read it."},"enabled":{"type":"boolean","default":true,"description":"When true, the policy is enforced. Set to false to keep the\nconfiguration in place without enforcing it."},"config":{"type":"object","additionalProperties":false,"description":"Limit value and period. The maximum `limit` depends on the unit and\nequals the platform ceiling of 300 calls per second over one period.","required":["limit","periodTime","periodTimeUnit"],"properties":{"limit":{"type":"integer","minimum":1,"description":"Maximum number of counted calls in one period. Ceilings per unit:\n18000 per MINUTE, 1080000 per HOUR, 25920000 per DAY, 181440000 per\nWEEK, 777600000 per MONTH — higher values are rejected with 422\n`policy_config_invalid`."},"periodTime":{"type":"integer","const":1,"default":1,"description":"Number of `periodTimeUnit` units in one period. Only a single unit\nis supported; any other value is rejected with 422."},"periodTimeUnit":{"type":"string","enum":["MINUTE","HOUR","DAY","WEEK","MONTH"],"description":"Length of one period. Rate limits take MINUTE, HOUR, or DAY; quotas\ntake DAY, WEEK, or MONTH — any other pairing, or a lowercase value,\nis rejected with 422 `policy_config_invalid`."},"keyResolver":{"type":"string","enum":["endpoint","consumer"],"default":"endpoint","description":"Whose allowance the limit tracks. Omit it (or send endpoint) for a\nserver-level limit and send consumer for a per-user rate limit;\nquotas accept endpoint only."}},"if":{"properties":{"periodTimeUnit":{"const":"MINUTE"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":18000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"HOUR"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":1080000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"DAY"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":25920000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"WEEK"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":181440000}}},"else":{"properties":{"limit":{"maximum":777600000}}}}}}}},"if":{"properties":{"type":{"const":"rate-limit"}},"required":["type"]},"then":{"properties":{"config":{"properties":{"periodTimeUnit":{"enum":["MINUTE","HOUR","DAY"]}}}}},"else":{"properties":{"config":{"properties":{"periodTimeUnit":{"enum":["DAY","WEEK","MONTH"]},"keyResolver":{"enum":["endpoint"]}}}}}},"OAuthConfig":{"type":"object","description":"OAuth 2.0 configuration for the MCP server. Three modes are supported:\n\n**Celigo-managed OAuth** — set `useCeligoOauth: true`. No issuer or\naudience configuration needed; Celigo handles token validation.\n\n**OAuth provider reference** — set `_mcpOAuthProviderId` to the ID of\na shared MCP OAuth provider resource (see `/v1/mcpoauthproviders`).\nThe provider holds the issuer, audience, and introspection settings.\n\n**Inline custom OAuth** — set `issuerURL` and `audience` directly.\nTokens are validated against the issuer's JWKS. Optionally enable\n`useIntrospection` for opaque tokens via RFC 7662.\n\nOmit `oauth` entirely (or send `{}`) to disable OAuth on the server.\nIn responses, `oauth` is absent when no OAuth mode is configured.\nThe three modes are mutually exclusive. When using inline custom\nOAuth, both `issuerURL` and `audience` are required. When\n`useIntrospection` is `true`, `clientId` is also required.","properties":{"useCeligoOauth":{"type":"boolean","description":"When `true`, enables Celigo-managed OAuth. No external issuer\nconfiguration is needed. Mutually exclusive with\n`_mcpOAuthProviderId` and inline OAuth fields."},"_mcpOAuthProviderId":{"type":"string","format":"objectId","description":"References a shared MCP OAuth provider resource that holds the\nissuer, audience, scopes, and introspection settings. Mutually\nexclusive with `useCeligoOauth` and inline OAuth fields.\n\nUse `GET /v1/mcpoauthproviders` to list available providers."},"issuerURL":{"type":"string","format":"uri","description":"OAuth 2.0 issuer URL for inline custom OAuth.\n\nMust be a well-formed URL with an explicit scheme — bare hostnames\nand protocol-less values are rejected with 422 `invalid_uri`.\nUse `https://` for production issuers."},"audience":{"type":"string","description":"Expected `aud` claim on incoming access tokens. Required when\nusing inline custom OAuth — omitting it returns\n`missing_required_field` on `oauth.audience`."},"useIntrospection":{"type":"boolean","default":false,"description":"When `true`, opaque access tokens are validated by calling the\nissuer's RFC 7662 introspection endpoint using `clientId` /\n`clientSecret`. When `false`, only JWT access tokens are accepted."},"scopes":{"type":"array","description":"Required OAuth scopes. Incoming tokens must carry every listed scope.\n\nRejected values return `enum` / `invalid_field_value` on\n`oauth.scopes.<index>`.","items":{"type":"string","enum":["mcp:read","mcp:write"]}},"clientId":{"type":["string","null"],"description":"OAuth client ID used when introspecting opaque tokens. Required\nwhen `useIntrospection` is `true`."},"clientSecret":{"type":["string","null"],"description":"OAuth client secret used with `clientId` for introspection. Masked\nas `\"******\"` in response payloads; sending the masked value on\nPUT is treated as \"leave unchanged\"."}},"dependentRequired":{"issuerURL":["audience"],"audience":["issuerURL"]},"if":{"properties":{"useIntrospection":{"const":true}},"required":["useIntrospection"]},"then":{"required":["clientId"]}},"MCPServer":{"type":"object","required":["_id","name","relativeURI","disabled","createdAt","lastModified"],"description":"MCP server object as returned by the API.","allOf":[{"$ref":"#/components/schemas/MCPServerBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"Owning user ID."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"When this draft MCP server expires and will be automatically deleted. Only present\non servers created as drafts by the AI-assisted builder that have not yet been\nconfirmed. Unlike other resource types, MCP server drafts carry no `draft` boolean —\nthe presence of this field is what marks the draft state."}}}]},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/mcpservers":{"post":{"summary":"Create an MCP server","description":"Creates an MCP server. The server is created disabled by default.\n`name` and `relativeURI` are the only required fields;\n`relativeURI` must be unique per account.","operationId":"createMcpServer","tags":["MCP Servers"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"responses":{"201":{"description":"Created MCP server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPServer"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Get an MCP server

> Returns the full configuration of an MCP server including tools, APIs, prompts, resources, and OAuth settings.

```json
{"openapi":"3.2.0","info":{"title":"MCP Servers","version":"1.0.0"},"tags":[{"name":"MCP Servers","description":"MCP servers expose integration tools and builder-mode APIs as\nMCP-compatible endpoints consumed by AI agents and MCP clients.\n\nEach server has a unique `relativeURI`, a collection of tools and APIs\n(each individually enable/disable), optional prompt templates, optional\nfile resources from Celigo Storage, and optional OAuth configuration.\nTools support MCP annotations (read-only, idempotent, destructive,\nopen-world) and per-server overrides for connections, exports, imports,\nand routing. Permission sets (\"Capability Sets\" in the UI) bundle a\nserver's tools and APIs into named grants for end users, and the\nserver-scoped access endpoints bulk-assign capabilities to end users\nand groups and report compiled effective access. Optional traffic\nlimits (`policies`) — a server-level rate limit, a per-user rate\nlimit, and a usage quota — reject calls over the limit with HTTP 429\nand `Retry-After` before any tool runs.\n\n## MCP server schema\n\n{% openapi-schemas spec=\"mcp-server\" schemas=\"MCPServer\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"MCPServer":{"type":"object","required":["_id","name","relativeURI","disabled","createdAt","lastModified"],"description":"MCP server object as returned by the API.","allOf":[{"$ref":"#/components/schemas/MCPServerBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"Owning user ID."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"When this draft MCP server expires and will be automatically deleted. Only present\non servers created as drafts by the AI-assisted builder that have not yet been\nconfirmed. Unlike other resource types, MCP server drafts carry no `draft` boolean —\nthe presence of this field is what marks the draft state."}}}]},"MCPServerBase":{"type":"object","description":"Writable MCP server fields shared by the request and response schemas.","properties":{"name":{"type":"string","minLength":1,"maxLength":150,"description":"Display name for the MCP server."},"relativeURI":{"type":"string","maxLength":131072,"pattern":"^\\/[a-zA-Z0-9_\\-]+$","description":"URI path segment for the MCP server endpoint. Must be unique per account —\nduplicates are rejected with 422 `mcp_server_duplicate_relative_uri`. Only letters,\nnumbers, dashes, and underscores after the leading slash (the server's error message\nalso claims colons and dots are allowed, but they are rejected in practice). Creation\nalso requires the account to have an account alias set (422\n`mcp_server_account_alias_required` otherwise)."},"description":{"type":"string","maxLength":1000,"description":"Description of the MCP server's purpose."},"disabled":{"type":"boolean","default":true,"description":"Whether the MCP server is disabled. Defaults to `true` on creation.\nTo serve requests, at least one tool, API, resource, or prompt must\nalso be enabled."},"tools":{"type":"array","description":"Tool entries referencing Celigo Tool resources. Duplicate `_toolId`\nvalues are rejected. Names must be unique across both `tools` and `apis`.","items":{"$ref":"#/components/schemas/IOTool"}},"apis":{"type":"array","description":"API entries referencing Celigo builder-mode API resources. Only\nbuilder-type APIs are supported. Names must be unique across both\n`tools` and `apis`.","items":{"$ref":"#/components/schemas/ApiTool"}},"resources":{"type":"array","description":"Files from Celigo Storage exposed to MCP clients as MCP resources.\nEach entry references a storage file by `_fileId`; the same file can\nappear only once. Always returned in responses — servers created\nbefore resource support return an empty array. Not supported on\nsandbox servers.","items":{"$ref":"#/components/schemas/McpResource"}},"prompts":{"type":"array","description":"Prompt templates exposed to MCP clients. Each prompt has a unique\n`name` and may declare `arguments` that clients supply via\n`prompts/get`.","items":{"$ref":"#/components/schemas/Prompt"}},"permissionSets":{"type":"array","description":"Named bundles of this server's tools and APIs — shown as \"Capability\nSets\" in the UI — granted to end users as a unit via `pset:<_id>`\ncapability strings. Omitting the field on PUT resets it to an empty\narray, erasing every set and rewriting the grants that reference\nthem — always send the complete array back. Absent from responses for\nservers not saved since permission sets were introduced (unlike\n`resources`, the field is not normalized to an empty array).","items":{"$ref":"#/components/schemas/PermissionSet"}},"policies":{"type":"array","description":"Traffic limits enforced on this server before a tool runs — a\nserver-level rate limit, a per-user rate limit, and a usage quota, each\noptional and independent. An empty array (the default) means unlimited.\nAlways returned; servers saved before traffic limits existed return an\nempty array. Omitting the field on PUT clears every limit — send the\ncomplete array back, or edit it with PATCH.","items":{"$ref":"#/components/schemas/Policy"}},"oauth":{"$ref":"#/components/schemas/OAuthConfig"}}},"IOTool":{"type":"object","description":"A tool entry that maps a Celigo Tool resource to an MCP tool endpoint.\nThe referenced tool's input schema must have `type: \"object\"`.","properties":{"_toolId":{"type":"string","format":"objectId","description":"Tool resource ID. The referenced tool must exist and have an\ninput schema with `type: \"object\"`."},"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP tool name exposed to clients. Must be unique across all tools\nand APIs within this server."},"disabled":{"type":"boolean","default":true,"description":"When true, this tool is disabled and will not be exposed to MCP clients."},"annotations":{"$ref":"#/components/schemas/Annotations"},"overrides":{"$ref":"#/components/schemas/Overrides"}},"required":["_toolId","name"]},"Annotations":{"type":"object","description":"MCP-standard annotations that hint at the behavior of a tool.\n\nThese annotations follow the Model Context Protocol specification and help\nAI agents and MCP clients understand how a tool behaves without executing it.\nAll fields are optional hints — they are not enforced by the server.\n","properties":{"title":{"type":"string","maxLength":300,"description":"Human-readable title for the tool, displayed in MCP client UIs.\n\nIf not provided, the tool's `name` field is used instead.\n"},"destructiveHint":{"type":"boolean","description":"Hints that the tool may perform destructive operations such as\ndeleting or permanently modifying data.\n"},"idempotentHint":{"type":"boolean","description":"Hints that calling the tool multiple times with the same input\nproduces the same result without additional side effects.\n"},"openWorldHint":{"type":"boolean","description":"Hints that the tool interacts with an open-world environment\n(e.g., external APIs) where results may vary between calls.\n"},"readOnlyHint":{"type":"boolean","description":"Hints that the tool only reads data and does not modify any state.\n"}}},"Overrides":{"type":"object","description":"Per-server overrides for a tool's internal resources.\n\nWhen a tool is added to an MCP server, its connections, exports, imports,\nand routers can be customized for this specific server context without\nmodifying the underlying tool definition. This enables reusing the same\ntool across multiple MCP servers with different configurations.\n","properties":{"connections":{"type":"array","description":"Connection overrides. Each entry maps an abstract connection reference\nin the tool to a concrete connection resource for this server.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"The abstract connection identifier from the tool definition.\nThis is the connection reference that will be replaced.\n"},"_id":{"type":"string","format":"objectId","description":"The concrete connection resource to use in place of the abstract reference.\n"},"_borrowConcurrencyFromConnectionId":{"type":"string","description":"Optional connection from which to borrow concurrency limits.\n"}},"required":["_abstractId"]}},"exports":{"type":"array","description":"Export (lookup) overrides. Customize export resources used within the tool,\nincluding connection bindings, scheduling, response mappings, and\nadaptor-specific settings.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract export identifier from the tool definition"},"_id":{"type":"string","format":"objectId","description":"Concrete export resource to use"},"_connectionId":{"type":"string","format":"objectId","description":"Override the connection used by this export"},"type":{"type":"string","enum":["webhook","distributed","test","delta","once","tranlinedelta","simple","blob","all"],"description":"Override the export type"},"pageSize":{"type":"number","description":"Override the page size for pagination"},"skipRetries":{"type":"boolean","description":"When true, skips retries on failure."},"proceedOnFailure":{"type":"boolean","description":"When true, continues processing subsequent records after a failure."},"responseMapping":{"type":"object","description":"Override the response field mappings","properties":{"fields":{"type":"array","description":"Field-level mappings that copy individual values from the response back onto the record.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path in the response to extract the value from. Uses dot notation to navigate nested objects."},"generate":{"type":"string","description":"Target field path on the record where the extracted value is stored."}}}},"lists":{"type":"array","description":"Array-level mappings for one-to-many data in the response.","items":{"type":"object","properties":{"generate":{"type":"string","description":"Target array field on the record where the mapped list items are stored."},"fields":{"type":"array","description":"Field mappings applied to each item in the response array.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within each response list item to extract the value from."},"generate":{"type":"string","description":"Target field path within each mapped list item."}}}}}}}}}},"required":["_abstractId"]}},"imports":{"type":"array","description":"Import overrides. Customize import resources used within the tool,\nincluding connection bindings, hooks, response mappings, and\nadaptor-specific settings.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract import identifier from the tool definition"},"_connectionId":{"type":"string","format":"objectId","description":"Override the connection used by this import"},"proceedOnFailure":{"type":"boolean","description":"When true, continues processing subsequent records after a failure."},"responseMapping":{"type":"object","description":"Override the response field mappings","properties":{"fields":{"type":"array","description":"Field-level mappings that copy individual values from the response back onto the record.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path in the response to extract the value from. Uses dot notation to navigate nested objects."},"generate":{"type":"string","description":"Target field path on the record where the extracted value is stored."}}}},"lists":{"type":"array","description":"Array-level mappings for one-to-many data in the response.","items":{"type":"object","properties":{"generate":{"type":"string","description":"Target array field on the record where the mapped list items are stored."},"fields":{"type":"array","description":"Field mappings applied to each item in the response array.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within each response list item to extract the value from."},"generate":{"type":"string","description":"Target field path within each mapped list item."}}}}}}}}},"hooks":{"type":"object","description":"Override script hooks","properties":{"preMap":{"type":"object","description":"Hook that runs on each page of records before the import's mappings are applied.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}},"postMap":{"type":"object","description":"Hook that runs after the import's mappings are applied but before records\nare sent to the destination system.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}}}}},"required":["_abstractId"]}},"routers":{"type":"array","description":"Router overrides. Customize routing behavior for specific branches\nwithin the tool, including branch filters and routing strategies.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract router identifier from the tool definition"},"name":{"type":"string","description":"Override the router name"},"routeRecordsTo":{"type":"string","enum":["first_matching_branch","all_matching_branches"],"description":"Override the routing strategy"},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"Override the routing evaluation method"},"script":{"type":"object","description":"Override the router script","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Script containing the routing function named in `function`."},"function":{"type":"string","description":"Function within the referenced script that returns the name of the branch to route to."}}},"branches":{"type":"array","description":"Override specific branch configurations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract branch identifier"},"name":{"type":"string","description":"Override the branch name"},"description":{"type":"string","description":"Override the branch description"},"inputFilter":{"type":"object","description":"Override the branch filter criteria","properties":{"version":{"type":"string","enum":["1"],"description":"Filter format version."},"rules":{"type":"array","description":"Filter rules in Celigo expression-based filter format. Array-based DSL where\nthe first element is an operator (e.g. \"equals\", \"and\", \"or\"), followed by\noperands which can be nested expressions.","items":{}}}}}}}},"required":["_abstractId"]}}}},"ApiTool":{"type":"object","description":"An API entry that maps a Celigo builder-mode API resource to an MCP\ntool endpoint. Script-type APIs are not supported.","properties":{"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP tool name exposed to clients. Must be unique across all tools\nand APIs within this server."},"_apiId":{"type":"string","format":"objectId","description":"API resource ID. Must reference a builder-type API (not script-type)."},"disabled":{"type":"boolean","default":true,"description":"When true, this API tool is disabled and will not be exposed to MCP clients."}},"required":["name","_apiId"]},"McpResource":{"type":"object","description":"A resource entry that exposes a Celigo Storage file to MCP clients.\nClients discover resources via `resources/list` and fetch file content\nvia `resources/read`. Resources are not supported on sandbox servers —\nsetting `resources` together with `sandbox: true` returns 422\n`mcp_server_resources_not_allowed_in_sandbox`.","properties":{"title":{"type":"string","maxLength":250,"description":"Human-readable display title shown to MCP clients alongside the\nfile. Free text, unlike tool and API names (which are\nregex-constrained MCP identifiers)."},"_fileId":{"type":"string","format":"objectId","description":"Celigo Storage file exposed by this resource. Must reference an\nactive file (not a folder) owned by the account — invalid references\nreturn 422 `mcp_server_file_not_found`. Each file can be referenced\nonly once per server; duplicates return 422\n`mcp_server_duplicate_file_not_allowed`. Manage files via\n`GET /v1/storage/items`."},"disabled":{"type":"boolean","default":true,"description":"When true, the resource is hidden from MCP clients and its file is\nnot served. Resources are disabled by default; set to false to\nexpose the file."}},"required":["_fileId"]},"Prompt":{"type":"object","description":"A prompt template entry on an MCP server.\n\nPrompts are inline, reusable templates that MCP-compatible clients (Claude,\nCursor, Celigo AI Agents, etc.) discover via `prompts/list` and fetch via\n`prompts/get`. Each `{{placeholder}}` inside a message template becomes a\ndeclared argument that the client supplies at invocation time; the\nbackend performs Handlebars substitution before returning the rendered\nmessages.\n\nUnlike `tools[]` and `apis[]` — which reference other Celigo resources by\nID — a prompt is stored inline on the MCP server document. There is no\nseparate \"Prompt\" resource type.\n\n`prompts/get` returns rendered messages of shape\n`[{role, content: {type, text | data, mimeType?}}]` — `text` for `text`\ncontent, or `data` (base64) + `mimeType` for `image`/`audio`. This schema\ncaptures the stored template; the rendered output is not part of the\npersisted document.\n","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Server-generated identifier for the prompt — the grant handle\nreferenced as `tool:<_id>` in end-user, group, and role resource\ngrants. Identity is preserved across updates by matching on `name`,\nso renaming a prompt assigns a new `_id` and breaks grants that\nreference the old one.\n"},"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP prompt name exposed to clients via `prompts/list`.\n\nMust be unique within `prompts[]` on this server. Only alphanumeric\ncharacters, underscores, hyphens, and dots are allowed. Prompts have\ntheir own namespace — a prompt named `summarize_meeting` does not\ncollide with a tool or API of the same name.\n\nMaximum length: 128 characters. Duplicate names return 422\n`mcp_server_duplicate_prompt_name`.\n"},"title":{"type":"string","maxLength":1000,"description":"Human-readable display title shown alongside `name` in MCP clients.\n\nUnlike `name` (the MCP identifier, regex-constrained), `title` is\nfree text. Optional — clients fall back to `name` when omitted.\n"},"description":{"type":"string","maxLength":1000,"description":"Optional description of what the prompt does. Shown to MCP clients\nduring discovery so users and LLMs can choose the right prompt.\n"},"arguments":{"type":"array","description":"Declared arguments for the prompt. Every `{{placeholder}}` referenced\nin `messagesTemplate[*].template` should appear here so MCP clients\nknow what to supply when invoking the prompt.\n","items":{"$ref":"#/components/schemas/PromptArgument"}},"messagesTemplate":{"type":"array","description":"Ordered list of message templates forming the prompt body. At least\none entry is required. Each entry renders to a single message after\nHandlebars substitution.\n","minItems":1,"items":{"$ref":"#/components/schemas/PromptMessage"}},"mockInput":{"type":"object","description":"Sample argument values used to preview / test-run the prompt in the\nauthoring UI — a plain object mapping argument names to sample values\n(e.g. `{\"username\": \"John Doe\"}`). Keys usually mirror `arguments[].name`\nbut this is not enforced. Has no effect on `prompts/get` rendering for\nMCP clients.\n"},"disabled":{"type":"boolean","default":true,"description":"When true, the prompt is hidden from MCP clients — omitted from\n`prompts/list` and not fetchable via `prompts/get`. New prompts\ndefault to disabled; set to false to expose the prompt. An enabled\nprompt also satisfies the server-level enablement rule on its own.\nPrompts saved before this field existed are reported as\n`disabled: false`."}},"required":["name","messagesTemplate"]},"PromptArgument":{"type":"object","description":"A single declared argument for a prompt. Argument names appear as\n`{{name}}` placeholders inside `messagesTemplate[*].template` and are\nsubstituted with client-supplied values at invocation time.\n","properties":{"name":{"type":"string","maxLength":256,"pattern":"^\\w+$","description":"Argument name. Must match `^\\\\w+$` (letters, digits, and underscores\nonly) so it can be referenced as a Handlebars `{{placeholder}}` in the\nmessage template. Hyphens, dots, and other characters are not allowed\nhere (even though prompt `name` permits them) — they would break the\ntemplate parser.\n"},"description":{"type":"string","maxLength":1000,"description":"Optional human-readable description of the argument. Shown to MCP\nclients during discovery; useful for guiding LLMs that supply values.\n"},"required":{"type":"boolean","default":true,"description":"Whether the client must supply this argument. Defaults to `true`.\nWhen `false`, the client may omit the argument and the\n`{{placeholder}}` is left empty after substitution.\n"}},"required":["name"]},"PromptMessage":{"type":"object","description":"A single message entry inside a prompt's `messagesTemplate[]`. Renders to\na `{role, content: {type, text|data, mimeType?}}` object in the\n`prompts/get` response after Handlebars substitution.\n","properties":{"role":{"type":"string","enum":["user","assistant"],"description":"Message role exposed to MCP clients.\n\nOnly `user` and `assistant` are supported. `system` role messages are\nnot allowed at this layer — express system-level intent inside the\nfirst user or assistant template.\n"},"contentType":{"type":"string","enum":["text","image","audio","resource"],"default":"text","description":"Type of content this message carries.\n\n- `text` — `template` holds the Handlebars-templated text body.\n- `image` / `audio` — `data` (base64) and `mimeType` are required\n  (omitting `mimeType` returns 422 `mcp_server_prompt_mimetype_required`);\n  `template` is not used.\n- `resource` — reserved for future use; the authoring UI does not\n  currently expose this option.\n"},"template":{"type":"string","maxLength":4096,"description":"Handlebars-templated text body. Use `{{argumentName}}` to reference\ndeclared arguments — they are substituted server-side before the\nmessage is returned to the client.\n\nUp to 4 KB inline. Templates larger than 4 KB are automatically\noffloaded to S3 (up to a 1 MB hard limit) and rehydrated on read.\n\nOnly relevant when `contentType` is `text` (the default).\n"},"data":{"type":"string","description":"Base64-encoded binary content for image / audio messages. Only allowed\nwhen `contentType` is `image` or `audio`.\n\nUp to 10 MB via S3 offload.\n"},"mimeType":{"type":"string","maxLength":100,"description":"MIME type for the binary `data`. Required when `contentType` is `image`\nor `audio` (e.g. `image/png`, `audio/wav`).\n"}},"required":["role"]},"PermissionSet":{"type":"object","description":"A named bundle of this server's tools and APIs — shown as a \"Capability\nSet\" in the integrator.io UI — granted to end users as one unit through\nthe `pset:<_id>` capability string on end-user, group, and role resource\ngrants. There is no standalone permission-set resource: sets live only\ninside the MCP server document, and each set's `_id` is the stable handle\nthat grants reference.\n\nDeleting a set — or resubmitting it without its `_id` — rewrites every\ngrant that references it: the `pset:` capability is replaced with the\nset's constituent `tool:`/`api:` capabilities at removal time.","properties":{"_id":{"type":"string","format":"objectId","description":"Server-generated identifier for the set — the grant handle referenced\nas `pset:<_id>` in resource grants. Send it back unchanged on PUT to\npreserve the set's identity; a set submitted without its `_id` is\ntreated as a brand-new set and assigned a fresh one."},"name":{"type":"string","maxLength":300,"description":"Display name for the set. Must be unique per server,\ncase-insensitively — duplicates are rejected with 422."},"description":{"type":"string","maxLength":1000,"description":"Description of what the set grants and who it is for."},"accessLevel":{"type":"string","enum":["read","write"],"description":"OAuth-aligned access level the set pins for everyone it is granted to."},"_toolIds":{"type":"array","description":"Tool resources included in the set. Every entry must reference a tool\nalready attached to this server through `tools[]._toolId` —\nreferencing one that is not attached is rejected with 422.","items":{"type":"string","format":"objectId"}},"_apiIds":{"type":"array","description":"Builder-mode API resources included in the set. Every entry must\nreference an API already attached to this server through\n`apis[]._apiId` — referencing one that is not attached is rejected\nwith 422.","items":{"type":"string","format":"objectId"}}},"required":["name","accessLevel"]},"Policy":{"type":"object","description":"One traffic limit the server enforces before a tool runs — shown under\n**Access > Governance** in the UI. A `rate-limit` caps calls per MINUTE,\nHOUR, or DAY with a continuously refilling allowance, either for the whole\nserver (`keyResolver` `endpoint`) or separately for each OAuth end user\n(`keyResolver` `consumer`); a `quota` caps cumulative calls over a UTC\ncalendar DAY, WEEK, or MONTH across every consumer. A call must pass every\nenabled policy. A rejected call is not executed and receives HTTP 429 with\na `Retry-After` header (seconds until the allowance refills or the quota\nperiod resets), an `X-RateLimit-Limit` header, and a JSON-RPC error\n(code -32004) whose message names the policy: `Rate limit exceeded: <name>`\nor `Usage quota exceeded: <name>`.","required":["type","name","config"],"properties":{"type":{"type":"string","enum":["rate-limit","quota"],"description":"Kind of limit. Use rate-limit to protect downstream systems from bursts\nand, with `keyResolver` `consumer`, to keep one end user from consuming\nthe whole server; use quota to cap total consumption for cost control."},"name":{"type":"string","maxLength":100,"description":"Label for the limit, echoed verbatim in the 429 error message that\nrejected clients receive — name it the way consumers should read it."},"enabled":{"type":"boolean","default":true,"description":"When true, the policy is enforced. Set to false to keep the\nconfiguration in place without enforcing it."},"config":{"type":"object","additionalProperties":false,"description":"Limit value and period. The maximum `limit` depends on the unit and\nequals the platform ceiling of 300 calls per second over one period.","required":["limit","periodTime","periodTimeUnit"],"properties":{"limit":{"type":"integer","minimum":1,"description":"Maximum number of counted calls in one period. Ceilings per unit:\n18000 per MINUTE, 1080000 per HOUR, 25920000 per DAY, 181440000 per\nWEEK, 777600000 per MONTH — higher values are rejected with 422\n`policy_config_invalid`."},"periodTime":{"type":"integer","const":1,"default":1,"description":"Number of `periodTimeUnit` units in one period. Only a single unit\nis supported; any other value is rejected with 422."},"periodTimeUnit":{"type":"string","enum":["MINUTE","HOUR","DAY","WEEK","MONTH"],"description":"Length of one period. Rate limits take MINUTE, HOUR, or DAY; quotas\ntake DAY, WEEK, or MONTH — any other pairing, or a lowercase value,\nis rejected with 422 `policy_config_invalid`."},"keyResolver":{"type":"string","enum":["endpoint","consumer"],"default":"endpoint","description":"Whose allowance the limit tracks. Omit it (or send endpoint) for a\nserver-level limit and send consumer for a per-user rate limit;\nquotas accept endpoint only."}},"if":{"properties":{"periodTimeUnit":{"const":"MINUTE"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":18000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"HOUR"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":1080000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"DAY"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":25920000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"WEEK"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":181440000}}},"else":{"properties":{"limit":{"maximum":777600000}}}}}}}},"if":{"properties":{"type":{"const":"rate-limit"}},"required":["type"]},"then":{"properties":{"config":{"properties":{"periodTimeUnit":{"enum":["MINUTE","HOUR","DAY"]}}}}},"else":{"properties":{"config":{"properties":{"periodTimeUnit":{"enum":["DAY","WEEK","MONTH"]},"keyResolver":{"enum":["endpoint"]}}}}}},"OAuthConfig":{"type":"object","description":"OAuth 2.0 configuration for the MCP server. Three modes are supported:\n\n**Celigo-managed OAuth** — set `useCeligoOauth: true`. No issuer or\naudience configuration needed; Celigo handles token validation.\n\n**OAuth provider reference** — set `_mcpOAuthProviderId` to the ID of\na shared MCP OAuth provider resource (see `/v1/mcpoauthproviders`).\nThe provider holds the issuer, audience, and introspection settings.\n\n**Inline custom OAuth** — set `issuerURL` and `audience` directly.\nTokens are validated against the issuer's JWKS. Optionally enable\n`useIntrospection` for opaque tokens via RFC 7662.\n\nOmit `oauth` entirely (or send `{}`) to disable OAuth on the server.\nIn responses, `oauth` is absent when no OAuth mode is configured.\nThe three modes are mutually exclusive. When using inline custom\nOAuth, both `issuerURL` and `audience` are required. When\n`useIntrospection` is `true`, `clientId` is also required.","properties":{"useCeligoOauth":{"type":"boolean","description":"When `true`, enables Celigo-managed OAuth. No external issuer\nconfiguration is needed. Mutually exclusive with\n`_mcpOAuthProviderId` and inline OAuth fields."},"_mcpOAuthProviderId":{"type":"string","format":"objectId","description":"References a shared MCP OAuth provider resource that holds the\nissuer, audience, scopes, and introspection settings. Mutually\nexclusive with `useCeligoOauth` and inline OAuth fields.\n\nUse `GET /v1/mcpoauthproviders` to list available providers."},"issuerURL":{"type":"string","format":"uri","description":"OAuth 2.0 issuer URL for inline custom OAuth.\n\nMust be a well-formed URL with an explicit scheme — bare hostnames\nand protocol-less values are rejected with 422 `invalid_uri`.\nUse `https://` for production issuers."},"audience":{"type":"string","description":"Expected `aud` claim on incoming access tokens. Required when\nusing inline custom OAuth — omitting it returns\n`missing_required_field` on `oauth.audience`."},"useIntrospection":{"type":"boolean","default":false,"description":"When `true`, opaque access tokens are validated by calling the\nissuer's RFC 7662 introspection endpoint using `clientId` /\n`clientSecret`. When `false`, only JWT access tokens are accepted."},"scopes":{"type":"array","description":"Required OAuth scopes. Incoming tokens must carry every listed scope.\n\nRejected values return `enum` / `invalid_field_value` on\n`oauth.scopes.<index>`.","items":{"type":"string","enum":["mcp:read","mcp:write"]}},"clientId":{"type":["string","null"],"description":"OAuth client ID used when introspecting opaque tokens. Required\nwhen `useIntrospection` is `true`."},"clientSecret":{"type":["string","null"],"description":"OAuth client secret used with `clientId` for introspection. Masked\nas `\"******\"` in response payloads; sending the masked value on\nPUT is treated as \"leave unchanged\"."}},"dependentRequired":{"issuerURL":["audience"],"audience":["issuerURL"]},"if":{"properties":{"useIntrospection":{"const":true}},"required":["useIntrospection"]},"then":{"required":["clientId"]}},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/mcpservers/{_id}":{"get":{"summary":"Get an MCP server","description":"Returns the full configuration of an MCP server including tools, APIs, prompts, resources, and OAuth settings.","operationId":"getMcpServerById","tags":["MCP Servers"],"parameters":[{"name":"_id","in":"path","description":"MCP server ID.","required":true,"schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"MCP server configuration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPServer"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Update an MCP server

> Full replacement of an MCP server's configuration. Omitted arrays\
> (\`tools\`, \`apis\`, \`prompts\`, \`resources\`, \`permissionSets\`, \`policies\`)\
> are cleared, so include the complete arrays — clearing \`permissionSets\`\
> this way also rewrites the \`pset:\` grants that referenced the erased sets,\
> and clearing \`policies\` removes every traffic limit. \`relativeURI\` can be\
> changed but must remain unique per account.

```json
{"openapi":"3.2.0","info":{"title":"MCP Servers","version":"1.0.0"},"tags":[{"name":"MCP Servers","description":"MCP servers expose integration tools and builder-mode APIs as\nMCP-compatible endpoints consumed by AI agents and MCP clients.\n\nEach server has a unique `relativeURI`, a collection of tools and APIs\n(each individually enable/disable), optional prompt templates, optional\nfile resources from Celigo Storage, and optional OAuth configuration.\nTools support MCP annotations (read-only, idempotent, destructive,\nopen-world) and per-server overrides for connections, exports, imports,\nand routing. Permission sets (\"Capability Sets\" in the UI) bundle a\nserver's tools and APIs into named grants for end users, and the\nserver-scoped access endpoints bulk-assign capabilities to end users\nand groups and report compiled effective access. Optional traffic\nlimits (`policies`) — a server-level rate limit, a per-user rate\nlimit, and a usage quota — reject calls over the limit with HTTP 429\nand `Retry-After` before any tool runs.\n\n## MCP server schema\n\n{% openapi-schemas spec=\"mcp-server\" schemas=\"MCPServer\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Request":{"type":"object","description":"Request body for creating or updating an MCP server. On PUT, include\nthe full `tools`, `apis`, `prompts`, `resources`, `permissionSets`, and\n`policies` arrays because omitted arrays are cleared. Use PATCH to update individual\nfields without affecting these arrays.","required":["name","relativeURI"],"allOf":[{"$ref":"#/components/schemas/MCPServerBase"}]},"MCPServerBase":{"type":"object","description":"Writable MCP server fields shared by the request and response schemas.","properties":{"name":{"type":"string","minLength":1,"maxLength":150,"description":"Display name for the MCP server."},"relativeURI":{"type":"string","maxLength":131072,"pattern":"^\\/[a-zA-Z0-9_\\-]+$","description":"URI path segment for the MCP server endpoint. Must be unique per account —\nduplicates are rejected with 422 `mcp_server_duplicate_relative_uri`. Only letters,\nnumbers, dashes, and underscores after the leading slash (the server's error message\nalso claims colons and dots are allowed, but they are rejected in practice). Creation\nalso requires the account to have an account alias set (422\n`mcp_server_account_alias_required` otherwise)."},"description":{"type":"string","maxLength":1000,"description":"Description of the MCP server's purpose."},"disabled":{"type":"boolean","default":true,"description":"Whether the MCP server is disabled. Defaults to `true` on creation.\nTo serve requests, at least one tool, API, resource, or prompt must\nalso be enabled."},"tools":{"type":"array","description":"Tool entries referencing Celigo Tool resources. Duplicate `_toolId`\nvalues are rejected. Names must be unique across both `tools` and `apis`.","items":{"$ref":"#/components/schemas/IOTool"}},"apis":{"type":"array","description":"API entries referencing Celigo builder-mode API resources. Only\nbuilder-type APIs are supported. Names must be unique across both\n`tools` and `apis`.","items":{"$ref":"#/components/schemas/ApiTool"}},"resources":{"type":"array","description":"Files from Celigo Storage exposed to MCP clients as MCP resources.\nEach entry references a storage file by `_fileId`; the same file can\nappear only once. Always returned in responses — servers created\nbefore resource support return an empty array. Not supported on\nsandbox servers.","items":{"$ref":"#/components/schemas/McpResource"}},"prompts":{"type":"array","description":"Prompt templates exposed to MCP clients. Each prompt has a unique\n`name` and may declare `arguments` that clients supply via\n`prompts/get`.","items":{"$ref":"#/components/schemas/Prompt"}},"permissionSets":{"type":"array","description":"Named bundles of this server's tools and APIs — shown as \"Capability\nSets\" in the UI — granted to end users as a unit via `pset:<_id>`\ncapability strings. Omitting the field on PUT resets it to an empty\narray, erasing every set and rewriting the grants that reference\nthem — always send the complete array back. Absent from responses for\nservers not saved since permission sets were introduced (unlike\n`resources`, the field is not normalized to an empty array).","items":{"$ref":"#/components/schemas/PermissionSet"}},"policies":{"type":"array","description":"Traffic limits enforced on this server before a tool runs — a\nserver-level rate limit, a per-user rate limit, and a usage quota, each\noptional and independent. An empty array (the default) means unlimited.\nAlways returned; servers saved before traffic limits existed return an\nempty array. Omitting the field on PUT clears every limit — send the\ncomplete array back, or edit it with PATCH.","items":{"$ref":"#/components/schemas/Policy"}},"oauth":{"$ref":"#/components/schemas/OAuthConfig"}}},"IOTool":{"type":"object","description":"A tool entry that maps a Celigo Tool resource to an MCP tool endpoint.\nThe referenced tool's input schema must have `type: \"object\"`.","properties":{"_toolId":{"type":"string","format":"objectId","description":"Tool resource ID. The referenced tool must exist and have an\ninput schema with `type: \"object\"`."},"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP tool name exposed to clients. Must be unique across all tools\nand APIs within this server."},"disabled":{"type":"boolean","default":true,"description":"When true, this tool is disabled and will not be exposed to MCP clients."},"annotations":{"$ref":"#/components/schemas/Annotations"},"overrides":{"$ref":"#/components/schemas/Overrides"}},"required":["_toolId","name"]},"Annotations":{"type":"object","description":"MCP-standard annotations that hint at the behavior of a tool.\n\nThese annotations follow the Model Context Protocol specification and help\nAI agents and MCP clients understand how a tool behaves without executing it.\nAll fields are optional hints — they are not enforced by the server.\n","properties":{"title":{"type":"string","maxLength":300,"description":"Human-readable title for the tool, displayed in MCP client UIs.\n\nIf not provided, the tool's `name` field is used instead.\n"},"destructiveHint":{"type":"boolean","description":"Hints that the tool may perform destructive operations such as\ndeleting or permanently modifying data.\n"},"idempotentHint":{"type":"boolean","description":"Hints that calling the tool multiple times with the same input\nproduces the same result without additional side effects.\n"},"openWorldHint":{"type":"boolean","description":"Hints that the tool interacts with an open-world environment\n(e.g., external APIs) where results may vary between calls.\n"},"readOnlyHint":{"type":"boolean","description":"Hints that the tool only reads data and does not modify any state.\n"}}},"Overrides":{"type":"object","description":"Per-server overrides for a tool's internal resources.\n\nWhen a tool is added to an MCP server, its connections, exports, imports,\nand routers can be customized for this specific server context without\nmodifying the underlying tool definition. This enables reusing the same\ntool across multiple MCP servers with different configurations.\n","properties":{"connections":{"type":"array","description":"Connection overrides. Each entry maps an abstract connection reference\nin the tool to a concrete connection resource for this server.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"The abstract connection identifier from the tool definition.\nThis is the connection reference that will be replaced.\n"},"_id":{"type":"string","format":"objectId","description":"The concrete connection resource to use in place of the abstract reference.\n"},"_borrowConcurrencyFromConnectionId":{"type":"string","description":"Optional connection from which to borrow concurrency limits.\n"}},"required":["_abstractId"]}},"exports":{"type":"array","description":"Export (lookup) overrides. Customize export resources used within the tool,\nincluding connection bindings, scheduling, response mappings, and\nadaptor-specific settings.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract export identifier from the tool definition"},"_id":{"type":"string","format":"objectId","description":"Concrete export resource to use"},"_connectionId":{"type":"string","format":"objectId","description":"Override the connection used by this export"},"type":{"type":"string","enum":["webhook","distributed","test","delta","once","tranlinedelta","simple","blob","all"],"description":"Override the export type"},"pageSize":{"type":"number","description":"Override the page size for pagination"},"skipRetries":{"type":"boolean","description":"When true, skips retries on failure."},"proceedOnFailure":{"type":"boolean","description":"When true, continues processing subsequent records after a failure."},"responseMapping":{"type":"object","description":"Override the response field mappings","properties":{"fields":{"type":"array","description":"Field-level mappings that copy individual values from the response back onto the record.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path in the response to extract the value from. Uses dot notation to navigate nested objects."},"generate":{"type":"string","description":"Target field path on the record where the extracted value is stored."}}}},"lists":{"type":"array","description":"Array-level mappings for one-to-many data in the response.","items":{"type":"object","properties":{"generate":{"type":"string","description":"Target array field on the record where the mapped list items are stored."},"fields":{"type":"array","description":"Field mappings applied to each item in the response array.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within each response list item to extract the value from."},"generate":{"type":"string","description":"Target field path within each mapped list item."}}}}}}}}}},"required":["_abstractId"]}},"imports":{"type":"array","description":"Import overrides. Customize import resources used within the tool,\nincluding connection bindings, hooks, response mappings, and\nadaptor-specific settings.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract import identifier from the tool definition"},"_connectionId":{"type":"string","format":"objectId","description":"Override the connection used by this import"},"proceedOnFailure":{"type":"boolean","description":"When true, continues processing subsequent records after a failure."},"responseMapping":{"type":"object","description":"Override the response field mappings","properties":{"fields":{"type":"array","description":"Field-level mappings that copy individual values from the response back onto the record.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path in the response to extract the value from. Uses dot notation to navigate nested objects."},"generate":{"type":"string","description":"Target field path on the record where the extracted value is stored."}}}},"lists":{"type":"array","description":"Array-level mappings for one-to-many data in the response.","items":{"type":"object","properties":{"generate":{"type":"string","description":"Target array field on the record where the mapped list items are stored."},"fields":{"type":"array","description":"Field mappings applied to each item in the response array.","items":{"type":"object","properties":{"extract":{"type":"string","description":"Path within each response list item to extract the value from."},"generate":{"type":"string","description":"Target field path within each mapped list item."}}}}}}}}},"hooks":{"type":"object","description":"Override script hooks","properties":{"preMap":{"type":"object","description":"Hook that runs on each page of records before the import's mappings are applied.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}},"postMap":{"type":"object","description":"Hook that runs after the import's mappings are applied but before records\nare sent to the destination system.","properties":{"function":{"type":"string","description":"Function to invoke within the referenced script."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the hook function named in `function`."}}}}}},"required":["_abstractId"]}},"routers":{"type":"array","description":"Router overrides. Customize routing behavior for specific branches\nwithin the tool, including branch filters and routing strategies.\n","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract router identifier from the tool definition"},"name":{"type":"string","description":"Override the router name"},"routeRecordsTo":{"type":"string","enum":["first_matching_branch","all_matching_branches"],"description":"Override the routing strategy"},"routeRecordsUsing":{"type":"string","enum":["input_filters","script"],"description":"Override the routing evaluation method"},"script":{"type":"object","description":"Override the router script","properties":{"_scriptId":{"type":"string","format":"objectId","description":"Script containing the routing function named in `function`."},"function":{"type":"string","description":"Function within the referenced script that returns the name of the branch to route to."}}},"branches":{"type":"array","description":"Override specific branch configurations","items":{"type":"object","properties":{"_abstractId":{"type":"string","description":"Abstract branch identifier"},"name":{"type":"string","description":"Override the branch name"},"description":{"type":"string","description":"Override the branch description"},"inputFilter":{"type":"object","description":"Override the branch filter criteria","properties":{"version":{"type":"string","enum":["1"],"description":"Filter format version."},"rules":{"type":"array","description":"Filter rules in Celigo expression-based filter format. Array-based DSL where\nthe first element is an operator (e.g. \"equals\", \"and\", \"or\"), followed by\noperands which can be nested expressions.","items":{}}}}}}}},"required":["_abstractId"]}}}},"ApiTool":{"type":"object","description":"An API entry that maps a Celigo builder-mode API resource to an MCP\ntool endpoint. Script-type APIs are not supported.","properties":{"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP tool name exposed to clients. Must be unique across all tools\nand APIs within this server."},"_apiId":{"type":"string","format":"objectId","description":"API resource ID. Must reference a builder-type API (not script-type)."},"disabled":{"type":"boolean","default":true,"description":"When true, this API tool is disabled and will not be exposed to MCP clients."}},"required":["name","_apiId"]},"McpResource":{"type":"object","description":"A resource entry that exposes a Celigo Storage file to MCP clients.\nClients discover resources via `resources/list` and fetch file content\nvia `resources/read`. Resources are not supported on sandbox servers —\nsetting `resources` together with `sandbox: true` returns 422\n`mcp_server_resources_not_allowed_in_sandbox`.","properties":{"title":{"type":"string","maxLength":250,"description":"Human-readable display title shown to MCP clients alongside the\nfile. Free text, unlike tool and API names (which are\nregex-constrained MCP identifiers)."},"_fileId":{"type":"string","format":"objectId","description":"Celigo Storage file exposed by this resource. Must reference an\nactive file (not a folder) owned by the account — invalid references\nreturn 422 `mcp_server_file_not_found`. Each file can be referenced\nonly once per server; duplicates return 422\n`mcp_server_duplicate_file_not_allowed`. Manage files via\n`GET /v1/storage/items`."},"disabled":{"type":"boolean","default":true,"description":"When true, the resource is hidden from MCP clients and its file is\nnot served. Resources are disabled by default; set to false to\nexpose the file."}},"required":["_fileId"]},"Prompt":{"type":"object","description":"A prompt template entry on an MCP server.\n\nPrompts are inline, reusable templates that MCP-compatible clients (Claude,\nCursor, Celigo AI Agents, etc.) discover via `prompts/list` and fetch via\n`prompts/get`. Each `{{placeholder}}` inside a message template becomes a\ndeclared argument that the client supplies at invocation time; the\nbackend performs Handlebars substitution before returning the rendered\nmessages.\n\nUnlike `tools[]` and `apis[]` — which reference other Celigo resources by\nID — a prompt is stored inline on the MCP server document. There is no\nseparate \"Prompt\" resource type.\n\n`prompts/get` returns rendered messages of shape\n`[{role, content: {type, text | data, mimeType?}}]` — `text` for `text`\ncontent, or `data` (base64) + `mimeType` for `image`/`audio`. This schema\ncaptures the stored template; the rendered output is not part of the\npersisted document.\n","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Server-generated identifier for the prompt — the grant handle\nreferenced as `tool:<_id>` in end-user, group, and role resource\ngrants. Identity is preserved across updates by matching on `name`,\nso renaming a prompt assigns a new `_id` and breaks grants that\nreference the old one.\n"},"name":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_\\-.]+$","description":"MCP prompt name exposed to clients via `prompts/list`.\n\nMust be unique within `prompts[]` on this server. Only alphanumeric\ncharacters, underscores, hyphens, and dots are allowed. Prompts have\ntheir own namespace — a prompt named `summarize_meeting` does not\ncollide with a tool or API of the same name.\n\nMaximum length: 128 characters. Duplicate names return 422\n`mcp_server_duplicate_prompt_name`.\n"},"title":{"type":"string","maxLength":1000,"description":"Human-readable display title shown alongside `name` in MCP clients.\n\nUnlike `name` (the MCP identifier, regex-constrained), `title` is\nfree text. Optional — clients fall back to `name` when omitted.\n"},"description":{"type":"string","maxLength":1000,"description":"Optional description of what the prompt does. Shown to MCP clients\nduring discovery so users and LLMs can choose the right prompt.\n"},"arguments":{"type":"array","description":"Declared arguments for the prompt. Every `{{placeholder}}` referenced\nin `messagesTemplate[*].template` should appear here so MCP clients\nknow what to supply when invoking the prompt.\n","items":{"$ref":"#/components/schemas/PromptArgument"}},"messagesTemplate":{"type":"array","description":"Ordered list of message templates forming the prompt body. At least\none entry is required. Each entry renders to a single message after\nHandlebars substitution.\n","minItems":1,"items":{"$ref":"#/components/schemas/PromptMessage"}},"mockInput":{"type":"object","description":"Sample argument values used to preview / test-run the prompt in the\nauthoring UI — a plain object mapping argument names to sample values\n(e.g. `{\"username\": \"John Doe\"}`). Keys usually mirror `arguments[].name`\nbut this is not enforced. Has no effect on `prompts/get` rendering for\nMCP clients.\n"},"disabled":{"type":"boolean","default":true,"description":"When true, the prompt is hidden from MCP clients — omitted from\n`prompts/list` and not fetchable via `prompts/get`. New prompts\ndefault to disabled; set to false to expose the prompt. An enabled\nprompt also satisfies the server-level enablement rule on its own.\nPrompts saved before this field existed are reported as\n`disabled: false`."}},"required":["name","messagesTemplate"]},"PromptArgument":{"type":"object","description":"A single declared argument for a prompt. Argument names appear as\n`{{name}}` placeholders inside `messagesTemplate[*].template` and are\nsubstituted with client-supplied values at invocation time.\n","properties":{"name":{"type":"string","maxLength":256,"pattern":"^\\w+$","description":"Argument name. Must match `^\\\\w+$` (letters, digits, and underscores\nonly) so it can be referenced as a Handlebars `{{placeholder}}` in the\nmessage template. Hyphens, dots, and other characters are not allowed\nhere (even though prompt `name` permits them) — they would break the\ntemplate parser.\n"},"description":{"type":"string","maxLength":1000,"description":"Optional human-readable description of the argument. Shown to MCP\nclients during discovery; useful for guiding LLMs that supply values.\n"},"required":{"type":"boolean","default":true,"description":"Whether the client must supply this argument. Defaults to `true`.\nWhen `false`, the client may omit the argument and the\n`{{placeholder}}` is left empty after substitution.\n"}},"required":["name"]},"PromptMessage":{"type":"object","description":"A single message entry inside a prompt's `messagesTemplate[]`. Renders to\na `{role, content: {type, text|data, mimeType?}}` object in the\n`prompts/get` response after Handlebars substitution.\n","properties":{"role":{"type":"string","enum":["user","assistant"],"description":"Message role exposed to MCP clients.\n\nOnly `user` and `assistant` are supported. `system` role messages are\nnot allowed at this layer — express system-level intent inside the\nfirst user or assistant template.\n"},"contentType":{"type":"string","enum":["text","image","audio","resource"],"default":"text","description":"Type of content this message carries.\n\n- `text` — `template` holds the Handlebars-templated text body.\n- `image` / `audio` — `data` (base64) and `mimeType` are required\n  (omitting `mimeType` returns 422 `mcp_server_prompt_mimetype_required`);\n  `template` is not used.\n- `resource` — reserved for future use; the authoring UI does not\n  currently expose this option.\n"},"template":{"type":"string","maxLength":4096,"description":"Handlebars-templated text body. Use `{{argumentName}}` to reference\ndeclared arguments — they are substituted server-side before the\nmessage is returned to the client.\n\nUp to 4 KB inline. Templates larger than 4 KB are automatically\noffloaded to S3 (up to a 1 MB hard limit) and rehydrated on read.\n\nOnly relevant when `contentType` is `text` (the default).\n"},"data":{"type":"string","description":"Base64-encoded binary content for image / audio messages. Only allowed\nwhen `contentType` is `image` or `audio`.\n\nUp to 10 MB via S3 offload.\n"},"mimeType":{"type":"string","maxLength":100,"description":"MIME type for the binary `data`. Required when `contentType` is `image`\nor `audio` (e.g. `image/png`, `audio/wav`).\n"}},"required":["role"]},"PermissionSet":{"type":"object","description":"A named bundle of this server's tools and APIs — shown as a \"Capability\nSet\" in the integrator.io UI — granted to end users as one unit through\nthe `pset:<_id>` capability string on end-user, group, and role resource\ngrants. There is no standalone permission-set resource: sets live only\ninside the MCP server document, and each set's `_id` is the stable handle\nthat grants reference.\n\nDeleting a set — or resubmitting it without its `_id` — rewrites every\ngrant that references it: the `pset:` capability is replaced with the\nset's constituent `tool:`/`api:` capabilities at removal time.","properties":{"_id":{"type":"string","format":"objectId","description":"Server-generated identifier for the set — the grant handle referenced\nas `pset:<_id>` in resource grants. Send it back unchanged on PUT to\npreserve the set's identity; a set submitted without its `_id` is\ntreated as a brand-new set and assigned a fresh one."},"name":{"type":"string","maxLength":300,"description":"Display name for the set. Must be unique per server,\ncase-insensitively — duplicates are rejected with 422."},"description":{"type":"string","maxLength":1000,"description":"Description of what the set grants and who it is for."},"accessLevel":{"type":"string","enum":["read","write"],"description":"OAuth-aligned access level the set pins for everyone it is granted to."},"_toolIds":{"type":"array","description":"Tool resources included in the set. Every entry must reference a tool\nalready attached to this server through `tools[]._toolId` —\nreferencing one that is not attached is rejected with 422.","items":{"type":"string","format":"objectId"}},"_apiIds":{"type":"array","description":"Builder-mode API resources included in the set. Every entry must\nreference an API already attached to this server through\n`apis[]._apiId` — referencing one that is not attached is rejected\nwith 422.","items":{"type":"string","format":"objectId"}}},"required":["name","accessLevel"]},"Policy":{"type":"object","description":"One traffic limit the server enforces before a tool runs — shown under\n**Access > Governance** in the UI. A `rate-limit` caps calls per MINUTE,\nHOUR, or DAY with a continuously refilling allowance, either for the whole\nserver (`keyResolver` `endpoint`) or separately for each OAuth end user\n(`keyResolver` `consumer`); a `quota` caps cumulative calls over a UTC\ncalendar DAY, WEEK, or MONTH across every consumer. A call must pass every\nenabled policy. A rejected call is not executed and receives HTTP 429 with\na `Retry-After` header (seconds until the allowance refills or the quota\nperiod resets), an `X-RateLimit-Limit` header, and a JSON-RPC error\n(code -32004) whose message names the policy: `Rate limit exceeded: <name>`\nor `Usage quota exceeded: <name>`.","required":["type","name","config"],"properties":{"type":{"type":"string","enum":["rate-limit","quota"],"description":"Kind of limit. Use rate-limit to protect downstream systems from bursts\nand, with `keyResolver` `consumer`, to keep one end user from consuming\nthe whole server; use quota to cap total consumption for cost control."},"name":{"type":"string","maxLength":100,"description":"Label for the limit, echoed verbatim in the 429 error message that\nrejected clients receive — name it the way consumers should read it."},"enabled":{"type":"boolean","default":true,"description":"When true, the policy is enforced. Set to false to keep the\nconfiguration in place without enforcing it."},"config":{"type":"object","additionalProperties":false,"description":"Limit value and period. The maximum `limit` depends on the unit and\nequals the platform ceiling of 300 calls per second over one period.","required":["limit","periodTime","periodTimeUnit"],"properties":{"limit":{"type":"integer","minimum":1,"description":"Maximum number of counted calls in one period. Ceilings per unit:\n18000 per MINUTE, 1080000 per HOUR, 25920000 per DAY, 181440000 per\nWEEK, 777600000 per MONTH — higher values are rejected with 422\n`policy_config_invalid`."},"periodTime":{"type":"integer","const":1,"default":1,"description":"Number of `periodTimeUnit` units in one period. Only a single unit\nis supported; any other value is rejected with 422."},"periodTimeUnit":{"type":"string","enum":["MINUTE","HOUR","DAY","WEEK","MONTH"],"description":"Length of one period. Rate limits take MINUTE, HOUR, or DAY; quotas\ntake DAY, WEEK, or MONTH — any other pairing, or a lowercase value,\nis rejected with 422 `policy_config_invalid`."},"keyResolver":{"type":"string","enum":["endpoint","consumer"],"default":"endpoint","description":"Whose allowance the limit tracks. Omit it (or send endpoint) for a\nserver-level limit and send consumer for a per-user rate limit;\nquotas accept endpoint only."}},"if":{"properties":{"periodTimeUnit":{"const":"MINUTE"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":18000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"HOUR"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":1080000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"DAY"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":25920000}}},"else":{"if":{"properties":{"periodTimeUnit":{"const":"WEEK"}},"required":["periodTimeUnit"]},"then":{"properties":{"limit":{"maximum":181440000}}},"else":{"properties":{"limit":{"maximum":777600000}}}}}}}},"if":{"properties":{"type":{"const":"rate-limit"}},"required":["type"]},"then":{"properties":{"config":{"properties":{"periodTimeUnit":{"enum":["MINUTE","HOUR","DAY"]}}}}},"else":{"properties":{"config":{"properties":{"periodTimeUnit":{"enum":["DAY","WEEK","MONTH"]},"keyResolver":{"enum":["endpoint"]}}}}}},"OAuthConfig":{"type":"object","description":"OAuth 2.0 configuration for the MCP server. Three modes are supported:\n\n**Celigo-managed OAuth** — set `useCeligoOauth: true`. No issuer or\naudience configuration needed; Celigo handles token validation.\n\n**OAuth provider reference** — set `_mcpOAuthProviderId` to the ID of\na shared MCP OAuth provider resource (see `/v1/mcpoauthproviders`).\nThe provider holds the issuer, audience, and introspection settings.\n\n**Inline custom OAuth** — set `issuerURL` and `audience` directly.\nTokens are validated against the issuer's JWKS. Optionally enable\n`useIntrospection` for opaque tokens via RFC 7662.\n\nOmit `oauth` entirely (or send `{}`) to disable OAuth on the server.\nIn responses, `oauth` is absent when no OAuth mode is configured.\nThe three modes are mutually exclusive. When using inline custom\nOAuth, both `issuerURL` and `audience` are required. When\n`useIntrospection` is `true`, `clientId` is also required.","properties":{"useCeligoOauth":{"type":"boolean","description":"When `true`, enables Celigo-managed OAuth. No external issuer\nconfiguration is needed. Mutually exclusive with\n`_mcpOAuthProviderId` and inline OAuth fields."},"_mcpOAuthProviderId":{"type":"string","format":"objectId","description":"References a shared MCP OAuth provider resource that holds the\nissuer, audience, scopes, and introspection settings. Mutually\nexclusive with `useCeligoOauth` and inline OAuth fields.\n\nUse `GET /v1/mcpoauthproviders` to list available providers."},"issuerURL":{"type":"string","format":"uri","description":"OAuth 2.0 issuer URL for inline custom OAuth.\n\nMust be a well-formed URL with an explicit scheme — bare hostnames\nand protocol-less values are rejected with 422 `invalid_uri`.\nUse `https://` for production issuers."},"audience":{"type":"string","description":"Expected `aud` claim on incoming access tokens. Required when\nusing inline custom OAuth — omitting it returns\n`missing_required_field` on `oauth.audience`."},"useIntrospection":{"type":"boolean","default":false,"description":"When `true`, opaque access tokens are validated by calling the\nissuer's RFC 7662 introspection endpoint using `clientId` /\n`clientSecret`. When `false`, only JWT access tokens are accepted."},"scopes":{"type":"array","description":"Required OAuth scopes. Incoming tokens must carry every listed scope.\n\nRejected values return `enum` / `invalid_field_value` on\n`oauth.scopes.<index>`.","items":{"type":"string","enum":["mcp:read","mcp:write"]}},"clientId":{"type":["string","null"],"description":"OAuth client ID used when introspecting opaque tokens. Required\nwhen `useIntrospection` is `true`."},"clientSecret":{"type":["string","null"],"description":"OAuth client secret used with `clientId` for introspection. Masked\nas `\"******\"` in response payloads; sending the masked value on\nPUT is treated as \"leave unchanged\"."}},"dependentRequired":{"issuerURL":["audience"],"audience":["issuerURL"]},"if":{"properties":{"useIntrospection":{"const":true}},"required":["useIntrospection"]},"then":{"required":["clientId"]}},"MCPServer":{"type":"object","required":["_id","name","relativeURI","disabled","createdAt","lastModified"],"description":"MCP server object as returned by the API.","allOf":[{"$ref":"#/components/schemas/MCPServerBase"},{"$ref":"#/components/schemas/ResourceResponse"},{"type":"object","properties":{"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"Owning user ID."},"draftExpiresAt":{"type":"string","format":"date-time","readOnly":true,"description":"When this draft MCP server expires and will be automatically deleted. Only present\non servers created as drafts by the AI-assisted builder that have not yet been\nconfirmed. Unlike other resource types, MCP server drafts carry no `draft` boolean —\nthe presence of this field is what marks the draft state."}}}]},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/mcpservers/{_id}":{"put":{"summary":"Update an MCP server","description":"Full replacement of an MCP server's configuration. Omitted arrays\n(`tools`, `apis`, `prompts`, `resources`, `permissionSets`, `policies`)\nare cleared, so include the complete arrays — clearing `permissionSets`\nthis way also rewrites the `pset:` grants that referenced the erased sets,\nand clearing `policies` removes every traffic limit. `relativeURI` can be\nchanged but must remain unique per account.","operationId":"updateMcpServer","tags":["MCP Servers"],"parameters":[{"name":"_id","in":"path","description":"MCP server ID.","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"responses":{"200":{"description":"Updated MCP server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPServer"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Delete an MCP server

> Soft-deletes an MCP server. Retained in the recycle bin for 30 days\
> before permanent removal.

```json
{"openapi":"3.2.0","info":{"title":"MCP Servers","version":"1.0.0"},"tags":[{"name":"MCP Servers","description":"MCP servers expose integration tools and builder-mode APIs as\nMCP-compatible endpoints consumed by AI agents and MCP clients.\n\nEach server has a unique `relativeURI`, a collection of tools and APIs\n(each individually enable/disable), optional prompt templates, optional\nfile resources from Celigo Storage, and optional OAuth configuration.\nTools support MCP annotations (read-only, idempotent, destructive,\nopen-world) and per-server overrides for connections, exports, imports,\nand routing. Permission sets (\"Capability Sets\" in the UI) bundle a\nserver's tools and APIs into named grants for end users, and the\nserver-scoped access endpoints bulk-assign capabilities to end users\nand groups and report compiled effective access. Optional traffic\nlimits (`policies`) — a server-level rate limit, a per-user rate\nlimit, and a usage quota — reject calls over the limit with HTTP 429\nand `Retry-After` before any tool runs.\n\n## MCP server schema\n\n{% openapi-schemas spec=\"mcp-server\" schemas=\"MCPServer\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/mcpservers/{_id}":{"delete":{"summary":"Delete an MCP server","description":"Soft-deletes an MCP server. Retained in the recycle bin for 30 days\nbefore permanent removal.","operationId":"deleteMcpServer","tags":["MCP Servers"],"parameters":[{"name":"_id","in":"path","description":"MCP server ID.","required":true,"schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"Deleted."},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Patch an MCP server

> Partially updates an MCP server using a JSON Patch document (RFC 6902).\
> Only \`/name\`, \`/disabled\`, and \`/policies\` are whitelisted paths — all\
> other paths are rejected with \`not a whitelisted property\`. Under\
> \`/policies\`, \`add\`, \`replace\`, and \`remove\` work on the whole array,\
> \`add\` works at \`/policies/-\` or an index, and \`replace\` works at an index\
> or a sub-path such as \`/policies/0/config/limit\`; \`remove\` at an array\
> index is rejected with 422 \`Remove at array index is not supported\`. The\
> resulting array is validated as a whole, and an invalid policy rejects\
> the entire patch.

```json
{"openapi":"3.2.0","info":{"title":"MCP Servers","version":"1.0.0"},"tags":[{"name":"MCP Servers","description":"MCP servers expose integration tools and builder-mode APIs as\nMCP-compatible endpoints consumed by AI agents and MCP clients.\n\nEach server has a unique `relativeURI`, a collection of tools and APIs\n(each individually enable/disable), optional prompt templates, optional\nfile resources from Celigo Storage, and optional OAuth configuration.\nTools support MCP annotations (read-only, idempotent, destructive,\nopen-world) and per-server overrides for connections, exports, imports,\nand routing. Permission sets (\"Capability Sets\" in the UI) bundle a\nserver's tools and APIs into named grants for end users, and the\nserver-scoped access endpoints bulk-assign capabilities to end users\nand groups and report compiled effective access. Optional traffic\nlimits (`policies`) — a server-level rate limit, a per-user rate\nlimit, and a usage quota — reject calls over the limit with HTTP 429\nand `Retry-After` before any tool runs.\n\n## MCP server schema\n\n{% openapi-schemas spec=\"mcp-server\" schemas=\"MCPServer\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"JsonPatchRequest":{"type":"array","description":"A JSON Patch document (RFC 6902). Send an array of patch\noperations on whitelisted fields — all other paths are rejected\nwith 422.","minItems":1,"items":{"$ref":"#/components/schemas/JsonPatchOperation"}},"JsonPatchOperation":{"type":"object","description":"A single JSON Patch operation (RFC 6902).","required":["op","path"],"properties":{"op":{"type":"string","enum":["replace","add","remove"],"description":"The operation to perform."},"path":{"type":"string","description":"JSON Pointer (RFC 6901) to the field to patch. Only\nwhitelisted paths are accepted — unlisted paths return\n`422` with `\"<path> is not a whitelisted property\"`."},"value":{"description":"The new value to set. Required for `replace` and `add`, omit for `remove`."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/mcpservers/{_id}":{"patch":{"summary":"Patch an MCP server","description":"Partially updates an MCP server using a JSON Patch document (RFC 6902).\nOnly `/name`, `/disabled`, and `/policies` are whitelisted paths — all\nother paths are rejected with `not a whitelisted property`. Under\n`/policies`, `add`, `replace`, and `remove` work on the whole array,\n`add` works at `/policies/-` or an index, and `replace` works at an index\nor a sub-path such as `/policies/0/config/limit`; `remove` at an array\nindex is rejected with 422 `Remove at array index is not supported`. The\nresulting array is validated as a whole, and an invalid policy rejects\nthe entire patch.","operationId":"patchMcpServer","tags":["MCP Servers"],"parameters":[{"name":"_id","in":"path","description":"MCP server ID.","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonPatchRequest"}}}},"responses":{"204":{"description":"Patch applied."},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## List dependencies of an MCP server

> Returns the set of resources that depend on the specified resource.\
> The response is an object whose keys are dependent-resource types\
> (e.g. \`flows\`, \`imports\`) and whose values are arrays of dependency\
> entries. Returns \`{}\` when no dependents exist, including for\
> well-formatted but nonexistent IDs.

```json
{"openapi":"3.2.0","info":{"title":"MCP Servers","version":"1.0.0"},"tags":[{"name":"MCP Servers","description":"MCP servers expose integration tools and builder-mode APIs as\nMCP-compatible endpoints consumed by AI agents and MCP clients.\n\nEach server has a unique `relativeURI`, a collection of tools and APIs\n(each individually enable/disable), optional prompt templates, optional\nfile resources from Celigo Storage, and optional OAuth configuration.\nTools support MCP annotations (read-only, idempotent, destructive,\nopen-world) and per-server overrides for connections, exports, imports,\nand routing. Permission sets (\"Capability Sets\" in the UI) bundle a\nserver's tools and APIs into named grants for end users, and the\nserver-scoped access endpoints bulk-assign capabilities to end users\nand groups and report compiled effective access. Optional traffic\nlimits (`policies`) — a server-level rate limit, a per-user rate\nlimit, and a usage quota — reject calls over the limit with HTTP 429\nand `Retry-After` before any tool runs.\n\n## MCP server schema\n\n{% openapi-schemas spec=\"mcp-server\" schemas=\"MCPServer\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"DependencyResponse":{"type":"object","description":"Map of dependent-resource types to arrays of dependency entries.\nKeys are plural resource type strings (e.g. `flows`, `imports`,\n`connections`). An empty object `{}` means no dependents.\n","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/DependencyEntry"}}},"DependencyEntry":{"type":"object","description":"A single resource that depends on the queried resource.","properties":{"id":{"type":"string","description":"Unique identifier of the dependent resource."},"name":{"type":"string","description":"Display name of the dependent resource."},"paths":{"type":"array","description":"Dot-notation paths within the dependent resource that reference\nthe target resource. `[*]` denotes array elements.","items":{"type":"string"}},"accessLevel":{"type":"string","description":"The caller's access level on the dependent resource."},"dependencyIds":{"type":"object","description":"Map of resource types to arrays of IDs that this dependent\nresource references on the target. Keys are singular or plural\nresource type strings; values are arrays of ID strings.","additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["id","name","paths","accessLevel","dependencyIds"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/mcpservers/{_id}/dependencies":{"get":{"operationId":"listMcpServerDependencies","tags":["MCP Servers"],"summary":"List dependencies of an MCP server","description":"Returns the set of resources that depend on the specified resource.\nThe response is an object whose keys are dependent-resource types\n(e.g. `flows`, `imports`) and whose values are arrays of dependency\nentries. Returns `{}` when no dependents exist, including for\nwell-formatted but nonexistent IDs.","parameters":[{"name":"_id","in":"path","required":true,"description":"Resource ID.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Dependency map. Keys are resource-type strings; values are arrays\nof dependency entries. Returns `{}` when no dependents exist.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DependencyResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"}}}}}}
```

## Get effective end-user access for an MCP server

> Server-scoped reverse lookup: finds every end user who can reach this MCP\
> server and compiles each one's effective tool access with source\
> attribution — the union of direct grants, group grants, role grants, and\
> permission sets. The result is recomputed on every request rather than\
> cached. The account owner is never listed — owners have MCP access\
> without an end-user record, so there is no record to compile — and an\
> empty result therefore means no end user has been granted this server.\
> Requires account owner or administrator access. The per-user view of the\
> same compilation is \`GET /v1/endusers/{\_ashareId}/effective-access\`\
> (End Users API).

```json
{"openapi":"3.2.0","info":{"title":"MCP Servers","version":"1.0.0"},"tags":[{"name":"MCP Servers","description":"MCP servers expose integration tools and builder-mode APIs as\nMCP-compatible endpoints consumed by AI agents and MCP clients.\n\nEach server has a unique `relativeURI`, a collection of tools and APIs\n(each individually enable/disable), optional prompt templates, optional\nfile resources from Celigo Storage, and optional OAuth configuration.\nTools support MCP annotations (read-only, idempotent, destructive,\nopen-world) and per-server overrides for connections, exports, imports,\nand routing. Permission sets (\"Capability Sets\" in the UI) bundle a\nserver's tools and APIs into named grants for end users, and the\nserver-scoped access endpoints bulk-assign capabilities to end users\nand groups and report compiled effective access. Optional traffic\nlimits (`policies`) — a server-level rate limit, a per-user rate\nlimit, and a usage quota — reject calls over the limit with HTTP 429\nand `Retry-After` before any tool runs.\n\n## MCP server schema\n\n{% openapi-schemas spec=\"mcp-server\" schemas=\"MCPServer\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"MCPServerEffectiveAccess":{"type":"object","description":"The compiled end-user access for one MCP server, with source attribution.\nEach user's access is the union of their direct grants, group grants,\nrole grants (direct or via groups), and permission sets, recompiled on\nevery request.","properties":{"_mcpServerId":{"type":"string","format":"objectId","readOnly":true,"description":"MCP server this compilation applies to."},"serverName":{"type":["string","null"],"readOnly":true,"description":"Display name of the MCP server."},"users":{"type":"array","description":"End users whose grants compile to tool access on this server. Users\nwhose grants resolve to no enabled tool are omitted, and disabled\ntools never materialize. An empty array means no end user currently\nhas access.","items":{"type":"object","properties":{"_ashareId":{"type":"string","format":"objectId","readOnly":true,"description":"End-user access-record id (from the end users list)."},"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"The end user's own user id."},"email":{"type":["string","null"],"description":"The end user's email. Null when the user record no longer resolves."},"name":{"type":["string","null"],"description":"The end user's display name. Null when unset or when the user record no longer resolves."},"tools":{"type":"array","description":"Tools the end user can invoke on this server.","items":{"type":"object","properties":{"_id":{"type":"string","format":"objectId","description":"Tool id."},"name":{"type":"string","description":"Tool name as exposed on this server."},"via":{"type":"array","description":"Source attribution strings such as `direct`, `group:<name>`,\n`pset:<name> (group:<name>)`, `role-direct:<name>`, or\n`role:<name> (group:<name>)`.","items":{"type":"string"}}}}}}}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/mcpservers/{_id}/effective-access":{"get":{"summary":"Get effective end-user access for an MCP server","operationId":"getMcpServerEffectiveAccess","tags":["MCP Servers"],"description":"Server-scoped reverse lookup: finds every end user who can reach this MCP\nserver and compiles each one's effective tool access with source\nattribution — the union of direct grants, group grants, role grants, and\npermission sets. The result is recomputed on every request rather than\ncached. The account owner is never listed — owners have MCP access\nwithout an end-user record, so there is no record to compile — and an\nempty result therefore means no end user has been granted this server.\nRequires account owner or administrator access. The per-user view of the\nsame compilation is `GET /v1/endusers/{_ashareId}/effective-access`\n(End Users API).","parameters":[{"name":"_id","in":"path","description":"MCP server ID.","required":true,"schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Compiled effective access by end user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPServerEffectiveAccess"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Bulk assign MCP server access to end users

> Assigns this server's capabilities to up to 100 end users in one request.\
> For each end user, the grant for this server is replaced with the supplied\
> capabilities; grants for other MCP servers and wildcard grants are\
> preserved. End users whose grants already match are counted as processed\
> without a save. Processing stops at the first failure — the response then\
> carries the entries completed before it, plus \`errors\`. Requires account\
> owner or administrator access.

```json
{"openapi":"3.2.0","info":{"title":"MCP Servers","version":"1.0.0"},"tags":[{"name":"MCP Servers","description":"MCP servers expose integration tools and builder-mode APIs as\nMCP-compatible endpoints consumed by AI agents and MCP clients.\n\nEach server has a unique `relativeURI`, a collection of tools and APIs\n(each individually enable/disable), optional prompt templates, optional\nfile resources from Celigo Storage, and optional OAuth configuration.\nTools support MCP annotations (read-only, idempotent, destructive,\nopen-world) and per-server overrides for connections, exports, imports,\nand routing. Permission sets (\"Capability Sets\" in the UI) bundle a\nserver's tools and APIs into named grants for end users, and the\nserver-scoped access endpoints bulk-assign capabilities to end users\nand groups and report compiled effective access. Optional traffic\nlimits (`policies`) — a server-level rate limit, a per-user rate\nlimit, and a usage quota — reject calls over the limit with HTTP 429\nand `Retry-After` before any tool runs.\n\n## MCP server schema\n\n{% openapi-schemas spec=\"mcp-server\" schemas=\"MCPServer\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"BulkAssignEndUsersRequest":{"type":"object","description":"Bulk assignment payload. The same capabilities are applied to every\nlisted end user.","required":["_ashareIds","capabilities"],"properties":{"_ashareIds":{"type":"array","minItems":1,"maxItems":100,"uniqueItems":true,"description":"End-user access-record ids (from the end users list) to assign this\nserver's capabilities to. Every id must belong to an end user of this\naccount or the whole request is rejected before any update.","items":{"type":"string","format":"objectId"}},"capabilities":{"type":"array","minItems":1,"description":"Capabilities to apply on this MCP server for every listed end user.\nEach capability must resolve on this server — tools and APIs must be\nattached to it and `pset:` ids must reference its permission sets.","items":{"$ref":"#/components/schemas/GrantCapability"}}}},"GrantCapability":{"type":"string","pattern":"^(?:tool|api):(?:[a-fA-F0-9]{24}|all)$|^pset:[a-fA-F0-9]{24}$","description":"Capability string granting access on this server: `tool:all`,\n`tool:<24-char-hex-id>` (an IO tool `_toolId` or attached prompt `_id`),\n`api:all`, `api:<24-char-hex-apiId>`, or\n`pset:<24-char-hex-permissionSetId>` referencing a permission set defined\non this server."},"BulkAssignEndUsersResult":{"type":"object","description":"Result of a bulk end-user assignment. On a mid-batch failure the same\nbody is returned with a non-2xx status: `endUsers` holds the entries\nprocessed before the failure and `errors` carries the error that stopped\nthe batch.","properties":{"updated":{"type":"integer","description":"Number of end users processed, including end users whose grants\nalready matched and were left unchanged."},"_mcpServerId":{"type":"string","format":"objectId","readOnly":true,"description":"MCP server the capabilities were assigned on."},"serverName":{"type":["string","null"],"readOnly":true,"description":"Display name of the MCP server."},"endUsers":{"type":"array","description":"Per-end-user assignment outcomes, in request order.","items":{"type":"object","properties":{"_id":{"type":"string","format":"objectId","description":"End-user access-record id."},"_sharedWithUserId":{"type":"string","format":"objectId","description":"The end user's own user id."},"resourceGrants":{"type":"array","description":"The end user's complete resource grants after the merge. Only\nthe grant for this server is replaced; grants for other MCP\nservers and wildcard grants are preserved.","items":{"type":"object","properties":{"resourceType":{"type":"string","enum":["mcpServer"],"description":"Resource type the grant applies to."},"_resourceId":{"type":["string","null"],"format":"objectId","description":"MCP server the grant applies to. Null for a wildcard grant\nacross all MCP servers in the account."},"capabilities":{"type":"array","description":"Capabilities granted on the target resource.","items":{"type":"string"}}}}},"capabilities":{"type":"array","description":"Capabilities applied on this server for this end user.","items":{"type":"string"}}}}},"errors":{"type":"array","description":"Present when the batch stopped early. Carries the first error\nencountered; `endUsers` then reflects partial progress.","items":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code."},"message":{"type":"string","description":"Human-readable error message."}}}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/mcpservers/{_id}/endusers":{"put":{"summary":"Bulk assign MCP server access to end users","operationId":"assignMcpServerEndUsers","tags":["MCP Servers"],"description":"Assigns this server's capabilities to up to 100 end users in one request.\nFor each end user, the grant for this server is replaced with the supplied\ncapabilities; grants for other MCP servers and wildcard grants are\npreserved. End users whose grants already match are counted as processed\nwithout a save. Processing stops at the first failure — the response then\ncarries the entries completed before it, plus `errors`. Requires account\nowner or administrator access.","parameters":[{"name":"_id","in":"path","description":"MCP server ID.","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkAssignEndUsersRequest"}}}},"responses":{"200":{"description":"All end users processed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkAssignEndUsersResult"}}}},"400":{"description":"Validation failed. Pre-flight failures (invalid MCP server id,\ninvalid request body, unknown end-user ids) return a bare `errors`\narray; a mid-batch failure from merged-grant re-validation returns\nthe result body with partial progress plus `errors`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"description":"MCP server not found in this account (pre-flight, a bare `errors`\narray), or an end-user share disappeared mid-batch (the result body\nwith partial progress plus `errors`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A duplicate end-user share was detected while persisting mid-batch\n(`enduser_ashare_exists`). Returns the result body with partial\nprogress plus `errors`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkAssignEndUsersResult"}}}}}}}}}
```

## Bulk assign MCP server access to groups

> Assigns this server's capabilities to up to 100 groups in one request.\
> For each group, the grant for this server is replaced with the supplied\
> capabilities; grants for other MCP servers and wildcard grants are\
> preserved, and the group's roles and members are not changed. Groups are\
> updated in batches of five; processing stops at the first failure — the\
> response then carries the groups completed before it, plus \`errors\`.\
> Requires account owner or administrator access.

```json
{"openapi":"3.2.0","info":{"title":"MCP Servers","version":"1.0.0"},"tags":[{"name":"MCP Servers","description":"MCP servers expose integration tools and builder-mode APIs as\nMCP-compatible endpoints consumed by AI agents and MCP clients.\n\nEach server has a unique `relativeURI`, a collection of tools and APIs\n(each individually enable/disable), optional prompt templates, optional\nfile resources from Celigo Storage, and optional OAuth configuration.\nTools support MCP annotations (read-only, idempotent, destructive,\nopen-world) and per-server overrides for connections, exports, imports,\nand routing. Permission sets (\"Capability Sets\" in the UI) bundle a\nserver's tools and APIs into named grants for end users, and the\nserver-scoped access endpoints bulk-assign capabilities to end users\nand groups and report compiled effective access. Optional traffic\nlimits (`policies`) — a server-level rate limit, a per-user rate\nlimit, and a usage quota — reject calls over the limit with HTTP 429\nand `Retry-After` before any tool runs.\n\n## MCP server schema\n\n{% openapi-schemas spec=\"mcp-server\" schemas=\"MCPServer\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"BulkAssignGroupsRequest":{"type":"object","description":"Bulk assignment payload. The same capabilities are applied to every\nlisted group.","required":["_groupIds","capabilities"],"properties":{"_groupIds":{"type":"array","minItems":1,"maxItems":100,"uniqueItems":true,"description":"Groups to assign this server's capabilities to. Every id must belong\nto a group of this account or the whole request is rejected before\nany update.","items":{"type":"string","format":"objectId"}},"capabilities":{"type":"array","minItems":1,"description":"Capabilities to apply on this MCP server for every listed group.\nEach capability must resolve on this server — tools and APIs must be\nattached to it and `pset:` ids must reference its permission sets.","items":{"$ref":"#/components/schemas/GrantCapability"}}}},"GrantCapability":{"type":"string","pattern":"^(?:tool|api):(?:[a-fA-F0-9]{24}|all)$|^pset:[a-fA-F0-9]{24}$","description":"Capability string granting access on this server: `tool:all`,\n`tool:<24-char-hex-id>` (an IO tool `_toolId` or attached prompt `_id`),\n`api:all`, `api:<24-char-hex-apiId>`, or\n`pset:<24-char-hex-permissionSetId>` referencing a permission set defined\non this server."},"BulkAssignGroupsResult":{"type":"object","description":"Result of a bulk group assignment. On a mid-batch failure the same body\nis returned with a non-2xx status: `groups` holds the entries processed\nbefore the failure and `errors` carries the error that stopped the batch.","properties":{"updated":{"type":"integer","description":"Number of groups processed, including groups whose grants already\nmatched and were left unchanged."},"_mcpServerId":{"type":"string","format":"objectId","readOnly":true,"description":"MCP server the capabilities were assigned on."},"serverName":{"type":["string","null"],"readOnly":true,"description":"Display name of the MCP server."},"groups":{"type":"array","description":"Per-group assignment outcomes, sorted by group name.","items":{"type":"object","properties":{"_id":{"type":"string","format":"objectId","description":"Group id."},"name":{"type":"string","description":"Group name."},"_roleIds":{"type":"array","description":"Roles pinned to the group. Not changed by this operation.","items":{"type":"string","format":"objectId"}},"capabilities":{"type":"array","description":"Capabilities applied on this server for this group.","items":{"type":"string"}}}}},"errors":{"type":"array","description":"Present when the batch stopped early. Carries the first error\nencountered; `groups` then reflects partial progress.","items":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code."},"message":{"type":"string","description":"Human-readable error message."}}}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/mcpservers/{_id}/groups":{"put":{"summary":"Bulk assign MCP server access to groups","operationId":"assignMcpServerGroups","tags":["MCP Servers"],"description":"Assigns this server's capabilities to up to 100 groups in one request.\nFor each group, the grant for this server is replaced with the supplied\ncapabilities; grants for other MCP servers and wildcard grants are\npreserved, and the group's roles and members are not changed. Groups are\nupdated in batches of five; processing stops at the first failure — the\nresponse then carries the groups completed before it, plus `errors`.\nRequires account owner or administrator access.","parameters":[{"name":"_id","in":"path","description":"MCP server ID.","required":true,"schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkAssignGroupsRequest"}}}},"responses":{"200":{"description":"All groups processed. `groups` is sorted by group name.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkAssignGroupsResult"}}}},"400":{"description":"Validation failed. Pre-flight failures (invalid MCP server id,\ninvalid request body, more than 100 or duplicate `_groupIds`, unknown\ngroup ids, capabilities that do not resolve on this server) return a\nbare `errors` array; a mid-batch failure returns the result body with\npartial progress plus `errors`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"description":"MCP server not found in this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developer.celigo.com/api/api-reference/mcp-servers.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
