Skip to content

Ontology Integration

This document describes ProEthica's integration with OntServe for ontology management.

Overview

ProEthica uses OntServe as its central ontology repository. The integration provides:

  • Concept definitions for extraction validation
  • Class hierarchy for entity classification
  • SPARQL queries for knowledge retrieval
  • Candidate concept submission

Architecture

ProEthica                            OntServe
+------------+                      +------------+
| MCP Client |-- Streamable HTTP -->| FastMCP 3  |
|            |<------ SSE ----------|   :8082    |
+------------+                      +------+-----+
                                           |
                                           v
                                    +------------+
                                    | PostgreSQL |
                                    | (ontologies|
                                    +------------+

Storage Flow

ProEthica Extraction Pipeline
         |
         v
+---------------------------+
| TemporaryRDFStorage       |  (ProEthica DB: ai_ethical_dm)
| - Draft entities          |
| - JSON-LD in rdf_json_ld  |
| - is_published flag       |
+---------------------------+
         |
         | commit_case_versioned()
         v
+---------------------------+
| OntServe concepts table   |  (OntServe DB: ontserve)
| - Versioned entities      |
| - is_current flag         |
| - extraction_run_version  |
+---------------------------+
         |
         | TTL generation
         v
+---------------------------+
| proethica-case-N.ttl      |  (Single file, overwritten)
| proethica-intermediate-   |
|   extended.ttl            |  (Classes, appended)
+---------------------------+

Versioning

Case TTL files are overwritten on re-extraction (no accumulation). The OntServe concepts table preserves version history via is_current and extraction_run_version columns. Classes are versioned individually.

TTL File Structure

Ontology files in OntServe/ontologies/:

File Purpose
proethica-core.ttl The nine component types (Role, Principle, etc.)
proethica-intermediate.ttl Intermediate concepts, engineering roles and ObjectProperties
proethica-intermediate-extended.ttl Extended Ontology: classes discovered during extraction, with provenance
proethica-cases.ttl Typing vocabulary of the Step 4 analysis records
proethica-case-N.ttl Case-specific individuals
proethica-provenance.ttl Provenance properties

Ontology Layers maps these files, and the seed vocabularies, to the conceptual layers.

URI namespaces:

@prefix proeth-core: <http://proethica.org/ontology/core#> .
@prefix proeth: <http://proethica.org/ontology/intermediate#> .
@prefix proeth-cases: <http://proethica.org/ontology/cases#> .
@prefix proeth-prov: <http://proethica.org/provenance#> .
@prefix caseN: <http://proethica.org/ontology/case/N#> .

Model Context Protocol (MCP)

Connection

ProEthica connects to OntServe via the MCP Streamable HTTP transport:

Setting Default
URL http://localhost:8082
Protocol MCP (JSON-RPC 2.0 over Streamable HTTP)
Server FastMCP 3.x

Configuration

Environment variables:

ONTSERVE_MCP_URL=http://localhost:8082

ProEthica auto-detects OntServe availability on startup and sets ONTSERVE_MCP_ENABLED accordingly.

MCP Client

Client Implementation

Two layers handle MCP communication:

File Purpose
app/services/ontserve/mcp_transport.py Low-level MCP Streamable HTTP transport (session management, SSE parsing)
app/services/ontserve/external_mcp_client.py High-level tool wrappers used by extraction pipeline

Connection Management

from app.services.ontserve.external_mcp_client import get_external_mcp_client

client = get_external_mcp_client()
result = client.get_entities_by_category("Role")

Available Methods

OntServe MCP provides 20 tools (12 integration, 5 reasoning/BFO, 3 conformance). The three most commonly used in ProEthica's extraction pipeline are documented below. See Architecture for the full tool list.

get_entities_by_category

Retrieves entities of a specific type from the ontology.

Request (MCP call_tool format):

{
  "jsonrpc": "2.0",
  "method": "call_tool",
  "params": {
    "name": "get_entities_by_category",
    "arguments": {
      "category": "Role",
      "domain_id": "proethica-intermediate"
    }
  },
  "id": 1
}

Response:

{
  "jsonrpc": "2.0",
  "result": {
    "content": [{
      "type": "text",
      "text": "{\"entities\": [{\"uri\": \"proeth:Engineer\", \"label\": \"Engineer\"}]}"
    }]
  },
  "id": 1
}

sparql_query

Executes SPARQL queries against the ontology.

Request:

{
  "jsonrpc": "2.0",
  "method": "call_tool",
  "params": {
    "name": "sparql_query",
    "arguments": {
      "query": "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10",
      "domain_id": "proethica-intermediate"
    }
  },
  "id": 2
}

submit_candidate_concept

Submits new concept for ontology review.

Request:

{
  "jsonrpc": "2.0",
  "method": "call_tool",
  "params": {
    "name": "submit_candidate_concept",
    "arguments": {
      "label": "AI Verification",
      "category": "Capability",
      "definition": "Ability to verify AI-generated outputs",
      "source": "Case 24-2",
      "domain_id": "proethica-intermediate"
    }
  },
  "id": 3
}

Ontology Structure

Ontology Layers

The ontologies are organized in layers from general to case-specific. The Core and Intermediate layers are general professional-ethics vocabulary. The domain layer and the case ontologies hold the engineering-ethics material obtained from the NSPE opinions. The table maps each layer to the files in OntServe/ontologies/ that hold it.

Layer Content Files
Core The nine component types (Role, Principle, Obligation, State, Resource, Action, Event, Capability, Constraint), declared pairwise disjoint and aligned to BFO proethica-core.ttl, with proethica-foundation.ttl (the cited BFO, IAO and RO terms) and proethica-shapes.ttl (SHACL shapes)
Intermediate Concepts from the professional-ethics literature that specialize the component types and recur across professions, such as ProfessionalRole, ProviderClientRole, PublicWelfarePrinciple and EthicalCode proethica-intermediate.ttl
Domain (engineering ethics) Engineering-specific classes, chiefly the engineering roles (EngineerRole and its specializations such as CivilEngineerRole); the case-derived Extended Ontology, whose classes are discovered during extraction and record the case and section they came from; and the optional seed vocabularies Engineering roles in proethica-intermediate.ttl; Extended Ontology in proethica-intermediate-extended.ttl; seeds in NSPE Code of Ethics.ttl (the code of ethics), ifc-roles.ttl (IFC actor roles) and engineering-ethics.ttl (technical standards)
Case The individuals of one opinion and the classes they instantiate, with the Step 4 analysis records proethica-case-N.ttl, one per committed case; proethica-cases.ttl types the analysis records

Classes of the Intermediate and Extended Ontologies share the proeth: namespace.

Core Ontology (proethica-core)

Defines the 9 component types:

Class URI Description
Role proeth-core:Role Professional positions
Principle proeth-core:Principle Abstract standards
Obligation proeth-core:Obligation Concrete duties
State proeth-core:State Situational context
Resource proeth-core:Resource Available knowledge
Action proeth-core:Action Professional behaviors
Event proeth-core:Event Precipitating occurrences
Capability proeth-core:Capability Competencies an agent possesses (dispositions)
Constraint proeth-core:Constraint Prohibitions

Intermediate Ontology (proethica-intermediate)

Subclasses of the core component types, general professional concepts first, then engineering roles:

proeth:ProfessionalRole rdfs:subClassOf proeth-core:Role .
proeth:ProfessionalObligation rdfs:subClassOf proeth-core:Obligation .
proeth:PublicWelfarePrinciple rdfs:subClassOf proeth:FundamentalEthicalPrinciple .
proeth:EngineerRole rdfs:subClassOf proeth:ProfessionalRole .
proeth:CivilEngineerRole rdfs:subClassOf proeth:EngineerRole .

Case Analysis Classes (Step 4)

Step 4 produces 8 additional entity types beyond the 9 base concepts:

Class Phase Description
CodeProvisionReference 2A NSPE code sections cited in the case
PrecedentCaseReference 2B BER cases referenced in the discussion
EthicalQuestion 2C Questions posed to the Board, and analytical questions added by the synthesis
EthicalConclusion 2C Board conclusions extracted from the opinion, and analytical conclusions added by the synthesis; each is labelled by type
CanonicalDecisionPoint Phase 3 Points where ethical choices must be made (E1-E3 synthesis)
ResolutionPattern 2E Patterns of how ethical tensions are resolved
CausalNormativeLink 2E Connections between causal factors and normative principles
QuestionEmergence 2E How ethical questions arise from case facts

Properties:

Property Domain Range Description
hasOption DecisionPoint DecisionOption Links decision point to options
involvesRole DecisionPoint Role Professional roles involved
appliesProvision DecisionPoint EthicalCode Applicable code provisions
isBoardChoice DecisionOption boolean Whether this option was chosen
answersQuestion BoardConclusion EthicalQuestion Links conclusion to question

The full extraction pipeline produces 17 entity types across all 4 steps (9 base concepts + 8 Step 4 types).

Entity Review Integration

Available Classes Display

During entity review, ProEthica fetches available classes:

# In entity_review.py
from app.services.ontserve.external_mcp_client import get_external_mcp_client

def get_available_classes(category):
    client = get_external_mcp_client()
    return client.get_entities_by_category(category)

Class Assignment

When user assigns entity to existing class:

  1. Entity class_uri updated to match ontology class
  2. Definition may be inherited or customized
  3. Relationship to parent class preserved

New Class Approval

When approving new class:

  1. submit_candidate_concept() called
  2. OntServe creates candidate entry
  3. Admin reviews in OntServe
  4. Approved classes added to ontology

SPARQL Queries

Common Queries

Get all Roles:

PREFIX proeth: <http://proethica.org/ontology#>
SELECT ?role ?label ?definition
WHERE {
  ?role rdfs:subClassOf proeth:Role .
  ?role rdfs:label ?label .
  OPTIONAL { ?role rdfs:comment ?definition }
}

Get Obligations for a Role:

PREFIX proeth: <http://proethica.org/ontology#>
SELECT ?obligation ?label
WHERE {
  ?role rdfs:label "Engineer" .
  ?obligation proeth:generatedBy ?role .
  ?obligation rdfs:label ?label .
}

Query Execution

Via MCP client:

query = """
SELECT ?s ?label WHERE {
  ?s rdfs:label ?label .
  ?s a proeth:Role .
}
"""
results = await client.sparql_query(query)

Error Handling

Connection Failures

If OntServe unavailable:

try:
    entities = await client.get_entities_by_category("Role")
except MCPConnectionError:
    # Fallback to cached data or empty list
    entities = []

Timeout Handling

Configurable timeout with retry:

from app.services.ontserve.mcp_transport import MCPTransport

transport = MCPTransport(timeout=30)

Graceful Degradation

ProEthica continues functioning without OntServe:

  • Available Classes section shows empty
  • Extraction still works
  • Entities stored locally
  • Manual ontology sync later

Caching

Class Cache

Available classes cached to reduce queries:

Setting Value
Cache duration 5 minutes
Invalidation On new class approval

Query Cache

SPARQL results cached:

Setting Value
Cache duration 1 minute
Key Query hash

Monitoring

Connection Status

Header shows connection status:

  • Green: Connected
  • Yellow: Degraded
  • Red: Disconnected

Health Check

Periodic health check:

async def health_check():
    try:
        await client.get_entities_by_category("Role")
        return True
    except:
        return False

Troubleshooting

MCP Not Responding

  1. Check OntServe MCP is running:

    curl -s http://localhost:8082/health
    

  2. Verify port 8082 not blocked

  3. Check OntServe logs

Empty Available Classes

  1. Verify MCP connection active
  2. Check ontology loaded in OntServe
  3. Query database directly:
    SELECT * FROM ontology_classes WHERE type = 'Role';
    

Query Failures

  1. Validate SPARQL syntax
  2. Check ontology namespaces
  3. Review OntServe error logs