Skip to content

Commit da26d70

Browse files
committed
fix: resolve MCP-Hub tool validation errors for project management functions
- Renamed list_projects() to list_memory_projects() - Renamed create_project() to create_memory_project() - Updated imports and exports accordingly - Fixed test environment variable isolation Fixes #190 Signed-off-by: Drew Cain <groksrc@gmail.com>
1 parent 3f70f5e commit da26d70

4 files changed

Lines changed: 29 additions & 29 deletions

File tree

src/basic_memory/mcp/tools/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,24 @@
1818
from basic_memory.mcp.tools.edit_note import edit_note
1919
from basic_memory.mcp.tools.move_note import move_note
2020
from basic_memory.mcp.tools.project_management import (
21-
list_projects,
21+
list_memory_projects,
2222
switch_project,
2323
get_current_project,
2424
set_default_project,
25-
create_project,
25+
create_memory_project,
2626
delete_project,
2727
)
2828

2929
__all__ = [
3030
"build_context",
3131
"canvas",
32-
"create_project",
32+
"create_memory_project",
3333
"delete_note",
3434
"delete_project",
3535
"edit_note",
3636
"get_current_project",
3737
"list_directory",
38-
"list_projects",
38+
"list_memory_projects",
3939
"move_note",
4040
"read_content",
4141
"read_note",

src/basic_memory/mcp/tools/project_management.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
from basic_memory.schemas.project_info import ProjectList, ProjectStatusResponse, ProjectInfoRequest
1717

1818

19-
@mcp.tool()
20-
async def list_projects(ctx: Context | None = None) -> str:
19+
@mcp.tool("list_memory_projects")
20+
async def list_memory_projects(ctx: Context | None = None) -> str:
2121
"""List all available projects with their status.
2222
2323
Shows all Basic Memory projects that are available, indicating which one
@@ -27,7 +27,7 @@ async def list_projects(ctx: Context | None = None) -> str:
2727
Formatted list of projects with status indicators
2828
2929
Example:
30-
list_projects()
30+
list_memory_projects()
3131
"""
3232
if ctx: # pragma: no cover
3333
await ctx.info("Listing all available projects")
@@ -186,8 +186,8 @@ async def set_default_project(project_name: str, ctx: Context | None = None) ->
186186
return add_project_metadata(result, session.get_current_project())
187187

188188

189-
@mcp.tool()
190-
async def create_project(
189+
@mcp.tool("create_memory_project")
190+
async def create_memory_project(
191191
project_name: str, project_path: str, set_default: bool = False, ctx: Context | None = None
192192
) -> str:
193193
"""Create a new Basic Memory project.
@@ -204,8 +204,8 @@ async def create_project(
204204
Confirmation message with project details
205205
206206
Example:
207-
create_project("my-research", "~/Documents/research")
208-
create_project("work-notes", "/home/user/work", set_default=True)
207+
create_memory_project("my-research", "~/Documents/research")
208+
create_memory_project("work-notes", "/home/user/work", set_default=True)
209209
"""
210210
if ctx: # pragma: no cover
211211
await ctx.info(f"Creating project: {project_name} at {project_path}")

test-int/mcp/test_project_management_integration.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ async def test_list_projects_basic_operation(mcp_server, app):
1515
async with Client(mcp_server) as client:
1616
# List all available projects
1717
list_result = await client.call_tool(
18-
"list_projects",
18+
"list_memory_projects",
1919
{},
2020
)
2121

@@ -248,7 +248,7 @@ async def test_project_management_workflow(mcp_server, app):
248248
assert "test-project" in current_result[0].text
249249

250250
# 2. List all projects
251-
list_result = await client.call_tool("list_projects", {})
251+
list_result = await client.call_tool("list_memory_projects", {})
252252
assert "Available projects:" in list_result[0].text
253253
assert "test-project" in list_result[0].text
254254

@@ -269,7 +269,7 @@ async def test_project_metadata_consistency(mcp_server, app):
269269
# Test all project management tools and verify they include project metadata
270270

271271
# list_projects
272-
list_result = await client.call_tool("list_projects", {})
272+
list_result = await client.call_tool("list_memory_projects", {})
273273
assert "Project: test-project" in list_result[0].text
274274

275275
# get_current_project
@@ -350,7 +350,7 @@ async def test_create_project_basic_operation(mcp_server, app):
350350
async with Client(mcp_server) as client:
351351
# Create a new project
352352
create_result = await client.call_tool(
353-
"create_project",
353+
"create_memory_project",
354354
{
355355
"project_name": "test-new-project",
356356
"project_path": "/tmp/test-new-project",
@@ -370,7 +370,7 @@ async def test_create_project_basic_operation(mcp_server, app):
370370
assert "Project: test-project" in create_text # Should still show current project
371371

372372
# Verify project appears in project list
373-
list_result = await client.call_tool("list_projects", {})
373+
list_result = await client.call_tool("list_memory_projects", {})
374374
list_text = list_result[0].text
375375
assert "test-new-project" in list_text
376376

@@ -382,7 +382,7 @@ async def test_create_project_with_default_flag(mcp_server, app):
382382
async with Client(mcp_server) as client:
383383
# Create a new project and set as default
384384
create_result = await client.call_tool(
385-
"create_project",
385+
"create_memory_project",
386386
{
387387
"project_name": "test-default-project",
388388
"project_path": "/tmp/test-default-project",
@@ -412,7 +412,7 @@ async def test_create_project_duplicate_name(mcp_server, app):
412412
async with Client(mcp_server) as client:
413413
# First create a project
414414
await client.call_tool(
415-
"create_project",
415+
"create_memory_project",
416416
{
417417
"project_name": "duplicate-test",
418418
"project_path": "/tmp/duplicate-test-1",
@@ -422,7 +422,7 @@ async def test_create_project_duplicate_name(mcp_server, app):
422422
# Try to create another project with same name
423423
with pytest.raises(Exception) as exc_info:
424424
await client.call_tool(
425-
"create_project",
425+
"create_memory_project",
426426
{
427427
"project_name": "duplicate-test",
428428
"project_path": "/tmp/duplicate-test-2",
@@ -431,7 +431,7 @@ async def test_create_project_duplicate_name(mcp_server, app):
431431

432432
# Should show error about duplicate name
433433
error_message = str(exc_info.value)
434-
assert "create_project" in error_message
434+
assert "create_memory_project" in error_message
435435
assert (
436436
"duplicate-test" in error_message
437437
or "already exists" in error_message
@@ -446,15 +446,15 @@ async def test_delete_project_basic_operation(mcp_server, app):
446446
async with Client(mcp_server) as client:
447447
# First create a project to delete
448448
await client.call_tool(
449-
"create_project",
449+
"create_memory_project",
450450
{
451451
"project_name": "to-be-deleted",
452452
"project_path": "/tmp/to-be-deleted",
453453
},
454454
)
455455

456456
# Verify it exists
457-
list_result = await client.call_tool("list_projects", {})
457+
list_result = await client.call_tool("list_memory_projects", {})
458458
assert "to-be-deleted" in list_result[0].text
459459

460460
# Delete the project
@@ -478,7 +478,7 @@ async def test_delete_project_basic_operation(mcp_server, app):
478478
assert "Project: test-project" in delete_text # Should show current project
479479

480480
# Verify project no longer appears in list
481-
list_result_after = await client.call_tool("list_projects", {})
481+
list_result_after = await client.call_tool("list_memory_projects", {})
482482
assert "to-be-deleted" not in list_result_after[0].text
483483

484484

@@ -540,7 +540,7 @@ async def test_project_lifecycle_workflow(mcp_server, app):
540540

541541
# 1. Create new project
542542
create_result = await client.call_tool(
543-
"create_project",
543+
"create_memory_project",
544544
{
545545
"project_name": project_name,
546546
"project_path": project_path,
@@ -595,7 +595,7 @@ async def test_project_lifecycle_workflow(mcp_server, app):
595595
assert "removed successfully" in delete_result[0].text
596596

597597
# 7. Verify project is gone from list
598-
list_result = await client.call_tool("list_projects", {})
598+
list_result = await client.call_tool("list_memory_projects", {})
599599
assert project_name not in list_result[0].text
600600

601601

@@ -609,7 +609,7 @@ async def test_create_delete_project_edge_cases(mcp_server, app):
609609

610610
# Create project with special characters
611611
create_result = await client.call_tool(
612-
"create_project",
612+
"create_memory_project",
613613
{
614614
"project_name": special_name,
615615
"project_path": f"/tmp/{special_name}",
@@ -619,7 +619,7 @@ async def test_create_delete_project_edge_cases(mcp_server, app):
619619
assert special_name in create_result[0].text
620620

621621
# Verify it appears in list
622-
list_result = await client.call_tool("list_projects", {})
622+
list_result = await client.call_tool("list_memory_projects", {})
623623
assert special_name in list_result[0].text
624624

625625
# Delete it
@@ -633,5 +633,5 @@ async def test_create_delete_project_edge_cases(mcp_server, app):
633633
assert special_name in delete_result[0].text
634634

635635
# Verify it's gone
636-
list_result_after = await client.call_tool("list_projects", {})
636+
list_result_after = await client.call_tool("list_memory_projects", {})
637637
assert special_name not in list_result_after[0].text

tests/mcp/test_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def test_create_auth_config_supabase_provider_missing_anon_key(self):
9393
# Missing SUPABASE_ANON_KEY
9494
}
9595

96-
with patch.dict(os.environ, env_vars):
96+
with patch.dict(os.environ, env_vars, clear=True):
9797
with pytest.raises(ValueError, match="SUPABASE_URL and SUPABASE_ANON_KEY must be set"):
9898
create_auth_config()
9999

0 commit comments

Comments
 (0)