basic-memory 0.8.0__py3-none-any.whl → 0.9.0__py3-none-any.whl

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.

Potentially problematic release.


This version of basic-memory might be problematic. Click here for more details.

Files changed (75) hide show
  1. basic_memory/__init__.py +1 -1
  2. basic_memory/alembic/migrations.py +4 -9
  3. basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py +106 -0
  4. basic_memory/api/app.py +9 -6
  5. basic_memory/api/routers/__init__.py +2 -1
  6. basic_memory/api/routers/knowledge_router.py +30 -4
  7. basic_memory/api/routers/memory_router.py +3 -2
  8. basic_memory/api/routers/project_info_router.py +275 -0
  9. basic_memory/api/routers/search_router.py +22 -4
  10. basic_memory/cli/app.py +54 -3
  11. basic_memory/cli/commands/__init__.py +15 -2
  12. basic_memory/cli/commands/db.py +9 -13
  13. basic_memory/cli/commands/import_chatgpt.py +26 -30
  14. basic_memory/cli/commands/import_claude_conversations.py +27 -29
  15. basic_memory/cli/commands/import_claude_projects.py +29 -31
  16. basic_memory/cli/commands/import_memory_json.py +26 -28
  17. basic_memory/cli/commands/mcp.py +7 -1
  18. basic_memory/cli/commands/project.py +119 -0
  19. basic_memory/cli/commands/project_info.py +167 -0
  20. basic_memory/cli/commands/status.py +7 -9
  21. basic_memory/cli/commands/sync.py +54 -9
  22. basic_memory/cli/commands/{tools.py → tool.py} +92 -19
  23. basic_memory/cli/main.py +40 -1
  24. basic_memory/config.py +155 -7
  25. basic_memory/db.py +19 -4
  26. basic_memory/deps.py +10 -3
  27. basic_memory/file_utils.py +32 -16
  28. basic_memory/markdown/utils.py +5 -0
  29. basic_memory/mcp/main.py +1 -2
  30. basic_memory/mcp/prompts/__init__.py +6 -2
  31. basic_memory/mcp/prompts/ai_assistant_guide.py +6 -8
  32. basic_memory/mcp/prompts/continue_conversation.py +65 -126
  33. basic_memory/mcp/prompts/recent_activity.py +55 -13
  34. basic_memory/mcp/prompts/search.py +72 -17
  35. basic_memory/mcp/prompts/utils.py +139 -82
  36. basic_memory/mcp/server.py +1 -1
  37. basic_memory/mcp/tools/__init__.py +11 -22
  38. basic_memory/mcp/tools/build_context.py +85 -0
  39. basic_memory/mcp/tools/canvas.py +17 -19
  40. basic_memory/mcp/tools/delete_note.py +28 -0
  41. basic_memory/mcp/tools/project_info.py +51 -0
  42. basic_memory/mcp/tools/{resource.py → read_content.py} +42 -5
  43. basic_memory/mcp/tools/read_note.py +190 -0
  44. basic_memory/mcp/tools/recent_activity.py +100 -0
  45. basic_memory/mcp/tools/search.py +56 -17
  46. basic_memory/mcp/tools/utils.py +245 -17
  47. basic_memory/mcp/tools/write_note.py +124 -0
  48. basic_memory/models/search.py +2 -1
  49. basic_memory/repository/entity_repository.py +3 -2
  50. basic_memory/repository/project_info_repository.py +9 -0
  51. basic_memory/repository/repository.py +23 -6
  52. basic_memory/repository/search_repository.py +33 -10
  53. basic_memory/schemas/__init__.py +12 -0
  54. basic_memory/schemas/memory.py +3 -2
  55. basic_memory/schemas/project_info.py +96 -0
  56. basic_memory/schemas/search.py +27 -32
  57. basic_memory/services/context_service.py +3 -3
  58. basic_memory/services/entity_service.py +8 -2
  59. basic_memory/services/file_service.py +105 -53
  60. basic_memory/services/link_resolver.py +5 -45
  61. basic_memory/services/search_service.py +45 -16
  62. basic_memory/sync/sync_service.py +274 -39
  63. basic_memory/sync/watch_service.py +160 -30
  64. basic_memory/utils.py +40 -40
  65. basic_memory-0.9.0.dist-info/METADATA +736 -0
  66. basic_memory-0.9.0.dist-info/RECORD +99 -0
  67. basic_memory/mcp/prompts/json_canvas_spec.py +0 -25
  68. basic_memory/mcp/tools/knowledge.py +0 -68
  69. basic_memory/mcp/tools/memory.py +0 -177
  70. basic_memory/mcp/tools/notes.py +0 -201
  71. basic_memory-0.8.0.dist-info/METADATA +0 -379
  72. basic_memory-0.8.0.dist-info/RECORD +0 -91
  73. {basic_memory-0.8.0.dist-info → basic_memory-0.9.0.dist-info}/WHEEL +0 -0
  74. {basic_memory-0.8.0.dist-info → basic_memory-0.9.0.dist-info}/entry_points.txt +0 -0
  75. {basic_memory-0.8.0.dist-info → basic_memory-0.9.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,99 @@
1
+ basic_memory/__init__.py,sha256=0_LT1EXC7q97Yg06x_HyIbgFHRqZg8II59ADHFmFcrc,122
2
+ basic_memory/config.py,sha256=uJ3s5Hka7rKVMDhKXMJhtxdwZHPfSVape7a4ySkJhws,7644
3
+ basic_memory/db.py,sha256=UDWBr52u7oBT4aXputhAG_Prmsv5og00sYVzPmaylhk,6026
4
+ basic_memory/deps.py,sha256=yI6RL_5-8LXw7ywSJ_84BXAczDtv2h9GFLw-E9XDJFg,5770
5
+ basic_memory/file_utils.py,sha256=6pcqhBXSp7r_KogLWx8HUUaWCWdoIsSJnM7psD92f-c,6604
6
+ basic_memory/utils.py,sha256=EPumxT4HkprZG9BzWZnym3teOjn24Vm3lgncQADN5ew,3764
7
+ basic_memory/alembic/alembic.ini,sha256=IEZsnF8CbbZnkwBr67LzKKNobHuzTaQNUvM8Psop5xc,3733
8
+ basic_memory/alembic/env.py,sha256=GyQpEpQu84flqAdelxR0-H9nbkHrVoCboYGfmltBDoA,2737
9
+ basic_memory/alembic/migrations.py,sha256=lriHPXDdBLSNXEW3QTpU0SJKuVd1V-8NrVkpN3qfsUQ,718
10
+ basic_memory/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
11
+ basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py,sha256=lTbWlAnd1es7xU99DoJgfaRe1_Kte8TL98riqeKGV80,4363
12
+ basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py,sha256=k6xYTmYPM9Ros-7CA7BwZBKYwoK_gmVdC-2n8FAjdoE,1840
13
+ basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py,sha256=RsGymQzfRXV1LSNKiyi0lMilTxW1NgwS9jR67ye2apI,1428
14
+ basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py,sha256=Lbo3dEzdId_vKRFe3jMkGFF3dNQpblPIQa4Bh7np-zA,4020
15
+ basic_memory/api/__init__.py,sha256=wCpj-21j1D0KzKl9Ql6unLBVFY0K1uGp_FeSZRKtqpk,72
16
+ basic_memory/api/app.py,sha256=NLcNpfNzVz4pgtbjaZUHTvRCqay16J_G4K1ok9DMDCU,1516
17
+ basic_memory/api/routers/__init__.py,sha256=SKuL-weA58hYj0NOMCQRfmsaumlNjjyVHDXNpRO38bQ,305
18
+ basic_memory/api/routers/knowledge_router.py,sha256=iYuBguMb6ERitAwoelSejBYJqLTGfjpkzAHrqwTKjVE,5876
19
+ basic_memory/api/routers/memory_router.py,sha256=W_uHJe2c4XN96mFj6XNvUH6INVbl1BMxy0KUchLcbxU,5421
20
+ basic_memory/api/routers/project_info_router.py,sha256=Heoz4mHaAeWQYDMsStk4fpwkVNmBlGh9XVbuJMpyGik,9015
21
+ basic_memory/api/routers/resource_router.py,sha256=WEJEqEaY_yTKj5-U-rW4kXQKUcJflykgwI6_g_R41ck,8058
22
+ basic_memory/api/routers/search_router.py,sha256=R_a5OF5_8rCjmoOMhmw3M4VLCy6I1KLGJ-otSLB0rbI,1953
23
+ basic_memory/cli/__init__.py,sha256=arcKLAWRDhPD7x5t80MlviZeYzwHZ0GZigyy3NKVoGk,33
24
+ basic_memory/cli/app.py,sha256=J4mkWnxbevOYmJwwRMx344olGOxoXq0o4RNG6DMQLKE,1804
25
+ basic_memory/cli/main.py,sha256=9uwxOUc4mDeTeZCEWyJh7X5PzPXG1fva2veV2OPbFtg,1442
26
+ basic_memory/cli/commands/__init__.py,sha256=aBihwtUFs0MpsxCed74A5fYoxFmJA4NOVXPRrVY4lnw,427
27
+ basic_memory/cli/commands/db.py,sha256=UL3JXGJrLzKZ-uRwgk6p0kbRznBy5x7keirvweVGNvY,754
28
+ basic_memory/cli/commands/import_chatgpt.py,sha256=bGKHz5pFD-oabaeeSqylHBcr9hnF4CzUqEIaFyRwpPE,8147
29
+ basic_memory/cli/commands/import_claude_conversations.py,sha256=Ba97fH5yfW642yrkxay3YkyDdgIYCeru-MUIZfEGblo,6812
30
+ basic_memory/cli/commands/import_claude_projects.py,sha256=GePfhEMstD97EIGoM8vJMmwDCnYfh1PjZH7DNcqzdqA,6634
31
+ basic_memory/cli/commands/import_memory_json.py,sha256=zqpU4eCzQXx04aRsigddJAyhvklmTgSAzeRTuEdNw0c,5194
32
+ basic_memory/cli/commands/mcp.py,sha256=ue_zDA8w0zZZToHLvu56s8hWkalgZsC64CfTyXX6z2I,715
33
+ basic_memory/cli/commands/project.py,sha256=vEPv34Grn8DGwP8Ig9xcFWeVW0cro_Qyfq2TU22pcQQ,4103
34
+ basic_memory/cli/commands/project_info.py,sha256=2XFe0eONsJ-FOmiOO6faYAS9AgX7Dmj4HNeTTrUr0ZE,7099
35
+ basic_memory/cli/commands/status.py,sha256=nbs3myxaNtehEEJ4BBngPuKs-vqZTHNCCb0bTgDsE-s,5277
36
+ basic_memory/cli/commands/sync.py,sha256=JxGJA6b7Qksz0ZKonHfB3s--7qzY7eWeLogPX8tR1pY,8351
37
+ basic_memory/cli/commands/tool.py,sha256=DjoB4slhmzfCjIgom1-xBP6sRl_gy7PrhGtQk3rNAqM,8855
38
+ basic_memory/markdown/__init__.py,sha256=DdzioCWtDnKaq05BHYLgL_78FawEHLpLXnp-kPSVfIc,501
39
+ basic_memory/markdown/entity_parser.py,sha256=LnjG_wg38LVN8JndsZJV2UVGPIaoIV5sGs94iQ9PL6k,3781
40
+ basic_memory/markdown/markdown_processor.py,sha256=mV3pYoDTaQMEl1tA5n_XztBvNlYyH2SzKs4vnKdAet4,4952
41
+ basic_memory/markdown/plugins.py,sha256=gtIzKRjoZsyvBqLpVNnrmzl_cbTZ5ZGn8kcuXxQjRko,6639
42
+ basic_memory/markdown/schemas.py,sha256=mzVEDUhH98kwETMknjkKw5H697vg_zUapsJkJVi17ho,1894
43
+ basic_memory/markdown/utils.py,sha256=zlHlUtrnXaUCnsaPNJzR0wlhg2kB1YbXx0DMvs-snJM,2973
44
+ basic_memory/mcp/__init__.py,sha256=dsDOhKqjYeIbCULbHIxfcItTbqudEuEg1Np86eq0GEQ,35
45
+ basic_memory/mcp/async_client.py,sha256=Eo345wANiBRSM4u3j_Vd6Ax4YtMg7qbWd9PIoFfj61I,236
46
+ basic_memory/mcp/main.py,sha256=0kbcyf1PxRC1bLnHv2zzParfJ6cOq7Am9ScF9UoI50U,703
47
+ basic_memory/mcp/server.py,sha256=VGv0uWma6JGkT6Y_GESYGhGMYfPavkhEKlCNza8bvtY,287
48
+ basic_memory/mcp/prompts/__init__.py,sha256=-Bl9Dgj2TD9PULjzggPqXuvPEjWCRy7S9Yg03h2-U7A,615
49
+ basic_memory/mcp/prompts/ai_assistant_guide.py,sha256=dgPdpC_WR88-ex4aMpAIC6TMZyZD3rgKyUu8qkSNIzw,824
50
+ basic_memory/mcp/prompts/continue_conversation.py,sha256=zb_3cOaO7NMFuStBkJDlMstQZqz1RCOYl6txwaHYM_Q,4424
51
+ basic_memory/mcp/prompts/recent_activity.py,sha256=7607MWiGJWY0vPurhVII17LxLZlXY_zmH3xH9LfT6SY,2793
52
+ basic_memory/mcp/prompts/search.py,sha256=nCz5wPxTszJLNQJ1CE7CIhnamy08EpGLQjoBMlXRRNc,6283
53
+ basic_memory/mcp/prompts/utils.py,sha256=u_bG8DMtMMERvGPJfA3gbl5VAs0xmkuK8ZJBkY8xyV8,5371
54
+ basic_memory/mcp/tools/__init__.py,sha256=mp8BiY-2YY5zzGBAIbf9hMCQM6uhDtst3eq1ApR2p2s,870
55
+ basic_memory/mcp/tools/build_context.py,sha256=8xYRPpeYCEU8F9Dv_ctvbunZ8ciKwmFu9i8Pdv5vYfI,2891
56
+ basic_memory/mcp/tools/canvas.py,sha256=fHC90eshnSSmROTBV-tBB-FSuXSpYVj_BcDrc96pWi0,2993
57
+ basic_memory/mcp/tools/delete_note.py,sha256=mnrgOv-D7f6nsgZIAK0Wvyn0dbkwCg8adW_xJd7jwc0,829
58
+ basic_memory/mcp/tools/project_info.py,sha256=pyoHpOMhjMIvZFku2iEIpXc2XDtbnNeb-OMrJlYR9LU,1710
59
+ basic_memory/mcp/tools/read_content.py,sha256=PKnvLzNmHfzoIxRKXNaYW5P5q0d1azVwG9juPXPYeQo,8148
60
+ basic_memory/mcp/tools/read_note.py,sha256=pM6FUxMdDxxCNxhnDrkrVqIJouIRPbUqSHsL3BVgiy8,6469
61
+ basic_memory/mcp/tools/recent_activity.py,sha256=S0LgIk9RaeYzIsi2FIHs0KK7R1K-LJy3QaSokGlY9ew,3501
62
+ basic_memory/mcp/tools/search.py,sha256=0PcLCpXe73X72jSudVLVMO8TQwEjnB6F1V9jCtjf2ZE,2999
63
+ basic_memory/mcp/tools/utils.py,sha256=tOWklfSlDcoAJCRBmxkCVwkTY_TDBa5vOGxzU8J5eiQ,13636
64
+ basic_memory/mcp/tools/write_note.py,sha256=CdUdFitmuDQl8z36IqrbSB0hSEdw20k_ZIXnpV_KDSc,4374
65
+ basic_memory/models/__init__.py,sha256=Bf0xXV_ryndogvZDiVM_Wb6iV2fHUxYNGMZNWNcZi0s,307
66
+ basic_memory/models/base.py,sha256=4hAXJ8CE1RnjKhb23lPd-QM7G_FXIdTowMJ9bRixspU,225
67
+ basic_memory/models/knowledge.py,sha256=lbKd8VOOVPqXtIhNMY30bIokoQutFjLpHwLD5At90MY,6644
68
+ basic_memory/models/search.py,sha256=YnF2YnP6NUFf7SSy9xvkY055MlfkBXJuxLoOhCTvB2Q,1244
69
+ basic_memory/repository/__init__.py,sha256=TnscLXARq2iOgQZFvQoT9X1Bn9SB_7s1xw2fOqRs3Jg,252
70
+ basic_memory/repository/entity_repository.py,sha256=VLKlQ97-_HhSqc-st_YToWUNE4pJIcKEOcGDxC25q1k,3575
71
+ basic_memory/repository/observation_repository.py,sha256=BOcy4wARqCXu-thYyt7mPxt2A2C8TW0le3s_X9wrK6I,1701
72
+ basic_memory/repository/project_info_repository.py,sha256=nHWzs0WBQ366WfzIYZgnAfU6tyQ_8slEszWNlDSeIlo,336
73
+ basic_memory/repository/relation_repository.py,sha256=DwpTcn9z_1sZQcyMOUABz1k1VSwo_AU63x2zR7aerTk,2933
74
+ basic_memory/repository/repository.py,sha256=cZFCjp7Q-fKwjEYe3ubG1rgYbPEQXsocAn9LgFNXCG0,12071
75
+ basic_memory/repository/search_repository.py,sha256=82NCjq06JUuUQXQ9k_D-h8BBlO5gl51XF9UdcY8gK8Q,11621
76
+ basic_memory/schemas/__init__.py,sha256=KHzF2lZhYXRsH2g6tV5Oivlk1EHFfrlbKuiRllqnBzs,1570
77
+ basic_memory/schemas/base.py,sha256=dwnaI5fJXsdp81mdH0ZpmJ-WICY-0M7ZPWeW5OUgBG8,5685
78
+ basic_memory/schemas/delete.py,sha256=UAR2JK99WMj3gP-yoGWlHD3eZEkvlTSRf8QoYIE-Wfw,1180
79
+ basic_memory/schemas/memory.py,sha256=qqQm89nZQKtrhquHlRnR6LaSWynPi4MgtcMcqvGH5zg,3136
80
+ basic_memory/schemas/project_info.py,sha256=qsZfafp8bn2oqCizX_CVwJZS4HE79kOmaNiNK9C_9_w,3380
81
+ basic_memory/schemas/request.py,sha256=58r9mPGc4Am9rR_zGzo-yqXcsrl5I6n3M5LjGK5gFFk,1626
82
+ basic_memory/schemas/response.py,sha256=lVYR31DTtSeFRddGWX_wQWnQgyiwX0LEpNJ4f4lKpTM,6440
83
+ basic_memory/schemas/search.py,sha256=mfPHo8lzZ8BMLzmID-0g_0pWHhBIBNIvy4c8KYHFuvQ,3655
84
+ basic_memory/services/__init__.py,sha256=oop6SKmzV4_NAYt9otGnupLGVCCKIVgxEcdRQWwh25I,197
85
+ basic_memory/services/context_service.py,sha256=fhJNHQoTEeIC9ZmZ49CXcNF2aVBghVnmo6LtdSDcAas,9708
86
+ basic_memory/services/entity_service.py,sha256=p4yP-VngdtfCqbvygQ968tGQVOJ1nFzN3XRyXenEcRM,12432
87
+ basic_memory/services/exceptions.py,sha256=VGlCLd4UD2w5NWKqC7QpG4jOM_hA7jKRRM-MqvEVMNk,288
88
+ basic_memory/services/file_service.py,sha256=Mz3_G1DyDcPX9bSR1pRHibqWcpiKtz4E29eoKsjWfYY,9905
89
+ basic_memory/services/link_resolver.py,sha256=yWqqKqJtGU_93xy25y6Us4xRTNijrBLz76Nvm_zFEOI,3326
90
+ basic_memory/services/search_service.py,sha256=t3d5jhABs5bXwtOu7_AvRCpVd8RRd2j6Gg59BAYZ0l8,10625
91
+ basic_memory/services/service.py,sha256=V-d_8gOV07zGIQDpL-Ksqs3ZN9l3qf3HZOK1f_YNTag,336
92
+ basic_memory/sync/__init__.py,sha256=CVHguYH457h2u2xoM8KvOilJC71XJlZ-qUh8lHcjYj4,156
93
+ basic_memory/sync/sync_service.py,sha256=YirSOgk0PyqPJoHXVUzAxhNKdd2pebP8sFeXeAYmGjM,21957
94
+ basic_memory/sync/watch_service.py,sha256=heIImU4d0nrVm5kr-zkHpFN2E3v1Z29LXUR2dLq2TPw,12995
95
+ basic_memory-0.9.0.dist-info/METADATA,sha256=Sz9gDlA_gEgMETHekkK-C2dQqCH73pQHPs4puzncXko,25391
96
+ basic_memory-0.9.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
97
+ basic_memory-0.9.0.dist-info/entry_points.txt,sha256=IDQa_VmVTzmvMrpnjhEfM0S3F--XsVGEj3MpdJfuo-Q,59
98
+ basic_memory-0.9.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
99
+ basic_memory-0.9.0.dist-info/RECORD,,
@@ -1,25 +0,0 @@
1
- from pathlib import Path
2
-
3
- import logfire
4
- from loguru import logger
5
-
6
- from basic_memory.mcp.server import mcp
7
-
8
-
9
- @mcp.resource(
10
- uri="memory://json_canvas_spec",
11
- name="json_canvas_spec",
12
- description="JSON Canvas specification for visualizing knowledge graphs in Obsidian"
13
- )
14
- def json_canvas_spec() -> str:
15
- """Return the JSON Canvas specification for Obsidian visualizations.
16
-
17
- Returns:
18
- The JSON Canvas specification document.
19
- """
20
- with logfire.span("Getting JSON Canvas spec"): # pyright: ignore
21
- logger.info("Loading JSON Canvas spec resource")
22
- canvas_spec = Path(__file__).parent.parent.parent.parent.parent / "data/json_canvas_spec_1_0.md"
23
- content = canvas_spec.read_text()
24
- logger.info(f"Loaded JSON Canvas spec ({len(content)} chars)")
25
- return content
@@ -1,68 +0,0 @@
1
- """Knowledge graph management tools for Basic Memory MCP server."""
2
-
3
- import logfire
4
-
5
- from basic_memory.mcp.server import mcp
6
- from basic_memory.mcp.tools.utils import call_get, call_post
7
- from basic_memory.schemas.memory import memory_url_path
8
- from basic_memory.schemas.request import (
9
- GetEntitiesRequest,
10
- )
11
- from basic_memory.schemas.delete import (
12
- DeleteEntitiesRequest,
13
- )
14
- from basic_memory.schemas.response import EntityListResponse, EntityResponse, DeleteEntitiesResponse
15
- from basic_memory.mcp.async_client import client
16
-
17
-
18
- @mcp.tool(
19
- description="Get complete information about a specific entity including observations and relations",
20
- )
21
- async def get_entity(identifier: str) -> EntityResponse:
22
- """Get a specific entity info by its permalink.
23
-
24
- Args:
25
- identifier: Path identifier for the entity
26
- """
27
- with logfire.span("Getting entity", permalink=identifier): # pyright: ignore [reportGeneralTypeIssues]
28
- permalink = memory_url_path(identifier)
29
- url = f"/knowledge/entities/{permalink}"
30
- response = await call_get(client, url)
31
- return EntityResponse.model_validate(response.json())
32
-
33
-
34
- @mcp.tool(
35
- description="Load multiple entities by their permalinks in a single request",
36
- )
37
- async def get_entities(request: GetEntitiesRequest) -> EntityListResponse:
38
- """Load multiple entities by their permalinks.
39
-
40
- Args:
41
- request: OpenNodesRequest containing list of permalinks to load
42
-
43
- Returns:
44
- EntityListResponse containing complete details for each requested entity
45
- """
46
- with logfire.span("Getting multiple entities", permalink_count=len(request.permalinks)): # pyright: ignore [reportGeneralTypeIssues]
47
- url = "/knowledge/entities"
48
- response = await call_get(
49
- client,
50
- url,
51
- params=[
52
- ("permalink", memory_url_path(identifier)) for identifier in request.permalinks
53
- ],
54
- )
55
- return EntityListResponse.model_validate(response.json())
56
-
57
-
58
- @mcp.tool(
59
- description="Permanently delete entities and all related content (observations and relations)",
60
- )
61
- async def delete_entities(request: DeleteEntitiesRequest) -> DeleteEntitiesResponse:
62
- """Delete entities from the knowledge graph."""
63
- with logfire.span("Deleting entities", permalink_count=len(request.permalinks)): # pyright: ignore [reportGeneralTypeIssues]
64
- url = "/knowledge/entities/delete"
65
-
66
- request.permalinks = [memory_url_path(permlink) for permlink in request.permalinks]
67
- response = await call_post(client, url, json=request.model_dump())
68
- return DeleteEntitiesResponse.model_validate(response.json())
@@ -1,177 +0,0 @@
1
- """Discussion context tools for Basic Memory MCP server."""
2
-
3
- from typing import Optional, List
4
-
5
- from loguru import logger
6
- import logfire
7
-
8
- from basic_memory.mcp.async_client import client
9
- from basic_memory.mcp.server import mcp
10
- from basic_memory.mcp.tools.utils import call_get
11
- from basic_memory.schemas.memory import (
12
- GraphContext,
13
- MemoryUrl,
14
- memory_url_path,
15
- normalize_memory_url,
16
- )
17
- from basic_memory.schemas.base import TimeFrame
18
- from basic_memory.schemas.search import SearchItemType
19
-
20
-
21
- @mcp.tool(
22
- description="""Build context from a memory:// URI to continue conversations naturally.
23
-
24
- Use this to follow up on previous discussions or explore related topics.
25
- Timeframes support natural language like:
26
- - "2 days ago"
27
- - "last week"
28
- - "today"
29
- - "3 months ago"
30
- Or standard formats like "7d", "24h"
31
- """,
32
- )
33
- async def build_context(
34
- url: MemoryUrl,
35
- depth: Optional[int] = 1,
36
- timeframe: Optional[TimeFrame] = "7d",
37
- page: int = 1,
38
- page_size: int = 10,
39
- max_related: int = 10,
40
- ) -> GraphContext:
41
- """Get context needed to continue a discussion.
42
-
43
- This tool enables natural continuation of discussions by loading relevant context
44
- from memory:// URIs. It uses pattern matching to find relevant content and builds
45
- a rich context graph of related information.
46
-
47
- Args:
48
- url: memory:// URI pointing to discussion content (e.g. memory://specs/search)
49
- depth: How many relation hops to traverse (1-3 recommended for performance)
50
- timeframe: How far back to look. Supports natural language like "2 days ago", "last week"
51
- page: Page number of results to return (default: 1)
52
- page_size: Number of results to return per page (default: 10)
53
- max_related: Maximum number of related results to return (default: 10)
54
-
55
- Returns:
56
- GraphContext containing:
57
- - primary_results: Content matching the memory:// URI
58
- - related_results: Connected content via relations
59
- - metadata: Context building details
60
-
61
- Examples:
62
- # Continue a specific discussion
63
- build_context("memory://specs/search")
64
-
65
- # Get deeper context about a component
66
- build_context("memory://components/memory-service", depth=2)
67
-
68
- # Look at recent changes to a specification
69
- build_context("memory://specs/document-format", timeframe="today")
70
-
71
- # Research the history of a feature
72
- build_context("memory://features/knowledge-graph", timeframe="3 months ago")
73
- """
74
- with logfire.span("Building context", url=url, depth=depth, timeframe=timeframe): # pyright: ignore [reportGeneralTypeIssues]
75
- logger.info(f"Building context from {url}")
76
- url = normalize_memory_url(url)
77
- response = await call_get(
78
- client,
79
- f"/memory/{memory_url_path(url)}",
80
- params={
81
- "depth": depth,
82
- "timeframe": timeframe,
83
- "page": page,
84
- "page_size": page_size,
85
- "max_related": max_related,
86
- },
87
- )
88
- return GraphContext.model_validate(response.json())
89
-
90
-
91
- @mcp.tool(
92
- description="""Get recent activity from across the knowledge base.
93
-
94
- Timeframe supports natural language formats like:
95
- - "2 days ago"
96
- - "last week"
97
- - "yesterday"
98
- - "today"
99
- - "3 weeks ago"
100
- Or standard formats like "7d"
101
- """,
102
- )
103
- async def recent_activity(
104
- type: Optional[List[SearchItemType]] = None,
105
- depth: Optional[int] = 1,
106
- timeframe: Optional[TimeFrame] = "7d",
107
- page: int = 1,
108
- page_size: int = 10,
109
- max_related: int = 10,
110
- ) -> GraphContext:
111
- """Get recent activity across the knowledge base.
112
-
113
- Args:
114
- type: Filter by content type(s). Valid options:
115
- - ["entity"] for knowledge entities
116
- - ["relation"] for connections between entities
117
- - ["observation"] for notes and observations
118
- Multiple types can be combined: ["entity", "relation"]
119
- depth: How many relation hops to traverse (1-3 recommended)
120
- timeframe: Time window to search. Supports natural language:
121
- - Relative: "2 days ago", "last week", "yesterday"
122
- - Points in time: "2024-01-01", "January 1st"
123
- - Standard format: "7d", "24h"
124
- page: Page number of results to return (default: 1)
125
- page_size: Number of results to return per page (default: 10)
126
- max_related: Maximum number of related results to return (default: 10)
127
-
128
- Returns:
129
- GraphContext containing:
130
- - primary_results: Latest activities matching the filters
131
- - related_results: Connected content via relations
132
- - metadata: Query details and statistics
133
-
134
- Examples:
135
- # Get all entities for the last 10 days (default)
136
- recent_activity()
137
-
138
- # Get all entities from yesterday
139
- recent_activity(type=["entity"], timeframe="yesterday")
140
-
141
- # Get recent relations and observations
142
- recent_activity(type=["relation", "observation"], timeframe="today")
143
-
144
- # Look back further with more context
145
- recent_activity(type=["entity"], depth=2, timeframe="2 weeks ago")
146
-
147
- Notes:
148
- - Higher depth values (>3) may impact performance with large result sets
149
- - For focused queries, consider using build_context with a specific URI
150
- - Max timeframe is 1 year in the past
151
- """
152
- with logfire.span("Getting recent activity", type=type, depth=depth, timeframe=timeframe): # pyright: ignore [reportGeneralTypeIssues]
153
- logger.info(
154
- f"Getting recent activity from {type}, depth={depth}, timeframe={timeframe}, page={page}, page_size={page_size}, max_related={max_related}"
155
- )
156
- params = {
157
- "page": page,
158
- "page_size": page_size,
159
- "max_related": max_related,
160
- }
161
- if depth:
162
- params["depth"] = depth
163
- if timeframe:
164
- params["timeframe"] = timeframe # pyright: ignore
165
-
166
- # send enum values if we have an enum, else send string value
167
- if type:
168
- params["type"] = [ # pyright: ignore
169
- type.value if isinstance(type, SearchItemType) else type for type in type
170
- ]
171
-
172
- response = await call_get(
173
- client,
174
- "/memory/recent",
175
- params=params,
176
- )
177
- return GraphContext.model_validate(response.json())
@@ -1,201 +0,0 @@
1
- """Note management tools for Basic Memory MCP server.
2
-
3
- These tools provide a natural interface for working with markdown notes
4
- while leveraging the underlying knowledge graph structure.
5
- """
6
-
7
- from typing import Optional, List
8
-
9
- from loguru import logger
10
- import logfire
11
-
12
- from basic_memory.mcp.server import mcp
13
- from basic_memory.mcp.async_client import client
14
- from basic_memory.schemas import EntityResponse, DeleteEntitiesResponse
15
- from basic_memory.schemas.base import Entity
16
- from basic_memory.mcp.tools.utils import call_get, call_put, call_delete
17
- from basic_memory.schemas.memory import memory_url_path
18
-
19
-
20
- @mcp.tool(
21
- description="Create or update a markdown note. Returns a markdown formatted summary of the semantic content.",
22
- )
23
- async def write_note(
24
- title: str,
25
- content: str,
26
- folder: str,
27
- tags: Optional[List[str]] = None,
28
- ) -> str:
29
- """Write a markdown note to the knowledge base.
30
-
31
- The content can include semantic observations and relations using markdown syntax.
32
- Relations can be specified either explicitly or through inline wiki-style links:
33
-
34
- Observations format:
35
- `- [category] Observation text #tag1 #tag2 (optional context)`
36
-
37
- Examples:
38
- `- [design] Files are the source of truth #architecture (All state comes from files)`
39
- `- [tech] Using SQLite for storage #implementation`
40
- `- [note] Need to add error handling #todo`
41
-
42
- Relations format:
43
- - Explicit: `- relation_type [[Entity]] (optional context)`
44
- - Inline: Any `[[Entity]]` reference creates a relation
45
-
46
- Examples:
47
- `- depends_on [[Content Parser]] (Need for semantic extraction)`
48
- `- implements [[Search Spec]] (Initial implementation)`
49
- `- This feature extends [[Base Design]] and uses [[Core Utils]]`
50
-
51
- Args:
52
- title: The title of the note
53
- content: Markdown content for the note, can include observations and relations
54
- folder: the folder where the file should be saved
55
- tags: Optional list of tags to categorize the note
56
-
57
- Returns:
58
- A markdown formatted summary of the semantic content, including:
59
- - Creation/update status
60
- - File path and checksum
61
- - Observation counts by category
62
- - Relation counts (resolved/unresolved)
63
- - Tags if present
64
- """
65
- with logfire.span("Writing note", title=title, folder=folder): # pyright: ignore [reportGeneralTypeIssues]
66
- logger.info(f"Writing note folder:'{folder}' title: '{title}'")
67
-
68
- # Create the entity request
69
- metadata = {"tags": [f"#{tag}" for tag in tags]} if tags else None
70
- entity = Entity(
71
- title=title,
72
- folder=folder,
73
- entity_type="note",
74
- content_type="text/markdown",
75
- content=content,
76
- entity_metadata=metadata,
77
- )
78
-
79
- # Create or update via knowledge API
80
- logger.info(f"Creating {entity.permalink}")
81
- url = f"/knowledge/entities/{entity.permalink}"
82
- response = await call_put(client, url, json=entity.model_dump())
83
- result = EntityResponse.model_validate(response.json())
84
-
85
- # Format semantic summary based on status code
86
- action = "Created" if response.status_code == 201 else "Updated"
87
- summary = [
88
- f"# {action} {result.file_path} ({result.checksum[:8] if result.checksum else 'unknown'})",
89
- f"permalink: {result.permalink}",
90
- ]
91
-
92
- if result.observations:
93
- categories = {}
94
- for obs in result.observations:
95
- categories[obs.category] = categories.get(obs.category, 0) + 1
96
-
97
- summary.append("\n## Observations")
98
- for category, count in sorted(categories.items()):
99
- summary.append(f"- {category}: {count}")
100
-
101
- if result.relations:
102
- unresolved = sum(1 for r in result.relations if not r.to_id)
103
- resolved = len(result.relations) - unresolved
104
-
105
- summary.append("\n## Relations")
106
- summary.append(f"- Resolved: {resolved}")
107
- if unresolved:
108
- summary.append(f"- Unresolved: {unresolved}")
109
- summary.append("\nUnresolved relations will be retried on next sync.")
110
-
111
- if tags:
112
- summary.append(f"\n## Tags\n- {', '.join(tags)}")
113
-
114
- return "\n".join(summary)
115
-
116
-
117
- @mcp.tool(description="Read note content by title, permalink, relation, or pattern")
118
- async def read_note(identifier: str, page: int = 1, page_size: int = 10) -> str:
119
- """Get note content in unified diff format.
120
-
121
- The content is returned in a unified diff inspired format:
122
- ```
123
- --- memory://docs/example 2025-01-31T19:32:49 7d9f1c8b
124
- <document content>
125
- ```
126
-
127
- Multiple documents (from relations or pattern matches) are separated by
128
- additional headers.
129
-
130
- Args:
131
- identifier: Can be one of:
132
- - Note title ("Project Planning")
133
- - Note permalink ("docs/example")
134
- - Relation path ("docs/example/depends-on/other-doc")
135
- - Pattern match ("docs/*-architecture")
136
- page: the page number of results to return (default 1)
137
- page_size: the number of results to return per page (default 10)
138
-
139
- Returns:
140
- Document content in unified diff format. For single documents, returns
141
- just that document's content. For relations or pattern matches, returns
142
- multiple documents separated by unified diff headers.
143
-
144
- Examples:
145
- # Single document
146
- content = await read_note("Project Planning")
147
-
148
- # Read by permalink
149
- content = await read_note("docs/architecture/file-first")
150
-
151
- # Follow relation
152
- content = await read_note("docs/architecture/depends-on/docs/content-parser")
153
-
154
- # Pattern matching
155
- content = await read_note("docs/*-architecture") # All architecture docs
156
- content = await read_note("docs/*/implements/*") # Find implementations
157
-
158
- Output format:
159
- ```
160
- --- memory://docs/example 2025-01-31T19:32:49 7d9f1c8b
161
- <first document content>
162
-
163
- --- memory://docs/other 2025-01-30T15:45:22 a1b2c3d4
164
- <second document content>
165
- ```
166
-
167
- The headers include:
168
- - Full memory:// URI for the document
169
- - Last modified timestamp
170
- - Content checksum
171
- """
172
- with logfire.span("Reading note", identifier=identifier): # pyright: ignore [reportGeneralTypeIssues]
173
- logger.info(f"Reading note {identifier}")
174
- url = memory_url_path(identifier)
175
- response = await call_get(
176
- client, f"/resource/{url}", params={"page": page, "page_size": page_size}
177
- )
178
- return response.text
179
-
180
-
181
- @mcp.tool(description="Delete a note by title or permalink")
182
- async def delete_note(identifier: str) -> bool:
183
- """Delete a note from the knowledge base.
184
-
185
- Args:
186
- identifier: Note title or permalink
187
-
188
- Returns:
189
- True if note was deleted, False otherwise
190
-
191
- Examples:
192
- # Delete by title
193
- delete_note("Meeting Notes: Project Planning")
194
-
195
- # Delete by permalink
196
- delete_note("notes/project-planning")
197
- """
198
- with logfire.span("Deleting note", identifier=identifier): # pyright: ignore [reportGeneralTypeIssues]
199
- response = await call_delete(client, f"/knowledge/entities/{identifier}")
200
- result = DeleteEntitiesResponse.model_validate(response.json())
201
- return result.deleted