Merge remote-tracking branch 'origin/master' into fix/qdrant-doc-id-keyword-index
This commit is contained in:
@@ -50,10 +50,10 @@ jobs:
|
|||||||
- nextcloud_version: "31"
|
- nextcloud_version: "31"
|
||||||
nextcloud_image: "docker.io/library/nextcloud:31.0.14@sha256:07ec73cc816e58d6f45a162cd53ef886462c29271a23fc68d0124cec276e3767"
|
nextcloud_image: "docker.io/library/nextcloud:31.0.14@sha256:07ec73cc816e58d6f45a162cd53ef886462c29271a23fc68d0124cec276e3767"
|
||||||
- nextcloud_version: "32"
|
- 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
|
# Disabled until all upstream apps support NC 33
|
||||||
# - nextcloud_version: "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-specific properties
|
||||||
- mode: single-user
|
- mode: single-user
|
||||||
|
|||||||
@@ -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/),
|
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/).
|
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)
|
## v0.83.4 (2026-05-10)
|
||||||
|
|
||||||
### Fix
|
### Fix
|
||||||
|
|||||||
@@ -142,6 +142,84 @@ def configure_contacts_tools(mcp: FastMCP):
|
|||||||
contacts=contacts, addressbook=addressbook, total_count=len(contacts)
|
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(
|
@mcp.tool(
|
||||||
title="Create Address Book",
|
title="Create Address Book",
|
||||||
annotations=ToolAnnotations(idempotentHint=False, openWorldHint=True),
|
annotations=ToolAnnotations(idempotentHint=False, openWorldHint=True),
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "nextcloud-mcp-server"
|
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"
|
description = "Model Context Protocol (MCP) server for Nextcloud integration - enables AI assistants to interact with Nextcloud data"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "Chris Coutinho", email = "chris@coutinho.io"}
|
{name = "Chris Coutinho", email = "chris@coutinho.io"}
|
||||||
|
|||||||
@@ -2123,7 +2123,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nextcloud-mcp-server"
|
name = "nextcloud-mcp-server"
|
||||||
version = "0.83.4"
|
version = "0.84.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "aiosqlite" },
|
{ name = "aiosqlite" },
|
||||||
|
|||||||
Reference in New Issue
Block a user