{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/stormmcp/json-schema/stormmcp-create-custom-server-request-schema.json",
  "title": "CreateCustomServerRequest",
  "description": "Request model for creating a new custom remote server.",
  "x-generated": "2026-11-10",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/stormmcp-customremoteservers-api-openapi.yml#/components/schemas/CreateCustomServerRequest",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "Gets or sets the server name (must be unique per tenant)."
    },
    "description": {
      "type": [
        "null",
        "string"
      ],
      "description": "Gets or sets the optional server description."
    },
    "longDescription": {
      "type": [
        "null",
        "string"
      ],
      "description": "Gets or sets the detailed description."
    },
    "category": {
      "type": "string",
      "description": "Gets or sets the category. Defaults to \"Custom\"."
    },
    "authTypes": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/McpServerAuthType"
      },
      "description": "Gets or sets the supported authentication types."
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Gets or sets the tags."
    },
    "remoteConfig": {
      "oneOf": [
        {
          "type": "null"
        },
        {
          "description": "Gets or sets the remote server configuration (URI, transport, etc.).",
          "$ref": "#/$defs/RemoteServerConfig"
        }
      ]
    },
    "ui": {
      "oneOf": [
        {
          "type": "null"
        },
        {
          "description": "Gets or sets the UI display configuration.",
          "$ref": "#/$defs/UiConfiguration"
        }
      ]
    },
    "testEndpoint": {
      "oneOf": [
        {
          "type": "null"
        },
        {
          "description": "Gets or sets the test endpoint configuration for credential validation.",
          "$ref": "#/$defs/TestEndpointConfig"
        }
      ]
    },
    "status": {
      "type": "string",
      "description": "Gets or sets the server status (Active/Inactive)."
    },
    "credentials": {
      "oneOf": [
        {
          "type": "null"
        },
        {
          "description": "Gets or sets the credentials for the server (optional).\nWill be encrypted before storage.",
          "$ref": "#/$defs/CreateCustomServerCredentialRequest"
        }
      ]
    }
  },
  "$defs": {
    "CreateCustomServerCredentialRequest": {
      "type": "object",
      "properties": {
        "authenticationType": {
          "description": "Gets or sets the authentication type.",
          "$ref": "#/$defs/McpServerAuthType"
        },
        "apiKey": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the API key value (used when AuthenticationType is ApiKey)."
        }
      },
      "description": "Request model for creating server credentials.\nCredentials are stored in User Credential Store (not locally)."
    },
    "McpServerAuthType": {
      "type": "integer",
      "description": "An enumeration representing the authentication types for MCP servers."
    },
    "OAuthConfig": {
      "type": "object",
      "properties": {
        "authorizationEndpoint": {
          "type": "string",
          "description": "Gets or sets the OAuth authorization endpoint URL."
        },
        "tokenEndpoint": {
          "type": "string",
          "description": "Gets or sets the OAuth token endpoint URL."
        },
        "revokeEndpoint": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the OAuth token revocation endpoint URL (optional)."
        },
        "refreshTokenEndpoint": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the OAuth refresh token endpoint URL (optional).\nWARNING: User Credential Store currently does not support separate refresh endpoints."
        },
        "grantType": {
          "type": "string",
          "description": "Gets or sets the grant type (default: Authorization Code with PKCE)."
        },
        "scopeSeparator": {
          "type": "string",
          "description": "Gets or sets the scope separator character (default: space)."
        },
        "tokenEndpointAuthMethod": {
          "type": "string",
          "description": "Gets or sets the token endpoint authentication method."
        },
        "grantTypesSupported": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Gets or sets the grant types supported (default: [\"authorization_code\"])."
        },
        "responseTypesSupported": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Gets or sets the response types supported (default: [\"code\"])."
        },
        "codeChallengeMethodsSupported": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Gets or sets the code challenge methods supported for PKCE (e.g., \"S256\", \"plain\")."
        },
        "authorizationParameters": {
          "type": [
            "null",
            "object"
          ],
          "additionalProperties": {
            "type": "string"
          },
          "description": "Gets or sets additional parameters to include in authorization requests."
        },
        "tokenParameters": {
          "type": [
            "null",
            "object"
          ],
          "additionalProperties": {
            "type": "string"
          },
          "description": "Gets or sets additional parameters to include in token requests."
        },
        "tokenHeaders": {
          "type": [
            "null",
            "object"
          ],
          "additionalProperties": {
            "type": "string"
          },
          "description": "Gets or sets additional headers to include in token requests."
        }
      },
      "description": "OAuth-specific configuration for Manual OAuth providers.\nContains OAuth endpoint URLs and behavior configuration."
    },
    "RemoteServerConfig": {
      "type": "object",
      "properties": {
        "transport": {
          "type": "string",
          "description": "Gets or sets the transport protocol (e.g., \"sse\" for Server-Sent Events)."
        },
        "connectionTimeoutSeconds": {
          "pattern": "^-?(?:0|[1-9]\\d*)$",
          "type": [
            "integer",
            "string"
          ],
          "description": "Gets or sets the connection timeout in seconds.",
          "format": "int32"
        },
        "autoReconnect": {
          "type": "boolean",
          "description": "Gets or sets a value indicating whether to automatically reconnect on disconnect."
        },
        "maxReconnectAttempts": {
          "pattern": "^-?(?:0|[1-9]\\d*)$",
          "type": [
            "integer",
            "string"
          ],
          "description": "Gets or sets the maximum number of reconnection attempts.",
          "format": "int32"
        },
        "endpointConfig": {
          "type": "object",
          "additionalProperties": {
            "type": "string"
          },
          "description": "Gets or sets additional endpoint-specific configuration."
        },
        "uri": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the remote server URI."
        },
        "uriVariables": {
          "type": [
            "null",
            "object"
          ],
          "additionalProperties": {
            "$ref": "#/$defs/UriVariable"
          },
          "description": "Gets or sets the URI variables that can be substituted in the URI.\nUsed for dynamic parameterization (e.g., {zone} for region, {token} for API keys)."
        },
        "headers": {
          "type": [
            "null",
            "object"
          ],
          "additionalProperties": {
            "type": "string"
          },
          "description": "Gets or sets HTTP headers to be sent with requests.\nSupports both static headers and dynamic placeholders like {AuthToken} and {BasicAuth:VarName}.\nFor auth-type-specific headers (e.g., different Authorization formats), use AuthHeaders instead."
        },
        "oAuth": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "description": "Gets or sets OAuth-specific configuration for Manual OAuth providers.\nContains OAuth endpoints and behavior configuration.",
              "$ref": "#/$defs/OAuthConfig"
            }
          ]
        },
        "authHeaders": {
          "type": [
            "null",
            "object"
          ],
          "additionalProperties": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "description": "Gets or sets auth-type-specific HTTP headers.\nKeys are auth types (e.g., \"ApiKey\", \"OAuth\"), values are header dictionaries.\nWhen a specific auth type is selected, headers from AuthHeaders[authType] are merged with/override base Headers.\nThis allows different Authorization header formats per auth type (e.g., \"Basic {AuthToken}\" for ApiKey, \"Bearer {AuthToken}\" for OAuth)."
        },
        "bodyParams": {
          "type": [
            "null",
            "object"
          ],
          "additionalProperties": {
            "type": "string"
          },
          "description": "Gets or sets parameters to inject into request bodies for MCP-Link servers.\nUsed for APIs that require authentication in the request body (e.g., Canny's apiKey parameter).\nSupports {AuthToken} placeholder for dynamic auth token injection.\nOnly applies to McpLink server types - regular remote servers ignore this property."
        },
        "oAuthResourceUrl": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the OAuth protected resource URL for DCR registration.\nWhen set, this URL is sent as `ResourceUrl` to UCS instead of string? RemoteServerConfig.Uri,\nenabling RFC 9728 (Protected Resource Metadata) discovery against an external OAuth provider\n(e.g., Atlassian) while routing MCP traffic through the internal mcp-link service."
        },
        "useAcc": {
          "type": "boolean",
          "description": "Gets or sets a value indicating whether to route traffic through the ACC connector.\nWhen true, the gateway routes traffic for this server through the tenant's on-premise\nACC connector instead of direct HTTP. Transport mechanism TBD (MCPG-455 Phase 3)."
        },
        "schemaHeaders": {
          "type": [
            "null",
            "object"
          ],
          "additionalProperties": {
            "type": "string"
          },
          "description": "Gets or sets HTTP headers serialized into mcp-link's `?sh=` query parameter for\nOpenAPI spec fetching at session start (MCPG-756). Values may contain\n`{SchemaCredential:FieldName}` placeholders, resolved at factory time against the\nbinder declared by string? RemoteServerConfig.SchemaCredentialProviderName and the per-tenant\nSchemaCredentialBinderId on the integration row. Only applies to McpLink server types."
        },
        "schemaCredentialProviderName": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the UCS provider name used to resolve the secondary spec-fetch credential\n(e.g. `\"GithubPersonalAccessToken\"`). Free-form string matching a provider in UCS\nprovider-definitions.json. The binder ID is selected per-tenant at integration-config\ntime and stored on the ProviderIntegration row, sibling to `CredentialProviderConfigId`.\nOnly meaningful when Dictionary&lt;string, string&gt;? RemoteServerConfig.SchemaHeaders contains a `{SchemaCredential:*}`\nplaceholder. Only applies to McpLink server types."
        },
        "accGroupId": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the ACC connector group to route traffic through when bool RemoteServerConfig.UseAcc is true.\nNull means \"any connector for this tenant\" (tenant-default routing).\nIgnored when bool RemoteServerConfig.UseAcc is false.",
          "format": "uuid"
        },
        "openApiYamlUrl": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the customer-supplied OpenAPI YAML URL for SpecLink (private-spec) custom servers (MCPG-803).\nWhen set, the gateway infers `Type = McpLink` server-side and builds the canonical mcp-link URI\nfrom this value + string? RemoteServerConfig.UpstreamApiBaseUrl. Ignored when both are null. Only meaningful on\ncustom servers created via the SpecLink wizard; seed entries use string? RemoteServerConfig.Uri directly."
        },
        "upstreamApiBaseUrl": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the upstream API base URL that the YAML at string? RemoteServerConfig.OpenApiYamlUrl describes (MCPG-803).\nMay contain `{Variable}` placeholders (e.g. `https://{Domain}.atlassian.net`) whose values are\nstored in Dictionary&lt;string, string&gt;? RemoteServerConfig.UpstreamVariableValues and substituted gateway-side at connection-build time\n(mcp-link does not expand base-URL variables). Used together with string? RemoteServerConfig.OpenApiYamlUrl to build\nthe canonical mcp-link URI server-side."
        },
        "upstreamVariableValues": {
          "type": [
            "null",
            "object"
          ],
          "additionalProperties": {
            "type": "string"
          },
          "description": "Gets or sets the values for the `{Variable}` placeholders in string? RemoteServerConfig.UpstreamApiBaseUrl\n(MCPG-803), keyed by variable name without braces (e.g. `{\"CloudId\": \"abc-123\"}`). Unlike the\nURL fields these <b>are persisted</b> — the stored string? RemoteServerConfig.Uri only carries the unresolved\ntemplate, so the values are not derivable from it. Substituted into the canonical URI at\nconnection-build time by `SpecLinkUriResolver`. Only meaningful for SpecLink (McpLink) servers."
        },
        "skillRepoUrl": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the repository URL exposed through mcp-link skills mode.\nThe current mcp-link contract accepts public github.com URLs.\nTransport-only: re-derived from string? RemoteServerConfig.Uri on responses and not persisted."
        },
        "skillRepoRef": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the optional Git ref used for skill discovery.\nWhen omitted, mcp-link resolves the repository's default branch.\nTransport-only: re-derived from string? RemoteServerConfig.Uri on responses and not persisted."
        },
        "skillRepoPath": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the optional repository-relative subpath used for skill discovery.\nTransport-only: re-derived from string? RemoteServerConfig.Uri on responses and not persisted."
        },
        "skillRepoProvider": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the repository host backing a SkillLink server, from\nSkillRepoProviders. Defaults to\nstring SkillRepoProviders.GitHub when a SkillLink shape is saved without one."
        },
        "sourceRef": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the source ref the administrator configured for a SpecLink or SkillLink server\n(MCPG-1891): the branch or tag name (for example `main`) that string? RemoteServerConfig.SourceRevision\nwas resolved from. Null for a content-hash pin (a non-GitHub spec URL) and for an unpinned row."
        },
        "sourceRevision": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the pinned source revision (MCPG-1891): the full 40-hex commit SHA for a GitHub\nsource, or the lowercase hex SHA-256 of the fetched document for any other https spec URL.\nThe canonical string? RemoteServerConfig.Uri embeds this value (as `ref=` inside `s=`, as the\nskills `ref=`, or as the `v=` query parameter), which is what makes an explicit\nrefresh a guaranteed cache miss on every mcp-link replica. Null when the row is unpinned."
        },
        "sourceResolvedAt": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the instant string? RemoteServerConfig.SourceRevision was last resolved (MCPG-1891).\nNull when the row is unpinned.",
          "format": "date-time"
        }
      },
      "description": "Template configuration for remote MCP servers, loaded from known-mcp-servers.json."
    },
    "TestEndpointConfig": {
      "type": "object",
      "properties": {
        "uri": {
          "type": "string",
          "description": "Gets or sets the URI of the test endpoint.\nSupports variable substitution (e.g., {AuthToken})."
        },
        "method": {
          "type": "string",
          "description": "Gets or sets the HTTP method to use (GET, POST, etc.)."
        },
        "headers": {
          "type": [
            "null",
            "object"
          ],
          "additionalProperties": {
            "type": "string"
          },
          "description": "Gets or sets the headers to include in the request.\nSupports variable substitution in values (e.g., \"Bearer {AuthToken}\")."
        },
        "expectedStatusCodes": {
          "type": "array",
          "items": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "description": "Gets or sets the expected HTTP status codes that indicate success."
        }
      },
      "description": "Configuration for testing credentials against an external API endpoint.\nUsed to validate authentication before establishing a full MCP connection."
    },
    "UiConfiguration": {
      "type": "object",
      "properties": {
        "icon": {
          "type": "string",
          "description": "Gets or sets the React Icons component name."
        },
        "colorClass": {
          "type": "string",
          "description": "Gets or sets the Tailwind CSS text color class."
        },
        "bgGradient": {
          "type": "string",
          "description": "Gets or sets the Tailwind CSS gradient classes."
        }
      },
      "description": "UI configuration for the MCP server display."
    },
    "UriVariable": {
      "type": "object",
      "properties": {
        "description": {
          "type": "string",
          "description": "Gets or sets the human-readable description of this variable."
        },
        "required": {
          "type": "boolean",
          "description": "Gets or sets a value indicating whether this variable is required."
        },
        "options": {
          "type": [
            "null",
            "array"
          ],
          "items": {
            "type": "string"
          },
          "description": "Gets or sets the available options for this variable (e.g., [\"eu\", \"us\"] for region).\nOnly applicable for variables with predefined choices."
        },
        "defaultValue": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the default value for this variable."
        },
        "placeholder": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the placeholder text to show in the UI."
        },
        "helpText": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets additional help text for this variable."
        },
        "type": {
          "type": [
            "null",
            "string"
          ],
          "description": "Gets or sets the variable type hint for UI rendering (e.g., \"string\", \"integer\", \"url\").\nUsed for UI validation and input control selection, but all values are ultimately strings."
        },
        "scope": {
          "type": [
            "null",
            "array"
          ],
          "items": {
            "type": "string"
          },
          "description": "Gets or sets the authentication types this variable applies to.\nIf null or empty, the variable applies to all authentication types (backward compatible).\nIf specified, the variable is only shown/validated for the listed auth types (e.g., [\"ApiKey\"], [\"OAuth\"], or [\"ApiKey\", \"OAuth\"])."
        },
        "sharing": {
          "description": "Gets or sets a value indicating whether this variable may be inherited onto another\nuser's Personal overlay at read time (MCPG-1609). The overlay runs only for OAuth/Fhir\nPersonal target rows. Omitted / default is UriVariableSharing.Shared.\nOnly UriVariableSharing.Personal is written in the seed.\nDoes not constrain a Tenant-level row, which is shared by design.\nThe name Scope is taken on this model for auth-type filtering.",
          "$ref": "#/$defs/UriVariableSharing"
        }
      },
      "description": "Represents a URI variable that can be substituted in remote MCP server URIs.\nUsed for dynamic parameterization of server endpoints (e.g., region, API keys).\nAll variables are treated as strings for URL substitution."
    },
    "UriVariableSharing": {
      "enum": [
        "Shared",
        "Personal"
      ],
      "description": "Whether a catalog URI variable may be inherited onto another user's Personal overlay\nat read time (MCPG-1609). The overlay runs only for OAuth/Fhir Personal target rows.\nAbsent / default is UriVariableSharing.Shared so hostname and instance variables inherit\nwithout marking every seed entry. Only UriVariableSharing.Personal is written in seed.\nDoes not constrain a Tenant-level row, which is shared by design."
    }
  }
}