-
Notifications
You must be signed in to change notification settings - Fork 13
Description
Problem
When testing the MCP gateway locally, tool calls fail with the error:
sys___init must be called before any other tool calls
This happens because FlowGuard requires a sys___init call to create a session before any other tool can be invoked.
Environment Setup
Step 1: Build the gateway
cd gh-aw-mcpg
go mod tidy
go build -o flowguard-goStep 2: Create config file (/tmp/mcpg-config.json)
{
"mcpServers": {
"github": {
"type": "local",
"container": "ghcr.io/github/github-mcp-server:v0.19.0",
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": ""
}
}
}
}Note: The config requires "type": "local" and uses container field (not raw command/args).
Step 3: Run the gateway
export GITHUB_PERSONAL_ACCESS_TOKEN="<your-token>"
./flowguard-go --routed --listen 127.0.0.1:8000 --config-stdin < /tmp/mcpg-config.jsonServer starts successfully with 46 GitHub tools registered:
Loaded 1 MCP server(s)
Registered 46 tools from github
Starting FlowGuard in ROUTED mode on 127.0.0.1:8000
Routes: /mcp/<server> where <server> is one of: [github]
Registered route: /mcp/sys
Registered route: /mcp/github
Step 4: Health check works
curl http://127.0.0.1:8000/health
# Returns: OKSteps to Reproduce the Issue
Using MCP Inspector (FAILS)
npx @modelcontextprotocol/inspector --cli http://127.0.0.1:8000/mcp/github \
--transport http \
--method tools/call \
--header "Authorization: Bearer test-token" \
--tool-name list_issues \
--tool-arg owner=containerd \
--tool-arg repo=runwasi \
--tool-arg state=OPENResult:
{
"content": [{ "type": "text", "text": "sys___init must be called before any other tool calls" }],
"isError": true
}Listing tools works fine
npx @modelcontextprotocol/inspector --cli http://127.0.0.1:8000/mcp/github \
--transport http \
--method tools/list \
--header "Authorization: Bearer test-token"This returns all 46 tools successfully.
Root Cause
In internal/server/unified.go:510-525, the requireSession() function checks if a session exists:
func (us *UnifiedServer) requireSession(ctx context.Context) error {
sessionID := us.getSessionID(ctx)
us.sessionMu.RLock()
session := us.sessions[sessionID]
us.sessionMu.RUnlock()
if session == nil {
return fmt.Errorf("sys___init must be called before any other tool calls")
}
return nil
}This session is only created when sys___init is called first.
Impact
Standard MCP clients (MCP Inspector, Claude Desktop, Copilot CLI, etc.) expect to:
- Initialize the MCP connection (via
initializeJSON-RPC method) - Immediately call tools
They don't expect a custom sys___init tool call as a prerequisite. This breaks compatibility with standard MCP tooling.
Workaround (curl with manual session handling)
This multi-step curl approach works:
MCP_SYS_URL="http://127.0.0.1:8000/mcp/sys"
MCP_GITHUB_URL="http://127.0.0.1:8000/mcp/github"
BEARER="my-session-token"
# Step 1: Initialize sys session
SYS_SESSION=$(curl -isS -X POST $MCP_SYS_URL \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H "Authorization: Bearer $BEARER" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"1.0.0","capabilities":{},"clientInfo":{"name":"curl","version":"0.1"}}}' \
| awk 'BEGIN{IGNORECASE=1} /^mcp-session-id:/{print $2}' | tr -d '\r')
# Step 2: Call sys___init to create session
curl -s \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: $SYS_SESSION" \
-H "Authorization: Bearer $BEARER" \
-X POST $MCP_SYS_URL \
-d '{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "init", "arguments": {}}}'
# Step 3: Initialize github session
GH_SESSION=$(curl -isS -X POST $MCP_GITHUB_URL \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H "Authorization: Bearer $BEARER" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"1.0.0","capabilities":{},"clientInfo":{"name":"curl","version":"0.1"}}}' \
| awk 'BEGIN{IGNORECASE=1} /^mcp-session-id:/{print $2}' | tr -d '\r')
# Step 4: Now tool calls work!
curl -s \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: $GH_SESSION" \
-H "Authorization: Bearer $BEARER" \
-X POST $MCP_GITHUB_URL \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "list_issues",
"arguments": {
"owner": "containerd",
"repo": "runwasi",
"state": "OPEN",
"perPage": 5
}
}
}'Note: The state parameter must be uppercase (OPEN not open).
Suggested Solutions
- Remove the requirement - Remove
requireSession()checks from tool handlers - Auto-create sessions - Create a session automatically on first tool call if none exists
- Make it configurable - Add a flag like
--require-initto enable/disable this behavior (default off)
Additional Notes
- The MCP Inspector creates a new session per invocation, so it can't maintain session state across calls
- The
sys___initdesign was intended for DIFC (Decentralized Information Flow Control) per-agent tracking - If DIFC tracking is not needed, the session requirement should be optional