nextcloud-agent 2.3.3__tar.gz → 2.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/PKG-INFO +3 -9
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/README.md +0 -2
- nextcloud_agent-2.3.4/nextcloud_agent/__init__.py +11 -0
- nextcloud_agent-2.3.4/nextcloud_agent/__main__.py +4 -0
- nextcloud_agent-2.3.4/nextcloud_agent/connector_sources.py +82 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/kg_ingest.py +5 -59
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/mcp_server.py +0 -68
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/certification.json +6 -6
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/mappings/source.yaml +1 -1
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent.egg-info/PKG-INFO +3 -9
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent.egg-info/SOURCES.txt +0 -7
- nextcloud_agent-2.3.4/nextcloud_agent.egg-info/entry_points.txt +8 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent.egg-info/requires.txt +1 -7
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent.egg-info/top_level.txt +0 -1
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/pyproject.toml +14 -14
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/tests/test_fleet_name.py +1 -1
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/tests/test_init.py +2 -2
- nextcloud_agent-2.3.4/tests/test_mcp_server.py +52 -0
- nextcloud_agent-2.3.3/nextcloud_agent/__init__.py +0 -1
- nextcloud_agent-2.3.3/nextcloud_agent/__main__.py +0 -4
- nextcloud_agent-2.3.3/nextcloud_agent/connector_sources.py +0 -114
- nextcloud_agent-2.3.3/nextcloud_agent/connectors/__init__.py +0 -0
- nextcloud_agent-2.3.3/nextcloud_agent/prompts/__init__.py +0 -0
- nextcloud_agent-2.3.3/nextcloud_agent/skills/__init__.py +0 -0
- nextcloud_agent-2.3.3/nextcloud_agent.egg-info/entry_points.txt +0 -14
- nextcloud_agent-2.3.3/scripts/security_sanitizer.py +0 -318
- nextcloud_agent-2.3.3/scripts/verify_api_integration.py +0 -320
- nextcloud_agent-2.3.3/tests/test_cli_server.py +0 -18
- nextcloud_agent-2.3.3/tests/test_default_content_surfaces.py +0 -43
- nextcloud_agent-2.3.3/tests/test_mcp_server.py +0 -100
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/LICENSE +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/api/__init__.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/api/api_client_base.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/api/api_client_calendar.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/api/api_client_contacts.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/api/api_client_files.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/api/xml_security.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/api_client.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/auth.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/mcp_config.json +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/__init__.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/fixtures/records.json +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/migrations/manifest.json +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/nextcloud.ttl +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/shapes/connector.shacl.ttl +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/prompts/file_steward.json +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-agent-operations/SKILL.md +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-agent-operations/agents/openai.yaml +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-agent-operations/references/catalog.md +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-files/SKILL.md +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-files/WORKFLOW.md +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-ingest/SKILL.md +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-ingest/WORKFLOW.md +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-shares/SKILL.md +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-shares/WORKFLOW.md +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/nextcloud_agent.egg-info/dependency_links.txt +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/setup.cfg +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/tests/conftest.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/tests/test_api_client.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/tests/test_auth.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/tests/test_init_dynamics.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/tests/test_kg_ingest.py +0 -0
- {nextcloud_agent-2.3.3 → nextcloud_agent-2.3.4}/tests/test_xml_security.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nextcloud-agent
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.4
|
|
4
4
|
Summary: Nextcloud MCP Server for Agentic AI!
|
|
5
|
-
Author-email:
|
|
5
|
+
Author-email: Repository Maintainers <maintainers@knuckles.team>
|
|
6
6
|
License: MIT
|
|
7
7
|
Classifier: Development Status :: 3 - Alpha
|
|
8
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -12,16 +12,12 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Requires-Python: >=3.12
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: agent-connector-sdk[mcp]<
|
|
15
|
+
Requires-Dist: agent-connector-sdk[mcp]<0.6.0,>=0.5.4
|
|
16
16
|
Requires-Dist: requests>=2.34.2
|
|
17
17
|
Requires-Dist: defusedxml>=0.7.1
|
|
18
18
|
Requires-Dist: python-dateutil>=2.9.0.post0
|
|
19
19
|
Requires-Dist: icalendar>=7.3.0
|
|
20
20
|
Requires-Dist: vobject>=0.9.9
|
|
21
|
-
Provides-Extra: mcp
|
|
22
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.4.1; extra == "mcp"
|
|
23
|
-
Provides-Extra: all
|
|
24
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.4.1; extra == "all"
|
|
25
21
|
Provides-Extra: test
|
|
26
22
|
Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
|
|
27
23
|
Requires-Dist: pytest>=9.1.1; extra == "test"
|
|
@@ -51,8 +47,6 @@ Dynamic: license-file
|
|
|
51
47
|

|
|
52
48
|

|
|
53
49
|
|
|
54
|
-
*Version: 2.3.3*
|
|
55
|
-
|
|
56
50
|
> **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
|
|
57
51
|
> interfaces, and guidance for provisioning the backing Nextcloud instance are
|
|
58
52
|
> maintained in the [official documentation](https://knuckles-team.github.io/nextcloud-agent/).
|
|
@@ -20,8 +20,6 @@
|
|
|
20
20
|

|
|
21
21
|

|
|
22
22
|
|
|
23
|
-
*Version: 2.3.3*
|
|
24
|
-
|
|
25
23
|
> **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
|
|
26
24
|
> interfaces, and guidance for provisioning the backing Nextcloud instance are
|
|
27
25
|
> maintained in the [official documentation](https://knuckles-team.github.io/nextcloud-agent/).
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from agent_connector_sdk.connector import Connector
|
|
2
|
+
|
|
3
|
+
from nextcloud_agent.api_client import NextcloudAPI
|
|
4
|
+
from nextcloud_agent.auth import get_client
|
|
5
|
+
|
|
6
|
+
connector = Connector(
|
|
7
|
+
api=NextcloudAPI,
|
|
8
|
+
get_client=get_client,
|
|
9
|
+
tools="nextcloud_agent.mcp_server",
|
|
10
|
+
instructions="nextcloud-agent MCP Server — Condensed Action-Routed Tools.",
|
|
11
|
+
)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Data sources of this connector, declared by tool name (generated by connector-ontology-map migrate).
|
|
2
|
+
|
|
3
|
+
Served live as ``connector://resources``. Regenerate by editing the declarations, not the tools.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# ruff: noqa: E501
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from agent_connector_sdk.ingest.live_declaration import source_meta
|
|
12
|
+
|
|
13
|
+
SOURCES: tuple[Any, ...] = (
|
|
14
|
+
source_meta(
|
|
15
|
+
tool="nextcloud_list_files",
|
|
16
|
+
source_id="nextcloud-files",
|
|
17
|
+
record_type="File",
|
|
18
|
+
id_field="file_id",
|
|
19
|
+
cursor_field="last_modified",
|
|
20
|
+
preset={
|
|
21
|
+
"doc_type": "file",
|
|
22
|
+
"params_style": "args",
|
|
23
|
+
},
|
|
24
|
+
records_path="",
|
|
25
|
+
server="nextcloud-mcp",
|
|
26
|
+
text_field="name",
|
|
27
|
+
title_field="name",
|
|
28
|
+
),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
SCHEMA_VERSION = 2
|
|
32
|
+
|
|
33
|
+
FIELD_SETS: dict[str, dict[str, str]] = {
|
|
34
|
+
"fields_1": {
|
|
35
|
+
"mimeType": "xsd:string",
|
|
36
|
+
"modifiedAt": "xsd:string",
|
|
37
|
+
"path": "xsd:string",
|
|
38
|
+
"sizeBytes": "xsd:integer",
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
SCHEMA_MAPPINGS: dict[str, Any] = {
|
|
43
|
+
"CalendarEvent": {
|
|
44
|
+
"field_sets": ["fields_1"],
|
|
45
|
+
"ontology_class": "Event",
|
|
46
|
+
},
|
|
47
|
+
"File": {
|
|
48
|
+
"field_sets": ["fields_1"],
|
|
49
|
+
"ontology_class": "File",
|
|
50
|
+
},
|
|
51
|
+
"Folder": {
|
|
52
|
+
"field_sets": ["fields_1"],
|
|
53
|
+
"ontology_class": None,
|
|
54
|
+
},
|
|
55
|
+
"Share": {
|
|
56
|
+
"field_sets": ["fields_1"],
|
|
57
|
+
"ontology_class": None,
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
RESOURCES: tuple[dict[str, str], ...] = (
|
|
62
|
+
{
|
|
63
|
+
"id_prefix": "calendarevent",
|
|
64
|
+
"label": "Calendar Event",
|
|
65
|
+
"name": "CalendarEvent",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id_prefix": "file",
|
|
69
|
+
"label": "Nextcloud File",
|
|
70
|
+
"name": "File",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id_prefix": "folder",
|
|
74
|
+
"label": "Nextcloud Folder",
|
|
75
|
+
"name": "Folder",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"id_prefix": "share",
|
|
79
|
+
"label": "Nextcloud Share",
|
|
80
|
+
"name": "Share",
|
|
81
|
+
},
|
|
82
|
+
)
|
|
@@ -17,65 +17,11 @@ import posixpath
|
|
|
17
17
|
from typing import Any
|
|
18
18
|
|
|
19
19
|
from agent_connector_sdk.ingest import (
|
|
20
|
-
ChangeSet,
|
|
21
|
-
Entity,
|
|
22
|
-
IngestBinding,
|
|
23
|
-
IngestError,
|
|
24
20
|
KnowledgeIngest,
|
|
25
|
-
|
|
26
|
-
current_ingest,
|
|
21
|
+
SourceStream,
|
|
27
22
|
)
|
|
28
23
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
_ENTITY_RESERVED_KEYS = frozenset({"id", "node_type"})
|
|
32
|
-
_RELATIONSHIP_RESERVED_KEYS = frozenset({"source", "target", "relationship"})
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def _to_entity(record: dict[str, Any]) -> Entity:
|
|
36
|
-
return Entity(
|
|
37
|
-
id=record.get("id"),
|
|
38
|
-
node_type=record.get("node_type"),
|
|
39
|
-
properties={
|
|
40
|
-
key: value
|
|
41
|
-
for key, value in record.items()
|
|
42
|
-
if key not in _ENTITY_RESERVED_KEYS
|
|
43
|
-
},
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def _to_relationship(record: dict[str, Any]) -> Relationship:
|
|
48
|
-
properties = {
|
|
49
|
-
key: value
|
|
50
|
-
for key, value in record.items()
|
|
51
|
-
if key not in _RELATIONSHIP_RESERVED_KEYS
|
|
52
|
-
}
|
|
53
|
-
return Relationship(
|
|
54
|
-
source=record["source"],
|
|
55
|
-
target=record["target"],
|
|
56
|
-
relationship=record["relationship"],
|
|
57
|
-
properties=properties or None,
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
async def _ingest(
|
|
62
|
-
entities: list[dict[str, Any]],
|
|
63
|
-
relationships: list[dict[str, Any]] | None = None,
|
|
64
|
-
*,
|
|
65
|
-
ingest: KnowledgeIngest | None = None,
|
|
66
|
-
) -> dict[str, int]:
|
|
67
|
-
"""Route typed nodes/edges through the SDK ingest facade (injectable for tests)."""
|
|
68
|
-
if not entities:
|
|
69
|
-
raise IngestError("ingest needs at least one entity")
|
|
70
|
-
change_set = ChangeSet(
|
|
71
|
-
entities=tuple(_to_entity(entity) for entity in entities),
|
|
72
|
-
relationships=tuple(
|
|
73
|
-
_to_relationship(relationship) for relationship in relationships or ()
|
|
74
|
-
),
|
|
75
|
-
)
|
|
76
|
-
service = ingest or current_ingest()
|
|
77
|
-
receipt = await service.submit(_BINDING, change_set)
|
|
78
|
-
return {"nodes": receipt.affected_count, "edges": receipt.relationship_count}
|
|
24
|
+
STREAM = SourceStream.for_package(__package__.split(".")[0], "nextcloud")
|
|
79
25
|
|
|
80
26
|
|
|
81
27
|
async def ingest_listing(
|
|
@@ -143,7 +89,7 @@ async def ingest_listing(
|
|
|
143
89
|
{"source": node["id"], "target": parent_id, "relationship": "inFolder"}
|
|
144
90
|
)
|
|
145
91
|
|
|
146
|
-
return await
|
|
92
|
+
return await STREAM.entities(entities, relationships, ingest=ingest)
|
|
147
93
|
|
|
148
94
|
|
|
149
95
|
async def ingest_shares(
|
|
@@ -192,7 +138,7 @@ async def ingest_shares(
|
|
|
192
138
|
)
|
|
193
139
|
if not entities:
|
|
194
140
|
return None
|
|
195
|
-
return await
|
|
141
|
+
return await STREAM.entities(entities, relationships, ingest=ingest)
|
|
196
142
|
|
|
197
143
|
|
|
198
144
|
async def ingest_calendar_events(
|
|
@@ -218,4 +164,4 @@ async def ingest_calendar_events(
|
|
|
218
164
|
)
|
|
219
165
|
if not entities:
|
|
220
166
|
return None
|
|
221
|
-
return await
|
|
167
|
+
return await STREAM.entities(entities, None, ingest=ingest)
|
|
@@ -3,7 +3,6 @@ import warnings
|
|
|
3
3
|
|
|
4
4
|
from fastmcp import Context, FastMCP
|
|
5
5
|
from fastmcp.dependencies import Depends
|
|
6
|
-
from fastmcp.utilities.logging import get_logger
|
|
7
6
|
from pydantic import Field
|
|
8
7
|
|
|
9
8
|
# Filter RequestsDependencyWarning early to prevent log spam
|
|
@@ -19,26 +18,12 @@ with warnings.catch_warnings():
|
|
|
19
18
|
warnings.filterwarnings("ignore", message=".*urllib3.*or chardet.*")
|
|
20
19
|
warnings.filterwarnings("ignore", message=".*urllib3.*or charset_normalizer.*")
|
|
21
20
|
|
|
22
|
-
import logging
|
|
23
|
-
import sys
|
|
24
|
-
from typing import Any
|
|
25
21
|
|
|
26
|
-
from agent_connector_sdk.config import load_config
|
|
27
22
|
from agent_connector_sdk.mcp.action_dispatch import resolve_action
|
|
28
23
|
from agent_connector_sdk.mcp.concurrency import run_blocking
|
|
29
|
-
from agent_connector_sdk.mcp.server import create_mcp_server
|
|
30
|
-
from agent_connector_sdk.mcp.tool_surface import register_tool_surface
|
|
31
|
-
from starlette.requests import Request
|
|
32
|
-
from starlette.responses import JSONResponse
|
|
33
24
|
|
|
34
|
-
from nextcloud_agent.api_client import NextcloudAPI
|
|
35
25
|
from nextcloud_agent.auth import get_client
|
|
36
26
|
|
|
37
|
-
__version__ = "2.3.3"
|
|
38
|
-
|
|
39
|
-
logger = get_logger(name="nextcloud-agent")
|
|
40
|
-
logger.setLevel(logging.INFO)
|
|
41
|
-
|
|
42
27
|
|
|
43
28
|
def register_files_tools(mcp: FastMCP):
|
|
44
29
|
"""
|
|
@@ -303,56 +288,3 @@ def register_contacts_tools(mcp: FastMCP):
|
|
|
303
288
|
if action == "create_contact":
|
|
304
289
|
return await run_blocking(client.create_contact, **kwargs)
|
|
305
290
|
raise ValueError(f"Unknown action: {action}")
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
def get_mcp_instance() -> tuple[Any, ...]:
|
|
309
|
-
"""
|
|
310
|
-
Initialize and return the MCP instance.
|
|
311
|
-
"""
|
|
312
|
-
load_config()
|
|
313
|
-
args, mcp, middlewares = create_mcp_server(
|
|
314
|
-
name="nextcloud-agent MCP",
|
|
315
|
-
version=__version__,
|
|
316
|
-
instructions="nextcloud-agent MCP Server — Condensed Action-Routed Tools.",
|
|
317
|
-
)
|
|
318
|
-
|
|
319
|
-
@mcp.custom_route("/health", methods=["GET"])
|
|
320
|
-
async def health_check(request: Request) -> JSONResponse:
|
|
321
|
-
return JSONResponse({"status": "OK"})
|
|
322
|
-
|
|
323
|
-
register_tool_surface(
|
|
324
|
-
mcp,
|
|
325
|
-
client_cls=NextcloudAPI,
|
|
326
|
-
get_client=get_client,
|
|
327
|
-
service="nextcloud-agent",
|
|
328
|
-
tools_module=sys.modules[__name__],
|
|
329
|
-
)
|
|
330
|
-
|
|
331
|
-
for mw in middlewares:
|
|
332
|
-
mcp.add_middleware(mw)
|
|
333
|
-
return mcp, args, middlewares
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
def mcp_server() -> None:
|
|
337
|
-
"""
|
|
338
|
-
Launch the MCP server process.
|
|
339
|
-
"""
|
|
340
|
-
mcp, args, middlewares = get_mcp_instance()
|
|
341
|
-
print(f"nextcloud-agent MCP v{__version__}", file=sys.stderr)
|
|
342
|
-
print("\nStarting MCP Server", file=sys.stderr)
|
|
343
|
-
print(f" Transport: {args.transport.upper()}", file=sys.stderr)
|
|
344
|
-
print(f" Auth: {args.auth_type}", file=sys.stderr)
|
|
345
|
-
|
|
346
|
-
if args.transport == "stdio":
|
|
347
|
-
mcp.run(transport="stdio")
|
|
348
|
-
elif args.transport == "streamable-http":
|
|
349
|
-
mcp.run(transport="streamable-http", host=args.host, port=args.port)
|
|
350
|
-
elif args.transport == "sse":
|
|
351
|
-
mcp.run(transport="sse", host=args.host, port=args.port)
|
|
352
|
-
else:
|
|
353
|
-
logger.error("Invalid transport", extra={"transport": args.transport})
|
|
354
|
-
sys.exit(1)
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if __name__ == "__main__":
|
|
358
|
-
mcp_server()
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"api_version": "
|
|
2
|
+
"api_version": "graphos.io/v1",
|
|
3
3
|
"artifacts": {
|
|
4
4
|
"nextcloud_agent/ontology/fixtures/records.json": "aeff7048eae4bc5068dcd2070ad0f0e02b1de63bf9fd5dbecf6a51c5ebd26dc7",
|
|
5
|
-
"nextcloud_agent/ontology/mappings/source.yaml": "
|
|
5
|
+
"nextcloud_agent/ontology/mappings/source.yaml": "88a1d3c331f53626adcb3998eb8f262a33a59065ad8f99ad70e7a82a14c41d49",
|
|
6
6
|
"nextcloud_agent/ontology/migrations/manifest.json": "25716b991f14c59cc202177dfa6d410b396e18a5c9accc92238e5433825535e7",
|
|
7
|
-
"nextcloud_agent/ontology/nextcloud.ttl": "
|
|
7
|
+
"nextcloud_agent/ontology/nextcloud.ttl": "19a6a86795f930ab216e58fa59f02aa4f26ccf0cd08a3dee859383b640d1f30f",
|
|
8
8
|
"nextcloud_agent/ontology/shapes/connector.shacl.ttl": "9a8192289bd6b9a24b4d215cf0fe0391d7e706cf461704dff4c537b5f82724f6"
|
|
9
9
|
},
|
|
10
10
|
"checks": {
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"synthetic_fixture_contract": "passed"
|
|
16
16
|
},
|
|
17
17
|
"compatibility": {
|
|
18
|
-
"
|
|
18
|
+
"agent_utilities": ">=2.5.0,<3",
|
|
19
19
|
"bundle_schema": "2",
|
|
20
20
|
"epistemic_graph": ">=2.27.0,<3"
|
|
21
21
|
},
|
|
22
|
-
"connector": "nextcloud-
|
|
22
|
+
"connector": "nextcloud-agent",
|
|
23
23
|
"kind": "ConnectorSourceAttestation",
|
|
24
24
|
"live_certified": false,
|
|
25
25
|
"mode": "offline-source",
|
|
@@ -29,5 +29,5 @@
|
|
|
29
29
|
"signer": "UNSIGNED-PREVIEW",
|
|
30
30
|
"signing_public_key": "",
|
|
31
31
|
"status": "source-validated",
|
|
32
|
-
"validated_at": "2026-
|
|
32
|
+
"validated_at": "2026-10-24T13:49:17Z"
|
|
33
33
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nextcloud-agent
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.4
|
|
4
4
|
Summary: Nextcloud MCP Server for Agentic AI!
|
|
5
|
-
Author-email:
|
|
5
|
+
Author-email: Repository Maintainers <maintainers@knuckles.team>
|
|
6
6
|
License: MIT
|
|
7
7
|
Classifier: Development Status :: 3 - Alpha
|
|
8
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -12,16 +12,12 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Requires-Python: >=3.12
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: agent-connector-sdk[mcp]<
|
|
15
|
+
Requires-Dist: agent-connector-sdk[mcp]<0.6.0,>=0.5.4
|
|
16
16
|
Requires-Dist: requests>=2.34.2
|
|
17
17
|
Requires-Dist: defusedxml>=0.7.1
|
|
18
18
|
Requires-Dist: python-dateutil>=2.9.0.post0
|
|
19
19
|
Requires-Dist: icalendar>=7.3.0
|
|
20
20
|
Requires-Dist: vobject>=0.9.9
|
|
21
|
-
Provides-Extra: mcp
|
|
22
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.4.1; extra == "mcp"
|
|
23
|
-
Provides-Extra: all
|
|
24
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.4.1; extra == "all"
|
|
25
21
|
Provides-Extra: test
|
|
26
22
|
Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
|
|
27
23
|
Requires-Dist: pytest>=9.1.1; extra == "test"
|
|
@@ -51,8 +47,6 @@ Dynamic: license-file
|
|
|
51
47
|

|
|
52
48
|

|
|
53
49
|
|
|
54
|
-
*Version: 2.3.3*
|
|
55
|
-
|
|
56
50
|
> **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
|
|
57
51
|
> interfaces, and guidance for provisioning the backing Nextcloud instance are
|
|
58
52
|
> maintained in the [official documentation](https://knuckles-team.github.io/nextcloud-agent/).
|
|
@@ -21,7 +21,6 @@ nextcloud_agent/api/api_client_calendar.py
|
|
|
21
21
|
nextcloud_agent/api/api_client_contacts.py
|
|
22
22
|
nextcloud_agent/api/api_client_files.py
|
|
23
23
|
nextcloud_agent/api/xml_security.py
|
|
24
|
-
nextcloud_agent/connectors/__init__.py
|
|
25
24
|
nextcloud_agent/ontology/__init__.py
|
|
26
25
|
nextcloud_agent/ontology/certification.json
|
|
27
26
|
nextcloud_agent/ontology/nextcloud.ttl
|
|
@@ -29,9 +28,7 @@ nextcloud_agent/ontology/fixtures/records.json
|
|
|
29
28
|
nextcloud_agent/ontology/mappings/source.yaml
|
|
30
29
|
nextcloud_agent/ontology/migrations/manifest.json
|
|
31
30
|
nextcloud_agent/ontology/shapes/connector.shacl.ttl
|
|
32
|
-
nextcloud_agent/prompts/__init__.py
|
|
33
31
|
nextcloud_agent/prompts/file_steward.json
|
|
34
|
-
nextcloud_agent/skills/__init__.py
|
|
35
32
|
nextcloud_agent/skills/nextcloud-agent-operations/SKILL.md
|
|
36
33
|
nextcloud_agent/skills/nextcloud-agent-operations/agents/openai.yaml
|
|
37
34
|
nextcloud_agent/skills/nextcloud-agent-operations/references/catalog.md
|
|
@@ -41,13 +38,9 @@ nextcloud_agent/skills/nextcloud-ingest/SKILL.md
|
|
|
41
38
|
nextcloud_agent/skills/nextcloud-ingest/WORKFLOW.md
|
|
42
39
|
nextcloud_agent/skills/nextcloud-shares/SKILL.md
|
|
43
40
|
nextcloud_agent/skills/nextcloud-shares/WORKFLOW.md
|
|
44
|
-
scripts/security_sanitizer.py
|
|
45
|
-
scripts/verify_api_integration.py
|
|
46
41
|
tests/conftest.py
|
|
47
42
|
tests/test_api_client.py
|
|
48
43
|
tests/test_auth.py
|
|
49
|
-
tests/test_cli_server.py
|
|
50
|
-
tests/test_default_content_surfaces.py
|
|
51
44
|
tests/test_fleet_name.py
|
|
52
45
|
tests/test_init.py
|
|
53
46
|
tests/test_init_dynamics.py
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
agent-connector-sdk[mcp]<
|
|
1
|
+
agent-connector-sdk[mcp]<0.6.0,>=0.5.4
|
|
2
2
|
requests>=2.34.2
|
|
3
3
|
defusedxml>=0.7.1
|
|
4
4
|
python-dateutil>=2.9.0.post0
|
|
5
5
|
icalendar>=7.3.0
|
|
6
6
|
vobject>=0.9.9
|
|
7
7
|
|
|
8
|
-
[all]
|
|
9
|
-
agent-connector-sdk[mcp]<1.0.0,>=0.4.1
|
|
10
|
-
|
|
11
|
-
[mcp]
|
|
12
|
-
agent-connector-sdk[mcp]<1.0.0,>=0.4.1
|
|
13
|
-
|
|
14
8
|
[test]
|
|
15
9
|
pytest-xdist>=3.8.0
|
|
16
10
|
pytest>=9.1.1
|
|
@@ -4,40 +4,32 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nextcloud-agent"
|
|
7
|
-
version = "2.3.
|
|
7
|
+
version = "2.3.4"
|
|
8
8
|
description = "Nextcloud MCP Server for Agentic AI!"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
classifiers = [ "Development Status :: 3 - Alpha", "License :: OSI Approved :: MIT License", "Environment :: Console", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3",]
|
|
11
11
|
requires-python = ">=3.12"
|
|
12
|
-
dependencies = [ "agent-connector-sdk[mcp]>=0.4
|
|
12
|
+
dependencies = [ "agent-connector-sdk[mcp]>=0.5.4,<0.6.0", "requests>=2.34.2", "defusedxml>=0.7.1", "python-dateutil>=2.9.0.post0", "icalendar>=7.3.0", "vobject>=0.9.9",]
|
|
13
13
|
[[project.authors]]
|
|
14
|
-
name = "
|
|
15
|
-
email = "maintainers@
|
|
14
|
+
name = "Repository Maintainers"
|
|
15
|
+
email = "maintainers@knuckles.team"
|
|
16
16
|
|
|
17
17
|
[project.license]
|
|
18
18
|
text = "MIT"
|
|
19
19
|
|
|
20
20
|
[project.scripts]
|
|
21
|
-
nextcloud-mcp = "
|
|
21
|
+
nextcloud-mcp = "agent_connector_sdk.cli:serve"
|
|
22
22
|
|
|
23
23
|
[project.optional-dependencies]
|
|
24
|
-
mcp = [ "agent-connector-sdk[mcp]>=0.4.1,<1.0.0",]
|
|
25
|
-
all = [ "agent-connector-sdk[mcp]>=0.4.1,<1.0.0",]
|
|
26
24
|
test = [
|
|
27
25
|
"pytest-xdist>=3.8.0", "pytest>=9.1.1", "pytest-asyncio>=1.4.0", "pytest-cov>=7.1.0",]
|
|
28
26
|
|
|
29
|
-
[project.entry-points."agent_connector_sdk.skill_providers"]
|
|
30
|
-
nextcloud-agent = "nextcloud_agent.skills"
|
|
31
|
-
|
|
32
|
-
[project.entry-points."agent_connector_sdk.ontology_providers"]
|
|
33
|
-
nextcloud-agent = "nextcloud_agent.ontology"
|
|
34
|
-
|
|
35
27
|
[project.entry-points."agent_connector_sdk.prompt_providers"]
|
|
36
28
|
nextcloud-agent = "nextcloud_agent.prompts"
|
|
37
29
|
|
|
38
30
|
# The one declared connector identity: the fleet name (SDK-CONNECTOR-CONTROL-R071).
|
|
39
31
|
[project.entry-points."agent_connector_sdk.connector"]
|
|
40
|
-
nextcloud-mcp = "nextcloud_agent"
|
|
32
|
+
nextcloud-mcp = "nextcloud_agent:connector"
|
|
41
33
|
|
|
42
34
|
[tool.uv.workspace]
|
|
43
35
|
members = ["."]
|
|
@@ -51,6 +43,7 @@ override-dependencies = [
|
|
|
51
43
|
]
|
|
52
44
|
|
|
53
45
|
[tool.ruff]
|
|
46
|
+
extend-exclude = ["tests", "scripts"]
|
|
54
47
|
line-length = 88
|
|
55
48
|
target-version = "py310"
|
|
56
49
|
|
|
@@ -79,3 +72,10 @@ ignore_names = ["request", "config"]
|
|
|
79
72
|
|
|
80
73
|
[tool.pipelines_hooks.ste]
|
|
81
74
|
exempt = ["specs/*", "specs/**/*"]
|
|
75
|
+
|
|
76
|
+
[tool.pipelines.container]
|
|
77
|
+
debug_apt = ["default-jre", "ripgrep", "tree", "fd-find", "curl", "nano", "build-essential", "cmake", "libssl-dev", "libcurl4-openssl-dev", "pkg-config", "cargo", "rustc"]
|
|
78
|
+
limits = {"mcp" = {"memory_limit_env" = "AGENT_CONTAINER_MEMORY_LIMIT", "memory_limit" = "4g", "cpu_limit_env" = "AGENT_CONTAINER_CPU_LIMIT", "cpu_limit" = "2.0"}}
|
|
79
|
+
|
|
80
|
+
[tool.pipelines.api_integration]
|
|
81
|
+
baseline = 52.6
|
|
@@ -35,7 +35,7 @@ def _call_connectors(path: Path) -> list[str]:
|
|
|
35
35
|
def test_connector_name_is_the_fleet_name() -> None:
|
|
36
36
|
pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))
|
|
37
37
|
assert pyproject["project"]["entry-points"]["agent_connector_sdk.connector"] == {
|
|
38
|
-
FLEET: "nextcloud_agent"
|
|
38
|
+
FLEET: "nextcloud_agent:connector"
|
|
39
39
|
}
|
|
40
40
|
assert connector_name("nextcloud_agent") == FLEET
|
|
41
41
|
for module in sorted(PACKAGE.glob("*.py")):
|
|
@@ -4,14 +4,14 @@ from unittest.mock import patch
|
|
|
4
4
|
import pytest
|
|
5
5
|
from fastmcp import FastMCP
|
|
6
6
|
|
|
7
|
-
from
|
|
7
|
+
from agent_connector_sdk.connector import build_server
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
@pytest.mark.concept("OS-5.4")
|
|
11
11
|
def test_mcp_instance_creation():
|
|
12
12
|
"""Test that the MCP instance can be created successfully."""
|
|
13
13
|
with patch.object(sys, "argv", [""]):
|
|
14
|
-
|
|
14
|
+
_, mcp = build_server("nextcloud_agent", command_args=[])
|
|
15
15
|
assert isinstance(mcp, FastMCP)
|
|
16
16
|
|
|
17
17
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from unittest.mock import patch
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
VALID_TOOL_ACTIONS = {
|
|
7
|
+
"nextcloud_files": [
|
|
8
|
+
"list_files",
|
|
9
|
+
"read_file",
|
|
10
|
+
"write_file",
|
|
11
|
+
"create_folder",
|
|
12
|
+
"delete_item",
|
|
13
|
+
"move_item",
|
|
14
|
+
"copy_item",
|
|
15
|
+
"get_properties",
|
|
16
|
+
],
|
|
17
|
+
"nextcloud_user": ["get_user_info"],
|
|
18
|
+
"nextcloud_sharing": ["list_shares", "create_share", "delete_share"],
|
|
19
|
+
"nextcloud_calendar": [
|
|
20
|
+
"list_calendars",
|
|
21
|
+
"list_calendar_events",
|
|
22
|
+
"create_calendar_event",
|
|
23
|
+
],
|
|
24
|
+
"nextcloud_contacts": ["list_address_books", "list_contacts", "create_contact"],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.mark.concept("ECO-4.0")
|
|
29
|
+
def test_requests_dependency_warning_import_error():
|
|
30
|
+
original_import = __import__
|
|
31
|
+
|
|
32
|
+
def mock_import(name, *args, **kwargs):
|
|
33
|
+
if "RequestsDependencyWarning" in name or "requests.exceptions" in name:
|
|
34
|
+
raise ImportError("mocked import error")
|
|
35
|
+
return original_import(name, *args, **kwargs)
|
|
36
|
+
|
|
37
|
+
if "nextcloud_agent.mcp_server" in sys.modules:
|
|
38
|
+
del sys.modules["nextcloud_agent.mcp_server"]
|
|
39
|
+
|
|
40
|
+
with patch("builtins.__import__", side_effect=mock_import):
|
|
41
|
+
import importlib
|
|
42
|
+
|
|
43
|
+
import nextcloud_agent.mcp_server
|
|
44
|
+
|
|
45
|
+
importlib.reload(nextcloud_agent.mcp_server)
|
|
46
|
+
|
|
47
|
+
# Explicit assertion resolving FR-024 (1 tests have no assertions)
|
|
48
|
+
assert sys.modules["nextcloud_agent.mcp_server"] is not None
|
|
49
|
+
from agent_connector_sdk.connector import build_server
|
|
50
|
+
|
|
51
|
+
_, server = build_server("nextcloud_agent", command_args=["--transport", "stdio"])
|
|
52
|
+
assert server is not None
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.3.3"
|