Skip to main content
Glama
engineering-with-ai

python-mcp-server

Python MCP Server ๐Ÿง 

A Model Context Protocol (MCP) server that gives AI agents access to a Graphiti knowledge graph and a pgvector document store for grounded, evidence-backed responses.

Features

  • ๐Ÿ” Hybrid graph search โ€” semantic + BM25 + graph traversal via Graphiti

  • ๐Ÿ“š Vector RAG โ€” pgvector similarity search; query strings are embedded internally via OpenAI (no pre-computed vectors required from callers)

  • ๐Ÿงพ Evidence retrieval, not fake verification โ€” verify_fact returns related graph evidence; the calling LLM judges entailment

  • โšก Fail fast โ€” client errors surface as MCP errors, not silent empty results

  • โš™๏ธ Clean config split โ€” cfg.yml for config, env vars for secrets only

Related MCP server: Memory MCP

Tools

Tool

Input

Returns

search_knowledge

query: str

Graph entities/relationships

rag_search

query: str

Document chunks ranked by similarity

verify_fact

statement: str

FactEvidence { statement, evidence }

combined_search

query: str

Graph results + document chunks

All tools take strings โ€” embeddings are generated server-side.

Resources: knowledge://instructions, knowledge://examples. Prompt: answer_with_verification.

Quick Start

pip install python-mcp-server
# or
uvx python-mcp-server

Configuration

cfg.yml holds all non-secret config. Secrets live only in environment variables โ€” never in cfg.yml, never in the Postgres URL.

cfg.yml

local:
  log_level: DEBUG
  neo4j:
    uri: bolt://localhost:7687
    user: neo4j
    database: neo4j
  postgres:
    host: localhost
    port: 5432
    database: knowledge
    user: postgres
    embeddings_table: energy_embeddings
    embedding_model: text-embedding-3-small

The server selects the top-level key based on the ENV env var (default local). A beta section is also supported.

Secrets (environment)

export NEO4J_PASSWORD="..."
export POSTGRES_PASSWORD="..."
export OPENAI_API_KEY="..."
export ENV="local"

Programmatic usage

from python_mcp_server import create_server
from python_mcp_server.config import Config, Neo4jConfig, PostgresConfig, LogLevel

config = Config(
    log_level=LogLevel.INFO,
    neo4j=Neo4jConfig(uri="bolt://localhost:7687", user="neo4j", database="neo4j"),
    postgres=PostgresConfig(
        host="localhost", port=5432, database="knowledge", user="postgres",
        embeddings_table="energy_embeddings",
        embedding_model="text-embedding-3-small",
    ),
)
server = create_server(
    config=config,
    neo4j_password="...",
    postgres_password="...",
    openai_api_key="...",
)

Usage

Claude Code

export NEO4J_PASSWORD=... POSTGRES_PASSWORD=... OPENAI_API_KEY=...
claude mcp add domain-expert -- uvx python-mcp-server

Claude Desktop (claude_desktop_config.json)

{
  "mcpServers": {
    "knowledge-graph": {
      "command": "uvx",
      "args": ["python-mcp-server"],
      "env": {
        "NEO4J_PASSWORD": "...",
        "POSTGRES_PASSWORD": "...",
        "OPENAI_API_KEY": "..."
      }
    }
  }
}

Pydantic-AI

from pydantic_ai import Agent
from pydantic_ai.mcp import MCPServerStdio

mcp = MCPServerStdio("uvx", "python-mcp-server")
agent = Agent(toolsets=[mcp])
result = await agent.run("What connects Tesla and battery technology?")

Database Schema

pgvector table expected by rag_search:

CREATE TABLE energy_embeddings (
    id SERIAL PRIMARY KEY,
    title TEXT,
    content TEXT NOT NULL,
    book TEXT,
    section_level TEXT,
    analysis_relevance TEXT,
    embedding vector(1536),  -- text-embedding-3-small
    content_tsv tsvector
        GENERATED ALWAYS AS (to_tsvector('english', content)) STORED
);

CREATE INDEX ON energy_embeddings USING ivfflat (embedding vector_cosine_ops);
CREATE INDEX idx_content_tsv ON energy_embeddings USING gin(content_tsv);

Embedding dimension must match embedding_model in cfg.yml.

rag_search issues two rankings against this table โ€” cosine over embedding and BM25 over content_tsv โ€” and fuses them via Reciprocal Rank Fusion (k=60). Exact-term matches (protocol field names, enum values, requirement IDs) come through the BM25 leg that pure cosine would miss.

Development

git clone <repo> && cd python-mcp-server
uv sync --dev
cp template-secrets.env .env  # fill in secrets

uv run poe checks   # deptry, black, ruff, mypy, bandit, pip-audit
uv run poe cover    # tests with coverage
uv run python-mcp-server

Architecture

src/python_mcp_server/
โ”œโ”€โ”€ clients/
โ”‚   โ”œโ”€โ”€ embedder.py         # OpenAI embeddings (injected)
โ”‚   โ”œโ”€โ”€ graphiti_client.py  # Neo4j via Graphiti
โ”‚   โ””โ”€โ”€ rag_client.py       # pgvector similarity search
โ”œโ”€โ”€ config.py               # cfg.yml loader
โ”œโ”€โ”€ models.py               # Pydantic response models
โ”œโ”€โ”€ server.py               # FastMCP tools, resources, prompt
โ””โ”€โ”€ __main__.py             # CLI entry point

Design Principles

  1. String-in, evidence-out. Callers pass natural language; the server handles embeddings and returns typed Pydantic results.

  2. No fake verification. verify_fact returns evidence; the caller LLM decides entailment. The server never invents a verified: bool.

  3. Fail fast. Database errors propagate to the MCP client so Claude sees "Neo4j unreachable" instead of "no results."

  4. Config vs. secrets are separate concerns. cfg.yml is checked in; passwords and API keys never are.

Available Tools

4 tools
search_knowledgeA

Search factual knowledge in the Graphiti knowledge graph.

USE WHEN: You need verified facts, entities, relationships, or structured knowledge. Combines semantic search, BM25, and graph traversal.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
queryYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYesList of search results
totalYesTotal number of results
sourceNoSource of the results - verified facts from knowledge graph

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the behavioral disclosure burden. It does meaningful work by revealing the hybrid nature of the search: 'Combines semantic search, BM25, and graph traversal.' It does not mention result freshness, permissions, rate limits, or whether results are reranked, but the hybrid mechanism is a useful behavioral disclosure beyond a bare 'search' statement.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the core purpose: 'Search factual knowledge in the Graphiti knowledge graph.' The USE WHEN section adds usage context, and the final sentence explains the search mechanism, with no fluff or redundancy. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter search with an output schema, the description covers the purpose, the underlying techniques, and the main use case. The main completeness gap is the lack of differentiation among the siblings (rag_search, verify_fact, combined_search), and the absence of any clarification of the limit parameter's role leaves a modest but real decision gap for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description does not mention query or limit at all. The query parameter's expected format, syntax hints, or semantics, and the meaning of limit, are left entirely to the schema names/defaults, so the description fails to compensate for the schema's minimal documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a clear verb and resource: 'Search factual knowledge in the Graphiti knowledge graph.' It also clarifies the content types covered ('verified facts, entities, relationships, or structured knowledge' and the hybrid retrieval approach ('semantic search, BM25, and graph traversal'). It does not explicitly differentiate this tool from siblings like rag_search, verify_fact, or combined_search, so it stops short of full discrimination.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'USE WHEN: You need verified facts, entities, relationships, or structured knowledge' clearly states when an agent should consider this tool. However, it provides no exclusions, no 'use instead' guidance, and no comparison to the sibling tools, so it lacks the full when/not-when structure.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

verify_factA

Retrieve knowledge-graph evidence relevant to a statement.

USE WHEN: You want to check a claim against the graph. Returns related facts; the caller judges whether they support or contradict the statement. No boolean verdict โ€” entailment is the caller's job.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
statementYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
evidenceYesRelated facts from the knowledge graph, ranked by relevance
statementYesThe statement the evidence was gathered for

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden. It explicitly discloses a non-obvious trait: 'No boolean verdict โ€” entailment is the caller's job,' which prevents the agent from expecting a yes/no answer. This is meaningful behavioral context beyond the schema, though it does not discuss safety or permissions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well-organized: a one-line purpose, a 'USE WHEN' trigger, and a crucial behavioral caveat. Every sentence earns its place and the most important scoping information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter retrieval tool with an output schema, the description covers purpose, usage context, and the key behavioral boundary. It does not explicitly route between sibling tools, but the name and 'USE WHEN' clause make the intended use reasonably complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It clarifies that 'statement' is the claim to verify against the graph, adding meaning beyond the schema. However, 'limit' receives no explanation, though its default of 5 and name make its basic meaning inferable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'Retrieve knowledge-graph evidence relevant to a statement.' It clearly frames the tool as a fact-checking/evidence-gathering operation, distinguishing it from generic search siblings by emphasizing that the caller, not the tool, judges entailment.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'USE WHEN' clause explicitly states when to invoke the tool: 'You want to check a claim against the graph.' It provides clear context and sets expectations about no boolean verdict, but it does not name sibling alternatives or state when not to use them, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv1.0.0-beta
    • First observedcombined_search
    • First observedrag_search
    • First observedsearch_knowledge
    • First observedverify_fact

TDQS

A3.8/5.0

Scored across 4 tools

Disambiguation4/5

Each tool has a reasonably clear purpose: graph knowledge search, document vector search, combined search, and claim verification. The only mild overlap is between search_knowledge and verify_fact, but the descriptions distinguish general exploration from targeted claim checking.

Naming Consistency3/5

Names are all lowercase snake_case and readable, but the pattern is inconsistent: search_knowledge and verify_fact are verb_noun, while rag_search and combined_search are qualifier_search. This makes the naming convention less predictable across the set.

Tool Count5/5

Four tools is a well-scoped size for a retrieval-focused server. Each tool has a distinct role, and combined_search earns a place as a convenience for workflows needing both knowledge graph and document context.

Completeness4/5

For a read-only search and verification server, the core operations are covered: graph search, RAG search, combined search, and claim verification. Missing ingestion or update/delete tools would be a gap only if the server were meant to manage the underlying knowledge store, which the descriptions do not indicate.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    Not graded
    maintenance
    A lightweight server implementation of the Model Context Protocol that connects Memgraph database with LLMs, allowing users to interact with graph databases through natural language.
    1
    25
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A Model Context Protocol server that provides AI assistants with persistent semantic memory and knowledge graph capabilities using PostgreSQL and vector embeddings. It enables cross-session storage, hybrid search, and complex relationship tracking for enhanced contextual awareness.
    4 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A Model Context Protocol server implementing Graph RAG with local, embedded Knowledge Graph using FAISS for vector search and NetworkX for graph traversal, enabling hybrid retrieval through anchor discovery and relationship expansion.
    2
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A Model Context Protocol server that provides Claude CLI with a Graphiti knowledge-graph memory backed by Neo4j, featuring synchronous writes and no silent ingestion failures.
    Apache 2.0