PayCargo · AI-Sandbox · Step 6.r

6.rSDK distribution via MCP server cartridge

The SDK becomes a live service consumers query, not a snapshot they download. Real-time + protected + versioned MCP. Companion to Step 6.s (CMS authoring layer) and Step 6.o (SDK versioning v1).
Block: 6.r (Console doctrine; companion to 6.o SDK v1 and 6.s CMS) · State: Specced. v2 target. Ships when Request Roles + SSO are live. · Cartridge: cartridges/global/forge-sdk-mcp/
Specced
v1.x SDK ships via the git-pull pattern (Step 6.o). v2 SDK ships when this cartridge lands. Pull-sdk.sh becomes a thin wrapper over MCP. Agents speak MCP natively. Every fetch is Cognito-authenticated, audited, and version-pinned.

Sections

  1. Why MCP for SDK distribution
  2. Real-time + protected + versioned
  3. MCP protocol primer
  4. Resource URI layout
  5. Authentication model
  6. Per-resource versioning and deprecation
  7. Audit log schema
  8. Consumer migration: pull-sdk.sh wraps MCP
  9. Terraform integration
  10. Relationship to the CMS cartridge
  11. Bootstrap path
  12. Critical-path mitigation
  13. Ship plan

1. Why MCP for SDK distribution

v1's git-pull pattern has four limitations the MCP model fixes:

The MCP server model couples every fetch to Cognito identity, returns specific resources rather than bundles, and logs the requester + the resource + the version end-to-end. Same architectural pattern as the OAuth abstraction (Step 6.n): provider-as-data, identity-aware, audited.

2. Real-time + protected + versioned

PropertyDefinitionWhat it eliminates
Real-time Every fetch hits the MCP server. No local cache between consumer and source of truth. Lockfile drift. Stale SDK in a cartridge build six months after the last pull.
Protected Cognito JWT on every request. Authorization gated by Request Roles assignment. Off-boarding gap. GitHub-vs-Forge identity drift. Unaudited SDK consumption.
Versioned Each MCP resource carries its semver. Cartridge declares the SDK version it builds against; server returns that version's resources. Implicit version coupling. Silent breaking changes. Inability to deprecate.

3. MCP protocol primer

The Model Context Protocol (MCP) is Anthropic's open protocol for exposing tools and resources to AI agents. Two relevant pieces:

The transport is HTTPS at port 443 with JSON-RPC. From a Forge perspective, an MCP server is "a Lambda behind API Gateway HTTP API that speaks MCP," which fits the standard cartridge pattern.

Anthropic-published clients (Claude Code, Claude Desktop) speak MCP natively. Non-Claude clients (the future pull-sdk.sh) wrap MCP with a small HTTPS+JSON-RPC client.

4. Resource URI layout

The MCP server exposes resources at URIs that mirror the v1 path structure plus version awareness:

Resource URIReturns
forge-sdk://manifestThe bundle manifest (paths, version, compatibility, endpoints)
forge-sdk://VERSIONThe current published version string
forge-sdk://shared/modules/jwt-verify.jsThe hand-rolled JWT verifier source
forge-sdk://shared/modules/hmac.jsHMAC helpers
forge-sdk://shared/modules/log.jsStructured log helpers
forge-sdk://shared/modules/oauth/client.jsOAuth client factory
forge-sdk://shared/modules/oauth/adapters/salesforce.jsSalesforce capability adapter
forge-sdk://cartridges/_template/lambda/handler.jsScaffold handler
forge-sdk://cartridges/_template/backend.tf.snippetScaffold backend.tf snippet
forge-sdk://docs/cartridge-walkthrough.mdBuild walkthrough (full markdown)
forge-sdk://docs/handler-reference.mdHandler.js reference
forge-sdk://docs/backend-reference.mdbackend.tf reference
forge-sdk://docs/bedrock-pattern.mdBedrock invocation pattern
forge-sdk://docs/oauth-pattern.mdOAuth consumption pattern
forge-sdk://docs/observability-contract.md*-complete log schema
forge-sdk://Doctrine.mdFull doctrine (all sections)
forge-sdk://Doctrine.md#2.7Specific doctrine section (granular fetch)
forge-sdk://.claude/skills/forge-sdk/SKILL.mdAgent skill

Version selection: by default the server returns the latest stable for the requester's pinned version. The cartridge's manifest can declare sdk_version: "1.1.0" and the server scopes resource resolution to that version. Explicit version override is via a query string: forge-sdk://shared/modules/jwt-verify.js?version=1.0.0.

5. Authentication model

Every MCP request carries a Cognito JWT in the standard MCP auth header. Three layers of gate:

  1. Origin secret (X-Origin-Secret). Standard cartridge-doctrine layer: only CloudFront-originated traffic reaches the Lambda. Direct hits on API Gateway get 403.
  2. Cognito JWT. The user is who they claim to be. Federated SSO users are accepted; system admins are accepted; service accounts are accepted with a specific group.
  3. Request Roles. The user must have the sdk-readers Cognito group, granted via the Request Roles cartridge. New federated users land without this group; they request it; system admin approves; access begins.

Service accounts (for CI builds) get a longer-lived JWT issued via a system-admin-approved Cognito client. Audit log distinguishes service from interactive accounts.

What an external contractor sees

  1. PayCargo provisions them a Cognito identity (via the Request Roles cartridge or system admin invite).
  2. Contractor signs into the Console, requests sdk-readers via Request Roles, gets approved.
  3. Contractor's pull-sdk.sh (or Claude Code) authenticates with that identity and pulls.
  4. Contractor leaves PayCargo: Cognito access revoked. Next pull fails. No GitHub access change needed.

6. Per-resource versioning and deprecation

The server tracks every resource at every version. CMS publishes a new content row; the row gets a version stamp; the MCP server can serve any historical version on request.

Default version resolution

When a consumer asks for forge-sdk://shared/modules/jwt-verify.js with no version override, the server resolves to the highest version that satisfies the consumer's pinned manifest:

cartridge manifest: { sdk_version: "1.1.0" }
request:            forge-sdk://shared/modules/jwt-verify.js
server resolves to: latest patch version <= 1.1.x, returning jwt-verify.js@1.1.0

Deprecation flag

The response includes a deprecation field when the consumer's pinned version is below current major or minor:

{
  "resource":  "forge-sdk://shared/modules/jwt-verify.js",
  "version":   "1.1.0",
  "content":   "...",
  "deprecation": {
    "warn":   "You are pinned to SDK 1.1.0; current is 2.3.0. Upgrade required by 2027-06-01.",
    "current":  "2.3.0",
    "sunset":  "2027-06-01T00:00:00Z"
  }
}

Consumer CLIs print the warning. CI integrations can fail the build past a sunset date. Operators see the deprecation rate in the obs Cartridges tab.

Hard revoke

Past a sunset date, the server can refuse to serve the version. Response status 410 Gone with an explanation. Cartridge build fails loudly. Operators get a runbook entry.

7. Audit log schema

Every MCP request emits one log line on completion. The obs Cartridges tab joins on the line for the SDK-consumers view.

{
  "level":             "info",
  "msg":               "mcp-sdk-fetch-complete",
  "user":              "<cognito-username>",
  "service":           false,                       // true for CI service accounts
  "resource":          "forge-sdk://shared/modules/jwt-verify.js",
  "requested_version": "1.1.0",
  "served_version":    "1.1.0",
  "deprecated":        false,
  "client":            "pull-sdk.sh/1.1.0",         // or "claude-code/0.7.x"
  "prompt_context_hash": "<short hash of the agent's user-message>",  // null for human-driven
  "durationMs":        14
}

Operators query the log for "who has been pulling deprecated resources," "which consumers are on stale SDK," "which agents are pulling which docs in which prompts." Compounds into a real visibility surface, not just developer ergonomics.

8. Consumer migration: pull-sdk.sh wraps MCP

From the human author's perspective, almost nothing changes:

$ ./pull-sdk.sh v2.0.0
Authenticating with Forge SSO...     # device flow opens browser to Console
Browser opened: paste the verification code: ABCD-EFGH
Authenticated as mtang.

Pulling forge-sdk @ v2.0.0 from console.paycargo.org/mcp/forge-sdk ...
  forge-sdk://manifest                                                ok
  forge-sdk://shared/modules/jwt-verify.js                            ok
  forge-sdk://shared/modules/hmac.js                                  ok
  ... (29 resources)

Pulled forge-sdk v2.0.0
  ./forge-sdk/        29 resources written
  ./forge-sdk.lock    version pin + per-resource SHAs

The script is a thin wrapper. Auth via device flow (the OAuth pattern Anthropic uses for Claude CLI). Per-resource fetches over HTTPS+JSON-RPC. Lock file captures the version + per-resource SHA so reproducibility is preserved.

Agents (Claude Code)

Claude Code connects to the MCP server via its standard MCP client. It fetches resources on demand during a cartridge build, never materializing the bundle to disk. The agent's tool-use trace shows every fetch alongside the prompt that triggered it. The audit log line gets a non-null prompt_context_hash.

9. Terraform integration

Cartridge Terraform today stages SDK files into lambda/_shared/ via local_file reading from ./forge-sdk/shared/modules/. v2 has three options:

OptionHow it worksTrade-off
A. Pre-apply pull (recommended) CI step runs pull-sdk.sh v2.x.x before terraform plan. Materializes ./forge-sdk/ the same way v1 does. Terraform code is identical. Adds a step to CI. Same model as today; lowest disruption.
B. Terraform HTTP data source An http data source fetches each resource directly from MCP at plan time. local_file reads from the data source. No pre-apply step but needs auth token in TF state; tricky.
C. Custom Terraform provider A forge-sdk Terraform provider that knows how to authenticate with MCP and expose resources as TF data. Cleanest UX, most engineering work.

v2.0 ships Option A. Option C is a future iteration if consumers demand it.

10. Relationship to the CMS cartridge

The MCP server does not own the content. It serves content from the CMS cartridge (Step 6.s). Reading flow:

consumer (pull-sdk.sh or Claude Code) │ │ MCP request: forge-sdk://shared/modules/jwt-verify.js │ ▼ forge-sdk-mcp cartridge (this doc) │ │ DDB query: content_id = "shared/modules/jwt-verify.js" │ version = consumer's pinned manifest version │ ▼ forge-sdk-cms cartridge (Step 6.s) │ │ returns the published row at the requested version │ ▼ MCP server formats response with deprecation flag, emits audit log line │ ▼ consumer receives content + metadata

The MCP server is a stateless cache + protocol adapter on top of the CMS. Reads are hot (heavy caching); writes happen in the CMS, not here. This separation lets us evolve the protocol layer (add new MCP features, change the URI scheme) without touching the content store.

11. Bootstrap path

Chicken-and-egg risk: the MCP server cartridge needs the SDK to build itself. Resolved by sequence:

  1. v1.x ships via git-pull. The MCP server cartridge (this doc's subject) is built using v1 pull-sdk.sh.
  2. The MCP server cartridge applies. The CMS cartridge (Step 6.s) is built using v1 pull-sdk.sh too.
  3. The CMS cartridge applies. Initial seed: a one-time import job loads the existing git markdown (Doctrine.md, docs/*.md, SKILL.md, the cartridge template, the shared modules JS) as v1.x.x CMS rows.
  4. The MCP server starts serving from CMS.
  5. v2.0 SDK is the first version where pull-sdk.sh resolves through MCP. Consumers upgrade from v1.x to v2.0; v1.x git-pull continues to work as fallback for as long as the git tags exist.

System admins keep at least one current local v2.x checkout for the duration of the v1-to-v2 migration. This is the Doctrine 8.9 fallback: a git copy that diff-matches CMS published content.

12. Critical-path mitigation

Once v2 ships, the MCP server is critical-path infrastructure: every cartridge build depends on it. Three mitigations:

MitigationDescription
Read replica The MCP server fronts a DDB Global Table replica. Read failover automatic across regions.
CDN cache CloudFront caches responses with appropriate cache headers per resource. Stale-while-revalidate for content reads; no-cache for the manifest.
Git mirror fallback Doctrine 8.9: every CMS publish triggers a git mirror update. If MCP is down, consumers fall back to the git copy (last-known-good) via the legacy pull-sdk.sh --fallback-git flag.

SLA target: 99.95% MCP availability. Read failover < 30 seconds. Git fallback usable indefinitely (system admins maintain the mirror).

13. Ship plan

Five PRs after Request Roles + SSO are live.

  1. PR 1: doctrine (this doc, plus Step 6.s, plus Doctrine 2.9, 2.10, 8.9). No code.
  2. PR 2: CMS cartridge (Step 6.s). Editor UI in Console, draft / approve / publish, DDB-backed. The MCP server depends on it.
  3. PR 3: One-time import job. Lift existing git markdown content into CMS as v1.x.x rows. Run once, verify diff, commit the mirror back to git for the v1 git-pull path.
  4. PR 4: MCP server cartridge. Lambda + API Gateway speaking MCP over HTTPS. Cognito JWT verification. CMS read path. Audit log emission.
  5. PR 5: pull-sdk.sh v2. Device-flow auth, MCP client, per-resource fetch, lock file with per-resource SHAs. Backward-compat flag (--legacy-git) for the bootstrap period.

SDK version 2.0.0 ships at PR 5 apply. v1.x git tags remain available as fallback. Consumers upgrade on their own timeline.

References