repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
Mirrored from https://github.com/benmaster82/Kwipu
stars
latest
clone command
git clone gitlawb://did:key:z6MkqRzA...RfoM/benmaster82-Kwi...git clone gitlawb://did:key:z6MkqRzA.../benmaster82-Kwi...908f0e4eAdd MCP badge18d ago| #1 | """ |
| #2 | Kwipu MCP Server - Expose your knowledge graph to AI agents. |
| #3 | |
| #4 | This server implements the Model Context Protocol (MCP) to allow |
| #5 | Claude Code, Cursor, Windsurf, VS Code Copilot, and other MCP-compatible |
| #6 | clients to query your Obsidian vault / knowledge base. |
| #7 | |
| #8 | All queries are processed locally by Ollama, minimizing token usage |
| #9 | on the client side. |
| #10 | |
| #11 | Usage: |
| #12 | # As MCP server in Claude Desktop (claude_desktop_config.json): |
| #13 | { |
| #14 | "mcpServers": { |
| #15 | "kwipu": { |
| #16 | "command": "C:/path/to/python.exe", |
| #17 | "args": ["C:/path/to/kwipu_mcp_server.py"] |
| #18 | } |
| #19 | } |
| #20 | } |
| #21 | """ |
| #22 | |
| #23 | import os |
| #24 | import sys |
| #25 | |
| #26 | # Ensure UTF-8 on Windows |
| #27 | os.environ["PYTHONUTF8"] = "1" |
| #28 | |
| #29 | if sys.platform == "win32": |
| #30 | import asyncio |
| #31 | asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) |
| #32 | |
| #33 | import nest_asyncio |
| #34 | nest_asyncio.apply() |
| #35 | |
| #36 | from mcp.server.fastmcp import FastMCP |
| #37 | |
| #38 | # Set working directory to script location (resolves relative paths) |
| #39 | _SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| #40 | sys.path.insert(0, _SCRIPT_DIR) |
| #41 | os.chdir(_SCRIPT_DIR) |
| #42 | |
| #43 | from geode_graph import ( |
| #44 | WritHerGraphRAG, |
| #45 | _init_llm, |
| #46 | ) |
| #47 | |
| #48 | # ========================================== |
| #49 | # MCP SERVER |
| #50 | # ========================================== |
| #51 | mcp = FastMCP("Kwipu") |
| #52 | |
| #53 | # Redirect engine logs to stderr (stdout is reserved for MCP protocol) |
| #54 | import geode_graph |
| #55 | |
| #56 | def _stderr_print(*args, **kwargs): |
| #57 | kwargs["file"] = sys.stderr |
| #58 | try: |
| #59 | print(*args, **kwargs) |
| #60 | except Exception: |
| #61 | pass |
| #62 | |
| #63 | geode_graph.safe_print = _stderr_print |
| #64 | |
| #65 | # Lazy RAG instance |
| #66 | _rag_instance: WritHerGraphRAG | None = None |
| #67 | |
| #68 | |
| #69 | def _get_rag() -> WritHerGraphRAG: |
| #70 | """Get or create the RAG engine (lazy, on first query).""" |
| #71 | global _rag_instance |
| #72 | if _rag_instance is None: |
| #73 | _init_llm() |
| #74 | _rag_instance = WritHerGraphRAG(fast_mode=True) |
| #75 | return _rag_instance |
| #76 | |
| #77 | |
| #78 | # ========================================== |
| #79 | # TOOL |
| #80 | # ========================================== |
| #81 | @mcp.tool() |
| #82 | def query_graph(question: str) -> str: |
| #83 | """Ask a question about your knowledge base. Searches across all notes |
| #84 | using a knowledge graph with vector similarity, BM25, and temporal matching. |
| #85 | Returns an answer with cited source files. Supports multiple languages. |
| #86 | |
| #87 | Args: |
| #88 | question: Your question in natural language |
| #89 | """ |
| #90 | rag = _get_rag() |
| #91 | response = rag.ask(question) |
| #92 | return str(response) |
| #93 | |
| #94 | |
| #95 | # ========================================== |
| #96 | # ENTRY POINT |
| #97 | # ========================================== |
| #98 | if __name__ == "__main__": |
| #99 | mcp.run() |
| #100 |