references/schemas/annotations.yml
Annotations:
type: object
description: |
MCP-standard annotations that hint at the behavior of a tool.
These annotations follow the Model Context Protocol specification and help
AI agents and MCP clients understand how a tool behaves without executing it.
All fields are optional hints — they are not enforced by the server.
properties:
title:
type: string
maxLength: 300
description: |
Human-readable title for the tool, displayed in MCP client UIs.
If not provided, the tool's `name` field is used instead.
examples: ["Create Customer Record", "Fetch Order Status"]
destructiveHint:
type: boolean
description: |
Hints that the tool may perform destructive operations such as
deleting or permanently modifying data.
examples: [true, false]
idempotentHint:
type: boolean
description: |
Hints that calling the tool multiple times with the same input
produces the same result without additional side effects.
examples: [true, false]
openWorldHint:
type: boolean
description: |
Hints that the tool interacts with an open-world environment
(e.g., external APIs) where results may vary between calls.
examples: [true, false]
readOnlyHint:
type: boolean
description: |
Hints that the tool only reads data and does not modify any state.
examples: [true, false]
references/schemas/api-tool.yml
ApiTool:
type: object
description: |-
An API entry that maps a Celigo builder-mode API resource to an MCP
tool endpoint. Script-type APIs are not supported.
x-celigo-ai-guidance:
- |-
Each API tool maps a Celigo API to an MCP-compatible tool endpoint;
only builder-type APIs (not script-type) can be used in MCP servers.
- |-
Tool names across all tools and APIs within the same MCP server must be unique
and follow the MCP naming convention:
alphanumeric characters, underscores, hyphens, and dots only.
properties:
name:
type: string
maxLength: 128
pattern: "^[A-Za-z0-9_\\-.]+$"
description: |-
MCP tool name exposed to clients. Must be unique across all tools
and APIs within this server.
x-celigo-ai-guidance:
- |-
Must be unique across all tools and APIs within this MCP server.
Only alphanumeric characters, underscores, hyphens, and dots are allowed.
Maximum length: 128 characters (enforced by validation).
examples: ["customer_api", "order.lookup"]
_apiId:
type: string
x-celigo-refModel: apis
format: objectId
description: |-
API resource ID. Must reference a builder-type API (not script-type).
x-celigo-ai-guidance:
- |-
The referenced API resource exposed by this MCP tool must exist,
belong to the same user, and be of type "builder";
script-type APIs are not supported.
examples: ["68ae4264b5f755d2dd3796b4"]
disabled:
type: boolean
default: true
description: When true, this API tool is disabled and will not be exposed to MCP clients.
x-celigo-ai-guidance:
- Whether this API tool is disabled within the MCP server.
examples: [false, true]
required:
- name
- _apiId
references/schemas/io-tool.yml
IOTool:
type: object
description: |-
A tool entry that maps a Celigo Tool resource to an MCP tool endpoint.
The referenced tool's input schema must have `type: "object"`.
x-celigo-ai-guidance:
- |-
A tool entry within an MCP server references a Tool resource;
tool names across all tools and APIs within the same MCP server must be unique
and follow the MCP naming convention (alphanumeric,
underscores, hyphens, dots only).
properties:
_toolId:
type: string
x-celigo-refModel: tools
format: objectId
description: |-
Tool resource ID. The referenced tool must exist and have an
input schema with `type: "object"`.
x-celigo-ai-guidance:
- Reference to the Tool resource that this MCP tool exposes.
examples: ["69d462d5b9c28ea0b7f82522"]
name:
type: string
maxLength: 128
pattern: "^[A-Za-z0-9_\\-.]+$"
description: |-
MCP tool name exposed to clients. Must be unique across all tools
and APIs within this server.
x-celigo-ai-guidance:
- |-
Must be unique across all tools and APIs within this MCP server.
Only alphanumeric characters, underscores, hyphens, and dots are allowed.
Maximum length: 128 characters (enforced by validation).
examples: ["get_customer", "create_order", "validate.input"]
disabled:
type: boolean
default: true
description: When true, this tool is disabled and will not be exposed to MCP clients.
x-celigo-ai-guidance:
- |-
Indicates whether this tool is disabled within the MCP server;
disabled tools are not exposed to MCP clients.
At least one tool, API, resource, or prompt must be enabled for the
server itself to be enabled.
examples: [false, true]
annotations:
$ref: "./annotations.yml#/Annotations"
overrides:
$ref: "./overrides.yml#/Overrides"
required:
- _toolId
- name
references/schemas/overrides.yml
Overrides:
type: object
description: |
Per-server overrides for a tool's internal resources.
When a tool is added to an MCP server, its connections, exports, imports,
and routers can be customized for this specific server context without
modifying the underlying tool definition. This enables reusing the same
tool across multiple MCP servers with different configurations.
properties:
connections:
type: array
description: |
Connection overrides. Each entry maps an abstract connection reference
in the tool to a concrete connection resource for this server.
items:
type: object
properties:
_abstractId:
type: string
description: |
The abstract connection identifier from the tool definition.
This is the connection reference that will be replaced.
examples: ["60a2c4e6f321d800129a1a3c"]
_id:
type: string
x-celigo-refModel: connections
format: objectId
description: |
The concrete connection resource to use in place of the abstract reference.
examples: ["5f8d43a1b9e5a80011a35f2c"]
x-celigo-canon:
decision: not-required
reason: >-
Server accepts and stores _abstractId-only entries verbatim, and
_borrowConcurrencyFromConnectionId is a documented alternative — uniform
stored pairing is not a requirement.
method: live-probe
verified: '2026-07-04'
_borrowConcurrencyFromConnectionId:
type: string
x-celigo-refModel: connections
description: |
Optional connection from which to borrow concurrency limits.
examples: ["5f8d43a1b9e5a80011a35f2c"]
required:
- _abstractId
exports:
type: array
description: |
Export (lookup) overrides. Customize export resources used within the tool,
including connection bindings, scheduling, response mappings, and
adaptor-specific settings.
items:
type: object
properties:
_abstractId:
type: string
description: Abstract export identifier from the tool definition
examples: ["60a2c4e6f321d800129a1a3c"]
_id:
type: string
x-celigo-refModel: exports
format: objectId
description: Concrete export resource to use
examples: ["5f8d43a1b9e5a80011a35f2c"]
_connectionId:
type: string
x-celigo-refModel: connections
format: objectId
description: Override the connection used by this export
examples: ["5f8d43a1b9e5a80011a35f2c"]
type:
type: string
enum: ["webhook", "distributed", "test", "delta", "once", "tranlinedelta", "simple", "blob", "all"]
x-enumDescriptions:
webhook: Event-driven export triggered by incoming webhook calls.
distributed: Export distributed across multiple NetSuite worker nodes.
test: Export used for testing and validation only.
delta: Incremental export that fetches only records changed since the last run.
once: One-time export that runs a single time and does not repeat.
tranlinedelta: Transaction line-level delta export for NetSuite transaction lines.
simple: Basic export that fetches all matching records on each run.
blob: Binary large object export for file-based data.
all: Export that retrieves all records without filtering.
description: Override the export type
pageSize:
type: number
description: Override the page size for pagination
examples: [100]
skipRetries:
type: boolean
description: When true, skips retries on failure.
x-celigo-ai-guidance:
- Whether to skip retries on failure
proceedOnFailure:
type: boolean
description: When true, continues processing subsequent records after a failure.
x-celigo-ai-guidance:
- Whether to continue processing on 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.
examples: ["data.id"]
generate:
type: string
description: Target field path on the record where the extracted value is stored.
examples: ["customerId"]
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.
examples: ["lineItems"]
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.
examples: ["sku"]
generate:
type: string
description: Target field path within each mapped list item.
examples: ["itemCode"]
required:
- _abstractId
imports:
type: array
description: |
Import overrides. Customize import resources used within the tool,
including connection bindings, hooks, response mappings, and
adaptor-specific settings.
items:
type: object
properties:
_abstractId:
type: string
description: Abstract import identifier from the tool definition
examples: ["60a2c4e6f321d800129a1a3c"]
_connectionId:
type: string
x-celigo-refModel: connections
format: objectId
description: Override the connection used by this import
examples: ["5f8d43a1b9e5a80011a35f2c"]
proceedOnFailure:
type: boolean
description: When true, continues processing subsequent records after a failure.
x-celigo-ai-guidance:
- Whether to continue processing on 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.
examples: ["data.id"]
generate:
type: string
description: Target field path on the record where the extracted value is stored.
examples: ["customerId"]
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.
examples: ["lineItems"]
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.
examples: ["sku"]
generate:
type: string
description: Target field path within each mapped list item.
examples: ["itemCode"]
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.
examples: ["preMap"]
_scriptId:
type: string
x-celigo-refModel: scripts
format: objectId
description: Script containing the hook function named in `function`.
examples: ["66a1f2c3b4d5e6f7a8b9c0d1"]
postMap:
type: object
description: |-
Hook that runs after the import's mappings are applied but before records
are sent to the destination system.
properties:
function:
type: string
description: Function to invoke within the referenced script.
examples: ["postMap"]
_scriptId:
type: string
x-celigo-refModel: scripts
format: objectId
description: Script containing the hook function named in `function`.
examples: ["66a1f2c3b4d5e6f7a8b9c0d2"]
required:
- _abstractId
routers:
type: array
description: |
Router overrides. Customize routing behavior for specific branches
within the tool, including branch filters and routing strategies.
items:
type: object
properties:
_abstractId:
type: string
description: Abstract router identifier from the tool definition
examples: ["router_001"]
name:
type: string
description: Override the router name
examples: ["route_by_region"]
routeRecordsTo:
type: string
enum: ["first_matching_branch", "all_matching_branches"]
x-enumDescriptions:
first_matching_branch: Routes each record to only the first branch whose criteria match.
all_matching_branches: Routes each record to every branch whose criteria match, creating copies.
description: Override the routing strategy
routeRecordsUsing:
type: string
enum: ["input_filters", "script"]
x-enumDescriptions:
input_filters: Evaluate routing criteria using declarative filter expressions.
script: Evaluate routing criteria using a custom JavaScript function.
description: Override the routing evaluation method
script:
type: object
description: Override the router script
properties:
_scriptId:
type: string
x-celigo-refModel: scripts
format: objectId
description: Script containing the routing function named in `function`.
examples: ["66a1f2c3b4d5e6f7a8b9c0d3"]
function:
type: string
description: Function within the referenced script that returns the name of the branch to route to.
examples: ["routeRecord"]
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
examples: ["North America"]
description:
type: string
description: Override the branch description
examples: ["Records routed to the North America region"]
inputFilter:
type: object
description: Override the branch filter criteria
properties:
version:
type: string
enum: ["1"]
x-enumDescriptions:
"1": Version 1 of the Celigo expression-based filter format.
description: Filter format version.
rules:
type: array
description: |-
Filter rules in Celigo expression-based filter format. Array-based DSL where
the first element is an operator (e.g. "equals", "and", "or"), followed by
operands which can be nested expressions.
items: {}
required:
- _abstractId
references/schemas/request.yml
Request:
type: object
description: |-
Request body for creating or updating an MCP server. On PUT, include
the full `tools`, `apis`, and `resources` arrays because omitted arrays
are cleared. Use PATCH to update individual fields without affecting
these arrays.
x-celigo-ai-guidance:
- |-
MCP servers expose Celigo tools, builder-mode APIs,
and inline prompt templates as MCP-compatible endpoints for consumption by AI
agents and MCP clients.
required:
- name
- relativeURI
x-celigo-canon:
decision: not-required
reason: >-
Do not require apis, description, disabled, or oauth on write — a minimal
name-plus-relativeURI create succeeds and the server defaults the rest (empty
description, disabled true, empty arrays, no oauth). Universal stored presence is
server-defaulted/UI-written.
method: live-probe
verified: '2026-07-04'
allOf:
- $ref: "./base.yml#/MCPServerBase"
references/schemas/response.yml
MCPServer:
type: object
required:
- _id
- name
- relativeURI
- disabled
- createdAt
- lastModified
description: MCP server object as returned by the API.
allOf:
- $ref: './base.yml#/MCPServerBase'
- $ref: '../../../common/schemas/resource-response.yml#/ResourceResponse'
- type: object
properties:
_userId:
type: string
format: objectId
readOnly: true
x-celigo-refModel: users
description: Owning user ID.
examples: ["624cb0346309dc3a543733a2"]
sandbox:
type: boolean
deprecated: true
description: Legacy sandbox flag. Not present in current responses.
draftExpiresAt:
type: string
format: date-time
readOnly: true
description: |-
When this draft MCP server expires and will be automatically deleted. Only present
on servers created as drafts by the AI-assisted builder that have not yet been
confirmed. Unlike other resource types, MCP server drafts carry no `draft` boolean —
the presence of this field is what marks the draft state.
examples: ["2026-05-14T17:16:05.595Z"]
x-celigo-ai-guidance:
- |-
Contains the complete MCP server configuration including metadata,
tool entries, API entries, and their override settings.
SKILL.md
---
name: building-mcp-servers
description: Build Celigo MCP server resources -- endpoints that expose Tools and builder-mode APIs to external AI agents and MCP clients. Use when creating MCP servers, linking tools or APIs, or configuring annotations and overrides.
---
<!-- TIER:1 -->
# Building MCP Servers
An MCP server is a **Model Context Protocol endpoint** that exposes Celigo Tools and builder-mode APIs as callable tools for external AI agents and MCP clients. Concerns when building an MCP server:
- **Endpoint identity** -- unique `relativeURI` that forms the server's URL path
- **Tool selection** -- which Tool resources to expose, each with an MCP-compatible name
- **API selection** -- which builder-mode API resources to expose (script-mode APIs are not supported)
- **Annotations** -- MCP-standard behavior hints (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) that help AI agents decide when and how to call a tool
- **Overrides** -- per-server customization of a tool's connections, exports, imports, and routers without modifying the underlying tool definition
- **Name uniqueness** -- tool names must be unique across all `tools[]` and `apis[]` entries within the server
MCP servers support configurable **authentication** of their own -- Celigo OAuth (the default), an external IdP, or static API tokens, gated by `mcp:read` / `mcp:write` scopes (see [Authentication and Scoping](#authentication-and-scoping)). Outbound calls to external systems use the connections referenced by the underlying tools and APIs.
Used alongside tools and APIs. The MCP server is a thin exposure layer -- all processing logic lives in the referenced Tool and API resources.
## Composition Patterns
MCP servers combine two types of entries:
### Tool Entries (`tools[]`)
Reference Celigo Tool resources. Each tool becomes an MCP tool endpoint. The tool's `input.schema` must have `type: "object"` at the root to comply with the MCP specification. Tool entries support annotations (behavior hints) and overrides (per-server connection/resource customization).
### API Entries (`apis[]`)
Reference Celigo builder-mode API resources. Each API becomes an MCP tool endpoint. Only `type: "builder"` APIs are supported -- script-mode and legacy APIs cannot be exposed via MCP. API entries do not support annotations or overrides.
### Typical Compositions
In production, most MCP servers expose APIs only. Servers that combine both tools and APIs are less common but valid for mixed read/write patterns (e.g., tools for writes with annotations, APIs for lookups).
## Quick Reference
### Decision Matrix
| You need to... | Use tool entry | Use API entry |
|---|---|---|
| Expose reusable logic with connection flexibility | Yes | -- |
| Hint behavior to AI agents (read-only, destructive) | Yes (annotations) | -- |
| Swap connections per-server without modifying the resource | Yes (overrides) | -- |
| Expose a builder-mode API as an MCP endpoint | -- | Yes |
| Expose a script-mode or legacy API | Not supported | Not supported |
### Minimum Required Fields
Every MCP server needs at minimum:
- `name` -- human-readable label
- `relativeURI` -- unique URI path segment (must start with `/`, single segment, alphanumeric + underscores + hyphens)
Each tool entry needs: `_toolId`, `name`
Each API entry needs: `_apiId`, `name`
### Schema Index
All schemas are in [references/schemas/](references/schemas/):
| Schema | What it defines |
|--------|----------------|
| [request.yml](references/schemas/request.yml) | Top-level MCP server fields (name, relativeURI, description, disabled, tools, apis) |
| [response.yml](references/schemas/response.yml) | MCP server response shape (includes _id, timestamps, sandbox) |
| [io-tool.yml](references/schemas/io-tool.yml) | Tool entry schema (_toolId, name, disabled, annotations, overrides) |
| [api-tool.yml](references/schemas/api-tool.yml) | API entry schema (_apiId, name, disabled) |
| [annotations.yml](references/schemas/annotations.yml) | MCP behavior hints (title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint) |
| [overrides.yml](references/schemas/overrides.yml) | Per-server overrides for connections, exports, imports, and routers |
## Related Skills
- [building-tools > How to Build a Tool](../building-tools/SKILL.md#how-to-build-a-tool) -- building the Tool resources that MCP servers expose
- [building-apis > How to Build an API](../building-apis/SKILL.md#how-to-build-an-api) -- building the builder-mode APIs that MCP servers expose
- [configuring-connections > Quick Reference](../configuring-connections/SKILL.md#quick-reference) -- connections used by tools and overridden per-server
- [configuring-exports > Quick Reference](../configuring-exports/SKILL.md#quick-reference) -- exports used as lookups within tool pipelines
- [configuring-imports > Quick Reference](../configuring-imports/SKILL.md#quick-reference) -- imports used as action steps within tool pipelines
<!-- TIER:2 -->
## How to Build an MCP Server
### 1. Plan what the server exposes
Before creating anything, determine what capabilities the MCP server should offer to AI agents. Each capability maps to either a Tool or a builder-mode API. Group related capabilities under a single server with a meaningful `relativeURI`.
### 2. Check for existing resources
Look for tools and APIs that can be reused before creating new ones.
```bash
# Search across all resource types in the account
celigo account search "<keyword>"
# Check existing tools
celigo tools list
# Check existing APIs (only builder-mode can be used)
celigo apis list
# Check existing MCP servers for patterns
celigo mcp-servers list
```
### 3. Build the underlying resources (bottom-up)
MCP servers reference tools and APIs -- these must exist first. Build order:
1. **Connections** -- create or reuse connections to target systems
2. **Exports + Imports** -- data sources and destinations for tool/API pipelines
3. **Tools** -- reusable logic blocks (use `building-tools` skill). Ensure `input.schema` has `type: "object"` at root for MCP compatibility
4. **APIs** -- builder-mode endpoints (use `building-apis` skill). Ensure `type: "builder"` is set
5. **MCP Server** -- the exposure layer that references tools and APIs
### 4. Choose tool names
Each entry (tool or API) needs a `name` that becomes the MCP tool name visible to AI agents. Names must:
- Be unique across all `tools[]` and `apis[]` entries in the server
- Contain only alphanumeric characters, underscores, hyphens, and dots
- Be descriptive enough for an AI agent to understand the tool's purpose (e.g., `get_customer`, `create_order`, `validate.input`)
### 5. Configure annotations (tool entries only)
Annotations are optional MCP-standard hints that help AI agents decide when and how to call a tool. Set them based on what the underlying tool actually does:
- `readOnlyHint: true` -- tool only reads data, no side effects (e.g., a lookup)
- `destructiveHint: true` -- tool deletes or permanently modifies data
- `idempotentHint: true` -- calling multiple times with the same input produces the same result
- `openWorldHint: true` -- tool interacts with external APIs where results may vary between calls
Annotations are hints only -- they are not enforced by the server.
### 6. Configure overrides (tool entries only)
Overrides let you customize a tool's internal resources for this specific MCP server without modifying the tool definition. This enables reusing the same tool across multiple servers with different configurations.
The most common override is **connection overrides** -- mapping the tool's abstract connection references to concrete connections for this server. Override entries use `_abstractId` (the connection ID in the tool definition) and `_id` (the concrete connection to use instead).
Export, import, and router overrides are also available but rarely used in practice.
### 7. Build the MCP server JSON
Reference the [Schema Index](#schema-index) for exact field schemas. Every MCP server needs at minimum: `name` and `relativeURI`. Add `tools[]` and/or `apis[]` entries to expose capabilities. Set `disabled: false` to enable the server (at least one tool or API entry must also be enabled).
## Authentication and Scoping
Deciding who can call a server is the second design decision after deciding what it exposes. MCP servers have their own configurable authentication, independent of the connections their underlying tools use. Celigo OAuth and API tokens can be enabled at the same time on one server -- a common shape when a server serves both human users (OAuth) and automation (tokens).
### Authentication modes
- **Celigo OAuth** -- the default identity provider on every new server. Consumers authenticate with their Celigo credentials (routed to your SSO provider automatically if the account has SSO). Only this mode supports **per-user downstream connections** (each caller runs against their own Celigo connections) and an explicit **Users list** on the server's Access tab.
- **External IdP (external OAuth)** -- validates OAuth tokens issued by your own identity provider (Auth0, Okta, etc.). External providers are configured once at the account level and referenced from any server; the server stores the issuer URL, audience, validation method (JWKS or introspection), and required scopes (`mcp:read`, `mcp:write`, or both). With External, the Users list is not shown and per-user downstream connections are not available. Provider limits to check first: Auth0 requires the *Resource Parameter Compatibility Profile* on its application, and Microsoft Entra ID and Google Identity are not currently supported for MCP OAuth.
- **API tokens** -- static bearer tokens the consumer sends on every request. Created on the server (they also appear in the account's global API tokens list) with a name, optional description, and an auto-purge window; the token value is shown once at creation. Right for service-to-service callers, legacy clients that can't do OAuth, short-lived access, or as a fallback alongside OAuth. API tokens have no scope-narrowing UI of their own -- their granularity comes from the server's tool list and the `mcp:read` / `mcp:write` split.
Default to Celigo OAuth, and add an API token alongside it when automation is in scope. Reach for an external IdP only when the consumer explicitly requires a specific provider.
### Scopes -- `mcp:read` vs `mcp:write`
Every OAuth path (Celigo or external) requires the issued token to carry MCP scopes:
- **`mcp:read`** -- non-destructive operations, such as listing available tools (`tools/list`) and invoking tools whose underlying Tool or API has no side effects.
- **`mcp:write`** -- operations that may change data or state.
The scope is checked on every request; a structurally valid token missing the required scope is rejected. Grant the minimum scope a consumer needs -- a read-only partner should not receive `mcp:write`. The scope claim usually lives in the standard OAuth `scope` or `scp` claim, depending on the IdP.
## CLI Commands
```bash
# CRUD
celigo mcp-servers list
celigo mcp-servers get <id>
celigo mcp-servers create < mcp-server.json
celigo mcp-servers update <id> < mcp-server.json
celigo mcp-servers set <id> key=value [key2=value2 ...]
celigo mcp-servers delete <id>
# Discovery
celigo account search "<keyword>"
celigo tools list
celigo apis list
```
<!-- TIER:3 -->
## Pre-Submit Checklist
Before creating or updating an MCP server, verify:
- [ ] `name` is set and descriptive
- [ ] `relativeURI` starts with `/`, contains a single path segment, uses only alphanumeric characters, underscores, and hyphens
- [ ] `relativeURI` is unique across all MCP servers in the account
- [ ] All `_toolId` references in `tools[]` point to existing Tool resources
- [ ] All `_apiId` references in `apis[]` point to existing builder-mode API resources (not script-mode or legacy)
- [ ] Tool names are unique across all `tools[]` and `apis[]` entries in the server
- [ ] Tool names contain only alphanumeric characters, underscores, hyphens, and dots
- [ ] Tool entries referencing Tools verify that the tool's `input.schema` has `type: "object"` at root
- [ ] At least one tool or API entry is enabled (`disabled: false`) if the server itself is enabled
- [ ] Connection overrides (if used) map `_abstractId` to valid concrete connection IDs
- [ ] Sandbox MCP servers only reference sandbox connections and resources
## Gotchas
1. **PUT erases omitted fields.** Always GET first, modify, then PUT. The `set` command handles this automatically.
2. **Script-mode and legacy APIs cannot be exposed.** Only `type: "builder"` APIs work in MCP servers. If you get a validation error on an API entry, verify the referenced API has `type: "builder"` set.
3. **Tool input schema must be `type: "object"`.** The MCP specification requires tool inputs to be JSON objects. If a tool's `input.schema` has a different root type (e.g., `array`, `string`), it cannot be exposed via MCP.
4. **Annotations are hints, not enforcement.** Setting `readOnlyHint: true` does not prevent the tool from writing data. The AI agent may ignore annotations entirely.
5. **Name uniqueness spans both arrays.** A tool named `get_customer` in `tools[]` conflicts with an API also named `get_customer` in `apis[]`. Names must be unique across the combined set.
6. **Overrides only apply to tool entries.** API entries in `apis[]` do not support annotations or overrides. To customize an API's behavior per-server, modify the API resource itself.
7. **Enabling the server requires at least one enabled entry.** Setting `disabled: false` on the server alone is not sufficient -- at least one tool or API within it must also have `disabled: false`.
8. **Preview and logs endpoints are session-auth only.** The `/preview` and `/logs` endpoints for MCP servers are not accessible via bearer token -- they require the UI session.
9. **MCP server and MCP connection are opposite things.** An MCP *server* (this resource) publishes your capabilities outward, so external MCP clients call in. An MCP *connection* is a separate Connection resource (`type: "mcp"`) that consumes an external MCP server, so Celigo calls out. They share the word "MCP" and are configured in different places -- confusing the two is a common mistake here. If the goal is to wire Celigo to consume someone else's MCP server, reach for an MCP connection, not this resource.
10. **Every invocation counts as one MCP call.** Each tool or API invocation counts against the account's MCP entitlement, including failed calls -- a 500 still consumes a call -- and usage is aggregated across all MCP servers in the account. Enforcement is soft (threshold notifications, not blocking), so aggressive consumer-side retries inflate usage.
## Common Errors
| Error | Cause | Fix |
|-------|-------|-----|
| 422 on create/update | Missing required fields or invalid `relativeURI` format | Check `name` and `relativeURI`; ensure URI starts with `/` and is a single valid segment |
| 422 `_toolId not found` | Referenced tool does not exist or was deleted | Verify the tool exists with `celigo tools get <id>` |
| 422 `_apiId not found` | Referenced API does not exist or was deleted | Verify the API exists with `celigo apis get <id>` |
| 422 `duplicate tool name` | Two entries share the same `name` | Ensure all names across `tools[]` and `apis[]` are unique |
| 422 `relativeURI already in use` | Another MCP server in the account uses the same URI | Choose a different `relativeURI`; check with `celigo mcp-servers list` |
| 422 `invalid API type` | API entry references a script-mode or legacy API | Only `type: "builder"` APIs are supported; check with `celigo apis get <id>` |
| 422 `input schema invalid` | Tool's `input.schema` root type is not `object` | Update the tool's input schema to have `type: "object"` at root |
| Server enabled but not accessible | All tool/API entries are disabled | Enable at least one entry with `disabled: false` |