Short version: once your credit approval process is algorithmated and packaged as a .uapf, you can turn it into a real AI β€œskill” by exposing it as tools over the Model Context Protocol (MCP). This article shows how to do that step by step.

1. Recap – Algorithmated credit approval as UAPF

In Algorithmating a Credit Approval Process we took a retail credit use case and turned it into an explicit model set:

  • BPMN for the straight-through flow from application to decision.
  • DMN for eligibility, risk grading and offer configuration.
  • CMMN for manual review cases and exceptions.

Everything is packaged into a single UAPF archive, for example:

retail-credit-approval.uapf
β”œβ”€ manifest.json
β”œβ”€ models/
β”‚  β”œβ”€ bpmn/
β”‚  β”‚   └─ credit-approval-main.bpmn.xml
β”‚  β”œβ”€ dmn/
β”‚  β”‚   β”œβ”€ eligibility-rules.dmn.xml
β”‚  β”‚   β”œβ”€ risk-grading.dmn.xml
β”‚  β”‚   └─ offer-configuration.dmn.xml
β”‚  └─ cmmn/
β”‚      └─ manual-review.cmmn.xml
β”œβ”€ docs/
β”‚  └─ README.md
└─ tests/
   └─ scenarios/…

That UAPF file is the algorithm. The missing piece is: how does an AI agent actually call it?

2. Architecture – From UAPF to AI agent capability

We split responsibilities into four layers:

  1. UAPF package – defines the algorithm: BPMN + DMN + CMMN + manifest.
  2. Algomation Engine – executes that package via BPMN/DMN/CMMN runtimes.
  3. MCP server – exposes the engine as typed tools for AI agents.
  4. AI agent host – uses those tools to answer user questions and make decisions.
User
↓
AI Agent (LLM + tools)
↓
MCP client
↓
UAPF MCP server
↓
Algomation Engine (HTTP API)
↓
retail-credit-approval.uapf

The UAPF model set remains the single source of truth; the agent is just a well-behaved client.

3. Step 1 – Add a simple HTTP facade in front of the UAPF engine

The first step is to give the engine a small, stable HTTP API. It doesn’t have to expose every internal detail – just two core endpoints are enough for the credit example:

  • POST /uapf/execute-process – run a BPMN process from a UAPF package.
  • POST /uapf/evaluate-decision – call a DMN decision from a UAPF package.

Example Express router (TypeScript) wrapping the engine:

// src/uapf/engineRouter.ts
import express from "express";
import { executeProcessOnce, evaluateDecision } from "./uapfRuntime";

export const uapfRouter = express.Router();

// Run the full BPMN credit approval process
uapfRouter.post("/execute-process", async (req, res, next) => {
  try {
    const { packageId, processId, input } = req.body;
    const result = await executeProcessOnce(packageId, processId, input);
    res.json(result);
  } catch (err) {
    next(err);
  }
});

// Evaluate just a DMN decision (no workflow)
uapfRouter.post("/evaluate-decision", async (req, res, next) => {
  try {
    const { packageId, decisionId, input } = req.body;
    const result = await evaluateDecision(packageId, decisionId, input);
    res.json(result);
  } catch (err) {
    next(err);
  }
});

In your main server, you mount the router under /uapf:

// src/server.ts
import express from "express";
import { uapfRouter } from "./uapf/engineRouter";

const app = express();
app.use(express.json());
app.use("/uapf", uapfRouter);

app.listen(process.env.PORT ?? 3000);

Runtime glue: the actual BPMN/DMN/CMMN execution lives in uapfRuntime.ts. For the article we can show a simplified version that illustrates the shape of the result:

// src/uapf/uapfRuntime.ts
type UapfExecutionResult = {
  applicationId: string;
  status: "approved" | "rejected" | "pending";
  creditLimit?: number;
  interestRate?: number;
  explanations: Array<{
    decisionId: string;
    rule: string;
    reason: string;
  }>;
};

export async function executeProcessOnce(
  packageId: string,
  processId: string,
  input: any
): Promise {
  // TODO: load .uapf ZIP, parse manifest.json and run BPMN + DMN + CMMN

  return {
    applicationId: input.applicationId ?? "APP-2025-0001",
    status: "approved",
    creditLimit: 5000,
    interestRate: 0.12,
    explanations: [
      {
        decisionId: "creditEligibilityDecision",
        rule: "LOW_RISK",
        reason: "Credit score β‰₯ 720 and DTI ≀ 35%"
      }
    ]
  };
}

export async function evaluateDecision(
  packageId: string,
  decisionId: string,
  input: any
) {
  // TODO: call DMN engine for the given decisionId

  return {
    decisionId,
    outcome: "APPROVED",
    score: 0.93,
    reasons: [
      "Credit score above configured low-risk threshold",
      "Debt-to-income ratio under 35%",
      "No recent defaults"
    ]
  };
}

Once this is running, you have a clean REST contract that can be reused by MCP servers, internal services and test harnesses.

4. Step 2 – Wrap the UAPF engine as an MCP server

Next, we turn the HTTP API into tools via the Model Context Protocol. Any MCP-capable AI agent (e.g. Claude Desktop, internal assistants, custom orchestrators) can then use your credit logic as a first-class skill.

We create a small MCP server with three tools:

  • uapf_describe_credit_service – metadata about the credit UAPF package.
  • uapf_run_credit_process – run the full BPMN process for a given application.
  • uapf_evaluate_credit_decision – evaluate just the DMN eligibility/risk decision.

Example server (TypeScript, using @modelcontextprotocol/sdk):

// mcp/uapf-credit/src/server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import axios from "axios";

const server = new McpServer({
  name: "uapf-credit",
  version: "1.0.0"
});

const ENGINE_BASE = process.env.UAPF_ENGINE_BASE ?? "http://localhost:3000/uapf";

// Tool 1: describe the credit service
server.tool(
  "uapf_describe_credit_service",
  {
    title: "Describe Credit Approval UAPF Service",
    description: "Returns manifest-level metadata for the credit approval UAPF package.",
    inputSchema: z.object({
      packageId: z.string().default("io.algomation.examples.retail-credit-approval")
    }),
    outputSchema: z.object({
      packageId: z.string(),
      name: z.string(),
      version: z.string(),
      processes: z.array(z.any()),
      decisions: z.array(z.any())
    })
  },
  async ({ input }) => {
    // For now we return static data matching the example manifest
    return {
      packageId: input.packageId,
      name: "Retail Credit Approval",
      version: "1.0.0",
      processes: [
        {
          id: "CreditApproval",
          bpmnProcessId: "credit_approval_main",
          entryPoint: "StartEvent_ApplicationReceived"
        }
      ],
      decisions: [
        { id: "EligibilityRules", dmnDecisionId: "EligibilityDecision" },
        { id: "RiskGrading", dmnDecisionId: "RiskGradeDecision" },
        { id: "OfferConfiguration", dmnDecisionId: "OfferConfigDecision" }
      ]
    };
  }
);

// Tool 2: run the full BPMN process
server.tool(
  "uapf_run_credit_process",
  {
    title: "Run Credit Approval BPMN Process",
    description: "Executes the algorithmated credit approval process for a single application.",
    inputSchema: z.object({
      packageId: z.string().default("io.algomation.examples.retail-credit-approval"),
      processId: z.string().default("CreditApproval"),
      application: z.object({
        applicantId: z.string(),
        name: z.string(),
        age: z.number().int(),
        creditScore: z.number().int(),
        monthlyIncome: z.number(),
        monthlyDebt: z.number(),
        requestedAmount: z.number(),
        requestedTermMonths: z.number()
      })
    }),
    outputSchema: z.object({
      applicationId: z.string(),
      status: z.enum(["approved", "rejected", "pending"]),
      creditLimit: z.number().optional(),
      interestRate: z.number().optional(),
      explanations: z.array(
        z.object({
          decisionId: z.string(),
          rule: z.string(),
          reason: z.string()
        })
      )
    })
  },
  async ({ input }) => {
    const response = await axios.post(`${ENGINE_BASE}/execute-process`, {
      packageId: input.packageId,
      processId: input.processId,
      input: input.application
    });
    return response.data;
  }
);

// Tool 3: evaluate only the DMN decision
server.tool(
  "uapf_evaluate_credit_decision",
  {
    title: "Evaluate Credit Eligibility DMN Decision",
    description: "Evaluates the DMN decision for credit eligibility and risk.",
    inputSchema: z.object({
      packageId: z.string().default("io.algomation.examples.retail-credit-approval"),
      decisionId: z.string().default("EligibilityRules"),
      application: z.object({
        creditScore: z.number().int(),
        monthlyIncome: z.number(),
        monthlyDebt: z.number(),
        hasRecentDefault: z.boolean()
      })
    }),
    outputSchema: z.object({
      decisionId: z.string(),
      outcome: z.string(),
      score: z.number(),
      reasons: z.array(z.string())
    })
  },
  async ({ input }) => {
    const response = await axios.post(`${ENGINE_BASE}/evaluate-decision`, {
      packageId: input.packageId,
      decisionId: input.decisionId,
      input: input.application
    });
    return response.data;
  }
);

const transport = new StdioServerTransport();
transport.connect(server).catch((err) => {
  console.error("Failed to start MCP server:", err);
  process.exit(1);
});

Once this server is registered in your MCP host configuration, any compatible agent can use these tools.

5. Step 3 – Give the AI agent a clear operating manual

Finally, we tell the agent how to use the UAPF tools. This is a system-level instruction block you can reuse across environments:

You are the Credit Algorithmation Agent.

You MUST treat the UAPF-based services as the single source of truth for
credit decisions, limits and explanations.

Tools available via Model Context Protocol:
- uapf_describe_credit_service
- uapf_run_credit_process
- uapf_evaluate_credit_decision

When the user asks you to approve, decline or price a credit:
1. Collect all required applicant data for the "application" structure.
2. Call uapf_run_credit_process once with the completed application.
3. Return:
   - status (approved / rejected / pending),
   - credit limit and interest rate (if present),
   - explanations in clear language.
4. Do NOT invent rules or override numeric outputs returned by the tool.

When the user only wants eligibility or risk assessment:
1. Call uapf_evaluate_credit_decision with the available data.
2. Use outcome / score / reasons to answer.
3. If required fields are missing, ask the user to provide them first.

Always include in your answer:
"Decision executed via UAPF package 'io.algomation.examples.retail-credit-approval' (v1.0.0)."

At this point, the credit approval process is no longer a slide, a diagram or a PDF. It is a living capability that AI agents can invoke – with clear boundaries, governance and audit trails.

6. Where to go next

  • Extend the package – add more DMN tables for pricing, cross-sell and collections.
  • Add CMMN detail – enrich the manual review case with tasks, milestones and committee steps.
  • Generalize the pattern – reuse the same UAPF + MCP pattern for KYC, onboarding and disputes.

If you want to see this in action, load the retail credit UAPF example into Algomation Studio, configure the MCP server and hook it into your preferred AI agent host. The result is not β€œAI magic”, but algorithmated, explainable intelligence in production.

For a conceptual third-party view on how an AI agent like Grok from xAI could use this pattern in practice, see Empowering Grok with Governed Intelligence: Algorithmating Credit Decisions via UAPF and MCP .

If you are exploring similar integrations with Google Gemini, read From Algorithmated Processes to Gemini: A Practical Guide , which shows how to use Gemini's function calling as the bridge to UAPF.

We have companion guides for specific agent platforms, including Claude via UAPF and MCP .

For a broader view on how UAPF scales from single workflows to an enterprise-wide algorithm layer, see From Single Processes to the Algorithmated Enterprise .