Visual Guide: MCP vs Direct API — At a Glance


Architecture Comparison

Option A: Direct API Calls (Week 1)

┌──────────────────────────────────┐
│   LangGraph Agent                │
│  (in agent/nodes.py)             │
├──────────────────────────────────┤
│                                  │
│  def fetch_ticket(state):        │
│      token = os.getenv("TOKEN")  │ ← Direct credentials
│      resp = requests.get(...)    │
│      return {...state, ...}      │
│                                  │
│  def create_branch(state):       │
│      token = os.getenv("TOKEN")  │ ← Direct credentials
│      resp = requests.post(...)   │
│      return {...state, ...}      │
│                                  │
└──────────────────────────────────┘
         │                │
         ↓                ↓
    JIRA API          GitHub API
   (DIRECT)          (DIRECT)

Pros: Simple, fast to code (2 hrs) Cons: Credentials scattered, not reusable, hard to test


Option B/C: MCP Servers (Week 2)

┌──────────────────────────────────────────────────────────┐
│   LangGraph Agent                                        │
│   (clean, focuses on logic only)                         │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  def fetch_ticket(state):                                │
│      ticket = jira_mcp_client.call_tool(...)  ← CLEAN    │
│      return {...state, 'ticket': ticket}                 │
│                                                          │
│  def create_branch(state):                               │
│      result = github_mcp_client.call_tool(...) ← CLEAN   │
│      return {...state, 'branch': result}                 │
│                                                          │
└──────────────────────────────────────────────────────────┘
         │                                    │
         ↓ HTTP :8001                         ↓ HTTP :8002
┌──────────────────────┐           ┌──────────────────────┐
│  JIRA MCP Server     │           │ GitHub MCP Server    │
│  (FastAPI)           │           │ (FastAPI)            │
├──────────────────────┤           ├──────────────────────┤
│ ✅ Credentials in    │           │ ✅ Credentials in    │
│    Secrets Manager   │           │    Secrets Manager   │
│ ✅ Centralized logic │           │ ✅ Centralized logic │
│ ✅ Easy to test      │           │ ✅ Easy to test      │
└──────────────────────┘           └──────────────────────┘
         │                                    │
         ↓ HTTPS                              ↓ HTTPS
    JIRA API                            GitHub API
    (REMOTE)                            (REMOTE)

Pros: Secure, reusable, testable, production-ready Cons: Takes longer to code (6 hrs), needs 2 extra processes


Security: Credentials Handling

Direct API Calls (❌ Not Secure)

┌─────────────────────────────────┐
│  Agent Process                  │
├─────────────────────────────────┤
│                                 │
│  JIRA_TOKEN = "xxx"  ← IN MEMORY│
│  GITHUB_TOKEN = "yyy" ← IN MEMORY
│                                 │
│  # Agent code can leak tokens   │
│  if error:                      │
│      log(JIRA_TOKEN)  ← 💥 LEAK │
│                                 │
└─────────────────────────────────┘

Problems: - Credentials in agent process memory ❌ - If agent crashes and logs, credentials exposed ❌ - Multiple agents = duplicate credentials ❌ - No audit trail ❌


MCP Servers (✅ Secure)

┌─────────────────────────────────────────────────────────┐
│  Agent Process                   │  JIRA MCP Process   │
├────────────────────────────────┬──────────────────────┤
│                                │                      │
│  tickets = mcp_call(...)       │  Fetch secret at:   │
│  (no credentials in scope)     │  - Request time     │
│                                │  - Use once         │
│                                │  - Discard after    │
│                                │  (not in memory)    │
│                                │                     │
└────────────────────────────────┴──────────────────────┘

Benefits: - No credentials in agent ✅ - Credentials fetched fresh per request ✅ - Automatic credential rotation ✅ - AWS CloudTrail audit log ✅


Code Comparison: Side by Side

Fetching a JIRA Ticket

Direct API (Simple but Messy)

# agent/nodes.py
import requests, os

def fetch_ticket(state):
    # ⚠️ Direct access to secret
    token = os.getenv("JIRA_TOKEN")

    # ⚠️ HTTP error handling inline
    try:
        resp = requests.get(
            f"{os.getenv('JIRA_URL')}/issue/{state['key']}",
            headers={"Authorization": f"Bearer {token}"},
            timeout=10
        )
        resp.raise_for_status()
    except requests.exceptions.Timeout:
        # ⚠️ Each node must handle errors
        return {...state, 'error': 'Timeout'}
    except requests.exceptions.HTTPError as e:
        # ⚠️ Error handling duplicated across all nodes
        return {...state, 'error': str(e)}

    data = resp.json()
    return {...state, 'ticket': data}

Problems: - Error handling duplicated in every node ❌ - Token in memory for duration of process ❌ - Hard to test without mocking requests ❌ - Not reusable from other clients ❌


MCP Server (Clean and Secure)

MCP Server:

# jira_mcp/server.py
from fastapi import FastAPI

app = FastAPI()

def get_jira_secret():
    # ✅ Fresh fetch each request
    sm = boto3.client('secretsmanager')
    return json.loads(sm.get_secret_value(SecretId='taskmaster/jira')['SecretString'])

@app.post("/tools/call")
def call_tool(call: ToolCall):
    if call.name == "get_ticket":
        creds = get_jira_secret()  # ✅ Secret fetched now
        resp = requests.get(
            f"{creds['url']}/issue/{call.arguments['issue_key']}",
            headers={...},
            timeout=10
        )
        resp.raise_for_status()
        return resp.json()  # ✅ Secret goes out of scope

Agent:

# agent/nodes.py
from mcp_clients import jira_mcp_client

def fetch_ticket(state):
    # ✅ Clean: just call the tool
    ticket = jira_mcp_client.call_tool(
        "get_ticket",
        {"issue_key": state['key']}
    )
    return {...state, 'ticket': ticket}

Benefits: - Credentials never in agent ✅ - Error handling in one place ✅ - Easy to test MCP independently ✅ - Agent code is clean ✅


Timeline & Effort

Week 1: Direct API (Option A)

Monday AM     : 1.5 hrs → JIRA client code + tests
Monday PM     : 1.5 hrs → GitHub client code + tests
Tuesday AM    : 1 hr    → Wire into agent nodes
Tuesday PM    : 1 hr    → Test E2E
────────────────────────────────────────
Total         : ~5 hours
Result        : ✅ Working demo (but not production-ready)

Week 1 (As above)
├─ Direct API: 3 hours
├─ Result: Working demo ✅

Week 2
├─ Extract client → FastAPI: 1.5 hrs
├─ Build docker-compose: 0.5 hrs
├─ Test locally: 1 hr
├─ Deploy to AWS: 0.5 hrs
├─────────────────────────────────
└─ Total: 3 more hours
└─ Result: Production-ready MCP servers ✅

Week 1 Only: Full MCP (Option B)

Monday AM     : 2 hrs   → JIRA MCP server
Monday PM     : 2 hrs   → GitHub MCP server
Tuesday AM    : 1 hr    → Wire agent to MCP
Tuesday PM    : 1 hr    → Test docker-compose
────────────────────────────────────────
Total         : 6 hours
Result        : ✅ Production-ready from day 1
             : (No refactoring needed)

Decision Matrix: Effort vs Benefit

           Direct API    MCP Servers
           (Week 1)      (Week 2 Refactor)

Speed      ████░░░░░░    ██████░░░░
           3 hours       6 hours

Quality    ███░░░░░░░    ██████████
           Not prod      Production

Reuse      ░░░░░░░░░░    ██████████
           Not reusable  Fully reusable

Security   ██░░░░░░░░    ██████████
           Poor          Excellent

Effort     Easy          Moderate
           (Pros know    (Needs FastAPI,
            requests lib) Docker basics)

When to Choose Each Option

Choose Direct API Calls IF:

✓ "I need a working demo by tomorrow"
✓ "I just want to validate the concept"
✓ "I'm building a one-off script"
✓ "My team doesn't care about credentials safety"
✓ "I have only 3 hours available"

Timeline: 3 hours to working code
Cost: None
Production-ready: No

Choose MCP Servers IF:

✓ "I need production-ready code"
✓ "Multiple clients will use these tools"
✓ "Security/compliance matters"
✓ "I want to swap integrations later (JIRA→Linear)"
✓ "I have 5–6 hours for a better solution"

Timeline: 5–6 hours (or 3+3 with hybrid)
Cost: None
Production-ready: Yes

✓ "I want a working demo quickly"
✓ "AND I want production-ready code"
✓ "AND I have 6 hours total (spread over 2 weeks)"

Week 1: 3 hours → Direct API demo
Week 2: 3 hours → Refactor to MCP servers

Timeline: 3 hours + 3 hours = 6 hours
Cost: None
Production-ready: Yes (after Week 2)
Demo available: Yes (after Week 1)

The 30-Second Decision

START HERE
Am I building → NO → Use Direct API
production code?     (3 hours, not prod)
    ↓ YES
Do I have → NO → Use Direct API now
5–6 hours?        Refactor Week 2
    ↓ YES         (Hybrid: recommended)
Use MCP from start
(6 hours, fully prod)

Bottom Line

Approach Speed Quality When
Direct API ⭐⭐⭐⭐⭐ Quick validation
Hybrid (A→B) ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ RECOMMENDED
MCP from start ⭐⭐⭐ ⭐⭐⭐⭐⭐ If you have time

Recommendation: Start with Direct API (3 hrs), refactor to MCP (3 hrs). Result: Demo ready Day 2. Production ready Day 8.


Visual Timeline

NOW:
├─ Read [MCP-Decision-OnePager](MCP-Decision-OnePager.md)    (3 mins)
├─ Read [Implementation-Quickstart](Implementation-Quickstart.md)    (10 mins)
└─ Decision: Hybrid Approach

WEEK 1 (Days 1–2):
├─ Follow [Week1-Checklist](Week1-Checklist.md)    (3 hours)
├─ Build direct API version
└─ ✅ Demo works: fetch JIRA → generate code → create PR

WEEK 2 (Days 3–4):
├─ Read [07-mcp-servers](07-mcp-servers.md) for reference    (1 hour)
├─ Refactor direct clients → FastAPI MCP servers    (2 hours)
└─ ✅ Production-ready MCP servers, AWS-deployable

WEEK 2+ (Days 5+):
├─ Deploy to AWS ECS
└─ ✅ Running in production

Next action: Open MCP-Decision-OnePager (3 mins) or jump to Week1-Checklist (to start coding).