From ab93ec3e8f1ad4d88859c54e9e6c96b540226674 Mon Sep 17 00:00:00 2001 From: KaifAhmad1 Date: Mon, 13 Apr 2026 16:59:45 +0530 Subject: [PATCH] feat(plugins): add MCP server + 4 new plugin bundles (Windsurf, Cline, Continue, VS Code) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MCP Server (semantica/mcp_server.py): - Full stdio-based MCP server compatible with Claude Desktop, Windsurf, Cline, Continue, VS Code, Roo Code, and any MCP-aware tool - 12 tools: extract_entities, extract_relations, record_decision, query_decisions, find_precedents, get_causal_chain, add_entity, add_relationship, run_reasoning, get_graph_analytics, export_graph, get_graph_summary - 3 resources: semantica://graph/summary, semantica://decisions/list, semantica://schema/info - Lazy graph session with optional SEMANTICA_KG_PATH env var - JSON-RPC 2.0 over stdin/stdout; run with: python -m semantica.mcp_server New plugin bundles (each: plugin.json + marketplace.json + README.md): - plugins/.windsurf-plugin/ — Windsurf MCP config + 17 skills + 3 agents - plugins/.cline-plugin/ — Cline MCP config + 17 skills + 3 agents - plugins/.continue-plugin/ — Continue MCP config + 17 skills + 3 agents - plugins/.vscode-plugin/ — VS Code MCP config + 17 skills + 3 agents Updated plugins/.claude-plugin/README.md: - Platform support table expanded to 9 tools - Full MCP server section: per-tool config snippets for Claude Desktop, Windsurf, Cline, Continue, VS Code; tool/resource reference tables; environment variables Updated README.md: - Hero line updated to mention MCP server - Visual grid: Windsurf/VS Code/Cline/Continue → 'MCP server + plugin'; Claude Desktop → 'MCP server' - Plugin Bundles section: expanded table listing all 7 bundles with dirs - New MCP Server section with quick-start snippet and tool/resource list - Detailed integrations table: corrected connection types and config paths Co-Authored-By: Claude Sonnet 4.6 --- README.md | 65 ++- plugins/.claude-plugin/README.md | 140 ++++- plugins/.cline-plugin/README.md | 24 + plugins/.cline-plugin/marketplace.json | 17 + plugins/.cline-plugin/plugin.json | 35 ++ plugins/.continue-plugin/README.md | 26 + plugins/.continue-plugin/marketplace.json | 17 + plugins/.continue-plugin/plugin.json | 33 ++ plugins/.vscode-plugin/README.md | 36 ++ plugins/.vscode-plugin/marketplace.json | 17 + plugins/.vscode-plugin/plugin.json | 35 ++ plugins/.windsurf-plugin/README.md | 29 ++ plugins/.windsurf-plugin/marketplace.json | 17 + plugins/.windsurf-plugin/plugin.json | 35 ++ semantica/mcp_server.py | 606 ++++++++++++++++++++++ 15 files changed, 1108 insertions(+), 24 deletions(-) create mode 100644 plugins/.cline-plugin/README.md create mode 100644 plugins/.cline-plugin/marketplace.json create mode 100644 plugins/.cline-plugin/plugin.json create mode 100644 plugins/.continue-plugin/README.md create mode 100644 plugins/.continue-plugin/marketplace.json create mode 100644 plugins/.continue-plugin/plugin.json create mode 100644 plugins/.vscode-plugin/README.md create mode 100644 plugins/.vscode-plugin/marketplace.json create mode 100644 plugins/.vscode-plugin/plugin.json create mode 100644 plugins/.windsurf-plugin/README.md create mode 100644 plugins/.windsurf-plugin/marketplace.json create mode 100644 plugins/.windsurf-plugin/plugin.json create mode 100644 semantica/mcp_server.py diff --git a/README.md b/README.md index 6385c279..dd0e2abe 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ pip install semantica ## 🔌 Works With Every AI Tool -Semantica ships **native plugin bundles** for Claude Code, Cursor, and Codex — and connects to any other tool via its **REST API** (FastAPI server, port 8000) or as an **MCP data source** you can pull from. +Semantica ships **native plugin bundles** for Claude Code, Cursor, and Codex, an **MCP server** (`python -m semantica.mcp_server`) for Windsurf, Cline, Continue, VS Code, and Claude Desktop, and a **REST API** (FastAPI, port 8000) for any other tool. @@ -77,17 +77,17 @@ Semantica ships **native plugin bundles** for Claude Code, Cursor, and Codex — @@ -109,7 +109,7 @@ Semantica ships **native plugin bundles** for Claude Code, Cursor, and Codex —
Windsurf
Windsurf
-REST API +MCP server + plugin
Claude Desktop
Claude Desktop
-REST API +MCP server
VS Code
VS Code
-REST API +MCP server + plugin
GitHub Copilot
@@ -97,7 +97,7 @@ Semantica ships **native plugin bundles** for Claude Code, Cursor, and Codex —
Cline
Cline
-REST API +MCP server + plugin
Continue
Continue
-REST API +MCP server + plugin
Goose
@@ -146,7 +146,17 @@ Semantica ships **native plugin bundles** for Claude Code, Cursor, and Codex — ### Plugin Bundles (Claude Code · Cursor · Codex) -Native plugin bundles live under [`plugins/`](plugins/) — install once, works across all three tools. +Native plugin bundles live under [`plugins/`](plugins/). Each directory contains a `plugin.json`, `marketplace.json`, and `README.md`. + +| Bundle | Directory | Tools | +|---|---|---| +| Claude Code | [`plugins/.claude-plugin/`](plugins/.claude-plugin/) | 17 skills · 3 agents · hooks | +| Cursor | [`plugins/.cursor-plugin/`](plugins/.cursor-plugin/) | 17 skills · 3 agents · hooks | +| Codex CLI | [`plugins/.codex-plugin/`](plugins/.codex-plugin/) | 17 skills · 3 agents | +| Windsurf | [`plugins/.windsurf-plugin/`](plugins/.windsurf-plugin/) | 17 skills · 3 agents · MCP config | +| Cline | [`plugins/.cline-plugin/`](plugins/.cline-plugin/) | 17 skills · 3 agents · MCP config | +| Continue | [`plugins/.continue-plugin/`](plugins/.continue-plugin/) | 17 skills · 3 agents · MCP config | +| VS Code | [`plugins/.vscode-plugin/`](plugins/.vscode-plugin/) | 17 skills · 3 agents · MCP config | **17 domain skills:** @@ -182,9 +192,36 @@ Native plugin bundles live under [`plugins/`](plugins/) — install once, works → [`plugins/.claude-plugin/README.md`](plugins/.claude-plugin/README.md) +### MCP Server (expose Semantica to any MCP-aware tool) + +Semantica ships a full **MCP server** (`semantica/mcp_server.py`) — run it once and any MCP-compatible tool connects automatically: + +```bash +python -m semantica.mcp_server +``` + +Add to your tool's config (Claude Desktop, Windsurf, Cline, Continue, VS Code, Roo Code): + +```json +{ + "mcpServers": { + "semantica": { + "command": "python", + "args": ["-m", "semantica.mcp_server"] + } + } +} +``` + +**12 tools exposed:** `extract_entities`, `extract_relations`, `record_decision`, `query_decisions`, `find_precedents`, `get_causal_chain`, `add_entity`, `add_relationship`, `run_reasoning`, `get_graph_analytics`, `export_graph`, `get_graph_summary` + +**3 resources:** `semantica://graph/summary`, `semantica://decisions/list`, `semantica://schema/info` + +See [`plugins/.claude-plugin/README.md`](plugins/.claude-plugin/README.md) for per-tool config snippets. + ### MCP Client (Ingest from MCP Servers) -Semantica includes an **MCP client** (`semantica/ingest/mcp_client.py`) that lets you pull data from any Python/FastMCP server into a knowledge graph: +Semantica also includes an **MCP client** (`semantica/ingest/mcp_client.py`) that lets you pull data from any Python/FastMCP server into a knowledge graph: ```python from semantica.ingest import MCPClient @@ -825,13 +862,13 @@ Start the Semantica server (`python -m semantica.server`, port 8000) and point a | [Claude Code](https://claude.com/product/claude-code) | **Native plugin** | `plugins/.claude-plugin/` — 17 skills, 3 agents, `hooks.json` | | [Cursor](https://cursor.com) | **Native plugin** | `plugins/.cursor-plugin/` — same 17 skills + 3 agents | | [Codex CLI](https://github.com/openai/codex) | **Native plugin** | `plugins/.codex-plugin/` — same 17 skills + 3 agents | -| [Windsurf](https://windsurf.com) | REST API | Point at `http://localhost:8000/api` | -| [Claude Desktop](https://claude.ai/download) | REST API | Point at `http://localhost:8000/api` | -| [VS Code](https://github.com/microsoft/vscode) | REST API | Use any REST client extension | +| [Windsurf](https://windsurf.com) | **MCP server** + plugin | `plugins/.windsurf-plugin/` · add `python -m semantica.mcp_server` to `~/.codeium/windsurf/mcp_config.json` | +| [Claude Desktop](https://claude.ai/download) | **MCP server** | Add `python -m semantica.mcp_server` to `claude_desktop_config.json` | +| [VS Code](https://github.com/microsoft/vscode) | **MCP server** + plugin | `plugins/.vscode-plugin/` · add to `settings.json` under `mcp.servers` | | [GitHub Copilot](https://github.com/features/copilot) | REST API | Use via Copilot Chat custom tools | -| [Cline](https://github.com/cline/cline) | REST API | Add as a custom tool endpoint | -| [Roo Code](https://github.com/RooCodeInc/Roo-Code) | REST API | Add as a custom tool endpoint | -| [Continue](https://github.com/continuedev/continue) | REST API | Add to `~/.continue/config.json` as context provider | +| [Cline](https://github.com/cline/cline) | **MCP server** + plugin | `plugins/.cline-plugin/` · add server in Cline MCP settings panel | +| [Roo Code](https://github.com/RooCodeInc/Roo-Code) | **MCP server** | Add `python -m semantica.mcp_server` in Roo Code MCP settings | +| [Continue](https://github.com/continuedev/continue) | **MCP server** + plugin | `plugins/.continue-plugin/` · add to `~/.continue/config.json` under `mcpServers` | | [Goose](https://github.com/block/goose) | REST API | Add to Goose toolset config | | [Kilo Code](https://github.com/Kilo-Org/kilocode) | REST API | Add as custom REST tool | | [Aider](https://github.com/Aider-AI/aider) | REST API | Pass context from the API into prompts | diff --git a/plugins/.claude-plugin/README.md b/plugins/.claude-plugin/README.md index 8aca646c..2b6beaad 100644 --- a/plugins/.claude-plugin/README.md +++ b/plugins/.claude-plugin/README.md @@ -2,13 +2,21 @@ Semantica ships a shared plugin bundle under `plugins/` with skills, agents, and hooks for knowledge graphs, context graphs, decision intelligence, reasoning, explainability, provenance, ontology, and export workflows. -This README is for community users who want to install or reuse the plugin package across Claude, Cursor, and Codex. +This README covers installation across every supported platform. ## Supported Platforms -- Claude Code -- Cursor -- Codex +| Platform | Method | Config file | +|---|---|---| +| Claude Code | Native plugin bundle | `plugins/.claude-plugin/plugin.json` | +| Cursor | Native plugin bundle | `plugins/.cursor-plugin/plugin.json` | +| Codex CLI | Native plugin bundle | `plugins/.codex-plugin/plugin.json` | +| Windsurf | MCP server + plugin bundle | `plugins/.windsurf-plugin/plugin.json` | +| Cline (VS Code) | MCP server + plugin bundle | `plugins/.cline-plugin/plugin.json` | +| Continue | MCP server | `plugins/.continue-plugin/plugin.json` | +| VS Code | MCP server | `plugins/.vscode-plugin/plugin.json` | +| Claude Desktop | MCP server | — (see MCP section below) | +| Any MCP client | MCP server | `python -m semantica.mcp_server` | ## Prerequisites @@ -23,12 +31,16 @@ cd semantica ```text plugins/ - skills/ - agents/ - hooks/ - .claude-plugin/ - .cursor-plugin/ - .codex-plugin/ + skills/ ← 17 domain skills + agents/ ← 3 specialized agents + hooks/ ← hooks.json + .claude-plugin/ ← Claude Code manifest + .cursor-plugin/ ← Cursor manifest + .codex-plugin/ ← Codex CLI manifest + .windsurf-plugin/← Windsurf manifest + MCP config + .cline-plugin/ ← Cline manifest + MCP config + .continue-plugin/← Continue manifest + MCP config + .vscode-plugin/ ← VS Code manifest + MCP config ``` ## Plugin Contents @@ -128,6 +140,114 @@ After installing on any platform, these are good smoke tests: 4. `/semantica:explain decision ` 5. `/semantica:validate graph` +## MCP Server (Windsurf · Cline · Continue · VS Code · Claude Desktop · Any tool) + +Semantica includes a full MCP server (`semantica/mcp_server.py`) that exposes 12 tools and 3 resources over stdio — compatible with any MCP-aware tool. + +### Start the server + +```bash +python -m semantica.mcp_server +``` + +### Configure in your tool + +**Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows): + +```json +{ + "mcpServers": { + "semantica": { + "command": "python", + "args": ["-m", "semantica.mcp_server"] + } + } +} +``` + +**Windsurf** — `~/.codeium/windsurf/mcp_config.json`: + +```json +{ + "mcpServers": { + "semantica": { + "command": "python", + "args": ["-m", "semantica.mcp_server"] + } + } +} +``` + +**Cline** — Cline MCP settings panel → Add server: + +```json +{ + "semantica": { + "command": "python", + "args": ["-m", "semantica.mcp_server"] + } +} +``` + +**Continue** — `~/.continue/config.json`: + +```json +{ + "mcpServers": [ + { + "name": "semantica", + "command": "python", + "args": ["-m", "semantica.mcp_server"] + } + ] +} +``` + +**VS Code** — `settings.json`: + +```json +{ + "mcp.servers": { + "semantica": { + "command": "python", + "args": ["-m", "semantica.mcp_server"] + } + } +} +``` + +### Available MCP tools + +| Tool | Description | +|---|---| +| `extract_entities` | Named entity recognition from text | +| `extract_relations` | Relation and triplet extraction from text | +| `record_decision` | Record a decision with full context and metadata | +| `query_decisions` | Query recorded decisions by natural language or category | +| `find_precedents` | Find past decisions similar to a scenario | +| `get_causal_chain` | Trace upstream/downstream causal chain from a decision | +| `add_entity` | Add a node/entity to the knowledge graph | +| `add_relationship` | Add a directed edge between two entities | +| `run_reasoning` | Run IF/THEN rules over facts to derive new facts | +| `get_graph_analytics` | PageRank centrality and community detection | +| `export_graph` | Export graph as Turtle, JSON-LD, N-Triples, or JSON | +| `get_graph_summary` | Node count, decision count, graph status | + +### Available MCP resources + +| URI | Description | +|---|---| +| `semantica://graph/summary` | High-level graph statistics | +| `semantica://decisions/list` | All recorded decisions | +| `semantica://schema/info` | Server info and capability list | + +### Environment variables + +| Variable | Description | +|---|---| +| `SEMANTICA_KG_PATH` | Path to a persisted graph to load on start | +| `SEMANTICA_LOG_LEVEL` | Log level: DEBUG, INFO, WARNING (default: WARNING) | + ## Community Notes - Keep plugin name/version/keywords updated in each manifest before publishing. diff --git a/plugins/.cline-plugin/README.md b/plugins/.cline-plugin/README.md new file mode 100644 index 00000000..c097b82b --- /dev/null +++ b/plugins/.cline-plugin/README.md @@ -0,0 +1,24 @@ +# Semantica — Cline Plugin + +Adds all 17 Semantica skills, 3 agents, and hook configuration to Cline (VS Code extension). + +## MCP Server Setup (recommended) + +In Cline settings, add a new MCP server: + +```json +{ + "semantica": { + "command": "python", + "args": ["-m", "semantica.mcp_server"], + "env": {} + } +} +``` + +Cline will discover all 12 Semantica tools automatically on connection. + +## Requirements + +- Python 3.8+ +- `pip install semantica` diff --git a/plugins/.cline-plugin/marketplace.json b/plugins/.cline-plugin/marketplace.json new file mode 100644 index 00000000..335fb8fc --- /dev/null +++ b/plugins/.cline-plugin/marketplace.json @@ -0,0 +1,17 @@ +{ + "name": "semantica-cline", + "plugins": [ + { + "name": "semantica", + "description": "Semantica plugin for Cline: knowledge graph skills, reasoning, extraction, and visualization.", + "source": "./", + "category": "Productivity", + "tags": [ + "knowledge-graph", + "reasoning", + "semantica", + "cline" + ] + } + ] +} diff --git a/plugins/.cline-plugin/plugin.json b/plugins/.cline-plugin/plugin.json new file mode 100644 index 00000000..81c004c4 --- /dev/null +++ b/plugins/.cline-plugin/plugin.json @@ -0,0 +1,35 @@ +{ + "name": "semantica-cline", + "displayName": "Semantica Cline Plugin", + "description": "Semantica plugin for Cline: knowledge graph skills, decision intelligence, reasoning, extraction, and visualization.", + "version": "0.1.0", + "author": { + "name": "Semantica Contributors" + }, + "homepage": "https://github.com/Hawksight-AI/semantica", + "repository": "https://github.com/Hawksight-AI/semantica", + "license": "MIT", + "keywords": [ + "semantica", + "knowledge graph", + "cline", + "context graphs", + "decision intelligence", + "explainability", + "causal analysis", + "provenance", + "ontology", + "graph analytics", + "semantic extraction", + "visualization", + "reasoning", + "mcp" + ], + "skills": "../skills", + "agents": "../agents", + "hooks": "../hooks/hooks.json", + "mcp": { + "server": "python -m semantica.mcp_server", + "transport": "stdio" + } +} diff --git a/plugins/.continue-plugin/README.md b/plugins/.continue-plugin/README.md new file mode 100644 index 00000000..b1a4ca2d --- /dev/null +++ b/plugins/.continue-plugin/README.md @@ -0,0 +1,26 @@ +# Semantica — Continue Plugin + +Adds Semantica as an MCP server and context provider to [Continue.dev](https://continue.dev). + +## MCP Server Setup + +Add to `~/.continue/config.json`: + +```json +{ + "mcpServers": [ + { + "name": "semantica", + "command": "python", + "args": ["-m", "semantica.mcp_server"] + } + ] +} +``` + +Continue will show all Semantica tools in the `@semantica` context provider dropdown. + +## Requirements + +- Python 3.8+ +- `pip install semantica` diff --git a/plugins/.continue-plugin/marketplace.json b/plugins/.continue-plugin/marketplace.json new file mode 100644 index 00000000..0ff7e099 --- /dev/null +++ b/plugins/.continue-plugin/marketplace.json @@ -0,0 +1,17 @@ +{ + "name": "semantica-continue", + "plugins": [ + { + "name": "semantica", + "description": "Semantica plugin for Continue.dev: knowledge graph context provider, reasoning, and extraction.", + "source": "./", + "category": "Productivity", + "tags": [ + "knowledge-graph", + "reasoning", + "semantica", + "continue" + ] + } + ] +} diff --git a/plugins/.continue-plugin/plugin.json b/plugins/.continue-plugin/plugin.json new file mode 100644 index 00000000..da93dc38 --- /dev/null +++ b/plugins/.continue-plugin/plugin.json @@ -0,0 +1,33 @@ +{ + "name": "semantica-continue", + "displayName": "Semantica Continue Plugin", + "description": "Semantica plugin for Continue.dev: knowledge graph context provider, decision intelligence, reasoning, and semantic extraction.", + "version": "0.1.0", + "author": { + "name": "Semantica Contributors" + }, + "homepage": "https://github.com/Hawksight-AI/semantica", + "repository": "https://github.com/Hawksight-AI/semantica", + "license": "MIT", + "keywords": [ + "semantica", + "knowledge graph", + "continue", + "context provider", + "decision intelligence", + "explainability", + "causal analysis", + "provenance", + "ontology", + "semantic extraction", + "reasoning", + "mcp" + ], + "skills": "../skills", + "agents": "../agents", + "hooks": "../hooks/hooks.json", + "mcp": { + "server": "python -m semantica.mcp_server", + "transport": "stdio" + } +} diff --git a/plugins/.vscode-plugin/README.md b/plugins/.vscode-plugin/README.md new file mode 100644 index 00000000..5a0b7531 --- /dev/null +++ b/plugins/.vscode-plugin/README.md @@ -0,0 +1,36 @@ +# Semantica — VS Code Plugin + +Adds Semantica as an MCP server to VS Code (via GitHub Copilot Chat or any MCP-aware extension). + +## MCP Server Setup + +Add to your VS Code `settings.json`: + +```json +{ + "github.copilot.chat.mcp.servers": { + "semantica": { + "command": "python", + "args": ["-m", "semantica.mcp_server"] + } + } +} +``` + +Or if using the VS Code MCP extension directly: + +```json +{ + "mcp.servers": { + "semantica": { + "command": "python", + "args": ["-m", "semantica.mcp_server"] + } + } +} +``` + +## Requirements + +- Python 3.8+ +- `pip install semantica` diff --git a/plugins/.vscode-plugin/marketplace.json b/plugins/.vscode-plugin/marketplace.json new file mode 100644 index 00000000..76f4b2a2 --- /dev/null +++ b/plugins/.vscode-plugin/marketplace.json @@ -0,0 +1,17 @@ +{ + "name": "semantica-vscode", + "plugins": [ + { + "name": "semantica", + "description": "Semantica plugin for VS Code: knowledge graph skills, reasoning, extraction, and visualization.", + "source": "./", + "category": "Productivity", + "tags": [ + "knowledge-graph", + "reasoning", + "semantica", + "vscode" + ] + } + ] +} diff --git a/plugins/.vscode-plugin/plugin.json b/plugins/.vscode-plugin/plugin.json new file mode 100644 index 00000000..a39c097e --- /dev/null +++ b/plugins/.vscode-plugin/plugin.json @@ -0,0 +1,35 @@ +{ + "name": "semantica-vscode", + "displayName": "Semantica VS Code Plugin", + "description": "Semantica plugin for VS Code: knowledge graph skills, decision intelligence, reasoning, extraction, and visualization via MCP server.", + "version": "0.1.0", + "author": { + "name": "Semantica Contributors" + }, + "homepage": "https://github.com/Hawksight-AI/semantica", + "repository": "https://github.com/Hawksight-AI/semantica", + "license": "MIT", + "keywords": [ + "semantica", + "knowledge graph", + "vscode", + "context graphs", + "decision intelligence", + "explainability", + "causal analysis", + "provenance", + "ontology", + "graph analytics", + "semantic extraction", + "visualization", + "reasoning", + "mcp" + ], + "skills": "../skills", + "agents": "../agents", + "hooks": "../hooks/hooks.json", + "mcp": { + "server": "python -m semantica.mcp_server", + "transport": "stdio" + } +} diff --git a/plugins/.windsurf-plugin/README.md b/plugins/.windsurf-plugin/README.md new file mode 100644 index 00000000..4718e807 --- /dev/null +++ b/plugins/.windsurf-plugin/README.md @@ -0,0 +1,29 @@ +# Semantica — Windsurf Plugin + +Adds all 17 Semantica skills, 3 agents, and hook configuration to Windsurf. + +## MCP Server Setup (recommended) + +Add to your Windsurf MCP config (`~/.codeium/windsurf/mcp_config.json`): + +```json +{ + "mcpServers": { + "semantica": { + "command": "python", + "args": ["-m", "semantica.mcp_server"] + } + } +} +``` + +Windsurf will then have access to all 12 Semantica tools (extract, record_decision, query_decisions, find_precedents, get_causal_chain, add_entity, add_relationship, run_reasoning, get_graph_analytics, export_graph, and more) directly in the AI panel. + +## Skills + +All 17 skills under `plugins/skills/` are available as slash commands once the plugin is loaded. + +## Requirements + +- Python 3.8+ +- `pip install semantica` diff --git a/plugins/.windsurf-plugin/marketplace.json b/plugins/.windsurf-plugin/marketplace.json new file mode 100644 index 00000000..e5ea82db --- /dev/null +++ b/plugins/.windsurf-plugin/marketplace.json @@ -0,0 +1,17 @@ +{ + "name": "semantica-windsurf", + "plugins": [ + { + "name": "semantica", + "description": "Semantica plugin for Windsurf: knowledge graph skills, reasoning, extraction, and visualization.", + "source": "./", + "category": "Productivity", + "tags": [ + "knowledge-graph", + "reasoning", + "semantica", + "windsurf" + ] + } + ] +} diff --git a/plugins/.windsurf-plugin/plugin.json b/plugins/.windsurf-plugin/plugin.json new file mode 100644 index 00000000..cbf45713 --- /dev/null +++ b/plugins/.windsurf-plugin/plugin.json @@ -0,0 +1,35 @@ +{ + "name": "semantica-windsurf", + "displayName": "Semantica Windsurf Plugin", + "description": "Semantica plugin for Windsurf: knowledge graph skills, decision intelligence, reasoning, extraction, and visualization.", + "version": "0.1.0", + "author": { + "name": "Semantica Contributors" + }, + "homepage": "https://github.com/Hawksight-AI/semantica", + "repository": "https://github.com/Hawksight-AI/semantica", + "license": "MIT", + "keywords": [ + "semantica", + "knowledge graph", + "windsurf", + "context graphs", + "decision intelligence", + "explainability", + "causal analysis", + "provenance", + "ontology", + "graph analytics", + "semantic extraction", + "visualization", + "reasoning", + "mcp" + ], + "skills": "../skills", + "agents": "../agents", + "hooks": "../hooks/hooks.json", + "mcp": { + "server": "python -m semantica.mcp_server", + "transport": "stdio" + } +} diff --git a/semantica/mcp_server.py b/semantica/mcp_server.py new file mode 100644 index 00000000..ee1fb805 --- /dev/null +++ b/semantica/mcp_server.py @@ -0,0 +1,606 @@ +""" +Semantica MCP Server + +Exposes Semantica's knowledge graph, decision intelligence, semantic extraction, +reasoning, and analytics capabilities as an MCP (Model Context Protocol) server +over stdio — compatible with Claude Desktop, Windsurf, Cline, Continue, VS Code, +Roo Code, and any other MCP-aware tool. + +Usage +----- +Configure in your tool's MCP settings: + + Claude Desktop / Windsurf / Cline / Continue / VS Code: + { + "mcpServers": { + "semantica": { + "command": "python", + "args": ["-m", "semantica.mcp_server"] + } + } + } + +Run directly: + python -m semantica.mcp_server + +Environment variables: + SEMANTICA_KG_PATH — path to a persisted graph to load on start (optional) + SEMANTICA_LOG_LEVEL — log level: DEBUG, INFO, WARNING (default: WARNING) +""" + +from __future__ import annotations + +import json +import logging +import os +import sys +from typing import Any + +# ── logging ──────────────────────────────────────────────────────────────── +_log_level = getattr(logging, os.environ.get("SEMANTICA_LOG_LEVEL", "WARNING").upper(), logging.WARNING) +logging.basicConfig(stream=sys.stderr, level=_log_level, + format="%(asctime)s [semantica-mcp] %(levelname)s %(message)s") +log = logging.getLogger("semantica.mcp_server") + +# ── lazy graph session ────────────────────────────────────────────────────── +_graph: Any = None + + +def _get_graph(): + global _graph + if _graph is None: + from semantica.context import ContextGraph + _graph = ContextGraph(advanced_analytics=True) + kg_path = os.environ.get("SEMANTICA_KG_PATH") + if kg_path and os.path.exists(kg_path): + try: + _graph.load(kg_path) + log.info("Loaded graph from %s", kg_path) + except Exception as exc: + log.warning("Could not load graph from %s: %s", kg_path, exc) + return _graph + + +# ══════════════════════════════════════════════════════════════════════════════ +# Tool implementations +# ══════════════════════════════════════════════════════════════════════════════ + +def _tool_extract_entities(args: dict) -> dict: + """Extract named entities from text.""" + text = args.get("text", "") + if not text: + return {"error": "text is required"} + from semantica.semantic_extract import NamedEntityRecognizer + from semantica.semantic_extract.cache import _result_cache + _result_cache.clear() + entities = NamedEntityRecognizer().extract(text) + return { + "entities": [ + {"label": getattr(e, "label", str(e)), + "type": getattr(e, "type", None), + "start": getattr(e, "start", None), + "end": getattr(e, "end", None)} + for e in (entities or []) + ] + } + + +def _tool_extract_relations(args: dict) -> dict: + """Extract relations and triplets from text.""" + text = args.get("text", "") + if not text: + return {"error": "text is required"} + from semantica.semantic_extract import RelationExtractor, TripletExtractor + from semantica.semantic_extract.cache import _result_cache + _result_cache.clear() + relations = RelationExtractor().extract(text) + triplets = TripletExtractor().extract(text) + return { + "relations": [ + {"source": getattr(r, "source", None), + "type": getattr(r, "type", None), + "target": getattr(r, "target", None)} + for r in (relations or []) + ], + "triplets": [ + {"subject": getattr(t, "subject", None), + "predicate": getattr(t, "predicate", None), + "object": getattr(t, "object", None)} + for t in (triplets or []) + ], + } + + +def _tool_record_decision(args: dict) -> dict: + """Record a decision with full context into the graph.""" + required = ["category", "scenario", "reasoning", "outcome", "confidence"] + for field in required: + if field not in args: + return {"error": f"missing required field: {field}"} + graph = _get_graph() + decision_id = graph.record_decision( + category=args["category"], + scenario=args["scenario"], + reasoning=args["reasoning"], + outcome=args["outcome"], + confidence=float(args["confidence"]), + entities=args.get("entities", []), + decision_maker=args.get("decision_maker", "mcp_client"), + valid_from=args.get("valid_from"), + valid_until=args.get("valid_until"), + ) + return {"decision_id": decision_id, "status": "recorded"} + + +def _tool_query_decisions(args: dict) -> dict: + """Query decisions by natural language or structured filters.""" + query = args.get("query", "") + category = args.get("category") + limit = int(args.get("limit", 10)) + graph = _get_graph() + try: + if query: + results = graph.find_similar_decisions(query, max_results=limit) + elif category: + nodes = graph.find_nodes(node_type="decision") + results = [n for n in nodes if n.get("category") == category][:limit] + else: + results = graph.find_nodes(node_type="decision")[:limit] + return {"decisions": results if isinstance(results, list) else list(results)} + except Exception as exc: + return {"error": str(exc), "decisions": []} + + +def _tool_find_precedents(args: dict) -> dict: + """Find past decisions similar to a given scenario.""" + scenario = args.get("scenario", "") + if not scenario: + return {"error": "scenario is required"} + max_results = int(args.get("max_results", 5)) + graph = _get_graph() + try: + precedents = graph.find_similar_decisions(scenario, max_results=max_results) + return {"precedents": precedents if isinstance(precedents, list) else list(precedents)} + except Exception as exc: + return {"error": str(exc), "precedents": []} + + +def _tool_get_causal_chain(args: dict) -> dict: + """Get the causal chain for a decision.""" + decision_id = args.get("decision_id", "") + if not decision_id: + return {"error": "decision_id is required"} + direction = args.get("direction", "downstream") + max_depth = int(args.get("max_depth", 5)) + graph = _get_graph() + try: + from semantica.context.causal_analyzer import CausalChainAnalyzer + analyzer = CausalChainAnalyzer(graph_store=graph) + chain = analyzer.get_causal_chain(decision_id, direction=direction, max_depth=max_depth) + return {"chain": chain if isinstance(chain, list) else list(chain)} + except Exception as exc: + return {"error": str(exc), "chain": []} + + +def _tool_add_entity(args: dict) -> dict: + """Add a node/entity to the knowledge graph.""" + node_id = args.get("id", "") + label = args.get("label", node_id) + node_type = args.get("type", "Entity") + if not node_id: + return {"error": "id is required"} + graph = _get_graph() + graph.add_node(node_id=node_id, label=label, node_type=node_type, + metadata=args.get("metadata", {})) + return {"status": "added", "id": node_id} + + +def _tool_add_relationship(args: dict) -> dict: + """Add a relationship (edge) between two entities.""" + source = args.get("source", "") + target = args.get("target", "") + rel_type = args.get("type", "RELATED_TO") + if not source or not target: + return {"error": "source and target are required"} + graph = _get_graph() + graph.add_edge(source_id=source, target_id=target, edge_type=rel_type, + metadata=args.get("metadata", {})) + return {"status": "added", "source": source, "target": target, "type": rel_type} + + +def _tool_run_reasoning(args: dict) -> dict: + """Run forward-chaining reasoning rules over a set of facts.""" + facts = args.get("facts", []) + rules = args.get("rules", []) + if not facts or not rules: + return {"error": "facts and rules are required"} + from semantica.reasoning import Reasoner + reasoner = Reasoner() + for rule in rules: + reasoner.add_rule(rule) + derived = reasoner.infer_facts(facts) + return {"derived_facts": derived if isinstance(derived, list) else list(derived)} + + +def _tool_get_graph_analytics(args: dict) -> dict: + """Compute graph analytics: centrality, community detection, metrics.""" + graph = _get_graph() + try: + from semantica.kg import CentralityCalculator, CommunityDetector + centrality = CentralityCalculator().calculate_pagerank(graph) + communities = CommunityDetector().detect_communities(graph) + node_count = len(list(graph.find_nodes())) + edge_count = getattr(graph, "edge_count", lambda: 0)() + return { + "node_count": node_count, + "edge_count": edge_count, + "top_nodes_by_pagerank": sorted( + centrality.items() if hasattr(centrality, "items") else [], + key=lambda x: x[1], reverse=True + )[:10], + "community_count": len(communities) if isinstance(communities, (list, dict)) else 0, + } + except Exception as exc: + return {"error": str(exc)} + + +def _tool_export_graph(args: dict) -> dict: + """Export the current knowledge graph to a serialised format.""" + fmt = args.get("format", "json-ld") + graph = _get_graph() + try: + from semantica.export import RDFExporter, JSONExporter + if fmt in ("turtle", "ttl", "nt", "xml", "json-ld"): + result = RDFExporter().export_to_rdf(graph, format=fmt) + else: + result = JSONExporter().export(graph) + return {"format": fmt, "data": result} + except Exception as exc: + return {"error": str(exc)} + + +def _tool_get_graph_summary(args: dict) -> dict: + """Return a high-level summary of the current graph.""" + graph = _get_graph() + try: + node_count = len(list(graph.find_nodes())) + decisions = graph.find_nodes(node_type="decision") + return { + "node_count": node_count, + "decision_count": len(list(decisions)), + "graph_ready": True, + } + except Exception as exc: + return {"error": str(exc), "graph_ready": False} + + +# ══════════════════════════════════════════════════════════════════════════════ +# MCP protocol tables +# ══════════════════════════════════════════════════════════════════════════════ + +TOOLS = [ + { + "name": "extract_entities", + "description": "Extract named entities (people, places, organisations, concepts) from text using Semantica NER.", + "inputSchema": { + "type": "object", + "properties": { + "text": {"type": "string", "description": "Input text to extract entities from"} + }, + "required": ["text"], + }, + "_handler": _tool_extract_entities, + }, + { + "name": "extract_relations", + "description": "Extract relations and (subject, predicate, object) triplets from text.", + "inputSchema": { + "type": "object", + "properties": { + "text": {"type": "string", "description": "Input text to extract relations from"} + }, + "required": ["text"], + }, + "_handler": _tool_extract_relations, + }, + { + "name": "record_decision", + "description": "Record a decision into the Semantica knowledge graph with full context, causal links, and metadata.", + "inputSchema": { + "type": "object", + "properties": { + "category": {"type": "string", "description": "Decision category, e.g. 'loan_approval'"}, + "scenario": {"type": "string", "description": "Natural-language situation description"}, + "reasoning": {"type": "string", "description": "Why this decision was made"}, + "outcome": {"type": "string", "description": "Decision outcome, e.g. 'approved'"}, + "confidence": {"type": "number", "description": "Confidence score 0–1"}, + "decision_maker":{"type": "string", "description": "Who/what made the decision"}, + "valid_from": {"type": "string", "description": "ISO date validity start (optional)"}, + "valid_until": {"type": "string", "description": "ISO date validity end (optional)"}, + }, + "required": ["category", "scenario", "reasoning", "outcome", "confidence"], + }, + "_handler": _tool_record_decision, + }, + { + "name": "query_decisions", + "description": "Query recorded decisions by natural language, category, or get all recent decisions.", + "inputSchema": { + "type": "object", + "properties": { + "query": {"type": "string", "description": "Natural language query (optional)"}, + "category": {"type": "string", "description": "Filter by category (optional)"}, + "limit": {"type": "integer", "description": "Max results (default 10)"}, + }, + }, + "_handler": _tool_query_decisions, + }, + { + "name": "find_precedents", + "description": "Find past decisions similar to a given scenario using hybrid similarity search.", + "inputSchema": { + "type": "object", + "properties": { + "scenario": {"type": "string", "description": "Scenario description to find precedents for"}, + "max_results": {"type": "integer", "description": "Max results (default 5)"}, + }, + "required": ["scenario"], + }, + "_handler": _tool_find_precedents, + }, + { + "name": "get_causal_chain", + "description": "Trace the causal chain upstream or downstream from a decision.", + "inputSchema": { + "type": "object", + "properties": { + "decision_id": {"type": "string", "description": "Decision ID to trace"}, + "direction": {"type": "string", "enum": ["upstream", "downstream"], "description": "Trace direction"}, + "max_depth": {"type": "integer", "description": "Max chain depth (default 5)"}, + }, + "required": ["decision_id"], + }, + "_handler": _tool_get_causal_chain, + }, + { + "name": "add_entity", + "description": "Add a node/entity to the Semantica knowledge graph.", + "inputSchema": { + "type": "object", + "properties": { + "id": {"type": "string", "description": "Unique node ID"}, + "label": {"type": "string", "description": "Human-readable label"}, + "type": {"type": "string", "description": "Node type, e.g. 'Person', 'Organisation'"}, + "metadata": {"type": "object", "description": "Additional properties"}, + }, + "required": ["id"], + }, + "_handler": _tool_add_entity, + }, + { + "name": "add_relationship", + "description": "Add a directed relationship (edge) between two entities in the knowledge graph.", + "inputSchema": { + "type": "object", + "properties": { + "source": {"type": "string", "description": "Source node ID"}, + "target": {"type": "string", "description": "Target node ID"}, + "type": {"type": "string", "description": "Relationship type, e.g. 'WORKS_AT'"}, + "metadata": {"type": "object", "description": "Additional edge properties"}, + }, + "required": ["source", "target"], + }, + "_handler": _tool_add_relationship, + }, + { + "name": "run_reasoning", + "description": "Run forward-chaining IF/THEN rules over a set of facts to derive new facts.", + "inputSchema": { + "type": "object", + "properties": { + "facts": { + "type": "array", "items": {"type": "string"}, + "description": "List of fact strings, e.g. ['Person(John)', 'Employee(John)']", + }, + "rules": { + "type": "array", "items": {"type": "string"}, + "description": "IF/THEN rule strings, e.g. ['IF Employee(?x) THEN WorkerBee(?x)']", + }, + }, + "required": ["facts", "rules"], + }, + "_handler": _tool_run_reasoning, + }, + { + "name": "get_graph_analytics", + "description": "Compute PageRank centrality and community detection over the knowledge graph.", + "inputSchema": {"type": "object", "properties": {}}, + "_handler": _tool_get_graph_analytics, + }, + { + "name": "export_graph", + "description": "Export the current knowledge graph. Formats: turtle, ttl, nt, xml, json-ld, json.", + "inputSchema": { + "type": "object", + "properties": { + "format": { + "type": "string", + "enum": ["turtle", "ttl", "nt", "xml", "json-ld", "json"], + "description": "Export format (default: json-ld)", + } + }, + }, + "_handler": _tool_export_graph, + }, + { + "name": "get_graph_summary", + "description": "Return a high-level summary of the current knowledge graph: node count, decision count, status.", + "inputSchema": {"type": "object", "properties": {}}, + "_handler": _tool_get_graph_summary, + }, +] + +RESOURCES = [ + { + "uri": "semantica://graph/summary", + "name": "Graph Summary", + "description": "High-level statistics about the current knowledge graph", + "mimeType": "application/json", + }, + { + "uri": "semantica://decisions/list", + "name": "Decisions", + "description": "List of all recorded decisions in the graph", + "mimeType": "application/json", + }, + { + "uri": "semantica://schema/info", + "name": "Schema Info", + "description": "Semantica server info and available capabilities", + "mimeType": "application/json", + }, +] + + +def _read_resource(uri: str) -> dict: + if uri == "semantica://graph/summary": + return _tool_get_graph_summary({}) + if uri == "semantica://decisions/list": + return _tool_query_decisions({"limit": 50}) + if uri == "semantica://schema/info": + return { + "name": "Semantica", + "version": "0.4.0", + "tools": [t["name"] for t in TOOLS], + "resources": [r["uri"] for r in RESOURCES], + } + return {"error": f"Unknown resource URI: {uri}"} + + +# ══════════════════════════════════════════════════════════════════════════════ +# JSON-RPC / MCP protocol handler +# ══════════════════════════════════════════════════════════════════════════════ + +SERVER_INFO = { + "name": "semantica", + "version": "0.4.0", +} + +CAPABILITIES = { + "tools": {"listChanged": False}, + "resources": {"listChanged": False, "subscribe": False}, +} + + +def _handle(req: dict) -> dict | None: + """Dispatch a single JSON-RPC request; return None for notifications.""" + method = req.get("method", "") + params = req.get("params") or {} + req_id = req.get("id") + + def ok(result): + return {"jsonrpc": "2.0", "id": req_id, "result": result} + + def err(code, message): + return {"jsonrpc": "2.0", "id": req_id, "error": {"code": code, "message": message}} + + # Notifications (no id) — acknowledge silently + if req_id is None and method.startswith("notifications/"): + return None + + if method == "initialize": + return ok({ + "protocolVersion": "2024-11-05", + "capabilities": CAPABILITIES, + "serverInfo": SERVER_INFO, + }) + + if method == "notifications/initialized": + return None + + if method == "ping": + return ok({}) + + if method == "tools/list": + tools_out = [ + {"name": t["name"], "description": t["description"], "inputSchema": t["inputSchema"]} + for t in TOOLS + ] + return ok({"tools": tools_out}) + + if method == "tools/call": + name = params.get("name", "") + arguments = params.get("arguments") or {} + handler = next((t["_handler"] for t in TOOLS if t["name"] == name), None) + if handler is None: + return err(-32601, f"Unknown tool: {name}") + try: + result = handler(arguments) + text = json.dumps(result, ensure_ascii=False, indent=2) + return ok({"content": [{"type": "text", "text": text}]}) + except Exception as exc: + log.exception("Tool %s raised", name) + return err(-32603, str(exc)) + + if method == "resources/list": + return ok({"resources": RESOURCES}) + + if method == "resources/read": + uri = params.get("uri", "") + data = _read_resource(uri) + text = json.dumps(data, ensure_ascii=False, indent=2) + return ok({"contents": [{"uri": uri, "mimeType": "application/json", "text": text}]}) + + if method == "prompts/list": + return ok({"prompts": []}) + + return err(-32601, f"Method not found: {method}") + + +# ══════════════════════════════════════════════════════════════════════════════ +# stdio event loop +# ══════════════════════════════════════════════════════════════════════════════ + +def _run_stdio(): + log.info("Semantica MCP server starting on stdio") + # Use binary stdin/stdout for reliable newline handling on Windows + stdin = sys.stdin.buffer + stdout = sys.stdout.buffer + + while True: + try: + line = stdin.readline() + if not line: + break + line = line.strip() + if not line: + continue + try: + req = json.loads(line) + except json.JSONDecodeError as exc: + resp = {"jsonrpc": "2.0", "id": None, + "error": {"code": -32700, "message": f"Parse error: {exc}"}} + stdout.write(json.dumps(resp).encode() + b"\n") + stdout.flush() + continue + + resp = _handle(req) + if resp is not None: + stdout.write(json.dumps(resp, ensure_ascii=False).encode() + b"\n") + stdout.flush() + except EOFError: + break + except KeyboardInterrupt: + break + except Exception as exc: + log.exception("Unhandled error in MCP loop: %s", exc) + + log.info("Semantica MCP server stopped") + + +def main(): + _run_stdio() + + +if __name__ == "__main__": + main()