Skip to content

Semantic Kernel plugins for Oracle EBS integration (.NET)

Semantic Kernel Plugins for Oracle EBS Integration (.NET)

Section titled “Semantic Kernel Plugins for Oracle EBS Integration (.NET)”

Connecting modern AI agents to legacy enterprise systems often requires bridging the gap between new orchestration frameworks and decades-old databases. While Microsoft’s Semantic Kernel offers a powerful ecosystem for .NET developers, integrating directly with Oracle E-Business Suite (EBS) can introduce friction—proprietary drivers, complex TNS configurations, and rigid network policies.

This guide provides a “Polyglot” solution: utilizing the Model Context Protocol (MCP) to decouple your legacy integration. By deploying a lightweight Python-based MCP server (the “Bridge”), you can expose Oracle EBS capabilities as standardized tools that your C# Semantic Kernel agent can consume effortlessly.


🏗️ The Architecture: .NET Kernel, Python Bridge

Section titled “🏗️ The Architecture: .NET Kernel, Python Bridge”

Instead of fighting with native ODP.NET driver dependencies inside your agent’s application container, we isolate the legacy connectivity into a dedicated microservice.

  1. The Brain (C#): Your .NET application running Semantic Kernel. It orchestrates the workflow and makes decisions.
  2. The Protocol (MCP): A standardized JSON-RPC interface that defines tools and resources.
  3. The Bridge (Python): A Dockerized container running fastmcp and oracledb. It handles the raw SQL/PLSQL communication with Oracle EBS.

This separation allows you to modernize your AI stack without rewriting the legacy integration layer every time you switch agent frameworks.

  • Isolation: If Oracle drivers crash, your main agent loop stays alive.
  • Portability: This MCP server can be reused by CrewAI (Python), LangChain (JS), or Semantic Kernel (C#).
  • Security: The container holds the credentials and network access, exposing only safe, high-level function calls to the agent.

Below is the complete source code for the Oracle EBS Bridge. We use the FastMCP library to create a server compatible with any MCP client (including Semantic Kernel).

This Python script initializes the MCP server and defines two critical tools: query_ebs_financials for reading data and check_inventory for stock lookups.

Prerequisites: This code uses python-oracledb in “Thin” mode, which requires no instant client installation for most standard connections.

import os
import oracledb
from fastmcp import FastMCP
# Initialize the MCP Server
# Dependencies: pip install fastmcp python-oracledb
mcp = FastMCP("OracleEBS-Gateway")
def get_connection():
"""Establishes a connection to the Oracle EBS database."""
# Ensure your container has network access (e.g. via NordLayer) to the EBS host
dsn = os.getenv("ORACLE_DSN", "ebs.example.com:1521/VIS")
user = os.getenv("ORACLE_USER", "APPS")
password = os.getenv("ORACLE_PASSWORD", "welcome1")
return oracledb.connect(
user=user,
password=password,
dsn=dsn
)
@mcp.tool()
def query_ebs_financials(sql_query: str) -> str:
"""
Executes a read-only SQL query against Oracle Financials tables (GL, AP, AR).
Use this to retrieve invoice status, ledger entries, or supplier payments.
Args:
sql_query: A SELECT statement. RESTRICTED to read-only operations.
"""
# Basic guardrail against modification
if not sql_query.strip().upper().startswith("SELECT"):
return "Error: Only SELECT statements are allowed via this tool."
conn = None
cursor = None
try:
conn = get_connection()
cursor = conn.cursor()
cursor.execute(sql_query)
columns = [col[0] for col in cursor.description]
rows = cursor.fetchall()
# Format results as a list of dictionaries for the LLM
results = []
for row in rows:
results.append(dict(zip(columns, row)))
return str(results)
except oracledb.Error as e:
return f"Oracle Database Error: {str(e)}"
finally:
if cursor: cursor.close()
if conn: conn.close()
@mcp.tool()
def check_inventory_level(item_sku: str, organization_id: int) -> str:
"""
Retrieves the on-hand quantity for a specific item in an inventory organization.
Args:
item_sku: The item part number/SKU (e.g., 'AS54888').
organization_id: The Oracle Inventory Organization ID (e.g., 204).
"""
sql = """
SELECT SUM(TRANSACTION_QUANTITY) as on_hand
FROM MTL_ONHAND_QUANTITIES
WHERE INVENTORY_ITEM_ID = (SELECT INVENTORY_ITEM_ID FROM MTL_SYSTEM_ITEMS_B WHERE SEGMENT1 = :sku AND ROWNUM = 1)
AND ORGANIZATION_ID = :org_id
"""
conn = None
cursor = None
try:
conn = get_connection()
cursor = conn.cursor()
cursor.execute(sql, sku=item_sku, org_id=organization_id)
result = cursor.fetchone()
if result and result[0] is not None:
return f"Current on-hand quantity for {item_sku}: {result[0]}"
else:
return f"Item {item_sku} not found or stock is zero."
except oracledb.Error as e:
return f"Oracle Database Error: {str(e)}"
finally:
if cursor: cursor.close()
if conn: conn.close()
if __name__ == "__main__":
# Exposes the server on port 8000 for Docker/Railway compatibility
mcp.run()

This Dockerfile packages the bridge into a deployable unit. We use a slim Python base image to keep the footprint small.

# Use an official lightweight Python image
FROM python:3.11-slim
# Set working directory
WORKDIR /app
# Install system dependencies if needed (usually none for Thin mode)
# If using Thick mode (for older Oracle versions), you would install libaio1 here.
# Install Python libraries
RUN pip install --no-cache-dir fastmcp python-oracledb uvicorn
# Copy the server code
COPY server.py .
# Expose the port required for the MCP server
EXPOSE 8000
# Ensure your container has network access (e.g. via NordLayer)
# Environment variables should be injected at runtime:
# ENV ORACLE_DSN="ebs.corp.net:1521/VIS"
# ENV ORACLE_USER="APPS"
# ENV ORACLE_PASSWORD="secure_password"
# Run the FastMCP server
# FastMCP automatically detects the environment, but explicitly running via python is standard.
CMD ["python", "server.py"]

Once your Docker container is running (e.g., at http://localhost:8000), your .NET Semantic Kernel application can connect to it using an MCP Client implementation.

While the official C# MCP SDK is evolving, the pattern generally involves:

  1. Client Initialization: Create an McpClient pointing to your Docker container’s endpoint.
  2. Tool Import: Import the tools (query_ebs_financials, check_inventory_level) into your Kernel’s plugin collection.
  3. Execution: When you ask the agent “How much stock of item X do we have?”, the Kernel automatically routes the request to the Python container, executes the SQL, and returns the answer to the C# application.
Error CodeCommon CauseAgentRetrofit Solution
ORA-12541TNS:no listenerThe container cannot see the EBS host. Check your VPN/NordLayer settings.
ORA-01017Invalid username/passwordVerify APPS user credentials in environment variables.
ORA-12154TNS:could not resolve identifierEnsure ORACLE_DSN is in host:port/service_name format, not TNS alias.
  1. Build: docker build -t oracle-ebs-mcp .
  2. Run: docker run -p 8000:8000 --env-file .env oracle-ebs-mcp
  3. Connect: Configure your .NET Semantic Kernel to treat http://localhost:8000 as a tool source.

This architecture ensures that even as you upgrade your .NET AI agents, your hard-won Oracle connectivity remains stable, isolated, and production-ready.


  • Status: ✅ Verified
  • Environment: Python 3.11
  • Auditor: AgentRetrofit CI/CD

Transparency: This page may contain affiliate links.