MCP Servers¶
Location: inception_mcp_servers/
The MCP (Model Context Protocol) servers are the tool execution layer of Project Inception. They expose enterprise backend operations — database queries, file storage, data warehousing — as structured, authenticated tools that AI agents can call via the MCP protocol over HTTP.
Available Servers¶
| Server | Module | Endpoint | Backend |
|---|---|---|---|
| SQLcl | mcp_sqlcl/ |
http://127.0.0.1:3001/mcp/ |
Oracle Database via SQLcl |
| Object Storage | mcp_os/ |
http://127.0.0.1:3002/mcp/ |
OCI Object Storage |
| ADW | mcp_adw/ |
http://127.0.0.1:8003/mcp/ |
Oracle Autonomous Data Warehouse |
Platform Architecture¶
MCP servers sit in the Tool Layer between the agent orchestration tier and OCI backend services.
┌─────────────────────────────────────────────────┐
│ AI Agent / LLM Client │
│ (Claude, OCI GenAI, LangChain) │
└─────────────────────┬───────────────────────────┘
│ MCP over HTTP
▼
┌─────────────────────────────────────────────────┐
│ MCP Tool Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌─────────┐ │
│ │ mcp_sqlcl │ │ mcp_os │ │ mcp_adw │ │
│ │ port 3001 │ │ port 3002 │ │ port │ │
│ │ │ │ │ │ 8003 │ │
│ └──────┬───────┘ └──────┬───────┘ └────┬────┘ │
└─────────┼────────────────┼──────────────┼──────┘
│ │ │
▼ ▼ ▼
Oracle DB OCI Object Oracle ADW
via SQLcl Storage (wallet mTLS)
Consistent 3-File Structure¶
Every MCP server follows the same module layout:
<server_module>/
├── src/
│ ├── server_oidc.py ← bootstrap: interactive OIDC auth
│ ├── server_token.py ← bootstrap: non-interactive bearer token auth
│ ├── registry.py ← TOOL_REGISTRY: the only tools exposed to callers
│ ├── tools.py ← all tool function implementations
│ └── common/
│ └── settings.py ← .env loading and config exports
├── tests/ ← test clients for both auth modes
└── .env ← environment configuration
| File | Role |
|---|---|
server_oidc.py / server_token.py |
Bootstrap only — load env, configure auth, create FastMCP, run transport |
registry.py |
Single source of truth for exposed tools; adding to tools.py alone does nothing |
tools.py |
All tool logic — never imports FastMCP, never creates a server |
common/settings.py |
Loads .env via python-dotenv; exports all settings as module-level variables |
Authentication Architecture¶
All three servers use OCI IAM (IDCS) for authentication. Two deployment modes are available for each server:
Mode 1 — Interactive OIDC (server_oidc.py)¶
Uses fastmcp.server.auth.providers.oci.OCIProvider. FastMCP handles the full OAuth 2.0 Authorization Code flow — the client opens a browser, the user logs in to OCI IAM, and a token is issued.
Client (auth="oauth")
→ FastMCP OAuth discovery endpoints
→ Browser redirect to OCI IAM login
→ Authorization code returned
→ FastMCP exchanges code for access token
→ Token validated; tool calls authorized
Use when: Bootstrapping a new token, interactive testing, MCP Inspector.
Mode 2 — Bearer Token (server_token.py)¶
Uses a custom OCITokenAuthMiddleware + JWTVerifier. The caller must supply a valid IDCS JWT in the Authorization: Bearer <token> header on every request, including the MCP initialize handshake.
Client (Authorization: Bearer <token>)
→ OCITokenAuthMiddleware intercepts request
→ JWTVerifier validates signature via IDCS JWKS endpoint
→ Claims (sub, aud, iss) verified
→ Tool call dispatched
Use when: Non-interactive clients, agents, CI/CD pipelines, production.
Important
Do not connect an OAuth-only client (auth="oauth") to server_token.py.
The middleware validates a bearer token on the MCP initialize handshake itself — before OAuth can complete.
Always connect OAuth clients to server_oidc.py.
Token Bootstrap Flow¶
First-time setup to obtain an MCP_ACCESS_TOKEN:
Step 1 → Start server_oidc.py
Step 2 → Run tests/get_token.py
Step 3 → Browser opens: OCI IAM login
Step 4 → Login completes → get_token tool returns access token
Step 5 → Token written to .env as MCP_ACCESS_TOKEN
Step 6 → Stop server_oidc.py
Step 7 → Start server_token.py (uses MCP_ACCESS_TOKEN for validation)
Shared Design Patterns¶
Explicit tool registry¶
Only tools listed in TOOL_REGISTRY are reachable by callers. A function in tools.py that is not registered is never exposed — no accidental surface area. Security audits are simple: one registry file = the complete capability inventory.
# registry.py
TOOL_REGISTRY = {
"execute_sql": sqlcl_tools.execute_sql,
"schema_information": sqlcl_tools.schema_information,
}
# anything not listed here cannot be called
Per-request token validation¶
There are no persistent authenticated sessions. Every MCP request is independently validated. If a token expires mid-session, the next call receives a 401 and the client must re-authenticate. This prevents stale sessions from retaining elevated access.
Stderr-only logging¶
The MCP protocol uses stdout for JSON-framed tool responses. All server-side diagnostic output goes to stderr to prevent protocol corruption. Redirect stderr to a log file for persistent logging:
Health check endpoint¶
Every server registers a /health route returning 200 OK. Use it for load balancer health checks and uptime monitoring.
IDCS Domain Configuration¶
IDCS_DOMAIN format
IDCS_DOMAIN must be set to the bare hostname only — no https:// prefix, no :443 port suffix.
# Correct
IDCS_DOMAIN=idcs-10ca4bf910534e0290c18c358e3226b2.identity.oraclecloud.com
# Wrong — will produce a malformed URL
IDCS_DOMAIN="https://idcs-10ca4bf910534e0290c18c358e3226b2.identity.oraclecloud.com:443"
Both auth_middleware.py and token_verifier.py prepend https:// and append :443 where needed — the env var should only contain the domain.
Diagnostics¶
# Kill a server on a stuck port
lsof -ti tcp:3001 | xargs kill -9
lsof -ti tcp:3002 | xargs kill -9
lsof -ti tcp:8003 | xargs kill -9
# Check health endpoints
curl http://127.0.0.1:3001/health
curl http://127.0.0.1:3002/health
curl http://127.0.0.1:8003/health
# MCP Inspector (requires server_oidc.py running)
fastmcp dev --server-spec src/server_oidc.py:mcp