MCP Fact Graph
Positioning:
mcp_fact_graphis an internal component of the MakeMind knowledge stack exposed through themcp_knowledgefacade. Application code should importpackage:mcp_knowledge/mcp_knowledge.dart— the symbols declared here are re-exported from there. Directpackage:mcp_fact_graph/imports remain valid for advanced or integration scenarios but are discouraged in product code.
A temporal knowledge graph for evidence-based fact management with candidates, summaries, and skill-execution claims. The persistence and query backbone of the MakeMind knowledge stack.
Architecture
A 4-layer model:
- L0 Evidence — raw fragments and evidence ingested from sources;
LlmEvidencePortsplits raw text into typed evidence units (decision, task, question, state, fact, insight) with an injectedLlmPort. - L1 FactGraph — entities, candidates, facts (who confirmed them, retraction that keeps the provenance, point-in-time queries with
asOf), relations, fact clusters, classifications, fact policies, automations, runs, artifacts. - L2 ContextOps — context bundles, summaries, claims, response validation.
- L3 SkillOps — patterns, skills, rubrics, evaluation runs.
Cross-cutting domain entities reduce LLM calls (extraction rules / validators, classifier memory, disambiguation decisions, LLM call log, idempotency records).
Contract Layer
Implements mcp_bundle standard ports through capability-named adapters under src/adapters/. FactGraphRuntime composes the services, the workers and the adapters over a set of storage ports (FactGraphStorages): FactGraphRuntime.inMemory() for development and tests, FactGraphRuntime.fromStorages(host) over a host's own persistence. Every write passes the integrity rules, and every read that selects records asks a store index (facts by workspace, type, entity, evidence, term and recency; entities by name and by mention; candidates and claims by status; relations and edges by node). checkStorageConformance tells a host what its storage honours. The package ships mechanisms and neutral defaults; what carries judgement is the host's and comes in as values or ports: the words of the response policy (ResponsePolicy, with ResponsePolicy.multilingual() as a ready-made set), the object types that require fields (FactGraphService.starterMinimumFields), the domain views (starterViewComputers), the query word forms (queryTermExpander), the token count for the model served (tokenEstimator), the normal form of names (nameNormalizer), the fragment extractor for the host's language, and the scales (ScalePort) that say which qualitative words name which value ranges — so "sky blue" and a stored hue of 197° are one fact, judged the same whatever model wrote the answer, and a value is spoken in the reader's words at the reader's resolution.
Quick Start
import 'package:mcp_fact_graph/mcp_fact_graph.dart';
Future<void> main() async {
// The engine ships mechanisms; the words it judges by, the object types it
// requires fields of and the domain views it computes are the host's. The
// multilingual policy and the starter sets are ready-made choices.
final graph = FactGraphRuntime.inMemory(
defaultWorkspaceId: 'demo',
responsePolicy: const ResponsePolicy.multilingual(),
minimumFields: FactGraphService.starterMinimumFields,
viewComputers: starterViewComputers,
);
// L0: evidence and a fragment read from it.
final evidence = await graph.evidenceService.ingestEvidence(IngestionInput(
workspaceId: 'demo',
sourceType: EvidenceSourceType.text,
sourceId: 'meeting-notes',
content: 'Pilot is set for December 12. Legal review is due November 8.',
));
final fragment = await graph.evidenceService.addFragment(
evidence.evidenceId,
{'summary': 'Pilot is set for December 12'},
);
// L1: a candidate built from the fragment, confirmed into a fact.
final candidate = await graph.factGraphService.createCandidate(
workspaceId: 'demo',
objectType: 'decision',
fragments: [fragment],
);
final confirmation =
await graph.factGraphService.confirmCandidate(candidate.candidateId);
print('fact ${confirmation.factId}');
// Read-only search, ranked by the terms the facts share with the query.
final found = await graph.factGraphService
.searchFacts(workspaceId: 'demo', query: 'pilot december');
// L2: the context bundle for a question, within a token budget.
final bundle = await graph.contextService.buildContext(
workspaceId: 'demo',
query: 'When is the pilot?',
tokenBudget: 512,
);
// L2: an answer checked against the facts before it reaches the user.
final check = await graph.responseValidationService!.validate(
workspaceId: 'demo',
responseText: 'The pilot is set for December 12.',
);
print('${found.length} found, ${bundle.facts.length} in the bundle, '
'${check.result.name}');
}
The same program is in example/example.dart. Korean, Japanese and Chinese text is searched and matched like English (one text analysis, TextTerms).
Support
License
MIT — see LICENSE.
Libraries
- mcp_fact_graph
- MCP Fact Graph - Knowledge representation with 4-layer architecture.