kbask
Hybrid MCP server combining Graphify's structural code graphs with Understand-Anything's semantic knowledge bases for code analysis, offering tools for querying code structure, semantic explanations, and hybrid operations like trace and ask.
README
kbask
Hybrid MCP server that combines Graphify (structural code graphs) with Understand-Anything (LLM-derived semantic knowledge bases) into a single MCP endpoint.
Graphify tells you where things are. Understand-Anything tells you why they exist. kbask joins both and exposes them as MCP tools usable from Claude Code, Codex, Gemini CLI, and any other MCP-compatible host.
Why a hybrid?
| Backend | Strength | Weakness |
|---|---|---|
| Graphify | Exact, cheap, deterministic AST graph (calls, imports, ownership) | No semantics — doesn't know why code exists |
| Understand-Anything | Semantic narrative, domain knowledge, onboarding context | Expensive to build, fuzzy, no edge-precise lookups |
kbask gives you:
- All 7 Graphify tools (
query_graph,get_node,get_neighbors,get_community,god_nodes,graph_stats,shortest_path) pass-through - 5 semantic tools from Understand-Anything (
semantic_explain,semantic_chat,semantic_diff,semantic_onboard,semantic_domain) - Hybrid tools that compose both:
ask(question)— structural BFS then semantic narrative on top candidatestrace(from, to)— shortest path + per-hop semantic glossonboard(area)— community detection + domain knowledge per cluster
Install
Latest release:
0.1.0— assets:kbask-0.1.0-py3-none-any.whl,kbask-0.1.0.tar.gz,SHA256SUMS,install.sh,tool-install.sh.Not yet on PyPI. Install from the GitHub Release, from
main, or pinned to a tag. Once on PyPI,--from kbaskresolves from there with no other change.
Releases are cut as X.Y.Z git tags (the leading v is optional — both 0.1.0 and v0.1.0 are accepted). The release GitHub Action
builds a wheel + sdist, attaches them (and install.sh / tool-install.sh /
SHA256SUMS) to the GitHub Release, and — if PYPI_TOKEN is configured —
uploads the wheel to PyPI. See Releases for the cut process.
Pick the install style that matches your workflow:
A. Persistent CLI (uv tool install) — recommended
Puts kbask on your PATH so you can type it like any other tool:
# Latest release (auto-discovers GitHub Release wheel)
curl -fsSL https://raw.githubusercontent.com/sughosh-pocketfm/kbask/main/tool-install.sh | bash
# Pin to a specific release tag
KBASK_TAG=0.1.0 \
curl -fsSL https://raw.githubusercontent.com/sughosh-pocketfm/kbask/main/tool-install.sh | bash
The script:
- Installs
uvif missing (Astral installer). - Hits
https://api.github.com/repos/sughosh-pocketfm/kbask/releases/latestto find the wheel asset. Pin a release withKBASK_TAG=X.Y.Z(e.g.KBASK_TAG=0.1.0). - Falls back to
git+https://github.com/sughosh-pocketfm/kbaskif no release exists yet (or formain). - Runs
uv tool install --forcesokbasklands in~/.local/bin.
After install:
kbask install claude --repo . # wire MCP into Claude Code
kbask update . # build/refresh knowledge graph
kbask doctor # check dependencies
kbask --help
Upgrade:
uv tool upgrade kbask
# or rerun the curl one-liner (always uses --force)
B. One-shot host installer (no persistent CLI)
Wires kbask into a single MCP host's config without leaving a global
kbask binary. The MCP server itself is spawned by the host via
uvx --from git+... on demand.
curl -fsSL https://raw.githubusercontent.com/sughosh-pocketfm/kbask/main/install.sh | bash -s claude
# or: bash -s codex | bash -s gemini
# Pin to a tag (the MCP config gets the same pin):
KBASK_SOURCE="git+https://github.com/sughosh-pocketfm/kbask@0.1.0" \
curl -fsSL https://raw.githubusercontent.com/sughosh-pocketfm/kbask/main/install.sh | bash -s claude
C. Direct uvx (no scripts)
# Latest main
uvx --from git+https://github.com/sughosh-pocketfm/kbask kbask install claude --repo .
# Pinned tag
uvx --from "git+https://github.com/sughosh-pocketfm/kbask@0.1.0" kbask install claude --repo .
# From a downloaded wheel (verify SHA256SUMS first)
uvx --from ./kbask-0.1.0-py3-none-any.whl kbask install claude --repo .
D. After PyPI publish
Everything above keeps working, plus:
uv tool install kbask # persistent CLI
uvx --from kbask kbask install claude # one-shot
uvx kbask --help # script + pkg share name
Verify a release artifact
# From the release page, grab SHA256SUMS + the wheel
shasum -a 256 -c SHA256SUMS
What the installer does
- Creates
<repo>/kbask-out/if missing. - Appends
kbask-out/to<repo>/.gitignore. - Writes/upserts the host's MCP server config (timestamped backup of any existing file).
- Writes a
/kbaskslash command for the host:- Claude Code →
<repo>/.claude/commands/kbask.md - Codex CLI →
~/.codex/prompts/kbask.md - Gemini CLI →
~/.gemini/commands/kbask.toml - Pass
--no-slash-commandto skip.
- Claude Code →
- Runs an MCP
initialize+tools/listsmoke test against the configured server.
After restart, you can invoke the slash command from chat: type /kbask how does X work? (or just /kbask to see its prompt).
Dependency preflight
Both kbask install <host> and kbask update print a status report for the upstreams kbask depends on:
[ok] graphifyy ........... 0.5.0 (importable)
[ok] graphify CLI ........ runnable (graphify or uvx on PATH)
[warn] understand-anything . knowledge graph not built yet
To build:
1. /plugin marketplace add Lum1104/Understand-Anything
2. /plugin install understand-anything (inside Claude Code)
3. /understand (from this repo, in Claude Code)
4. kbask update .
Run it standalone any time:
kbask doctor [path/to/repo]
graphifyyis a hard dep — installed transitively with kbask.understand-anythingis built by an LLM in Claude Code (no analyzer binary). Even Codex / Gemini users build the graph via Claude Code once, then kbask mirrors it.
Pin to a fork
KBASK_SOURCE=git+https://github.com/your-fork/kbask@v0.2.0 \
uvx --from $KBASK_SOURCE kbask install claude --repo .
Build the knowledge base
After installing, build the input artifacts inside your project repo:
cd /path/to/your/project
# 1. Structural graph (Graphify)
uvx --from graphifyy graphify update .
# 2. Semantic graph (Understand-Anything) — built by an LLM in your host.
# In Claude Code, run /understand once and let it populate
# .understand-anything/knowledge-graph.json.
# 3. Mirror both into kbask-out/
uvx --from git+https://github.com/sughosh-pocketfm/kbask kbask update .
Produces kbask-out/:
kbask-out/
├── graph.json # Graphify structural graph
├── knowledge-graph.json # Understand-Anything semantic graph (mirrored)
├── knowledge-graph.meta.json
└── meta.json # per-file hashes, versions, last-build timestamps
First run rebuilds everything. Subsequent kbask update runs are incremental — only files whose content hash changed are re-analysed. Token cost scales with diff size, not repo size.
Use it from your agent
After restart, any MCP-compatible host can call:
kbask.ask("how does login retry work?")
kbask.trace("LoginViewModel", "AuthRepository")
kbask.query_graph("ExoPlayer initialisation")
kbask.semantic_explain("aural/player/data/.../PlayerManager.kt")
Incremental updates
kbask update is a single command. There is no --structural / --semantic split — kbask figures out what changed and only regenerates the missing slice:
kbask update .
├── 1. Run Graphify → new graph.json
├── 2. Diff per-file content hashes against meta.json
│ → dirty = added | modified
│ → preserved = unchanged
│ → removed = deleted from repo
├── 3. Mirror <repo>/.understand-anything/knowledge-graph.json → kbask-out/
├── 4. Carry forward unchanged file entries; mark dirty/removed in meta.json
└── 5. Write meta.json (new hashes, timestamps, versions)
Note on the semantic graph. Understand-Anything has no self-running analyzer — its knowledge graph is built by an LLM (Claude Code) following the upstream plugin's prompts and persisted to
<repo>/.understand-anything/knowledge-graph.json.kbask updatemirrors that file intokbask-out/; rebuilding the upstream graph is owned by the LLM (e.g./understand-updatein Claude Code). If<repo>/.understand-anything/is absent, semantic tools still report a clean "not built" error and structural tools keep working.
Flags:
kbask update .— incremental (default)kbask update . --force— full rebuild, ignore meta.jsonkbask update . --dry-run— print planned work, no writeskbask update . --structural-only— Graphify only, skip semantic mirror
Host setup
kbask follows the MCP spec strictly (JSON-RPC 2.0 over stdio, standard tool schemas). It works in any host that speaks MCP.
Claude Code
Project-scope .mcp.json at your repo root:
{
"mcpServers": {
"kbask": {
"type": "stdio",
"command": "uvx",
"args": [
"--from", "git+https://github.com/sughosh-pocketfm/kbask",
"--with", "mcp",
"kbask", "serve", "kbask-out/"
]
}
}
}
After PyPI publish, replace
"git+https://github.com/sughosh-pocketfm/kbask"with"kbask".
Or run the installer:
uvx --from git+https://github.com/sughosh-pocketfm/kbask kbask install claude --repo .
Codex CLI
Writes to $CODEX_HOME/config.toml (default ~/.codex/config.toml):
[mcp_servers.kbask]
args = ["--from", "git+https://github.com/sughosh-pocketfm/kbask", "--with", "mcp", "kbask", "serve", "/absolute/path/to/kbask-out"]
command = "uvx"
startup_timeout_sec = 120
uvx --from git+https://github.com/sughosh-pocketfm/kbask kbask install codex --repo .
Gemini CLI
Writes mcpServers block into ~/.gemini/settings.json:
{
"mcpServers": {
"kbask": {
"command": "uvx",
"args": [
"--from", "git+https://github.com/sughosh-pocketfm/kbask",
"--with", "mcp",
"kbask", "serve", "/absolute/path/to/kbask-out"
]
}
}
}
uvx --from git+https://github.com/sughosh-pocketfm/kbask kbask install gemini --repo .
AGY
Status: not yet supported. Config path / format for AGY hosts is not documented here. Open an issue if you need it — installer template is one file (
scripts/install-agy.py) once the path is confirmed.
Other MCP hosts
kbask serve <kbask-out-dir> speaks stdio MCP. Wire it the same way as any stdio MCP server in your host of choice.
Tool catalogue
| Tool | Source | Description |
|---|---|---|
query_graph |
structural | BFS/DFS keyword search over the code graph |
get_node |
structural | Look up a single node by label/ID |
get_neighbors |
structural | First-hop neighbors of a node |
get_community |
structural | Members of a Louvain community |
god_nodes |
structural | Highest-centrality nodes (hot spots) |
graph_stats |
structural | Graph counts, density, top communities |
shortest_path |
structural | Path between two nodes |
semantic_explain |
semantic | Narrative explanation of a file or symbol |
semantic_chat |
semantic | Free-form question against the knowledge graph |
semantic_diff |
semantic | Explain what a git diff changes and why |
semantic_onboard |
semantic | Onboarding guide for a module |
semantic_domain |
semantic | Business-domain mapping for an area |
ask |
hybrid | Structural candidates + semantic narrative in one call |
trace |
hybrid | Shortest path with semantic gloss per hop |
onboard |
hybrid | Community clusters + domain knowledge per cluster |
All tools return structured JSON. None of them call an LLM internally — they return context bundles for the calling agent's LLM to reason over. This mirrors Graphify's token_budget discipline and keeps the MCP host-agnostic.
Token accounting
Every tool response carries a _meta block reporting the approximate
token + byte cost of that single call:
{
"...your tool payload...": "...",
"_meta": {
"tool": "query_graph",
"tokens": {"input": 12, "output": 1843, "total": 1855},
"bytes": {"input": 47, "output": 7321},
"encoder": "heuristic:chars/4"
}
}
By default kbask uses a len(text) / 4 heuristic (good to ~10%). For
tokenizer-accurate counts install the optional extra:
uv pip install 'kbask[tokens]' # or: pip install 'kbask[tokens]'
That swaps the encoder to tiktoken:cl100k_base. The agent can read
_meta.tokens.total per call and self-throttle (e.g. drop depth or
token_budget if a sweep is going hot).
Architecture
kbask (Python, stdio MCP)
├── backends/
│ ├── graphify.py # reuses graphify.serve internals via networkx (no subprocess)
│ └── understand.py # reads <repo>/.understand-anything/knowledge-graph.json
├── tools/
│ ├── structural.py # 7 pass-through wrappers around graphify
│ ├── semantic.py # 5 wrappers reading the mirrored knowledge graph
│ └── hybrid.py # ask / trace / onboard — compose both backends
├── installers/ # per-host config writers (Claude / Codex / Gemini / AGY)
├── update.py # incremental orchestrator (hash diff + mirror)
├── diff.py # per-file hash delta
├── meta.py # meta.json IO + hash_file
├── state.py # process-wide out_dir holder
└── serve.py # MCP stdio entry point — registers 15 tools
Design rules:
- Don't fork upstreams. Graphify and Understand-Anything are pinned dependencies, never patched.
- Schemas stay separate. Cross-reference by
(file_path, line)— the only stable join key between the two graphs. - stdout is sacred. All logs to stderr. stdout is reserved for JSON-RPC frames.
- No host detection. Server behaves identically regardless of caller. No Claude-isms.
- No auto-rebuild. Host decides when to refresh — no file watchers, no background work.
Releases
Versioning
v<MAJOR>.<MINOR>.<PATCH> (SemVer). Pre-1.0 — breaking changes can land on any minor bump.
The CI release job hard-fails when the tag and the version in pyproject.toml disagree, so keep these in sync:
pyproject.toml→[project] versionsrc/kbask/__init__.py→__version__
Cutting a release
# 1. Bump versions (must match the tag without the `v` prefix).
# pyproject.toml: version = "0.1.1"
# src/kbask/__init__.py: __version__ = "0.1.1"
# 2. Commit + tag + push.
git commit -am "Release 0.1.1"
git tag 0.1.1
git push origin main --tags
Manual run (e.g. to re-cut from a fixed branch) is also supported:
gh workflow run release.yml -f tag=0.1.1
What the release pipeline does
.github/workflows/release.yml on tag push:
- Checks out at the tag.
- Sets up
uvand Python 3.11. - Verifies
pyproject.toml version == tag without the leading v. Aborts otherwise. uv build→dist/kbask-X.Y.Z-py3-none-any.whlanddist/kbask-X.Y.Z.tar.gz.- Smoke-tests the wheel —
pip install+kbask --helpmust succeed. - Generates
SHA256SUMS. - Creates the GitHub Release with auto-generated changelog and the following assets attached:
kbask-X.Y.Z-py3-none-any.whlkbask-X.Y.Z.tar.gzSHA256SUMSinstall.sh(one-shot host installer bootstrap)tool-install.sh(uv tool installbootstrap)
- Publishes to PyPI only if the
PYPI_TOKENrepo secret is configured.
Required repo secrets
| Secret | Purpose | Optional? |
|---|---|---|
PYPI_TOKEN |
uv publish API token |
Yes — release runs without it; only PyPI step is skipped. |
GITHUB_TOKEN is provided automatically (used by softprops/action-gh-release for the Release write).
Consumer install paths after release
Once the release exists:
# A. Persistent CLI — auto-finds the wheel
curl -fsSL https://raw.githubusercontent.com/sughosh-pocketfm/kbask/main/tool-install.sh | bash
# B. Pinned tag
KBASK_TAG=0.1.1 curl -fsSL https://raw.githubusercontent.com/sughosh-pocketfm/kbask/main/tool-install.sh | bash
# C. Direct download
gh release download 0.1.1 --repo sughosh-pocketfm/kbask --pattern '*.whl'
shasum -a 256 -c SHA256SUMS
uv tool install ./kbask-0.1.1-py3-none-any.whl
tool-install.sh hits GET /repos/{owner}/{repo}/releases/latest to discover the newest tag and prefers the wheel asset over the git source.
Status
| Capability | State |
|---|---|
| MCP stdio server + 15 tools | ✅ |
Structural tools via graphify.serve internals |
✅ |
| Semantic tools reading mirrored knowledge graph | ✅ |
Hybrid ask / trace / onboard (3-stage cascade) |
✅ |
Incremental kbask update |
✅ structural rebuild + semantic mirror |
Per-tool _meta.tokens accounting |
✅ heuristic; kbask[tokens] extra for tiktoken |
| Tolerant node lookup (path / basename / label / id) | ✅ |
Dependency preflight (kbask doctor) |
✅ |
/kbask slash command writer (Claude/Codex/Gemini) |
✅ |
| Installer scripts (Claude/Codex/Gemini) | ✅ |
tool-install.sh + install.sh curl bootstraps |
✅ |
| GitHub Release pipeline (wheel/sdist/checksums) | ✅ |
| PyPI publish | ⏳ token not yet configured |
| AGY installer | ⏳ blocked on config-path docs |
This is an alpha MVP. APIs may change.
Development
git clone https://github.com/sughosh-pocketfm/kbask.git
cd kbask
uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"
pytest
License
MIT — see LICENSE.
Built on top of graphifyy and @understand-anything/core. Their licenses apply to their respective components.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.