Skip to content

Ahnlich MCP - #383

Open
osobotu wants to merge 19 commits into
deven96:mainfrom
osobotu:ahnlich-mcp
Open

Ahnlich MCP#383
osobotu wants to merge 19 commits into
deven96:mainfrom
osobotu:ahnlich-mcp

Conversation

@osobotu

@osobotu osobotu commented Aug 6, 2026

Copy link
Copy Markdown

This PR adds an MCP server for Ahnlich. Fixes #373

flowchart LR
    Agent["AI agent"] -->|"stdio"| MCP["ahnlich-mcp"]
    MCP -->|"DB profile: embeddings"| DB["ahnlich-db"]
    MCP -->|"AI profile: raw text"| AI["ahnlich-ai"]
    AI -->|"embeddings"| DB
Loading
  • Adds db and ai profiles with profile-specific tool schemas.
  • Exposes tools for store management, storage, similarity search, metadata filtering, and predicate indexes.
  • Adds environment and CLI configuration plus a doctor connectivity command.
  • Uses uv with Python 3.11 and the monorepo Python SDK.
  • Separates tools, server setup, configuration, and backend communication.
  • Centralizes shared backend behavior while preserving AI- and DB-specific logic.
  • Adds unit, real-service integration, and MCP stdio tests.
  • Adds CI with dependency/model caching and Docker-based integration testing.
  • Documents installation, profiles, configuration, architecture, and development workflows.

osobotu and others added 12 commits July 23, 2026 22:42
- implemented tools matching ahnlich functionalities
- add tests for tools
- local setup instructions
git-subtree-dir: mcp
git-subtree-mainline: a8fe85f
git-subtree-split: 3588aff
High-level implementation

- Add separate DB and AI profiles for raw-text and precomputed-embedding workflows.
- Introduce shared gRPC lifecycle, validation, metadata, and error-handling behavior.
- Build profile-specific tool schemas behind a consistent MCP tool catalog.
- Add CLI and environment profile selection, service warnings, and the doctor command.
- Manage MCP and local Python SDK dependencies with uv.
- Add unit, backend integration, and real MCP stdio tests for both profiles.
- Document architecture, source installation, configuration, tools, and development commands.
- Ignore the root .vscode directory.
- centralize shared backend operations, formatting, validation and error handling
- keep specific AI and DB behavior separate
- expand backend test coverage
- remove no longer used client.py file
@wizzywit

Copy link
Copy Markdown
Collaborator

After going through this implementation, there are some standards or optimization gaps that I think would be worth while to be implemented for this feature.

  1. No tool annotations. drop_store and delete_by_metadata are irreversible, and ping/list_stores/server_info/get_by_metadata are read-only, but nothing is declared. FastMCP supports mcp.tool(annotations=ToolAnnotations(readOnlyHint=..., destructiveHint=..., idempotentHint=...)) — clients use these to gate confirmation prompts. This is the single highest-value addition for a server whose tools can wipe a store.

  2. Errors are returned as successful results. error_response returns {"status": "error", ...} as a normal tool result, so isError is never set. The dict is LLM-legible, which is the important part, but protocol-level clients can't distinguish failure. Consider raising ToolError (or setting the error flag) while keeping the structured hint payload.

  3. No read-only mode. An AHNLICH_MCP_READ_ONLY=1 that suppresses registration of drop_store / delete_by_metadata / drop_predicate_index would be cheap and is a common pattern for database MCP servers.

  4. get_by_metadata and list_stores are unbounded. A predicate matching 100k entries returns all of them. Add a limit (with a sane default) and report truncation.

@wizzywit wizzywit left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall the implementation looks solid.

  • Transport errors are translated into domain exceptions carrying an actionable suggested_action, so a failing tool call tells the agent what to do rather than leaking a gRPC status.
  • The server stays up when Ahnlich is unreachable (server.py:52-77) instead of dying at startup — right call for a stdio server whose client owns the process lifecycle.
  • doctor is a genuinely useful operator affordance.
  • Real end-to-end coverage through ClientSession in tests/integration/test_mcp_stdio.py, not just unit mocks.
  • Reuses the in-repo sdk/ahnlich-client-py via [tool.uv.sources] rather than vendoring protobufs.

Comment thread mcp/src/ahnlich_mcp/backends/base.py Outdated
Comment thread mcp/src/ahnlich_mcp/backends/ai.py Outdated
Comment thread mcp/src/ahnlich_mcp/backends/ai.py Outdated
Comment thread mcp/src/ahnlich_mcp/config.py Outdated
Comment thread mcp/src/ahnlich_mcp/backends/ai.py Outdated
Comment thread mcp/src/ahnlich_mcp/tools.py
Comment thread mcp/src/ahnlich_mcp/tools.py Outdated
Comment thread mcp/src/ahnlich_mcp/backends/ai.py Outdated
Comment thread mcp/src/ahnlich_mcp/backends/ai.py Outdated
Comment thread mcp/src/ahnlich_mcp/backends/ai.py Outdated
Comment on lines +102 to +103
f"Unsupported AI model {model!r}."
f"Supported models: {supported}"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NON-BLOCKING (introduced by the fix for #383 (comment) — the validation itself is correct):

Missing separator in the implicit string concatenation, so the two sentences run together:

AHNLICH_AI_MODEL=bogus uv run ahnlich-mcp
ahnlich-mcp: error: Unsupported AI model 'bogus'.Supported models: all-minilm-l12-v2, all-minilm-l6-v2, bge-base-en-v1.5, bge-large-en-v1.5, jina-embeddings-v2-base-code
Suggested change
f"Unsupported AI model {model!r}."
f"Supported models: {supported}"
f"Unsupported AI model {model!r}. "
f"Supported models: {supported}"

I scanned the rest of mcp/src/ for the same pattern — this is the only occurrence, every other multi-line message keeps its trailing space.

While you're in this function: line 105 is whitespace-only. Same for backends/base.py:380,475,580. A ruff format --check step in mcp_test.yml would keep these from accumulating (raised in the review summary, not blocking).

@deven96
deven96 requested a review from wizzywit August 24, 2026 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ahnlich MCP

3 participants