mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
Adds a fully self-contained `mcp/` package that exposes Semantica as a
Model Context Protocol server over stdio (JSON-RPC 2.0).
17 tools across 5 domains:
- Extraction: extract_entities, extract_relations, extract_all
- Decision intelligence: record_decision, query_decisions, find_precedents,
get_causal_chain, analyze_decision_impact
- Knowledge graph: add_entity, add_relationship, search_graph,
get_graph_summary, get_graph_analytics
- Reasoning: run_reasoning, abductive_reasoning
- Export & provenance: export_graph (JSON/CSV/GraphML/Parquet/RDF), get_provenance
4 resources: semantica://graph/summary, semantica://decisions/list,
semantica://schema/info, semantica://ontology/schema
Package layout:
mcp/__init__.py + __main__.py — entry points (python -m mcp)
mcp/server.py — SemanticaMCPServer + stdio event loop
mcp/session.py — lazy ContextGraph singleton
mcp/schemas.py — JSON Schema for all 17 tool inputs
mcp/tools/{extraction,decisions,graph,reasoning,export}.py
mcp/resources/registry.py — URI → handler map
mcp/README.md — per-tool setup (Claude Code, Cursor, Windsurf,
Cline, Continue, VS Code, Amazon Q)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
74 lines
2.6 KiB
Python
74 lines
2.6 KiB
Python
"""
|
|
Reasoning tools — forward chaining, abductive reasoning.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from mcp.schemas import ABDUCTIVE_REASONING, RUN_REASONING
|
|
|
|
log = logging.getLogger("semantica.mcp.tools.reasoning")
|
|
|
|
|
|
def handle_run_reasoning(args: dict) -> dict:
|
|
"""Run forward-chaining IF/THEN rules over facts to derive new knowledge."""
|
|
facts = args.get("facts", [])
|
|
rules = args.get("rules", [])
|
|
if not facts:
|
|
return {"error": "facts list is required", "derived_facts": []}
|
|
if not rules:
|
|
return {"error": "rules list is required", "derived_facts": []}
|
|
try:
|
|
from semantica.reasoning import Reasoner
|
|
reasoner = Reasoner()
|
|
for rule in rules:
|
|
reasoner.add_rule(str(rule))
|
|
derived = reasoner.infer_facts(facts)
|
|
result = derived if isinstance(derived, list) else list(derived)
|
|
return {
|
|
"derived_facts": result,
|
|
"count": len(result),
|
|
"input_facts": len(facts),
|
|
"rules_applied": len(rules),
|
|
}
|
|
except Exception as exc:
|
|
log.exception("run_reasoning failed")
|
|
return {"error": str(exc), "derived_facts": []}
|
|
|
|
|
|
def handle_abductive_reasoning(args: dict) -> dict:
|
|
"""Generate plausible hypotheses that explain a set of observations."""
|
|
observations = args.get("observations", [])
|
|
if not observations:
|
|
return {"error": "observations list is required", "hypotheses": []}
|
|
max_hypotheses = int(args.get("max_hypotheses", 5))
|
|
try:
|
|
from semantica.reasoning import AbductiveReasoner
|
|
reasoner = AbductiveReasoner()
|
|
hypotheses = reasoner.generate_hypotheses(observations)
|
|
result = hypotheses if isinstance(hypotheses, list) else list(hypotheses)
|
|
return {
|
|
"hypotheses": result[:max_hypotheses],
|
|
"count": min(len(result), max_hypotheses),
|
|
}
|
|
except Exception as exc:
|
|
log.exception("abductive_reasoning failed")
|
|
return {"error": str(exc), "hypotheses": []}
|
|
|
|
|
|
REASONING_TOOLS = [
|
|
{
|
|
"name": "run_reasoning",
|
|
"description": "Run forward-chaining IF/THEN rules over a set of facts to derive new facts. E.g. facts=['Person(John)'], rules=['IF Person(?x) THEN Mortal(?x)'] → derives 'Mortal(John)'.",
|
|
"inputSchema": RUN_REASONING,
|
|
"_handler": handle_run_reasoning,
|
|
},
|
|
{
|
|
"name": "abductive_reasoning",
|
|
"description": "Generate plausible hypotheses that best explain a set of observed facts.",
|
|
"inputSchema": ABDUCTIVE_REASONING,
|
|
"_handler": handle_abductive_reasoning,
|
|
},
|
|
]
|