MCP Access Architecture Proposal - TerrenceMcGuinness-NOAA/global-workflow GitHub Wiki
Date: April 30, 2026
Author: Terry McGuinness, EMC/EIB
Account: <ACCOUNT_ID> (us-east-1)
System: MDC MCP RAG Server β 51 AI-powered development tools for the Global Forecast System (GFS)
The MDC MCP RAG Server provides 51 AI-powered tools (code analysis, semantic search, compliance checking, workflow tracing) to developers working on NOAA's Global Forecast System. The server queries a Neptune graph database (164,916 nodes, 2.9M relationships) and OpenSearch vector store (85,000+ documents) to provide contextual intelligence about the GFS codebase.
We propose a two-phase deployment strategy:
- Phase 1: Internal access for a 10-person cohort via GFE laptops with CAC-enabled VPN, using AgentCore Runtime for per-user session isolation and scaling
- Phase 2: External access for CI/CD pipelines (GitHub Actions) via FedRAMP-compliant Private API Gateway + Fargate, enabling automated code quality and compliance checks
Both phases maintain zero internet exposure for the data plane (Neptune, OpenSearch) with supporting security enhancments.
The Model Context Protocol (MCP) server exposes 51 tools that help developers understand, navigate, and validate the Global Forecast System codebase:
| Category | Tools | Backend |
|---|---|---|
| Code Analysis | 5 tools (call chains, dependencies, execution tracing) | Neptune graph |
| Semantic Search | 6 tools (documentation, related files, RAG explanations) | OpenSearch vectors + Neptune |
| EE2 Compliance | 4 tools (standards search, compliance scanning) | OpenSearch vectors |
| Workflow Operations | 3 tools (job scripts, component explanations) | Neptune + filesystem |
| SDD Framework | 9 tools (session management, workflow tracking) | Local state |
| Cross-Language Tracing | 4 tools (ShellβFortranβPython execution chains) | Neptune graph |
| Utilities | 3 tools (health, metrics, server info) | All backends |
| Resource | Type | Access |
|---|---|---|
| Neptune (graph) | mdc-mcp-graprag-neptune-1 |
Private subnet, IAM auth, port 8182 |
| OpenSearch (vectors) | vpc-mdc-mcp-rag-search |
Private subnet, port 443 |
| ECR (container image) | mdc-mcp-rag:agentcore |
ARM64, 302MB |
| Security Group | <SECURITY_GROUP_ID> |
Egress to Neptune + OpenSearch only |
- MCP server container built and tested (ARM64, Node.js 20)
- AgentCore Runtime deployed and validated (status: READY, 51 tools responding)
-
First user (developer lead) fully connected and operational:
- GFE laptop β CAC VPN β AWS VPC (working)
- Kiro IDE β IAM auth (SigV4) β AgentCore Runtime (working)
- All 51 MCP tools validated via
invoke_agent_runtime(working)
- No internet-facing endpoints
Enable 10 developers on GFE laptops to access the MCP server through their Kiro IDE, with per-user session isolation and automatic scaling.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GFE Laptop (Developer) β
β ββββββββββββ β
β β Kiro IDE βββββ MCP over HTTPS βββββ β
β ββββββββββββ β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
CAC-enabled VPN / Port Forward
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AWS VPC (Private, no Internet Gateway) β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β AgentCore Runtime (mdc_mcp_rag_server) β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββββ β β
β β β Session 1 β β Session 2 β β Session N β β β
β β β (User A) β β (User B) β β (User N) β β β
β β β microVM β β microVM β β microVM β β β
β β ββββββββ¬βββββββ ββββββββ¬βββββββ ββββββββ¬βββββββ β β
β β β β β β β
β β ββββββββββββββββββΌβββββββββββββββββ β β
β β β β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Data Plane (shared, read-only from MCP perspective) β β
β β βββββββββββββββββββ βββββββββββββββββββββββββββ β β
β β β Neptune (graph) β β OpenSearch (vectors) β β β
β β β 164,916 nodes β β 85,000+ documents β β β
β β β 2,941,593 rels β β 5 indices (titan1024) β β β
β β βββββββββββββββββββ βββββββββββββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Requirement | AgentCore | Fargate |
|---|---|---|
| Per-user session isolation | β Dedicated microVM per session | β Shared containers |
| Scale to zero (no idle cost) | β No sessions = no charges | β Min 1 task always running |
| No capacity planning | β Managed fleet | β Must configure desired count, scaling policies |
| Cold start for 10 users | β ~4s per session | |
| Observability per user | β Session-level CloudWatch/X-Ray | |
| Automatic session cleanup | β Idle timeout (15 min), max lifetime (8 hr) | β Must implement |
- Developer connects GFE laptop to NOAA VPN (CAC authentication)
- VPN provides access to the private VPC (no internet gateway)
- Kiro IDE (running on GFE) connects to EC2 via SSH remote development (same pattern as VS Code Remote SSH)
- Kiro pushes its server-side component onto the EC2 via the SSH connection
- Kiro spawns the AgentCore MCP Proxy as a
"command"type MCP server on the EC2 - The proxy calls
InvokeAgentRuntime(boto3, SigV4) to reach the AgentCore Runtime - AgentCore creates an isolated microVM session for that user
- MCP server in the microVM queries Neptune/OpenSearch on behalf of the user
- Session auto-terminates after 15 minutes idle (configurable)
AgentCore MCP runtimes are accessed via the InvokeAgentRuntime API with SigV4 signing β they do not expose a plain HTTPS URL. Kiro's MCP client expects either a plain HTTP URL or a local "command" process. The solution is a thin stdio proxy that runs on the EC2:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GFE Laptop β
β ββββββββββββ β
β β Kiro IDE β βββ SSH Remote Development ββββ β
β ββββββββββββ β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
CAC VPN β Jumpbox β SSH
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β EC2 Instance (Kiro remote workspace) β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β agentcore-kiro-proxy.py (command-type MCP server) β β
β β - Reads JSON-RPC from stdin (Kiro sends it) β β
β β - Calls invoke_agent_runtime via boto3 (SigV4/IAM) β β
β β - Parses SSE response from AgentCore β β
β β - Writes JSON-RPC to stdout (Kiro reads it) β β
β βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ β
β β β
β β boto3 API call (VPC-internal) β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β AgentCore Runtime (microVM per user session) β β
β β 51 MCP tools β Neptune + OpenSearch β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Key properties of the proxy:
- Single Python file (~100 lines), no dependencies beyond boto3 (already on EC2)
- Runs on the EC2 where Kiro's remote workspace lives β same pattern as the AWS Powers
- Each user's Kiro instance spawns its own proxy process β own AgentCore session β own microVM
- Transparent forwarding: proxy never interprets tool schemas, just passes JSON-RPC through
Kiro MCP configuration (on EC2 at /home/ec2-user/.kiro/settings/mcp.json):
{
"agentcore-mcp-rag": {
"command": "python3",
"args": ["/home/ec2-user/eib-mcp-rag-server/tools/agentcore-kiro-proxy.py",
"--runtime-id", "<RUNTIME_ID>"],
"env": {
"AWS_REGION": "us-east-1"
}
}
}This follows the same pattern as the three existing AWS Powers (IAM Policy Autopilot, AWS IaC, AgentCore) which are also configured as "command" type servers on the EC2.
- Nothing runs on the GFE laptop except Kiro itself (desktop application)
- All MCP servers, Powers, Python, uvx, boto3 β everything executes on the EC2
- Kiro connects to the EC2 via SSH remote development (analogous to VS Code Remote SSH)
- The GFE provides only the thin client UI and the CAC VPN network path
The access pattern is already proven and in use:
- VPN: CAC-enabled VPN from GFE laptop to private VPC β
- IAM: Kiro authenticates to AWS via IAM credentials (SigV4) β
-
AgentCore:
InvokeAgentRuntimeAPI call is authorized by IAM policy β
This is the same pattern that will be replicated for the 10-person cohort β each developer gets IAM credentials with bedrock-agentcore:InvokeAgentRuntime permission. The VPN provides the network boundary, IAM provides the identity boundary.
Runtime ID: <RUNTIME_ID>
ARN: arn:aws:bedrock-agentcore:us-east-1:<ACCOUNT_ID>:runtime/<RUNTIME_ID>
Protocol: MCP
Network: VPC (us-east-1a, us-east-1b)
Subnets: <SUBNET_ID_1>, <SUBNET_ID_2>
Security Group: <SECURITY_GROUP_ID>
Idle Timeout: 900s (15 minutes)
Max Lifetime: 28800s (8 hours)
Container: <ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com/mdc-mcp-rag:agentcore
Execution Role: arn:aws:iam::<ACCOUNT_ID>:role/mdc-mcp-rag-ecs-task-role
Status: READY
- IAM identities: β Done β 10 developer accounts provisioned by infrastructure team
- EC2 access: Each developer needs SSH remote development access to the EC2 (same jumpbox pattern as current setup)
- Kiro onboarding: Each developer configures Kiro with SSH remote connection to EC2 + their IAM credentials
-
Proxy deployment: The
agentcore-kiro-proxy.pyscript is already in the repo β no additional installation needed - No Internet Gateway required β all traffic stays within VPC
- VPN routing already in place β CAC VPN β private VPC connectivity confirmed working
- AgentCore Runtime: $0 when idle, ~$0.05/session-hour when active
- 10 users Γ 4 hours/day Γ 20 days/month = 800 session-hours/month
- Estimated: ~$40/month compute (plus Neptune/OpenSearch baseline which is already running)
Expose the MCP server as an API endpoint accessible from GitHub Actions workflows, enabling automated code quality checks, EE2 compliance scanning, and PR review assistance β while maintaining FedRAMP compliance and zero direct internet exposure to the data plane.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GitHub Actions Runner β
β ββββββββββββββββββββ β
β β MCP Client Step ββββββ HTTPS (mTLS) βββββ β
β ββββββββββββββββββββ β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
Public Internet (TLS 1.3)
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AWS VPC (FedRAMP Boundary) β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Private API Gateway (REST, PRIVATE endpoint type) β β
β β - WAF WebACL (rate limiting, IP allowlist, bot control) β β
β β - mTLS with client certificates β β
β β - API key + usage plan (per-workflow throttling) β β
β β - Request/response logging to CloudWatch β β
β β - Resource policy: deny all except VPC endpoint β β
β βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ β
β β β
β βββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββ β
β β Internal NLB (Network Load Balancer) β β
β β - Health checks on /ping β β
β β - TLS termination β β
β βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ β
β β β
β βββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββ β
β β ECS Fargate Service β β
β β - MCP Server container (ARM64, same image) β β
β β - Auto-scaling (1-10 tasks based on request count) β β
β β - Task role: Neptune + OpenSearch access β β
β β - No public IP, private subnets only β β
β βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ β
β β β
β βββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββ β
β β Data Plane (unchanged from Phase 1) β β
β β Neptune (graph) + OpenSearch (vectors) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Requirement | Fargate | AgentCore |
|---|---|---|
| GitHub Actions integration | β Standard HTTPS endpoint | |
| FedRAMP compliance documentation | β Well-established pattern | |
| API Gateway + WAF integration | β Native | |
| Stateless request/response (CI jobs) | β Perfect fit | β Overkill (session isolation unnecessary for CI) |
| Cost at scale (1000s of CI runs) | β Predictable, task-based | |
| mTLS client certificates | β API GW native | β Not supported |
| Control | Implementation |
|---|---|
| AC-4 (Information Flow) | Private API GW, VPC endpoint, no internet gateway |
| AC-17 (Remote Access) | mTLS + API keys for GitHub Actions; VPN + CAC for humans |
| AU-2 (Audit Events) | CloudWatch Logs for all API GW requests, Fargate task logs |
| IA-2 (Identification) | mTLS client certs (machine identity), Cognito (human identity) |
| SC-7 (Boundary Protection) | WAF WebACL, resource policy, security groups, no public subnets |
| SC-8 (Transmission Confidentiality) | TLS 1.3 end-to-end, no plaintext |
| SC-13 (Cryptographic Protection) | KMS-encrypted data at rest (Neptune, OpenSearch, S3) |
| SI-4 (Monitoring) | X-Ray tracing, CloudWatch alarms, WAF logging |
# .github/workflows/mcp-compliance-check.yml
name: EE2 Compliance Check
on: [pull_request]
jobs:
compliance:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run EE2 Compliance Scan
uses: noaa-emc/mcp-action@v1
with:
endpoint: ${{ secrets.MCP_ENDPOINT_URL }}
client-cert: ${{ secrets.MCP_CLIENT_CERT }}
client-key: ${{ secrets.MCP_CLIENT_KEY }}
tool: scan_repository_compliance
args: |
categories: ["error_handling", "environment_variables", "file_naming"]
- name: Check Code Context
uses: noaa-emc/mcp-action@v1
with:
endpoint: ${{ secrets.MCP_ENDPOINT_URL }}
client-cert: ${{ secrets.MCP_CLIENT_CERT }}
client-key: ${{ secrets.MCP_CLIENT_KEY }}
tool: get_change_impact
args: |
symbol: ${{ github.event.pull_request.title }}-
VPC Endpoint for API Gateway (already exists:
vpce-0b2f402157c32c1c8) - ACM certificate for the API Gateway custom domain (private CA or public ACM)
- mTLS client CA β private CA for issuing client certificates to GitHub Actions
- WAF WebACL β rate limiting, GitHub IP allowlist (GitHub publishes their IP ranges)
- DNS β private hosted zone entry for the API endpoint
- CDK deployment approval β we have the stacks coded, need permission to deploy
- FedRAMP documentation β SSP updates for the new access path
- API Gateway: ~$3.50/million requests
- Fargate: ~$0.04/vCPU-hour, ~$0.004/GB-hour (1 vCPU, 2GB per task)
- NLB: ~$0.006/hour + $0.006/LCU-hour
- WAF: $5/month + $1/million requests
- Estimated for 10,000 CI runs/month: ~$50/month (plus existing Neptune/OpenSearch baseline)
| Aspect | Phase 1 (Internal) | Phase 2 (CI/CD) |
|---|---|---|
| Users | 10 developers (human) | GitHub Actions (machine) |
| Access | VPN + CAC | mTLS + API key |
| Compute | AgentCore (microVM/session) | Fargate (shared tasks) |
| Scaling | Per-session, auto | Task count, auto-scaling |
| Auth | VPN trust / IAM / Cognito | mTLS client certs |
| Internet exposure | None | API Gateway only (WAF-protected) |
| State | Session-based (multi-turn) | Stateless (single request) |
| Cost model | Per session-hour | Per request + task-hour |
| FedRAMP boundary | Fully inside VPC | API GW at boundary, data inside |
| Phase | Milestone | Dependencies | Target |
|---|---|---|---|
| 1a | AgentCore Runtime deployed | β Done | April 30, 2026 |
| 1b | First user validated (VPN + IAM + Kiro) | β Done | April 30, 2026 |
| 1c | Cohort accounts provisioned | β Done (infra team) | April 2026 |
| 1d | AgentCore Kiro Proxy built and tested | Spec complete | May 2026 |
| 1e | 10-user pilot with Kiro | Developer onboarding | May 2026 |
| 2a | CDK stack deployment (API GW + Fargate) | Infra team approval | June 2026 |
| 2b | mTLS + WAF configuration | Security team | June 2026 |
| 2c | GitHub Actions integration | DevOps | July 2026 |
| 2d | FedRAMP documentation update | Compliance team | July 2026 |
| Asset | Location | Status |
|---|---|---|
| MCP Server container (ARM64) | <ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com/mdc-mcp-rag:agentcore |
β Pushed |
| AgentCore Runtime | <RUNTIME_ID> |
β READY |
| AgentCore Kiro Proxy | tools/agentcore-kiro-proxy.py |
π¨ Spec complete |
| CDK Stacks (API GW + Fargate) | infrastructure/cdk/lib/ |
β Coded, 27 tests passing |
| Neptune graph database | 164,916 nodes, 2,941,593 relationships | β Loaded |
| OpenSearch vector store | 85,000+ documents, 5 indices | β Loaded |
| IAM execution role | mdc-mcp-rag-ecs-task-role |
β Configured |
| Service-linked roles (AgentCore) | All 4 created | β Active |
- Can we provision 9 additional IAM users with
bedrock-agentcore:InvokeAgentRuntimepermission for the pilot cohort? - For Phase 2, is there a preferred private CA for mTLS client certificates?
- Do we need a separate ATO/SSP update for the API Gateway exposure, or does it fall under the existing system boundary?
- Is there a preferred WAF rule set for GitHub Actions IP allowlisting?
- Any concerns with the AgentCore service-linked roles that were created?
- AgentCore Runtime: https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-mcp.html
- AgentCore Kiro Proxy Spec:
.kiro/specs/agentcore-kiro-proxy/(requirements, design, tasks) - CDK Stacks:
infrastructure/cdk/lib/(this repository) - Container:
mcp_server_node/Dockerfile.agentcore - Permissions:
docs/agentcore-permissions-request.md - Phase 51b SDD:
sdd_framework/workflows/phase51b_agentcore_mcp_deployment.md