openapi: 3.0.3
info:
  title: CraftedTrust API
  version: 3.0.0
  description: |
    Public API for CraftedTrust's MCP trust workflow.

    Use this surface to:
    - search the registry
    - fetch public server trust data
    - trigger public scans
    - start publisher certification intake

    Paid publisher steps and pricing live on https://mcp.craftedtrust.com/publishers/.
  contact:
    name: Cyber Craft Solutions LLC
    email: cyber.craft@craftedcybersolutions.com
    url: https://mcp.craftedtrust.com
  license:
    name: Proprietary
    url: https://mcp.craftedtrust.com/terms/

servers:
  - url: https://mcp.craftedtrust.com
    description: Production

tags:
  - name: Public
    description: Public registry and trust data
  - name: Publisher
    description: Publisher scan and certification intake
  - name: MCP
    description: MCP discovery and MCP trust checks

paths:
  /api/v1/search:
    get:
      tags: [Public]
      summary: Search the registry
      operationId: searchServers
      parameters:
        - name: q
          in: query
          schema:
            type: string
          description: Search query by name, URL, publisher, or package.
        - name: sort
          in: query
          schema:
            type: string
            enum: [relevance, score-high, score-low, recent, name]
            default: relevance
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 50
        - name: certified
          in: query
          schema:
            type: string
            enum: [true, standard, premium]
        - name: grade
          in: query
          schema:
            type: string
            enum: [A, B, C, D, F]
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchResponse'
        '400':
          $ref: '#/components/responses/BadRequest'

  /api/v1/stats:
    get:
      tags: [Public]
      summary: Registry statistics
      operationId: getStats
      responses:
        '200':
          description: Registry-wide statistics
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsResponse'

  /api/v1/badge:
    get:
      tags: [Public]
      summary: Badge asset by query string
      operationId: getBadgeByQuery
      parameters:
        - name: url
          in: query
          required: true
          schema:
            type: string
        - name: style
          in: query
          schema:
            type: string
            enum: [flat, compact]
            default: flat
      responses:
        '200':
          description: SVG badge
          content:
            image/svg+xml:
              schema:
                type: string
        '404':
          $ref: '#/components/responses/NotFound'

  /.well-known/agent.json:
    get:
      tags: [MCP]
      summary: MCP discovery metadata
      operationId: getAgentMetadata
      responses:
        '200':
          description: Discovery document
          content:
            application/json:
              schema:
                type: object
                properties:
                  name:
                    type: string
                  description:
                    type: string
                  url:
                    type: string
                    format: uri
                  openapi:
                    type: string
                    format: uri
                  capabilities:
                    type: array
                    items:
                      type: string
                  endpoints:
                    type: object
                    properties:
                      mcp:
                        type: string
                        format: uri
                      rest:
                        type: string
                        format: uri

  /api/v1/server/{url}:
    get:
      tags: [Public]
      summary: Public server trust profile
      operationId: getServerProfile
      parameters:
        - name: url
          in: path
          required: true
          schema:
            type: string
          description: URL-encoded server URL.
      responses:
        '200':
          description: Server trust profile
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServerDetail'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/v1/server/{url}/report:
    get:
      tags: [Public]
      summary: Current report or evidence summary
      operationId: getServerReport
      parameters:
        - name: url
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Downloadable report or evidence artifact
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404':
          $ref: '#/components/responses/NotFound'

  /api/v1/server/{url}/badge:
    get:
      tags: [Public]
      summary: Server badge asset by path
      operationId: getServerBadge
      parameters:
        - name: url
          in: path
          required: true
          schema:
            type: string
        - name: style
          in: query
          schema:
            type: string
            enum: [flat, compact]
            default: compact
      responses:
        '200':
          description: SVG badge
          content:
            image/svg+xml:
              schema:
                type: string
        '404':
          $ref: '#/components/responses/NotFound'

  /api/v1/scan:
    post:
      tags: [Publisher]
      summary: Trigger a public scan
      operationId: triggerPublicScan
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScanRequest'
      responses:
        '200':
          description: Scan accepted or completed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScanResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/certify:
    post:
      tags: [Publisher]
      summary: Start certification intake
      operationId: startCertification
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CertificationRequest'
      responses:
        '200':
          description: Certification intake started
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/RateLimited'

components:
  responses:
    BadRequest:
      description: Invalid or missing request data.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: Requested server or asset not found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    RateLimited:
      description: Too many requests.
      headers:
        Retry-After:
          description: Number of seconds to wait before retrying.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

  schemas:
    SearchResponse:
      type: object
      properties:
        query:
          type: string
        sort:
          type: string
        page:
          type: integer
        limit:
          type: integer
        total:
          type: integer
        totalPages:
          type: integer
        results:
          type: array
          items:
            $ref: '#/components/schemas/ServerSummary'

    StatsResponse:
      type: object
      properties:
        stats:
          type: object
          additionalProperties: true
        recentlyScanned:
          type: array
          items:
            $ref: '#/components/schemas/ServerSummary'
        highestRated:
          type: array
          items:
            $ref: '#/components/schemas/ServerSummary'
        recentlyFlagged:
          type: array
          items:
            $ref: '#/components/schemas/ServerSummary'

    ServerSummary:
      type: object
      properties:
        url:
          type: string
          format: uri
        name:
          type: string
        publisherName:
          type: string
        trustScore:
          type: number
        grade:
          type: string
          enum: [A, B, C, D, F]
        trustSummary:
          type: string
        certificationStatus:
          type: string
          enum: [none, standard, premium]
        lastScanned:
          type: string
          format: date-time

    ServerDetail:
      allOf:
        - $ref: '#/components/schemas/ServerSummary'
        - type: object
          properties:
            findingsSummary:
              type: string
            scanCount:
              type: integer
            transportType:
              type: string
            scanType:
              type: string
            packageName:
              type: string
            repositoryUrl:
              type: string
              format: uri
            lastScanHistory:
              type: array
              items:
                type: object
                additionalProperties: true

    ScanRequest:
      type: object
      required: [server_url]
      properties:
        server_url:
          type: string
          format: uri

    ScanResponse:
      type: object
      properties:
        status:
          type: string
        server_url:
          type: string
          format: uri
        trustScore:
          type: number
        grade:
          type: string
        certificationStatus:
          type: string
        findings:
          type: array
          items:
            type: object
            additionalProperties: true

    CertificationRequest:
      type: object
      required: [server_url, tier, contact_email]
      properties:
        server_url:
          type: string
          format: uri
        tier:
          type: string
          enum: [standard, premium]
        contact_email:
          type: string
          format: email

    ErrorResponse:
      type: object
      properties:
        error:
          type: string
        message:
          type: string
