Merge remote-tracking branch 'origin/master' into fix/qdrant-doc-id-keyword-index

This commit is contained in:
Chris Coutinho
2026-05-10 18:37:07 +02:00
5 changed files with 88 additions and 4 deletions
+2 -2
View File
@@ -50,10 +50,10 @@ jobs:
- nextcloud_version: "31"
nextcloud_image: "docker.io/library/nextcloud:31.0.14@sha256:07ec73cc816e58d6f45a162cd53ef886462c29271a23fc68d0124cec276e3767"
- nextcloud_version: "32"
nextcloud_image: "docker.io/library/nextcloud:32.0.9@sha256:fdca48a6025e63d7b52913cad8ddf341c37b9dd8d03c4962ea0a1ec0c42c7442"
nextcloud_image: "docker.io/library/nextcloud:32.0.9@sha256:6052173f5abdd4e37868262234b9fa651f70223d3bcd7c178c51e59101fdb733"
# Disabled until all upstream apps support NC 33
# - nextcloud_version: "33"
# nextcloud_image: "docker.io/library/nextcloud:33.0.3@sha256:76f04e434a82572dbfee7ad6dca313229eade89ee538fccd2bf6396f4440d48b"
# nextcloud_image: "docker.io/library/nextcloud:33.0.3@sha256:90a730e9a3dd290d9626ca64740c4d2fa901b4f231fe4ab6eb0dcf300dbc7271"
# Mode-specific properties
- mode: single-user
+6
View File
@@ -5,6 +5,12 @@ All notable changes to the Nextcloud MCP Server will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [PEP 440](https://peps.python.org/pep-0440/).
## v0.84.0 (2026-05-10)
### Feat
- **contacts**: add nc_contacts_search_contacts free-text search tool
## v0.83.4 (2026-05-10)
### Fix
+78
View File
@@ -142,6 +142,84 @@ def configure_contacts_tools(mcp: FastMCP):
contacts=contacts, addressbook=addressbook, total_count=len(contacts)
)
@mcp.tool(
title="Search Contacts",
annotations=ToolAnnotations(readOnlyHint=True, openWorldHint=True),
)
@require_scopes("contacts.read")
@instrument_tool
async def nc_contacts_search_contacts(
ctx: Context, *, query: str, addressbook: str | None = None
) -> ListContactsResponse:
"""Search contacts by free-text query across name, nickname, email, and phone.
The query is matched case-insensitively as a substring against:
- the contact's full name (FN)
- any nickname
- every email address
- every phone number (digits only — formatting is stripped before
comparison so '+1 234 567 890' matches '2345678' and '234.567.890')
Args:
query: Free-text search string (case-insensitive substring match).
An empty query returns no results — use list_contacts for that.
addressbook: Optional URI slug of a specific addressbook to search.
When omitted, every addressbook for the user is searched.
Returns:
ListContactsResponse with matching contacts. The ``addressbook``
field is set to the searched addressbook, or ``"*"`` when all
addressbooks were searched.
"""
client = await get_client(ctx)
needle = (query or "").strip().lower()
if not needle:
return ListContactsResponse(
contacts=[], addressbook=addressbook or "*", total_count=0
)
# Phone numbers are normalised to digits-only for comparison so that
# users can search for "2345678" and find "+1 234-567-8" etc.
digits_needle = "".join(ch for ch in needle if ch.isdigit())
if addressbook:
address_books = [addressbook]
else:
address_books = [
ab["name"] for ab in await client.contacts.list_addressbooks()
]
matches: list[Contact] = []
for ab_slug in address_books:
raw_contacts = await client.contacts.list_contacts(addressbook=ab_slug)
for raw in raw_contacts:
contact = _raw_contact_to_model(raw)
hay_parts: list[str] = []
if contact.fn:
hay_parts.append(contact.fn.lower())
nickname = contact.custom_fields.get("nickname") if contact.custom_fields else None
if nickname:
hay_parts.append(str(nickname).lower())
for e in contact.emails:
hay_parts.append(e.value.lower())
hay = " ".join(hay_parts)
phone_digits = "".join(
"".join(ch for ch in p.value if ch.isdigit())
for p in contact.phones
)
if needle in hay:
matches.append(contact)
elif digits_needle and digits_needle in phone_digits:
matches.append(contact)
return ListContactsResponse(
contacts=matches,
addressbook=addressbook or "*",
total_count=len(matches),
)
@mcp.tool(
title="Create Address Book",
annotations=ToolAnnotations(idempotentHint=False, openWorldHint=True),
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "nextcloud-mcp-server"
version = "0.83.4"
version = "0.84.0"
description = "Model Context Protocol (MCP) server for Nextcloud integration - enables AI assistants to interact with Nextcloud data"
authors = [
{name = "Chris Coutinho", email = "chris@coutinho.io"}
Generated
+1 -1
View File
@@ -2123,7 +2123,7 @@ wheels = [
[[package]]
name = "nextcloud-mcp-server"
version = "0.83.4"
version = "0.84.0"
source = { editable = "." }
dependencies = [
{ name = "aiosqlite" },