MCP Tools - Model Context Protocol#
lit-mux implements the Model Context Protocol for extending AI capabilities with external tools. MCP provides a standardized way for LLMs to discover, describe, and execute tools.
MCP Architecture#
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ LLM Backend │────▶│ lit-mux │────▶│ MCP Server │
│ (Claude, etc) │◀────│ MCP Client │◀────│ (Jira, Git...) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
lit-mux acts as an MCP client, connecting to multiple MCP servers that provide tools. The LLM sees all available tools and can invoke them during conversations.
Built-in MCP Servers#
lit-mux includes several built-in MCP servers:
| Server | Tools | Use Case |
|---|---|---|
| jira | Search, create, update issues | Project management |
| agent-messaging | Send messages between agents | Multi-agent coordination |
| heartbeat-actions | Control agent behavior | Autonomous operations |
Jira Server#
Full Jira integration for issue tracking:
jira_search - Search issues with JQL
jira_get_issue - Get issue details
jira_create_issue - Create new issues
jira_update_issue - Update issue fields
jira_add_comment - Add comments
jira_transition_issue - Change issue status
jira_assign_issue - Assign to users
jira_link_issues - Link related issues
jira_get_epic_issues - Get epic children
Configuration:
mcp_servers:
jira:
command: "python"
args: ["-m", "lit_mux.mcp_servers.jira_server"]
env:
JIRA_URL: "https://your-company.atlassian.net"
JIRA_EMAIL: "${JIRA_EMAIL}"
JIRA_API_TOKEN: "${JIRA_API_TOKEN}"
Agent Messaging Server#
Enables agent-to-agent communication:
send_agent_message - Send message to another agent
get_my_agent_config - Get own configuration
list_connected_agents - List available agents
get_agent_info - Get agent details
get_message_status - Check message delivery
get_queue_status - Check queue status
send_message_to_user - Send message to human user
Heartbeat Actions Server#
Control autonomous agent behavior:
set_sleep_duration - Adjust sleep interval
wake_immediately - Force wake from sleep
pause_heartbeat - Pause autonomous operation
resume_heartbeat - Resume autonomous operation
External MCP Servers#
lit-mux can connect to any MCP-compatible server. Common external servers:
| Server | Description |
|---|---|
| filesystem | Read/write files |
| git | Git operations |
| postgres | Database queries |
| sqlite | Local database |
| puppeteer | Web automation |
| brave-search | Web search |
Configuring External Servers#
Add servers to your agent configuration:
{
"id": "dev-assistant",
"mcp_servers": ["jira", "git", "filesystem"],
"mcp_server_overrides": {
"filesystem": {
"args": ["--allowed-directories", "/home/projects"]
}
}
}
Or configure globally in config.yaml:
mcp_servers:
git:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-git"]
filesystem:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/projects"]
Per-Agent MCP Configuration#
Different agents can have different toolsets:
// project-manager.json
{
"id": "project-manager",
"mcp_servers": ["jira", "agent-messaging"],
"mcp_server_overrides": {
"jira": {
"env": { "JIRA_PROJECT": "PM" }
}
}
}
// developer.json
{
"id": "developer",
"mcp_servers": ["git", "filesystem", "jira"],
"mcp_server_overrides": {
"filesystem": {
"args": ["--allowed-directories", "/home/dev/projects"]
}
}
}
API Endpoints#
List Available Tools#
GET /tools
# Response
[
{
"name": "jira_search",
"description": "Search for Jira issues using JQL",
"inputSchema": {
"type": "object",
"properties": {
"jql": { "type": "string", "description": "JQL query" },
"max_results": { "type": "integer", "default": 50 }
},
"required": ["jql"]
}
},
...
]
List MCP Servers#
GET /mcp/servers
# Response
[
{ "name": "jira", "status": "connected", "tools": 12 },
{ "name": "git", "status": "connected", "tools": 8 },
{ "name": "filesystem", "status": "disconnected" }
]
MCP Health Check#
GET /mcp/health
# Response
{
"status": "healthy",
"servers": {
"jira": { "connected": true, "last_ping": "2024-01-15T10:30:00Z" },
"git": { "connected": true, "last_ping": "2024-01-15T10:30:00Z" }
}
}
Security Model#
Execute as User#
Unlike typical AI platforms, lit-mux tools execute with the user's actual permissions:
- Tools run as the authenticated user, not a service account
- No privilege escalation—tools can only access what the user can access
- Audit trails show real user identity
- Existing RBAC and ACLs are respected
Per-Agent Isolation#
- Each agent only sees tools from its configured
mcp_servers - MCP server overrides are agent-specific
- Working directories are isolated per agent
Tool Validation#
- Input schemas are validated before execution
- Output is sanitized before returning to LLM
- Errors are caught and reported gracefully
Creating Custom MCP Servers#
Python Server#
from mcp.server import Server
from mcp.types import Tool, TextContent
server = Server("my-tools")
@server.tool()
async def my_custom_tool(query: str) -> list[TextContent]:
"""Search for something custom.
Args:
query: The search query
"""
result = await do_search(query)
return [TextContent(type="text", text=result)]
if __name__ == "__main__":
import asyncio
asyncio.run(server.run())
TypeScript Server#
import { Server } from "@modelcontextprotocol/sdk/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
const server = new Server({
name: "my-tools",
version: "1.0.0"
});
server.setRequestHandler("tools/list", async () => ({
tools: [{
name: "my_custom_tool",
description: "Search for something custom",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "Search query" }
},
required: ["query"]
}
}]
}));
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;
if (name === "my_custom_tool") {
const result = await doSearch(args.query);
return { content: [{ type: "text", text: result }] };
}
throw new Error(`Unknown tool: ${name}`);
});
const transport = new StdioServerTransport();
server.connect(transport);
Registering Custom Servers#
Add to config.yaml:
mcp_servers:
my-tools:
command: "python"
args: ["/path/to/my_server.py"]
env:
MY_API_KEY: "${MY_API_KEY}"
Or per-agent:
{
"id": "my-agent",
"mcp_servers": ["my-tools"],
"mcp_server_overrides": {
"my-tools": {
"command": "python",
"args": ["/path/to/my_server.py"]
}
}
}
Tool Execution Flow#
1. User sends message
2. LLM decides to use tool
3. lit-mux validates tool call
4. lit-mux routes to appropriate MCP server
5. MCP server executes tool
6. Result returned to LLM
7. LLM incorporates result into response
Streaming Tool Execution#
During streaming, tool execution is communicated via events:
{"type": "tool_start", "tool_name": "jira_search", "tool_id": "call_123"}
{"type": "tool_input", "tool_id": "call_123", "input": {"jql": "project=PROJ"}}
{"type": "tool_result", "tool_id": "call_123", "result": "Found 5 issues..."}
Best Practices#
Tool Design#
- Single Purpose: Each tool should do one thing well
- Clear Descriptions: Help the LLM understand when to use the tool
- Validated Inputs: Use JSON Schema for input validation
- Graceful Errors: Return helpful error messages
Performance#
- Connection Pooling: Reuse MCP server connections
- Timeout Configuration: Set appropriate timeouts for slow tools
- Caching: Cache tool results where appropriate
Security#
- Least Privilege: Only enable tools an agent needs
- Input Sanitization: Validate and sanitize all inputs
- Audit Logging: Log all tool invocations
- Secret Management: Use environment variables for credentials
Troubleshooting#
Server Not Connecting#
Tool Not Appearing#
- Verify server is listed in agent's
mcp_servers - Check server is running and healthy
- Ensure tool has valid schema
Execution Errors#
- Check tool input matches schema
- Verify credentials/environment variables
- Look for timeout issues with slow tools