MCP Protocol
MCP (Model Context Protocol) is an open standard proposed by Anthropic for connecting AI models to external tools and data sources. MateClaw implements a full MCP client that dynamically discovers and invokes tools exposed by external MCP servers, allowing Agents to use third-party capabilities exactly like built-in tools without writing additional code.
What is MCP
MCP uses a client-server architecture and communicates over JSON-RPC 2.0:
┌───────────────────────┐ ┌───────────────────────┐
│ MateClaw │ │ MCP Server │
│ (MCP Client) │ │ (Tool Provider) │
│ │ JSON-RPC │ │
│ Agent Engine ───────┼──────────────┼──► Tool A │
│ │ │ Tool B │
│ Tool Registry ◄──────┼──────────────┼─── Tool Discovery │
│ │ │ (tools/list) │
└───────────────────────┘ └───────────────────────┘Core concepts:
- MCP Client: MateClaw acts as the client, responsible for connecting to MCP servers, discovering tools, and forwarding tool invocation requests
- MCP Server: A third-party tool server that declares its available tools and executes tool calls
- Tool Discovery: The client sends a
tools/listrequest to retrieve all tools and their parameter schemas from the server - Tool Invocation: When an Agent decides to call a tool during reasoning, the client forwards the request to the corresponding MCP server for execution
Through MCP, MateClaw can dynamically integrate new tool capabilities without modifying code or restarting the service.
Transport Types
MateClaw supports three MCP transport modes for different deployment scenarios:
stdio (Standard I/O)
Communicates through the stdin/stdout pipes of a subprocess. MateClaw spawns a local child process as the MCP server and exchanges JSON-RPC messages via standard I/O.
MateClaw ── stdin ──► MCP Server subprocess
◄─ stdout ──Use cases:
- Local Node.js/Python MCP tool packages (e.g.,
@anthropic/mcp-filesystem) - Command-line tool wrappers
- Development and debugging
Advantages: No network configuration needed, works immediately, process isolation Limitations: Local deployment only; MateClaw must be able to execute the specified command directly
streamable_http (Streamable HTTP)
The latest recommended HTTP transport for MCP. Uses standard HTTP POST requests to send JSON-RPC, with responses streamed back over HTTP.
MateClaw ── HTTP POST ──► Remote MCP Server
◄─ HTTP Stream ──Use cases:
- Cloud-deployed MCP servers
- Scenarios requiring load balancing or reverse proxies
- Recommended for production environments
Advantages: Standard HTTP protocol, compatible with all network infrastructure (CDN, load balancers, firewalls), supports authentication headers Limitations: Requires the server to support Streamable HTTP transport
sse (Server-Sent Events)
The earlier HTTP transport mode for MCP, using SSE for server-to-client push.
MateClaw ── HTTP POST ──► Remote MCP Server
◄─── SSE ────────Use cases:
- Compatibility with older MCP servers that only support SSE transport
- When the remote server has not yet upgraded to Streamable HTTP
Advantages: Good compatibility; many existing MCP servers still use this transport Limitations: Being gradually superseded by Streamable HTTP; new projects should prefer streamable_http
Transport Comparison
| Feature | stdio | streamable_http | sse |
|---|---|---|---|
| Deployment | Local only | Local or remote | Local or remote |
| Network requirement | None | HTTP reachable | HTTP reachable |
| Authentication | Via environment variables | HTTP Headers | HTTP Headers |
| Process management | MateClaw manages subprocess | External | External |
| Recommendation | Best for local tools | Best for remote services | Legacy compatibility |
Configuration via UI
Adding an MCP Server
- Log in to the MateClaw admin interface
- Navigate to the "Tool Management" page
- Switch to the "MCP Servers" tab
- Click the "Add MCP Server" button
- Fill in the configuration form:
- Name: Unique server identifier (letters, numbers,
_,-,., and spaces allowed; 1-128 characters) - Description: Optional, describes the server's purpose
- Transport type: Select
stdio,streamable_http, orsse - Command (stdio): The command to start the MCP server, e.g.,
npx,node,python - Arguments (stdio): Command-line arguments in JSON array format, e.g.,
["-y", "@anthropic/mcp-filesystem", "/path"] - Working directory (stdio): Optional, the working directory for command execution
- Environment variables (stdio): JSON object format, e.g.,
{"API_KEY": "xxx"}; supports${ENV_VAR}references to system environment variables - URL (streamable_http/sse): The MCP server endpoint URL
- HTTP Headers (streamable_http/sse): JSON object format, e.g.,
{"Authorization": "Bearer token"} - Connect timeout: Connection establishment timeout, default 30 seconds
- Read timeout: Request response timeout, default 30 seconds
- Name: Unique server identifier (letters, numbers,
- Click "Save"
After saving, if the server is enabled, MateClaw will automatically attempt to connect and discover tools.
Testing a Connection
In the MCP server list, click the "Test Connection" button for a specific server. The test will:
- Attempt to establish a connection to the MCP server
- Send a
tools/listrequest to discover available tools - Return the connection result (success/failure), latency, and discovered tool list
- Test connections do not affect currently active connections
Enabling and Disabling
Each MCP server has an independent enable/disable toggle:
- Enabled: MateClaw establishes a connection; discovered tools become available to Agents
- Disabled: Connection is dropped; the server's tools are no longer available, but configuration is preserved
Viewing Connection Status
The MCP server list displays real-time status for each server:
- connected: Connected and tools are available
- disconnected: Disconnected (manually disabled or not yet connected)
- error: Connection failed; error details are available
Configuration via REST API
Full CRUD operations for MCP servers are available through the /api/v1/mcp/servers endpoint. All endpoints require JWT authentication.
List All MCP Servers
curl -s http://localhost:18088/api/v1/mcp/servers \
-H "Authorization: Bearer <token>" | jqExample response:
{
"code": 200,
"data": [
{
"id": "1",
"name": "filesystem",
"transport": "stdio",
"command": "npx",
"argsJson": "[\"-y\", \"@anthropic/mcp-filesystem\", \"/home/user\"]",
"enabled": true,
"lastStatus": "connected",
"toolCount": 5,
"lastConnectedTime": "2026-04-01T10:30:00"
}
]
}Note: The headersJson and envJson fields in responses are automatically sanitized (e.g., sk-****abcd) to protect sensitive information.
Get a Single MCP Server
curl -s http://localhost:18088/api/v1/mcp/servers/{id} \
-H "Authorization: Bearer <token>"Create an MCP Server (stdio type)
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "filesystem",
"description": "File system read/write tools",
"transport": "stdio",
"command": "npx",
"argsJson": "[\"-y\", \"@anthropic/mcp-filesystem\", \"/home/user/workspace\"]",
"enabled": true
}'Create an MCP Server (streamable_http type)
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "remote-tools",
"description": "Remote tool service",
"transport": "streamable_http",
"url": "https://mcp.example.com/mcp",
"headersJson": "{\"Authorization\": \"Bearer your-api-key\"}",
"connectTimeoutSeconds": 15,
"readTimeoutSeconds": 60,
"enabled": true
}'Update an MCP Server
Uses PATCH semantics -- only pass the fields you want to change; unspecified fields remain unchanged:
curl -X PUT http://localhost:18088/api/v1/mcp/servers/{id} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"description": "Updated description",
"readTimeoutSeconds": 60
}'After updating, if the server is enabled, it will automatically reconnect.
Delete an MCP Server
curl -X DELETE http://localhost:18088/api/v1/mcp/servers/{id} \
-H "Authorization: Bearer <token>"The connection is automatically dropped before deletion. Note: Built-in servers (marked as builtin) cannot be deleted.
Enable/Disable an MCP Server
# Disable
curl -X PUT "http://localhost:18088/api/v1/mcp/servers/{id}/toggle?enabled=false" \
-H "Authorization: Bearer <token>"
# Enable
curl -X PUT "http://localhost:18088/api/v1/mcp/servers/{id}/toggle?enabled=true" \
-H "Authorization: Bearer <token>"Test Connection
curl -X POST http://localhost:18088/api/v1/mcp/servers/{id}/test \
-H "Authorization: Bearer <token>"Example response:
{
"code": 200,
"data": {
"success": true,
"message": "Connected",
"toolCount": 5,
"latencyMs": 1234,
"discoveredTools": ["read_file", "write_file", "list_directory", "search_files", "get_file_info"],
"timestamp": "2026-04-01T10:30:00"
}
}Refresh All Connections
Disconnects all existing connections and reconnects all enabled MCP servers:
curl -X POST http://localhost:18088/api/v1/mcp/servers/refresh \
-H "Authorization: Bearer <token>"Practical Examples
Example 1: Filesystem MCP Server (stdio)
Use the official Anthropic filesystem MCP server to give Agents file read/write and directory search capabilities.
Prerequisites: Node.js (v18+) and npm installed on the server.
Create via API:
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "filesystem",
"description": "File system read/write (restricted to specified directory)",
"transport": "stdio",
"command": "npx",
"argsJson": "[\"-y\", \"@anthropic/mcp-filesystem\", \"/home/user/workspace\"]",
"enabled": true
}'Once connected, the following tools will be discovered:
| Tool Name | Description |
|---|---|
read_file | Read file contents |
write_file | Write to a file |
list_directory | List directory contents |
search_files | Search for files |
get_file_info | Get file metadata |
Security note: @anthropic/mcp-filesystem only allows access to the directory specified in the startup arguments and its subdirectories, preventing access to other system files.
Example 2: Remote HTTP MCP Server (streamable_http with Authentication)
Connect to a remote MCP server that requires API key authentication, such as an internal enterprise data query service.
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "internal-data-service",
"description": "Internal enterprise data query MCP service",
"transport": "streamable_http",
"url": "https://mcp-api.internal.example.com/mcp",
"headersJson": "{\"Authorization\": \"Bearer sk-your-api-key\", \"X-Team-Id\": \"engineering\"}",
"connectTimeoutSeconds": 10,
"readTimeoutSeconds": 120,
"enabled": true
}'Configuration notes:
urlpoints to the remote MCP server's Streamable HTTP endpointheadersJsonprovides authentication; these headers are sent with every HTTP request- Header values support environment variable references:
{"Authorization": "Bearer ${MCP_API_KEY}"}will be replaced at runtime with the system environment variable value - A longer
readTimeoutSecondsis appropriate for long-running data queries
Example 3: Tavily Search MCP Server (stdio with Environment Variables)
Integrate the Tavily search MCP server to give Agents real-time web search capabilities.
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "tavily-search",
"description": "Tavily real-time web search",
"transport": "stdio",
"command": "npx",
"argsJson": "[\"-y\", \"@anthropic/mcp-tavily\"]",
"envJson": "{\"TAVILY_API_KEY\": \"${TAVILY_API_KEY}\"}",
"enabled": true
}'Configuration notes:
${TAVILY_API_KEY}inenvJsonis replaced at runtime with the corresponding system environment variable from the MateClaw process- You can also write the key directly:
{"TAVILY_API_KEY": "tvly-xxxxxx"}, but using environment variable references is recommended to avoid storing secrets in the database - The subprocess inherits the specified environment variables
Example 4: Legacy SSE MCP Server
Connect to an MCP server that only supports SSE transport:
curl -X POST http://localhost:18088/api/v1/mcp/servers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "legacy-mcp-server",
"description": "Legacy SSE transport MCP server",
"transport": "sse",
"url": "http://192.168.1.100:3001/sse",
"enabled": true
}'How MCP Tools Are Registered
MCP tools go through the following pipeline from discovery to becoming available for Agent invocation:
McpServerBootstrapRunner (application startup)
|
v
McpServerService.initEnabledServers()
| Iterates all enabled MCP servers
v
McpClientManager.connect(server)
| 1. Build McpSyncClient based on transport type
| 2. Call client.initialize() to establish connection
| 3. Call client.listTools() to discover tools
| 4. Cache in clients and toolsCache maps
v
McpToolCallbackProvider.getToolCallbacks()
| Implements Spring AI's ToolCallbackProvider interface
| Retrieves ToolCallbacks from all active clients in McpClientManager
v
ToolRegistry
| Aggregates built-in tools + MCP tools
v
Agent Tool Set
| Agents can invoke any registered tool during reasoningKey implementation details:
- McpToolCallbackProvider implements Spring AI's
ToolCallbackProviderinterface. Every call togetToolCallbacks()fetches the latest active tool list fromMcpClientManager, so adding or removing MCP servers takes effect without restarting the application. - SyncMcpToolCallbackProvider (built into Spring AI) converts a single
McpSyncClient's tools into aToolCallbackarray. - MCP tools and built-in
@Tool-annotated tools are completely identical at the Agent invocation layer -- Agents cannot and do not need to distinguish the tool source. - Each MCP tool's name, description, and parameter schema are declared by the MCP server in its
tools/listresponse.
Connection Management
Automatic Connection on Startup
After MateClaw finishes starting, McpServerBootstrapRunner automatically connects all MCP servers marked as enabled=true in the database. A single server's connection failure does not block other servers or application startup.
Thread Safety
McpClientManager uses a ConcurrentHashMap to store active clients and maintains an independent ReentrantLock per server, ensuring that connect/replace/remove operations on the same server do not conflict concurrently.
Connection Replacement
When MCP server configuration is updated, the system follows a "connect new, then disconnect old" replacement strategy:
- Create and initialize a new
McpSyncClientwith the updated configuration - After the new client connects successfully, place it into the active client pool
- Close the old client
If the new client fails to connect, the old client remains unaffected (if one exists).
Subprocess Cleanup
For stdio-type MCP servers, MateClaw spawns a child process. The following scenarios ensure proper subprocess cleanup:
- Manually disabling or deleting an MCP server
- Replacing an MCP server's configuration
- Application shutdown (via
@PreDestroyhook) - Connection failure (subprocesses started during initialization are closed)
Status Monitoring
After each connection operation, the system persists the connection result to the database:
last_status:connected/disconnected/errorlast_error: Error message (cleared on successful connection)last_connected_time: Timestamp of the last successful connectiontool_count: Number of currently discovered tools
Manual Refresh
The "Refresh All Connections" operation (API: POST /api/v1/mcp/servers/refresh) disconnects all existing connections and reconnects all enabled servers. This is useful for troubleshooting connection issues or when the MCP server-side tool list has changed and needs rediscovery.
Database Storage
MCP server configurations are stored in the mate_mcp_server table. The complete field list:
| Column | Type | Default | Description |
|---|---|---|---|
id | BIGINT | - | Primary key (snowflake ID) |
name | VARCHAR(128) | - | Server name, unique identifier. Allows letters, numbers, _, -, ., and spaces; 1-128 characters |
description | TEXT | NULL | Server description |
transport | VARCHAR(32) | stdio | Transport type: stdio / streamable_http / sse |
url | VARCHAR(512) | NULL | Remote URL (required for streamable_http/sse types) |
headers_json | TEXT | NULL | HTTP headers as JSON object, e.g., {"Authorization": "Bearer xxx"} |
command | VARCHAR(512) | NULL | Startup command (required for stdio type), e.g., npx, node, python |
args_json | TEXT | NULL | Command arguments as JSON array, e.g., ["-y", "@anthropic/mcp-filesystem"] |
env_json | TEXT | NULL | Environment variables as JSON object; supports ${VAR} references to system env vars |
cwd | VARCHAR(512) | NULL | Working directory (used by stdio type) |
enabled | BOOLEAN | TRUE | Whether the server is active |
connect_timeout_seconds | INT | 30 | Connection establishment timeout in seconds (used by HTTP transport types) |
read_timeout_seconds | INT | 30 | Request response timeout in seconds; controls initialize/listTools/callTool timeouts |
last_status | VARCHAR(32) | disconnected | Last connection status: connected / disconnected / error |
last_error | TEXT | NULL | Last error message |
last_connected_time | DATETIME | NULL | Last successful connection timestamp |
tool_count | INT | 0 | Number of discovered tools |
builtin | BOOLEAN | FALSE | Whether the server is built-in (built-in servers cannot be deleted) |
create_time | DATETIME | - | Creation timestamp |
update_time | DATETIME | - | Last update timestamp |
deleted | INT | 0 | Logical delete flag |
Sensitive Data Sanitization
When returning MCP server lists via the API, values in headers_json and env_json are automatically masked (showing the first few and last four characters, with * in between). args_json is returned as-is since it does not contain sensitive information.
Environment Variable References
Values in env_json and headers_json support system environment variable references:
${VAR_NAME}-- Exact match and replacement$VAR_NAME-- Regex match (ensures variables with similar prefixes are not accidentally replaced)
For example, {"TAVILY_API_KEY": "${TAVILY_API_KEY}"} is replaced at runtime with the corresponding value from the MateClaw process environment. This avoids storing plaintext secrets in the database.
Troubleshooting
Command Not Found (stdio type)
Symptom: Connection fails with an error containing "command not found" or "No such file or directory".
Steps:
- Confirm the command specified in the
commandfield is available in the PATH of the user running MateClaw - Manually run the command on the server terminal to verify:
which npxornpx --version - If deploying with Docker, confirm the command is installed inside the container
- You can use the full path instead of the command name, e.g.,
/usr/local/bin/npx
Connection Timeout
Symptom: Connection fails with an error containing "timeout" or "timed out".
Steps:
- For HTTP/SSE types, confirm the URL is reachable:
curl -v <url> - Check firewall rules to ensure outbound connections are allowed
- Increase
connectTimeoutSecondsandreadTimeoutSecondsas needed - For stdio type, the first
npx -yexecution may need to download packages, which takes longer -- increase the timeout or pre-install the package
SSL/TLS Errors
Symptom: Connection to an HTTPS endpoint fails with an error containing "SSL" or "certificate".
Steps:
- Confirm the remote MCP server's SSL certificate is valid and not expired
- If using a self-signed certificate, add the CA certificate to the JVM trust store
- Confirm the JDK version in the MateClaw runtime supports the required TLS version
Tools Not Showing Up
Symptom: MCP server status is connected, but corresponding tools do not appear in the Agent tool list.
Steps:
- Check whether the
tool_countfield is greater than 0 - Use the test connection feature to confirm the
discoveredToolslist is not empty - Verify that the MCP server correctly implements the
tools/listendpoint - Check MateClaw backend logs for
McpToolCallbackProvider-related output
Tool Invocation Failures
Symptom: Agent receives an error when calling an MCP tool.
Steps:
- Check the MateClaw backend logs for specific error messages
- Confirm the MCP server process is still running (stdio type)
- Confirm the remote MCP server is reachable (HTTP/SSE type)
- Check whether
readTimeoutSecondsis sufficient (some tools take longer to execute) - Try refreshing connections:
POST /api/v1/mcp/servers/refresh
Orphaned Subprocesses (stdio type)
Symptom: After stopping MateClaw, MCP child processes are still running.
Steps:
- Under normal circumstances, the
@PreDestroyhook cleans up all subprocesses - If MateClaw was forcefully terminated (kill -9), subprocesses may remain and must be cleaned up manually
- Use
ps aux | grep mcpto find and terminate orphaned processes
Next Steps
- Tool System -- How MCP tools relate to built-in tools
- Skill System -- MCP-backed skills
- Configuration -- Full configuration reference
