MCP Protocol API
JSON-RPC 2.0 endpoints for interacting with aggregated MCP tools.
MCP Protocol API
The MCP Protocol API provides JSON-RPC 2.0 endpoints for MCP clients to interact with aggregated tools.
Endpoints
POST /v1/mcp/:projectSlug/request
JSON-RPC 2.0 endpoint for MCP protocol requests.
Path Parameters:
projectSlug(string) - Project identifier
Headers:
Content-Type: application/jsonAuthorization: Bearer <api-key>(if project requires auth)
GET/POST /v1/mcp/:projectSlug/sse
SSE (Server-Sent Events) bridge for streaming tool calls.
Headers:
Accept: text/event-streamAuthorization: Bearer <api-key>(if project requires auth)
MCP Methods
initialize
Establishes a session and negotiates protocol version/capabilities.
Request:
{
"jsonrpc": "2.0",
"id": "0",
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "client", "version": "1.0.0" }
}
}Response:
{
"jsonrpc": "2.0",
"id": "0",
"result": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"serverInfo": { "name": "RouterMCP", "version": "1.0.0" }
}
}tools/list
List all enabled tools from all configured servers.
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "github__create_issue",
"description": "Create a new issue",
"inputSchema": {
"type": "object",
"properties": {
"title": { "type": "string" },
"body": { "type": "string" }
},
"required": ["title"]
}
}
]
}
}Tools are namespaced as {serverAlias}__{toolName} to prevent conflicts.
tools/call
Execute a tool on the appropriate upstream server.
Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "github__create_issue",
"arguments": {
"title": "Bug report",
"body": "Issue description"
}
}
}Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "Issue created: #123"
}
]
}
}routermcp_searchMcpForTask
This tool has two mutually exclusive modes. Use task for a non-empty natural-language task
(maximum 2,048 Unicode characters and 8,192 UTF-8 bytes), or query for literal terms and
supported qualifiers such as server:github. Do not pass both. Query syntax is described in the
search guide.
Legacy task mode accepts an optional exact server alias, a limit from 1 to 20 (default 5),
an offset from 0 to 10,000 (default 0), and includeSchema (default false). The response keeps
total, nextOffset, topTool, and candidates; total and topTool cover all positive ranked
matches, not only the current page. Pages shorten near offset 10,000 so nextOffset stays within the
accepted range. At offset 10,000, nextOffset is null; truncated is true if more matches remain
after that page.
Explicit query mode accepts limit from 1 to 50 (default 20), an optional opaque cursor, and
includeSchema (default false). It cannot be combined with server or offset; put server
constraints in the query and use the returned nextCursor to continue. Its JSON text envelope
contains results, the page count, nextCursor, warnings, and coverage. Results use the
callable name alias__tool; schemas are returned only for this page when requested and rechecked
against the current project policy. Invalid arguments return JSON-RPC error -32602.
Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "routermcp_searchMcpForTask",
"arguments": {
"task": "create GitHub issue",
"server": "github",
"limit": 5,
"offset": 0,
"includeSchema": false
}
}
}Legacy task response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"total\": 2,\n \"nextOffset\": null,\n \"truncated\": false,\n \"topTool\": \"github__create_issue\",\n \"candidates\": [\n { \"name\": \"github__create_issue\", \"score\": 3.5 },\n { \"name\": \"github__update_issue\", \"score\": 2 }\n ]\n}"
}
]
}
}The text value contains JSON with total, nextOffset, truncated, topTool, and the requested
page of candidates. Each candidate has an executable namespaced name and score; inputSchema
is included only when includeSchema is true. truncated is true only on the final page at
offset 10,000 when additional ranked matches cannot be reached within the offset limit.
Explicit query request:
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "routermcp_searchMcpForTask",
"arguments": {
"query": "server:github create issue",
"limit": 20,
"includeSchema": true
}
}
}The query response text contains the shared search envelope. Each result's name remains an
executable alias__tool callable name; pass that exact name to routermcp_executeTool. If
nextCursor is non-null, send another request with the same query and that cursor.
Invalid queries and search execution failures return the JSON-RPC error.message together with
error.data.code. Parser diagnostics may include a span with Unicode code-point offsets; all
search diagnostics include a boolean restart field. When code is CURSOR_STALE, restart is
true; repeat the search without the cursor to get a fresh page.
routermcp_listTools query mode
When Code Mode is enabled, routermcp_listTools still returns the existing full TypeScript
declaration string when called with no query (or with the legacy filter). Its additive query
mode accepts limit from 1 to 50 and an optional cursor; query cannot be combined with
filter. The JSON text response contains the current page's TypeScript declarations, count,
nextCursor, warnings, and coverage. Continue with the same query and returned cursor to load
further declarations. Each page's schemas are rechecked against current Code Mode policy. Use the
exact namespace identifier shown in declarations when writing code. Safe aliases keep their names;
reserved or invalid aliases use stable encoded identifiers. Adding another alias does not change an
existing alias's identifier. Query-page identifiers are allocated against the full authorized alias
catalog.
SSE Streaming
The SSE endpoint returns events in this format:
Content-Type: text/event-stream
data: {"type":"progress","message":"Starting..."}
data: {"type":"result","result":{"success":true}}
data: [DONE]Code Examples
JavaScript
async function callTool(projectSlug, apiKey, toolName, args) {
const response = await fetch(
`https://gateway.routermcp.com/v1/mcp/${projectSlug}/request`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
jsonrpc: '2.0',
id: Date.now(),
method: 'tools/call',
params: { name: toolName, arguments: args }
})
}
);
const data = await response.json();
if (data.error) throw new Error(data.error.message);
return data.result;
}Python
import requests
def call_tool(project_slug, api_key, tool_name, args):
response = requests.post(
f'https://gateway.routermcp.com/v1/mcp/{project_slug}/request',
headers={
'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}'
},
json={
'jsonrpc': '2.0',
'id': 1,
'method': 'tools/call',
'params': {'name': tool_name, 'arguments': args}
}
)
data = response.json()
if 'error' in data:
raise Exception(data['error']['message'])
return data['result']cURL
curl -X POST 'https://gateway.routermcp.com/v1/mcp/my-project/request' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer rmc_your_api_key' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}'