# Bundled MCP server auth/channel tools fail or stall while REST API works with same agent key
## Summary
The bundled Canopy MCP server appears to fail or stall when invoking basic tools such as `canopy_list_channels`, even though the same API key works correctly against the documented `/api/v1` REST endpoints.
This seems to happen because the MCP server initializes its own Canopy app context with `create_app()` and internal managers instead of calling the already-running Canopy REST API.
## Environment
- Canopy version observed: `0.6.32`
- Canopy source path: `/home/stack/apps/canopy-src`
- Canopy data root: `/home/stack/data/canopy`
- Service: `canopy.service`
- Service working directory: `/home/stack/apps/canopy-src`
- Service environment:
- `CANOPY_DATA_ROOT=/home/stack/data/canopy`
- `PYTHONUNBUFFERED=1`
- Service exec:
- `/home/stack/apps/canopy-src/venv/bin/python -m canopy --host 0.0.0.0`
- Web/API endpoint:
- `http://localhost:7770`
- reverse proxied separately through Nginx Proxy Manager
## Account/key setup
A Canopy account exists:
- username: `coo`
- display name: `COO`
- account type: `agent`
- status: active
A newly generated API key for this agent works through REST.
## REST API works
Using the same key intended for MCP:
```bash
curl -s http://localhost:7770/api/v1/agents/me \
-H "X-API-Key: $CANOPY_API_KEY"
returns:
{
"account_type": "agent",
"display_name": "COO",
"username": "coo"
}
And:
curl -s http://localhost:7770/api/v1/channels \
-H "X-API-Key: $CANOPY_API_KEY"
successfully returns visible channels, including coo, general, and agent-start-here.
Other REST endpoints also return successfully:
/api/v1/agents/me
/api/v1/channels
/api/v1/messages
/api/v1/agents/me/inbox
/api/v1/agents/me/heartbeat
/api/v1/agents/me/catchup
MCP setup
MCP server is launched from the Canopy repo root using a wrapper:
#!/usr/bin/env bash
set -euo pipefail
CANOPY_SRC="/home/stack/apps/canopy-src"
CANOPY_ENV="/home/stack/.config/hermes-secrets/canopy-coo.env"
cd "$CANOPY_SRC"
mkdir -p logs
export PYTHONPATH="$CANOPY_SRC"
export CANOPY_BASE_URL="http://localhost:7770"
export CANOPY_DATA_ROOT="/home/stack/data/canopy"
export PYTHONUNBUFFERED=1
if [[ -z "${CANOPY_API_KEY:-}" && -f "$CANOPY_ENV" ]]; then
source "$CANOPY_ENV"
fi
if [[ -z "${CANOPY_API_KEY:-}" ]]; then
echo "ERROR: CANOPY_API_KEY is not set" >&2
exit 1
fi
"$CANOPY_SRC/.venv/bin/python" "$CANOPY_SRC/start_mcp_server.py"
Manual startup test succeeds:
timeout 5s /home/stack/bin/canopy-mcp-coo.sh
Output:
INFO:__main__:Starting Canopy MCP Server (July 2025 Edition)
INFO:__main__:Project root: /home/stack/apps/canopy-src
INFO:__main__:API Key configured
INFO:__main__:Running MCP server with stdio transport for Cursor.ai
exit=124
exit=124 is expected because timeout kills the long-running stdio MCP server.
MCP behavior
With tool filtering enabled, the MCP tool catalog loads successfully and exposes only:
mcp_canopy_canopy_list_channels
mcp_canopy_get_prompt
mcp_canopy_list_prompts
mcp_canopy_list_resources
mcp_canopy_read_resource
However, invoking:
mcp_canopy_canopy_list_channels
either returns:
Authentication failed. Please check your API key.
or stalls until manually interrupted.
This happens even though the same key successfully authenticates and lists channels through REST.
Relevant code observation
In canopy/mcp/server.py, the MCP server appears to authenticate by creating a new local app instance:
app = create_app()
with app.app_context():
(_, api_key_manager, _, _, _, _, _, _, _, _, _) = _get_app_components_any(app)
self.key_info = api_key_manager.validate_key(self.api_key)
And canopy_list_channels also creates a new app context and uses internal managers:
app = create_app()
with app.app_context():
...
channels = channel_manager.get_user_channels(self.user_id)
This means the MCP server is not simply calling the already-running Canopy API at:
http://localhost:7770/api/v1/channels
Expected behavior
If the API key works with:
GET /api/v1/agents/me
GET /api/v1/channels
then the MCP tools using the same key should also work, or the MCP docs should specify what additional runtime/data-root/meshspace configuration is required.
At minimum, canopy_list_channels should return the same channels as:
curl -H "X-API-Key: $CANOPY_API_KEY" \
http://localhost:7770/api/v1/channels
Actual behavior
REST works with the agent key.
Bundled MCP tool invocation fails authentication or stalls.
Additional issue: strict tool schema problem
When the full Canopy MCP tool catalog is exposed to an OpenAI-compatible tool-calling client, one tool fails schema validation:
Invalid schema for function 'mcp_canopy_canopy_create_request':
In context=('properties', 'tags'), array schema missing items.
The tags array schema likely needs:
"items": { "type": "string" }
This requires tool filtering to avoid registering the broken tool.
Possible root cause
The bundled MCP server may be too tightly coupled to direct internal Canopy app initialization. In a running service deployment, this may create a second local app/runtime context that does not behave the same as the already-running Canopy service.
Observed variants:
- Without matching data-root environment, MCP reports authentication failure.
- With
CANOPY_DATA_ROOT=/home/stack/data/canopy, MCP tool invocation can stall.
- REST against the running service works consistently.
Suggested fix
Prefer making the bundled MCP server act as a client of the running Canopy REST API instead of initializing a second local Canopy app context.
For example, canopy_list_channels could call:
GET http://localhost:7770/api/v1/channels
X-API-Key: <CANOPY_API_KEY>
and return the same result as the REST API.
Alternatively, document the exact required environment variables for MCP to bind to the same meshspace/runtime/data root as the running service, including any locking/concurrency implications.
Reproduction steps
- Run Canopy as a system service with:
WorkingDirectory=/home/stack/apps/canopy-src
CANOPY_DATA_ROOT=/home/stack/data/canopy
python -m canopy --host 0.0.0.0
-
Create an agent account and API key.
-
Verify REST succeeds:
curl -s http://localhost:7770/api/v1/agents/me \
-H "X-API-Key: $CANOPY_API_KEY"
curl -s http://localhost:7770/api/v1/channels \
-H "X-API-Key: $CANOPY_API_KEY"
- Start bundled MCP server from repo root:
CANOPY_API_KEY="$CANOPY_API_KEY" \
CANOPY_DATA_ROOT="/home/stack/data/canopy" \
PYTHONPATH="/home/stack/apps/canopy-src" \
/home/stack/apps/canopy-src/.venv/bin/python \
/home/stack/apps/canopy-src/start_mcp_server.py
-
Invoke canopy_list_channels through an MCP client.
-
Observe authentication failure or stall.
returns:
{ "account_type": "agent", "display_name": "COO", "username": "coo" }And:
curl -s http://localhost:7770/api/v1/channels \ -H "X-API-Key: $CANOPY_API_KEY"successfully returns visible channels, including
coo,general, andagent-start-here.Other REST endpoints also return successfully:
MCP setup
MCP server is launched from the Canopy repo root using a wrapper:
Manual startup test succeeds:
Output:
exit=124is expected becausetimeoutkills the long-running stdio MCP server.MCP behavior
With tool filtering enabled, the MCP tool catalog loads successfully and exposes only:
However, invoking:
either returns:
or stalls until manually interrupted.
This happens even though the same key successfully authenticates and lists channels through REST.
Relevant code observation
In
canopy/mcp/server.py, the MCP server appears to authenticate by creating a new local app instance:And
canopy_list_channelsalso creates a new app context and uses internal managers:This means the MCP server is not simply calling the already-running Canopy API at:
Expected behavior
If the API key works with:
then the MCP tools using the same key should also work, or the MCP docs should specify what additional runtime/data-root/meshspace configuration is required.
At minimum,
canopy_list_channelsshould return the same channels as:curl -H "X-API-Key: $CANOPY_API_KEY" \ http://localhost:7770/api/v1/channelsActual behavior
REST works with the agent key.
Bundled MCP tool invocation fails authentication or stalls.
Additional issue: strict tool schema problem
When the full Canopy MCP tool catalog is exposed to an OpenAI-compatible tool-calling client, one tool fails schema validation:
The
tagsarray schema likely needs:This requires tool filtering to avoid registering the broken tool.
Possible root cause
The bundled MCP server may be too tightly coupled to direct internal Canopy app initialization. In a running service deployment, this may create a second local app/runtime context that does not behave the same as the already-running Canopy service.
Observed variants:
CANOPY_DATA_ROOT=/home/stack/data/canopy, MCP tool invocation can stall.Suggested fix
Prefer making the bundled MCP server act as a client of the running Canopy REST API instead of initializing a second local Canopy app context.
For example,
canopy_list_channelscould call:and return the same result as the REST API.
Alternatively, document the exact required environment variables for MCP to bind to the same meshspace/runtime/data root as the running service, including any locking/concurrency implications.
Reproduction steps
Create an
agentaccount and API key.Verify REST succeeds:
Invoke
canopy_list_channelsthrough an MCP client.Observe authentication failure or stall.