Tools¶
A LanguageTool is an MCP-compatible service that agents call to do things beyond generating text — query a database, search the web, run code, read files. The operator manages the Deployment and Service, discovers what the tool can do, and injects its endpoint into every agent that references it.
How it works¶
When you create a LanguageTool, the operator:
- Deploys the tool as a Kubernetes Deployment and Service. For
transport: streamable-httporsseit runsspec.imagedirectly; fortransport: stdioit injects a bridge image that wraps the stdio command and serves Streamable HTTP at/mcp. - Waits for the pod to become ready, then calls
tools/listto discover what the tool exposes. - Stores the discovered schemas in
status.toolSchemas. - Injects the tool's endpoint (including
/mcp) into every referencing agent via/etc/agent/config.yaml.
Agents connect to tools directly over MCP — the operator doesn't proxy or inspect tool traffic.
Transports¶
spec.transport selects how the tool's MCP endpoint is exposed:
| Transport | Description |
|---|---|
streamable-http (default) |
spec.image serves Streamable HTTP at /mcp on spec.port. |
sse |
spec.image serves the legacy MCP HTTP+SSE transport on spec.port. |
stdio |
The operator injects a bridge that runs spec.stdio.command as a persistent child and serves Streamable HTTP at /mcp. spec.image is ignored. |
stdio tools¶
For transport: stdio you provide the full argv of the stdio MCP server in spec.stdio.command. The operator injects a pinned bridge (ghcr.io/language-operator/mcp-bridge:latest) that bundles Node and Python+uv, so both npx and uvx commands work without a custom image:
The bridge keeps one long-lived child process — there is no per-request spawn. Writable scratch volumes (HOME and /tmp) are injected automatically so npm/uv caches work even with readOnlyRootFilesystem.
Deploying a tool¶
A LanguageTool is self-contained. You provide an image (or a stdio command); the operator creates the Deployment and Service:
apiVersion: langop.io/v1alpha1
kind: LanguageTool
metadata:
name: mem0-memory
namespace: language-operator-myapp
spec:
image: myregistry/mem0-mcp:latest
port: 8080
That's enough to get a running tool with an in-cluster endpoint at http://mem0-memory.language-operator-myapp.svc.cluster.local:8080.
The deploymentMode field controls whether the tool runs as a shared service (default) or as a sidecar inside each agent pod:
service— one Deployment shared across all agents that reference the tool. Good for stateless tools.sidecar— injected into each agent pod. Gets access to the agent's workspace volume. Good for tools that need per-agent state.
MCP protocol¶
The tool must implement MCP on the port defined in spec.port. The operator calls two methods: tools/list for schema discovery, and agents call tools/call at runtime.
Tool listing¶
POST /mcp
Content-Type: application/json
Accept: application/json, text/event-stream
{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "remember",
"description": "Store information in long-term memory",
"inputSchema": {
"type": "object",
"properties": {
"content": { "type": "string", "description": "Information to remember" },
"tags": { "type": "array", "items": { "type": "string" } }
},
"required": ["content"]
}
}
]
}
}
Tool invocation¶
POST /mcp
Content-Type: application/json
Accept: application/json, text/event-stream
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "remember",
"arguments": { "content": "User prefers metric units", "tags": ["preferences"] }
}
}
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [{ "type": "text", "text": "Stored successfully." }]
}
}
Health check¶
The operator uses GET /health to determine when the tool is ready before attempting schema discovery:
Error responses¶
Tool errors should use MCP error format rather than HTTP error status codes:
{
"jsonrpc": "2.0",
"id": 2,
"error": {
"code": -32603,
"message": "Memory store unavailable",
"data": { "reason": "connection refused" }
}
}
| Code | Meaning |
|---|---|
-32700 |
Parse error |
-32600 |
Invalid request |
-32601 |
Method not found |
-32602 |
Invalid params |
-32603 |
Internal error |
How agents receive tool endpoints¶
The operator writes each tool's endpoint into the referencing agent's /etc/agent/config.yaml under the tools: key:
tools:
mem0-memory:
endpoint: http://mem0-memory.language-operator-myapp.svc.cluster.local:8080/mcp
protocol: mcp
Runtime adapters (like openclaw-adapter and opencode-adapter) read this file and translate it into their runtime's native tool configuration before the agent starts.
Checklist¶
For transport: streamable-http or transport: sse, the tool image must:
- [ ] Implement MCP JSON-RPC at the port defined in
spec.port - [ ] Respond to
tools/listwith all available tools and their input schemas - [ ] Respond to
tools/callwith the result of invoking the named tool - [ ] Expose
GET /healthreturning200 OKwith{"status":"ok"}when ready - [ ] Return MCP error objects for failures, not HTTP error status codes
For transport: stdio, the operator-injected bridge handles all of the above — the stdio command only needs to speak the MCP stdio transport.