Project Knowledge Server
БесплатноНе проверенAnalyzes GitLab group projects to extract purpose, I/O, dependencies, and database tables, serving this knowledge via MCP tools and a read-only HTML visualizati
Описание
Analyzes GitLab group projects to extract purpose, I/O, dependencies, and database tables, serving this knowledge via MCP tools and a read-only HTML visualization.
README
An MCP server that builds and serves structured knowledge about projects in a GitLab group.
It runs in a single OS process and exposes two surfaces:
- MCP over stdio — eight tools that an MCP client can call to query projects and trigger refreshes.
- Read-only HTML visualization on
http://127.0.0.1:{port}— diagrams of project profiles, shared dependencies, and purpose conflicts.
Both surfaces read from the same Knowledge_Store (a single SQLite file with snapshot-based atomic-pointer-swap semantics) so readers always see a consistent view, even while a refresh is in flight.
What does the analysis? Static inspection in Python (no LLM). For every project, four sub-analyzers run: purpose (READMEs, GitLab description, manifests, top-level docstrings), I/O extractor (HTTP routes, scheduled tasks, message consumers/publishers, file I/O, CLI entrypoints), external services (HTTP clients, brokers, object stores), and database tables (SQL/ORM references, read/write modes). Source code is fetched at the configured
Analysis_Branch(defaultuat).
Go analyzer support
Go repositories are analyzed in-process with the same depth as Python, JavaScript/TypeScript, and Java repositories. No Go toolchain is invoked at runtime; a hand-written Python tokenizer reads .go source directly. The Go layer activates automatically when a RepositoryContents snapshot contains at least one .go file or a repo-root go.mod — there is no configuration to enable.
What gets detected
| Sub-analyzer | Go patterns recognized |
|---|---|
| Purpose | module <path> line in go.mod (and any adjacent //-comment), package doc comment on repo-root, cmd/main.go, or cmd/<name>/main.go files. Module-path host/org prefixes (github.com/acme/) are stripped so the binary name remains. |
| I/O extractor | http.HandleFunc / http.Handle / mux.HandleFunc / mux.Handle with Go 1.22 method-prefixed pattern support; cron.New(...) + AddFunc/AddJob (six- or five-field schedules), time.NewTicker, time.AfterFunc; *activemq.Receiver.Subscribe(..., &domain.SubscriberConfig{Destination: ...}, ...) and *activemq.Sender.SendMessage(..., &domain.Message{Destination: ...}); os.Open / os.ReadFile / os.Create / os.WriteFile / os.OpenFile (flag bitmask classified); flag.* registrations; cmd/<name>/main.go / cmd/main.go / root main.go binary names. |
| External services | fec_pool_service/pb clients (ExecuteQuery), esb-go-libs/dbadapter clients (PoolExecuteQuery), and ActiveMQ broker connections via activemq.NewClient(&activemq.JmsConfig{BrokerUrl: ...}). Elastic APM imports (go.elastic.co/apm/...) are filtered out. |
| Database tables | SQL extracted from QueryString fields on model.PoolServiceRequest, pb.PoolExecuteQueryRequest, and in-house wrapper structs whose value flows into PoolExecuteQuery/Execute/ExecuteRaw. Schema-qualified names (<schema>.<table>) are preserved. MERGE INTO is classified as a write. When a SQL keyword cannot be matched but a table name is identifiable, the access mode is recorded as unknown. |
What gets excluded
- Vendor directories. Any
.gofile whose path contains a directory segment namedvendoris skipped end-to-end. The Go scanners reject vendored paths at the parser boundary, and the language-agnostic detectors are also handed a vendor-aware view so vendored Go source's embedded string literals cannot leak into SQL, URL, or SDK-pattern detections. - Build-constraint-gated files. A file with a non-trivial
//go:buildor// +buildline (e.g.linux && amd64,darwin,!cgo) is wholesale skipped because honoring the constraint requires a Go toolchain. Skipped files are surfaced indegraded_sectionsas"<section>: skipped <path> (build constraint requires toolchain)". - cgo files. A file containing
import "C"is skipped for the same reason and surfaced under the samedegraded_sectionsshape with reasoncgo directive requires toolchain. - Tokenization errors. Unterminated strings, raw strings, block comments, and invalid escape sequences are contained per file: the affected file contributes zero detections and is surfaced with reason
tokenization failed: <detail>. - DI and config noise.
fx.New/fx.Provide/fx.Invoke/fx.Module/fx.Hook/*fx.Lifecyclecalls describe internal wiring and never produce HTTP, scheduler, ActiveMQ, file-I/O, CLI, or external-service detections by themselves.viperconfiguration reads (*viper.Viper.GetString,SetConfigName,AddConfigPath, etc.) never contribute to the purpose summary or any detection.
Triggering Go analysis
No flag, no environment variable, no client opt-in. Run the server as documented above against a GitLab group containing Go projects — every refresh that fetches a snapshot with .go files or a go.mod automatically routes through the Go sub-analyzers. The result is observable through the same MCP tools and visualization routes as any other project:
get_project_purposereturns a summary derived fromgo.mod/ package doc when no README is present.get_project_iolists HTTP routes, cron schedules, ActiveMQ destinations, file I/O, and binary entry points found in the Go source.get_project_dependencieslistsfec_pool_service(when reached via eitherpbordbadapter), ActiveMQ brokers, and any URL-literal-derived service, plus the database tables extracted from in-process SQL.
When a Go file is skipped for any reason listed above, the affected section name appears in the profile's degraded_sections list with a structured "<section>: skipped <path> (<reason>)" entry so the operator can see exactly which files the analyzer could not reach.
Requirements
- Python 3.11+
- A GitLab access token with
read_apiandread_repositoryscopes for the target group.
Install
From this repository:
pip install -e ".[dev]"
The install registers a console script:
project-knowledge-mcp = project_knowledge_mcp.main:main
Configuration
Configuration is read from environment variables. On any missing or invalid value the server prints a single line to stderr that names the offending key and exits non-zero before either surface accepts traffic.
| Variable | Required | Default | Notes |
|---|---|---|---|
GITLAB_BASE_URL |
yes | — | e.g. https://gitlab.example.com. Must be http:// or https:// with a host. |
GITLAB_GROUP_PATH |
yes | — | Top-level group path (e.g. acme/platform) or numeric group id. |
GITLAB_ACCESS_TOKEN |
yes | — | Token with read_api + read_repository. |
GITLAB_VERIFY_SSL |
no | true |
Whether outbound HTTPS calls to GITLAB_BASE_URL validate the server's TLS certificate. Set to false (or 0/no/off) for a GitLab instance with a self-signed certificate; doing so removes MITM protection for those requests. |
ANALYSIS_BRANCH |
no | uat |
Branch fetched per project, regardless of GitLab default branch. |
REFRESH_INTERVAL |
no | none | When set (e.g. 15m, 1h), schedules a periodic full refresh and fires one immediately at startup so the visualization populates without waiting a full interval. Minimum 1 minute. When unset, no scheduler runs and no automatic refresh fires — trigger ingestion via the refresh_all_projects MCP tool. |
VISUALIZATION_PORT |
no | 7345 |
Loopback-only TCP port (127.0.0.1 and ::1). Range 1..65535. |
KNOWLEDGE_STORE_PATH |
no | data/knowledge_store.db |
SQLite database path. The parent directory is created if missing. |
LOG_LEVEL |
no | WARNING |
Root logging level for stderr output. The application's operationally important lines (visualization "ready" banner, refresh-progress per-project lines, refresh-complete summary) are emitted at WARNING so they surface under this default without dragging in third-party libraries' per-request chatter. Set LOG_LEVEL=INFO to additionally see less essential application INFO lines, or LOG_LEVEL=DEBUG for full diagnostic verbosity (including httpx/httpcore/uvicorn). Unknown values fall back to WARNING. |
The store persists across restarts: on reopen, readers immediately serve the last successfully committed snapshot, and an in-flight job aborted at shutdown does not affect that pointer.
Run
GITLAB_BASE_URL=https://gitlab.example.com \
GITLAB_GROUP_PATH=acme/platform \
GITLAB_ACCESS_TOKEN=glpat-... \
project-knowledge-mcp
On startup you will see a single log line:
Visualization_Server ready at http://127.0.0.1:7345
The MCP server simultaneously speaks JSON-RPC over stdin/stdout, so this command is normally launched by an MCP client rather than run interactively.
Use from an MCP client
Configure your MCP-aware tool (Claude Desktop, an editor MCP integration, etc.) to spawn the server. Example config:
{
"mcpServers": {
"project-knowledge": {
"command": "project-knowledge-mcp",
"env": {
"GITLAB_BASE_URL": "https://gitlab.example.com",
"GITLAB_GROUP_PATH": "acme/platform",
"GITLAB_ACCESS_TOKEN": "glpat-...",
"ANALYSIS_BRANCH": "uat",
"REFRESH_INTERVAL": "1h"
}
}
}
}
Available MCP tools
Eight tools are registered. The first six are read-only; the last two trigger ingestion.
| Tool | Arguments | Purpose |
|---|---|---|
list_projects |
— | List in-scope projects from the current Project_Catalog. |
get_project_purpose |
gitlab_project_id |
Purpose summary + reason. |
get_project_io |
gitlab_project_id |
Abstract inputs and outputs. |
get_project_dependencies |
gitlab_project_id |
External services + database tables. |
get_project_profile |
gitlab_project_id |
The complete Project_Profile. |
list_purpose_conflicts |
— | Pairs of projects with overlapping or contradictory primary responsibilities. |
refresh_all_projects |
— | Start a full refresh of every in-scope project. |
refresh_project |
gitlab_project_id |
Re-analyze a single project, copying every other profile from the parent snapshot. |
Refresh tools enforce a single-flight rule: while one ingestion job is running, additional refresh requests (from any source — tool call or scheduler) are rejected with the message Ingestion_Job is already in progress. The Knowledge_Store is unchanged.
Out-of-scope project ids return a tool result with isError: true and the message project {id} is not in scope.
Visualization
Browse http://127.0.0.1:7345/ (or your configured port). All routes serve text/html; charset=utf-8:
| Route | Shows |
|---|---|
/ |
Index of in-scope projects, sorted by id. Empty catalog → No Projects are in scope. No completed ingestion yet → no project knowledge available; run an Ingestion_Job. |
/projects/{project_id} |
Single project: purpose summary; abstract inputs grouped by category; abstract outputs grouped by category; external services labeled by kind; database tables labeled by access mode. Each empty section shows a section-specific empty-state message. |
/dependencies |
Mermaid graph: nodes = in-scope projects, edges = shared database tables. |
/static/<filename> |
Static file mount serving the package's static/ directory. Used by /dependencies to load cytoscape.min.js (primary) and mermaid.min.js (fallback). |
Enable graph rendering
The /dependencies page renders an interactive knowledge graph using Cytoscape.js. Drop the bundle at src/project_knowledge_mcp/static/cytoscape.min.js:
curl -L -o src/project_knowledge_mcp/static/cytoscape.min.js \
https://cdn.jsdelivr.net/npm/cytoscape@3/dist/cytoscape.min.js
When Cytoscape is loaded the page emits an interactive node-and-edge graph with zoom, pan, drag, and hover tooltips. The same diagram is also emitted as a Mermaid <pre class="mermaid"> block; when cytoscape.min.js is absent the page falls back to Mermaid by dropping a Mermaid bundle at src/project_knowledge_mcp/static/mermaid.min.js:
curl -L -o src/project_knowledge_mcp/static/mermaid.min.js \
https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js
For air-gapped networks, fetch either file from any machine that can reach the CDN and copy it into the same path. See src/project_knowledge_mcp/static/README.md for details. When both files are missing the pages still load — graphs degrade to the raw graph LR ... text.
Behavior pinned by the spec:
- Reads happen at request time — no in-memory caching of profiles.
- Non-matching paths → 404 with the requested path echoed in the body.
- Non-
GETmethods → 405 withAllow: GET. Knowledge_Storefailures → 503 with no profile-derived content.- Every successful response begins within 5 seconds.
Typical workflow
- Start the server with
REFRESH_INTERVAL=1h(or trigger refreshes manually). - After the first ingestion completes, the visualization populates and the MCP query tools start returning data.
- Iterate: as code in your GitLab projects evolves on
Analysis_Branch, each refresh produces a new snapshot. Readers atomically switch to the new snapshot only when the ingestion commits.
Operations
- Skipped projects. When a project has no
Analysis_Branch, the ingestion records a skip with reasonanalysis_branch_missingand continues with the rest. NoProject_Profileis produced for skipped projects; they still appear in the catalog so you can tell "in scope but not yet analyzed" from "out of scope". - Auth failures. A
401/403from GitLab aborts the in-flight job and surfaces the status code; the previous snapshot remains current. A404for the configured group raisesGitLabGroupNotFoundError(group_path). - Shutdown. SIGTERM/SIGINT triggers a documented shutdown ordering: stop accepting new HTTP connections → close MCP stdio → mark any in-flight snapshot
failed(thecurrent_snapshotpointer is unchanged) → flush and close the SQLite store → exit. - Port already in use. Startup prints
startup error: visualization.port {port} is already in useand exits non-zero.
Tests
pytest -m unit # ~3s
pytest -m property # Hypothesis, max_examples=100, ~30s
pytest -m integration # subprocess + HTTP + SQLite, ~15s
Or all of them:
pytest
Project layout
src/project_knowledge_mcp/
config.py # env loader + validator (single termination path)
errors.py # error type hierarchy
models.py # Project_Profile, EnumeratedProject, ConflictResult, ...
knowledge_store.py # SQLite + snapshot pointer + WAL
project_catalog.py # snapshot-scoped in-scope set
gitlab_connector.py # paginated GitLab API client
project_analyzer/ # purpose, io_extractor, external_services, db_tables
conflict_detector.py # classify_pair + find_all_conflicts
ingestion_coordinator.py # single-flight state machine
scheduler.py # periodic refresh
mcp_server.py # MCP over stdio + 8 tools
visualization_server.py # Starlette + Uvicorn (loopback only)
diagram_renderer.py # Jinja2 + inline Mermaid
main.py # wiring, startup, shutdown ordering
The full specification (requirements, design, and the 30 correctness properties the implementation is verified against) lives under .kiro/specs/project-knowledge-mcp/.
Установка Project Knowledge Server
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/nampd3/gitlab-knowledegeFAQ
Project Knowledge Server MCP бесплатный?
Да, Project Knowledge Server MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Project Knowledge Server?
Нет, Project Knowledge Server работает без API-ключей и переменных окружения.
Project Knowledge Server — hosted или self-hosted?
Доступен hosted-вариант: Unyly запускает сервер в облаке, локальная установка не обязательна.
Как установить Project Knowledge Server в Claude Desktop, Claude Code или Cursor?
Открой Project Knowledge Server на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
wenb1n-dev/SmartDB_MCP
A universal database MCP server supporting simultaneous connections to multiple databases. It provides tools for database operations, health analysis, SQL optim
автор: wenb1n-devPostgres Server
This server enables interaction with PostgreSQL databases through the Model Context Protocol, optimized for the AWS Bedrock AgentCore Runtime. It provides tools
автор: madhurprashPostgres
Query your database in natural language
автор: AnthropicPostgreSQL
Read-only database access with schema inspection.
автор: modelcontextprotocolCompare Project Knowledge Server with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории data
