Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ DICE (Domain-Integrated Context Engineering) is a proposition-first knowledge su

| Module | What it owns |
|---|---|
| `dice` | The entire domain: `Proposition` model, `PropositionStore`/`PropositionRepository` SPIs, extraction pipeline, revision/conflict detection, entity resolution, projectors (graph, Prolog, memory), graph and discovery query/retrieval, incremental analysis, in-memory and file-backed stores, tuProlog integration, REST endpoints |
| `dice` | The entire domain: `Proposition` model, `PropositionStore`/`PropositionRepository` SPIs, extraction pipeline, revision/conflict detection, entity resolution, projectors (graph, Prolog, memory), graph and discovery query/retrieval, incremental analysis, in-memory and file-backed stores, tuProlog integration, REST endpoints, MCP tool surface (`DiceMcpTools`) |
| `dice-storage` | Drivine/Neo4j implementation of `PropositionRepository`, `ChunkHistoryStore`, and `DecayManager`; uses Kotlin 2.2 for the Drivine KSP-generated query DSL |
| `dice-storage-autoconfigure` | Spring Boot auto-configuration that wires the right backend based on `embabel.dice.store.type`, schedules the decay tick, and provides auto-configuration for the multi-signal duplicate collector (properties prefix `embabel.dice.collector`) |
| `dice-report` | Output projectors over propositions: rationale (why a fact is believed, with evidence), structured report, and surprising-link discovery |
| `dice-ingestion` | Ingestion SPI (artifacts → chunks) with a content-hash dedup ledger so the same source isn't extracted twice |
| `dice-integration-tests` | Test-only: the cross-feature end-to-end canonical-flow harness |
| `dice-mcp-autoconfigure` | Spring Boot auto-configuration that exports `DiceMcpTools` over MCP via embabel-agent when `embabel.dice.mcp.enabled=true` |

## Build & test

Expand Down Expand Up @@ -65,6 +66,7 @@ The `dice` module is organized by responsibility:
| `com.embabel.dice.provenance` | `ProvenanceEntry`, `SourceLocator` — rich evidence links from propositions back to source material |
| `com.embabel.dice.query.oracle` | `Oracle`, `LlmOracle`, `PrologTools` — natural language question answering over propositions |
| `com.embabel.dice.web.rest` | Optional REST endpoints for the pipeline and memory; activated by `spring-webmvc` on the classpath |
| `com.embabel.dice.mcp` | `DiceMcpTools`, `DiceMcpProfile` — simplified MCP/agent tool surface over propositions |

## Conventions

Expand All @@ -84,6 +86,7 @@ The `dice` module is organized by responsibility:

- **Adding or changing extraction logic** → `com.embabel.dice.proposition.extraction.LlmPropositionExtractor` and the Mustache prompt templates in `dice/src/main/resources/dice/`.
- **Wiring a new Spring Boot app** → `dice-storage-autoconfigure`, specifically `DiceStorageAutoConfiguration` (backend selection) and `DiceStoreProperties` (property keys). Set `embabel.dice.store.type=graph` for Neo4j.
- **Exposing DICE over MCP** → `DiceMcpTools` in `com.embabel.dice.mcp` for the tool surface; `dice-mcp-autoconfigure` + `embabel-agent-starter-mcpserver` for zero-code export (`embabel.dice.mcp.enabled=true`).
- **Understanding the proposition data model** → `Proposition.kt` in `com.embabel.dice.proposition`. Every field is documented inline.
- **Adding a new entity resolver strategy** → implement `CandidateSearcher` in `com.embabel.dice.common.resolver.searcher`, then compose it into an `EscalatingEntityResolver`.
- **Writing integration tests against Neo4j** → look at `DrivinePropositionStoreIntegrationTest` in `dice-storage/src/test`; it shows the `@SpringBootTest` + Testcontainers pattern in use.
Expand Down
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2412,6 +2412,56 @@ Everything is pushed into the database rather than scanned in memory:
> `dice-storage/HANDOFF.md` for architecture and `dice-storage/INTEGRATE-INTO-ASSISTANT.md` for a
> migration walkthrough.

### MCP Server

Expose DICE knowledge tools to any MCP-compatible client (Claude Desktop, Cursor, etc.)
using embabel-agent's MCP server starter and the `dice-mcp-autoconfigure` module.

```xml
<dependency>
<groupId>com.embabel.dice</groupId>
<artifactId>dice-mcp-autoconfigure</artifactId>
<version>${dice.version}</version>
</dependency>
<dependency>
<groupId>com.embabel.agent</groupId>
<artifactId>embabel-agent-starter-mcpserver</artifactId>
<version>${embabel-agent.version}</version>
</dependency>
```

```yaml
embabel:
dice:
mcp:
enabled: true
profile: core # dice_recall, dice_list, dice_store, dice_get
# profile: extended # + dice_extract, dice_assert_entities when wired
```

**Core tools** (always available when a `PropositionRepository` is configured):

| Tool | Description |
|------|-------------|
| `dice_recall` | Hybrid semantic + keyword search over propositions in a `context_id` |
| `dice_list` | List active propositions for a context |
| `dice_store` | Store a proposition directly |
| `dice_get` | Fetch one proposition by id |

**Extended tools** (exported when the host app wires the corresponding beans):

| Tool | Requires |
|------|----------|
| `dice_extract` | `PropositionPipeline`, `EntityResolver`, `SchemaRegistry` |
| `dice_assert_entities` | `EntityResolutionService` |

Programmatic export without Spring Boot:

```kotlin
val tools = DiceMcpTools(propositionRepository)
val export = McpToolExport.fromToolObject(ToolObject(objects = listOf(tools)))
```

### API Key Security

DICE provides API key authentication for the REST endpoints. Enable it via configuration:
Expand Down
81 changes: 81 additions & 0 deletions dice-mcp-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.embabel.dice</groupId>
<artifactId>dice-parent</artifactId>
<version>0.1.1-SNAPSHOT</version>
</parent>
<artifactId>dice-mcp-autoconfigure</artifactId>
<packaging>jar</packaging>
<name>Dice MCP Autoconfigure</name>
<description>Spring Boot auto-configuration that exports DICE tools over MCP via embabel-agent</description>

<dependencies>
<dependency>
<groupId>com.embabel.dice</groupId>
<artifactId>dice</artifactId>
</dependency>

<dependency>
<groupId>com.embabel.agent</groupId>
<artifactId>embabel-agent-mcpserver</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>com.embabel.agent</groupId>
<artifactId>embabel-agent-api</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<dependency>
<groupId>com.embabel.agent</groupId>
<artifactId>embabel-agent-test-common</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
<arg>-Xjvm-default=all</arg>
</args>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright 2024-2026 Embabel Pty Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.embabel.dice.mcp.autoconfigure

import com.embabel.agent.api.tool.ToolObject
import com.embabel.agent.mcpserver.McpToolExport
import com.embabel.dice.common.EntityResolver
import com.embabel.dice.common.SchemaRegistry
import com.embabel.dice.entity.EntityResolutionService
import com.embabel.dice.mcp.DiceMcpTools
import com.embabel.dice.pipeline.PropositionPipeline
import com.embabel.dice.proposition.PropositionRepository
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.ObjectProvider
import org.springframework.boot.autoconfigure.AutoConfiguration
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean

/**
* Registers [DiceMcpTools] and exports them as MCP tools when embabel-agent's MCP server is present.
*
* Typical application dependencies:
* ```xml
* <dependency>
* <groupId>com.embabel.dice</groupId>
* <artifactId>dice-mcp-autoconfigure</artifactId>
* </dependency>
* <dependency>
* <groupId>com.embabel.agent</groupId>
* <artifactId>embabel-agent-starter-mcpserver</artifactId>
* </dependency>
* ```
*
* ```yaml
* embabel:
* dice:
* mcp:
* enabled: true
* profile: core # or extended
* ```
*/
@AutoConfiguration
@ConditionalOnClass(McpToolExport::class)
@ConditionalOnProperty(prefix = "embabel.dice.mcp", name = ["enabled"], havingValue = "true")
@EnableConfigurationProperties(DiceMcpProperties::class)
open class DiceMcpAutoConfiguration {

private val logger = LoggerFactory.getLogger(DiceMcpAutoConfiguration::class.java)

@Bean
@ConditionalOnBean(PropositionRepository::class)
@ConditionalOnMissingBean(DiceMcpTools::class)
open fun diceMcpTools(
repository: PropositionRepository,
pipeline: ObjectProvider<PropositionPipeline>,
entityResolver: ObjectProvider<EntityResolver>,
schemaRegistry: ObjectProvider<SchemaRegistry>,
entityResolutionService: ObjectProvider<EntityResolutionService>,
properties: DiceMcpProperties,
): DiceMcpTools = DiceMcpTools(
repository = repository,
pipeline = pipeline.ifAvailable,
entityResolver = entityResolver.ifAvailable,
schemaRegistry = schemaRegistry.ifAvailable,
entityResolutionService = entityResolutionService.ifAvailable,
minConfidence = properties.minConfidence,
defaultLimit = properties.defaultLimit,
)

@Bean("diceMcpToolExport")
@ConditionalOnBean(DiceMcpTools::class)
@ConditionalOnMissingBean(name = ["diceMcpToolExport"])
open fun diceMcpToolExport(
tools: DiceMcpTools,
properties: DiceMcpProperties,
): McpToolExport {
val allowed = properties.profile.toolNames(
pipelineAvailable = tools.pipelineAvailable(),
entityResolutionAvailable = tools.entityResolutionAvailable(),
)
logger.info(
"Exporting DICE MCP tools (profile={}, count={}): {}",
properties.profile,
allowed.size,
allowed.sorted(),
)
return McpToolExport.fromToolObject(
ToolObject(
objects = listOf(tools),
filter = { name -> name in allowed },
),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2024-2026 Embabel Pty Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.embabel.dice.mcp.autoconfigure

import com.embabel.dice.mcp.DiceMcpProfile
import org.springframework.boot.context.properties.ConfigurationProperties

/**
* Configuration for exporting DICE as MCP tools.
*
* Requires `embabel-agent-starter-mcpserver` (or `embabel-agent-mcpserver`) on the classpath
* and `embabel.dice.mcp.enabled=true`.
*/
@ConfigurationProperties(prefix = "embabel.dice.mcp")
data class DiceMcpProperties(
/** Master switch. Default false so MCP export is opt-in. */
val enabled: Boolean = false,
/** Tool surface: [DiceMcpProfile.CORE] (4 tools) or [DiceMcpProfile.EXTENDED]. */
val profile: DiceMcpProfile = DiceMcpProfile.CORE,
/** Minimum effective confidence for recall/list tools (0.0–1.0). */
val minConfidence: Double = 0.5,
/** Default result limit for recall/list tools. */
val defaultLimit: Int = 10,
) {
init {
require(minConfidence in 0.0..1.0) { "embabel.dice.mcp.min-confidence must be between 0.0 and 1.0" }
require(defaultLimit > 0) { "embabel.dice.mcp.default-limit must be positive" }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.embabel.dice.mcp.autoconfigure.DiceMcpAutoConfiguration
1 change: 1 addition & 0 deletions dice/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ These map onto the lifecycle in [proposition-lifecycle](../docs/design/propositi
| `query.discovery` | `RetrievalRouter`, `DiscoveryQuery`, `RetrievalMode`, discovery DTOs — mode-routed retrieval entry point |
| `temporal` | `TemporalMetadata` — bitemporal valid/observed windows, explicit retraction |
| `agent` | `Memory`, `MemoryRetriever` (agent-facing view), `ProvenanceResolver`; **`DiscoveryTools`** — `@LlmTool`-annotated tools wrapping `RetrievalRouter` (query propositions, graph path, why-explain, projection health, collector dry-run) with context baked in at construction so an agent can't cross context boundaries; **`GraphQueryTools`** — `@LlmTool`-annotated tools wrapping the `GraphQuery` facade (entity neighbourhood, path between entities, why-explain) |
| `mcp` | `DiceMcpTools`, `DiceMcpProfile` — simplified MCP/agent tool surface (`dice_recall`, `dice_list`, `dice_store`, `dice_get`, optional `dice_extract` / `dice_assert_entities`) |
| `web.rest` | `PropositionPipelineController`, `MemoryController`, **`DiscoveryController`** — REST surface for discovery operations (`/api/v1/contexts/{contextId}/discovery`; routes query, path, why, projection health, and collector dry-run; context comes from the URL path only), API key security — optional, activated by `spring-webmvc` |
| `operations` | `PropositionAbstractor`, `PropositionContraster` — higher-level proposition management |
| `operations.consolidation` | The dream-loop steps as composable passes: `ConsolidationPass`/`ConsolidationPassResult`, `SessionConsolidationPass`, `AbstractionPass`, `ContradictionResolutionPass`, `DecaySweepPass` |
Expand Down
Loading