Skip to content

Custom Servers

You can create custom MCP servers and use them with MCP Gateway in your AgentBox sandboxes. Custom servers allow you to extend MCP Gateway with your own tools and resources.

Create a custom MCP server using the MCP SDK:

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent

# Create a server instance
server = Server("my-custom-server")

# Define a tool
@server.list_tools()
async def list_tools() -> list[Tool]:
   return [
       Tool(
           name="custom_tool",
           description="A custom tool that does something useful",
           inputSchema={
               "type": "object",
               "properties": {
                   "input": {
                       "type": "string",
                       "description": "Input for the tool"
                   }
               },
               "required": ["input"]
           }
       )
   ]

# Implement the tool
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
   if name == "custom_tool":
       input_value = arguments.get("input", "")
       result = f"Processed: {input_value}"
       return [TextContent(type="text", text=result)]
   else:
       raise ValueError(f"Unknown tool: {name}")

# Run the server
async def main():
   async with stdio_server() as (read_stream, write_stream):
       await server.run(read_stream, write_stream, server.create_initialization_options())

if __name__ == "__main__":
   import asyncio
   asyncio.run(main())

Create a package for your custom server:

# Create a package structure
mkdir my-custom-mcp-server
cd my-custom-mcp-server

# Create setup.py or pyproject.toml
cat > pyproject.toml << EOF
[project]
name = "my-custom-mcp-server"
version = "1.0.0"
requires-python = ">=3.9"
dependencies = ["mcp"]

[project.scripts]
my-custom-server = "my_custom_server:main"
EOF

# Install in development mode
pip install -e .

To use your custom server, you need to:

  1. Install the server in the sandbox template
  2. Configure it in the MCP Gateway configuration

Add your custom server to a template:

FROM agentbox/base:latest

# Install your custom MCP server
RUN pip install my-custom-mcp-server

# Or copy and install from source
COPY my-custom-mcp-server/ /opt/my-custom-mcp-server/
RUN cd /opt/my-custom-mcp-server && pip install -e .

Configure a custom server that runs as a command:

from agentbox import Sandbox

sandbox = Sandbox.create(
   api_key="ab_xxxxxxxxxxxxxxxxxxxxxxxx",
   mcp={
       "my-custom-server": {
           "command": "python",
           "args": ["-m", "my_custom_server"],
           "env": {
               "CUSTOM_VAR": "value"
           }
       }
   }
)
  1. Follow MCP protocol: Ensure your server follows the MCP protocol specification
  2. Handle errors gracefully: Implement proper error handling in your tools
  3. Document your tools: Provide clear descriptions and input schemas
  4. Test thoroughly: Test your server with various clients
  5. Version your server: Use semantic versioning for your server

Here’s a complete example of a simple calculator MCP server:

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent

server = Server("calculator-server")

@server.list_tools()
async def list_tools() -> list[Tool]:
   return [
       Tool(
           name="add",
           description="Add two numbers",
           inputSchema={
               "type": "object",
               "properties": {
                   "a": {"type": "number"},
                   "b": {"type": "number"}
               },
               "required": ["a", "b"]
           }
       ),
       Tool(
           name="multiply",
           description="Multiply two numbers",
           inputSchema={
               "type": "object",
               "properties": {
                   "a": {"type": "number"},
                   "b": {"type": "number"}
               },
               "required": ["a", "b"]
           }
       )
   ]

@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
   if name == "add":
       result = arguments["a"] + arguments["b"]
       return [TextContent(type="text", text=str(result))]
   elif name == "multiply":
       result = arguments["a"] * arguments["b"]
       return [TextContent(type="text", text=str(result))]
   else:
       raise ValueError(f"Unknown tool: {name}")

async def main():
   async with stdio_server() as (read_stream, write_stream):
       await server.run(read_stream, write_stream, server.create_initialization_options())

if __name__ == "__main__":
   import asyncio
   asyncio.run(main())