Skip to content

MCP v2 - I/O Definition

This page defines the implemented wire contract for guinness-backend/apps/mcp-v2. MCP v2 exposes six tools and delegates every domain operation to backend internal APIs.


Transport and Authentication

Endpoint:

POST /mcp
GET /mcp

Deployed request headers:

Content-Type: application/json
X-MCP-Token: <cloudfront-secret-header-value>
MCP-API-Key: guinness_<prefix>_<secret>

Authorization: Bearer <mcp-api-key> is accepted instead of MCP-API-Key.

Header Required Validation
X-MCP-Token yes outside ENVIRONMENT=local non-empty and constant-time equal to CLOUDFRONT_SECRET_HEADER
MCP-API-Key one API-key header required preferred source of MCP API key
Authorization alternative Bearer token used only when MCP-API-Key is absent
Content-Type POST JSON-RPC application/json

MCP API-key authentication:

  1. Parse the guinness_<prefix>_<secret> key.
  2. Read PostgreSQL mcp_api_keys by prefix with deleted_at IS NULL.
  3. Verify the stored salted scrypt hash.
  4. Reject revoked, expired, deleted, malformed, or unknown keys.
  5. Require a positive project scope; unscoped keys receive HTTP 403.
  6. Update last_used_at asynchronously.

Each HTTP request creates a fresh McpServer and StreamableHTTPTransport(sessionIdGenerator: undefined) to keep concurrent clients isolated.


Request Flow

sequenceDiagram
    participant Client
    participant MCP as MCP v2
    participant PG as PostgreSQL
    participant Backend as Backend internal API
    participant AI as AI-v2/SQS worker
    participant S3

    Client->>MCP: JSON-RPC tools/call
    MCP->>MCP: validate X-MCP-Token
    MCP->>PG: authenticate API key
    MCP->>MCP: require project scope + validate arguments
    MCP->>Backend: X-API-Key + X-MCP-Project-ID
    alt trigger-des2code
        Backend->>Backend: authorize completed design
        Backend->>AI: require current code_index ready
        Backend->>AI: send flat SQS payload
        AI->>S3: request artifact
        AI->>Backend: AI-status webhook
    else get-des2code
        Backend->>S3: newest scoped request artifact
    else source list/detail
        Backend->>AI: scoped internal read
    end
    Backend-->>MCP: JSON
    MCP-->>Client: content + structuredContent

MCP v2 has no AWS, DocumentDB, AI-provider, Figma, S3, or webhook client.


JSON-RPC Request

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "trigger-des2code",
    "arguments": {
      "design_id": "42_file_node:1",
      "project_id": 42,
      "organization_id": 1
    }
  }
}

Validation failures return an MCP response with isError: true. They do not call backend.


Tool Inputs

trigger-des2code

Field Type Required Validation
design_id string yes length 1-500; alphanumeric, _, :, -
project_id integer yes > 0; must equal authenticated project scope
organization_id integer yes > 0; backend revalidates against design scope

The authenticated key must have WRITE permission.

get-des2code

Field Type Required Validation
design_id string yes same design ID constraints; project parsed from ID is checked when available

list-designs and list-code

Field Type Required Validation
project_id integer yes > 0; equals authenticated scope
organization_id integer no > 0 when present
limit integer no default 20; 1..100
offset integer no default 0; >= 0

get-design-detail

Field Type Required Validation
design_id string yes same design ID constraints

get-code-detail

Field Type Required Validation
code_id string yes UUID v4
project_id integer yes > 0; equals authenticated scope
organization_id integer no > 0 when present

The current server does not register codebase-rule or code-index tools.


Processing Contract

  1. Create a fresh MCP server/transport for the HTTP request.
  2. Validate X-MCP-Token outside local development.
  3. Read the MCP API key from MCP-API-Key or Bearer auth.
  4. Authenticate the PostgreSQL key and require a positive project scope.
  5. Validate tool arguments with strict Zod schemas.
  6. Require WRITE permission for trigger-des2code.
  7. Enforce project scope before backend I/O.
  8. Call the mapped backend internal API with X-API-Key and X-MCP-Project-ID.
  9. Map non-2xx/invalid backend results to MCP isError: true.
  10. Return human-readable content plus machine-readable structuredContent.
  11. Update key last_used_at asynchronously.

The server returns six tools from tools/list. No operation bypasses backend authorization to call AI-v2 or storage directly.


MCP to Backend Internal API

MCP tool Backend request Body/query
trigger-des2code POST /internal/des2code {design_id, project_id, organization_id}
get-des2code GET /internal/des2code/{design_id} path ID
list-designs GET /internal/designs project, optional org, limit, offset
list-code GET /internal/code project, optional org, limit, offset
get-design-detail GET /internal/designs/{design_id} path ID
get-code-detail GET /internal/code/{code_id} project and optional org query

Headers:

Accept: application/json
Content-Type: application/json
X-API-Key: <BACKEND_INTERNAL_API_KEY>
X-MCP-Project-ID: <authenticated-project-id>

BACKEND_INTERNAL_API_KEY and project scope are required by current MCP-v2 configuration/authentication. Requests use BACKEND_INTERNAL_TIMEOUT_MS (default 10000, maximum 120000).

Backend may return raw JSON or { "ok": true, "data": ... }; MCP unwraps the success envelope.


Backend Producer Payloads

MCP v2 does not produce worker messages. Backend owns readiness and SQS.

design-import

Design import is outside MCP-v2 transport. The resulting canonical AI-v2 design is discoverable through list-designs/get-design-detail. Detail responses omit all vector_embedding fields.

code-import

Code and Storybook imports are outside MCP-v2 transport. Imported code is discoverable through list-code/get-code-detail; detail responses return source/CSS and metadata without embedding vectors.

des2code

Backend validates PostgreSQL design scope/status and the current AI-v2 DocumentDB index, generates UUIDv7 request_id, and sends:

{
  "design_id": "42_file_node:1",
  "project_id": 42,
  "organization_id": 1,
  "request_id": "0192a3b4-c5d6-7e8f-9a0b-1c2d3e4f5a6b"
}

The worker independently requires its current scoped code_index to be ready. The payload has no schema version, operation, index token, model, prompt, or bound override.


Backend Downstream AI-v2 Read API

Backendโ€”not MCPโ€”calls service-token-protected AI-v2 internal routes for:

  • current code-index readiness;
  • paginated design/code source summaries;
  • one design/code source detail without vectors.

Backend also reads Des2Code results directly from the backend AI S3 bucket. It authorizes the design, lists only canonical filenames under the scoped design prefix, selects the newest LastModified/key, validates artifact scope and shape, and returns the normalized result.


MCP Outputs

trigger-des2code success

{
  "content": [{"type": "text", "text": "Successfully triggered des2code matching for design ID: 42_file_node:1"}],
  "structuredContent": {
    "success": true,
    "design_id": "42_file_node:1",
    "project_id": 42,
    "organization_id": 1,
    "request_id": "0192a3b4-c5d6-7e8f-9a0b-1c2d3e4f5a6b",
    "timestamp": "2026-08-11T10:00:00.000Z"
  },
  "isError": false
}

get-des2code success

structuredContent includes:

{
  "design_id": "42_file_node:1",
  "status": "success",
  "matched_code_count": 1,
  "matched_codes": [{
    "code_id": "0192a3b4-c5d6-4e8f-9a0b-1c2d3e4f5a6b",
    "name": "Button",
    "semantic_similarity": 0.89,
    "context_similarity": 0.84,
    "region_similarity": 0.91,
    "variation_similarity": 0.95,
    "variation_mode": "state_required"
  }],
  "matched_usage_count": 1,
  "usage_matches": [{
    "node_id": "40002029:37101",
    "code_id": "0192a3b4-c5d6-4e8f-9a0b-1c2d3e4f5a6b",
    "variation_id": "visual_primary",
    "variation_name": "Primary",
    "confidence": 0.97
  }],
  "code_index_id": "code-index-scope-hash",
  "request_id": "0192a3b4-c5d6-7e8f-9a0b-1c2d3e4f5a6b",
  "retrieval_diagnostics": {},
  "usage_diagnostics": {},
  "matcher_configuration": {},
  "model_summary": {},
  "artifact": {
    "bucket": "dev-guinness-backend",
    "key": "1/42/des2code/42_file_node:1/request.json",
    "content_type": "application/json",
    "expires_at": "2026-09-10T10:00:00Z"
  },
  "processed_at": 1786442400000,
  "error": null
}

Human-readable text intentionally summarizes matched implementations and tells the client to use detail tools for complete source/CSS.

list-designs / list-code success

The structured result preserves:

{
  "project_id": 42,
  "organization_id": 1,
  "total_count": 563,
  "returned_count": 20,
  "limit": 20,
  "offset": 0,
  "items": []
}

Detail success

Design/code detail is returned under design or code with timestamp. Vector fields are omitted. Code detail includes source/CSS; design detail includes canonical visual/semantic/structure metadata.

Error response

{
  "content": [{"type": "text", "text": "Failed to trigger des2code matching: ..."}],
  "structuredContent": {
    "error": "...",
    "timestamp": "2026-08-11T10:00:00.000Z"
  },
  "isError": true
}
Condition Result
Missing/invalid edge token HTTP 401 outside local
Missing/invalid MCP API key HTTP 401
Unscoped API key HTTP 403
Cross-project tool arguments MCP isError: true before backend call
Read-only trigger MCP isError: true before backend call
Design import/index not ready MCP error mapped from backend 409
Backend timeout/non-2xx/invalid JSON MCP isError: true

Idempotency and Consistency

  • MCP server/transport state is request-local; no cross-client session state is reused.
  • Authentication last_used_at updates are non-blocking and do not change tool output.
  • One trigger creates one backend UUIDv7 request ID. Backend SQS retries preserve it.
  • The worker writes one request-scoped artifact key; retrying the same message reuses that key.
  • Re-triggering the same design creates another request artifact.
  • get-des2code returns the newest contract-valid success or failure artifact by S3 ordering, not a PostgreSQL run/status row.
  • Backend and worker both enforce current code-index readiness; the worker stores the used DocumentDB _id as codeIndexId.