Overview
Syncline implements the Model Context Protocol (MCP) v2024-11-05 for AI agent integration. MCP uses JSON-RPC 2.0 over stdio (standard input/output) for communication.
Transport
Connection
Communication happens over stdio (standard input/output):
- Input: JSON-RPC requests sent to the server’s stdin
- Output: JSON-RPC responses sent from the server’s stdout
Each message is a single line of JSON followed by a newline character (\n).
┌──────────┐ stdin ┌──────────┐
│ │ ───────────────────────>│ │
│ Client │ │ Server │
│ (Agent) │<────────────────────────│(Syncline)│
└──────────┘ stdout └──────────┘
Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "method_name",
"params": {
"key": "value"
}
}
Unique identifier for the request. Used to match responses.
The method to call (e.g., "tools/list", "tools/call")
Optional parameters for the method
Response (Success)
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"data": "value"
}
}
The result of the method call
Response (Error)
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Invalid request",
"data": {
"details": "Additional error information"
}
}
}
Standard JSON-RPC error code
Human-readable error message
Optional additional error information
Protocol Flow
1. Initialize
The client must initialize the connection before calling tools.
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "my-agent",
"version": "1.0.0"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"serverInfo": {
"name": "syncline",
"version": "1.0.0"
},
"capabilities": {
"tools": {
"listChanged": false
}
}
}
}
Discover available tools.
Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "find_mutual_availability",
"description": "Find time slots where all attendees are available",
"inputSchema": {
"type": "object",
"properties": {
"attendees": {
"type": "array",
"items": {
"type": "string",
"format": "email"
},
"description": "Array of attendee email addresses"
},
"duration_minutes": {
"type": "number",
"default": 30,
"description": "Meeting duration in minutes"
}
},
"required": ["attendees"]
}
},
{
"name": "schedule_meeting",
"description": "Create a calendar event with Google Meet link",
"inputSchema": {
"type": "object",
"properties": {
"attendees": {
"type": "array",
"items": {
"type": "string",
"format": "email"
}
},
"start_time": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 datetime"
},
"title": {
"type": "string",
"description": "Meeting title"
},
"duration_minutes": {
"type": "number",
"default": 30
}
},
"required": ["attendees", "start_time", "title"]
}
},
{
"name": "check_availability",
"description": "Check a user's calendar for busy/free time slots",
"inputSchema": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"start_date": {
"type": "string",
"format": "date-time"
},
"end_date": {
"type": "string",
"format": "date-time"
}
},
"required": ["email", "start_date", "end_date"]
}
},
{
"name": "update_preferences",
"description": "Update user scheduling preferences",
"inputSchema": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"preferences": {
"type": "object",
"description": "Preferences object with work hours, buffer time, etc."
}
},
"required": ["email", "preferences"]
}
}
]
}
}
Execute a tool with arguments.
Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "find_mutual_availability",
"arguments": {
"attendees": ["alice@example.com", "bob@example.com"],
"duration_minutes": 30
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"slots\": [\n {\n \"start_time\": \"2025-01-22T14:00:00-08:00\",\n \"end_time\": \"2025-01-22T14:30:00-08:00\",\n \"score\": 0.95,\n \"match_quality\": \"excellent\",\n \"attendee_quality\": {\n \"alice@example.com\": 0.96,\n \"bob@example.com\": 0.94\n }\n }\n ],\n \"total_found\": 5\n}"
}
]
}
}
Available Methods
initialize
Initialize the MCP session.
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "client-name",
"version": "1.0.0"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"serverInfo": {
"name": "syncline",
"version": "1.0.0"
},
"capabilities": {
"tools": { "listChanged": false }
}
}
}
List all available tools.
Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
Response: Returns array of tool schemas (see example above)
Execute a tool.
Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "tool_name",
"arguments": {
"arg1": "value1"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "{\"result\": \"data\"}"
}
]
}
}
find_mutual_availability
Find time slots where all attendees are available.
Input Schema:
{
"type": "object",
"properties": {
"attendees": {
"type": "array",
"items": { "type": "string", "format": "email" },
"description": "Email addresses of attendees"
},
"duration_minutes": {
"type": "number",
"default": 30,
"description": "Meeting duration in minutes"
},
"earliest_time": {
"type": "string",
"format": "date-time",
"description": "Optional earliest acceptable time"
},
"latest_time": {
"type": "string",
"format": "date-time",
"description": "Optional latest acceptable time"
}
},
"required": ["attendees"]
}
Output Format:
{
"slots": [
{
"start_time": "2025-01-22T14:00:00-08:00",
"end_time": "2025-01-22T14:30:00-08:00",
"score": 0.95,
"match_quality": "excellent"
}
],
"total_found": 5
}
schedule_meeting
Create a calendar event with Google Meet.
Input Schema:
{
"type": "object",
"properties": {
"attendees": {
"type": "array",
"items": { "type": "string", "format": "email" }
},
"start_time": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 datetime"
},
"title": {
"type": "string",
"description": "Meeting title"
},
"duration_minutes": {
"type": "number",
"default": 30
},
"description": {
"type": "string",
"description": "Optional meeting description"
}
},
"required": ["attendees", "start_time", "title"]
}
Output Format:
{
"meeting_id": "evt_abc123",
"google_meet_link": "https://meet.google.com/abc-defg-hij",
"calendar_event_link": "https://calendar.google.com/calendar/event?eid=...",
"start_time": "2025-01-22T14:00:00-08:00",
"end_time": "2025-01-22T14:30:00-08:00"
}
check_availability
Check a user’s calendar.
Input Schema:
{
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"start_date": {
"type": "string",
"format": "date-time"
},
"end_date": {
"type": "string",
"format": "date-time"
}
},
"required": ["email", "start_date", "end_date"]
}
Output Format:
{
"email": "alice@example.com",
"free_slots": [
{
"start": "2025-01-22T09:00:00-08:00",
"end": "2025-01-22T10:00:00-08:00"
}
],
"busy_slots": [
{
"start": "2025-01-22T10:00:00-08:00",
"end": "2025-01-22T11:00:00-08:00",
"title": "Team Standup"
}
]
}
update_preferences
Update user scheduling preferences.
Input Schema:
{
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"preferences": {
"type": "object",
"properties": {
"work_hours": { "type": "object" },
"timezone": { "type": "string" },
"buffer_minutes": { "type": "number" },
"energy_pattern": { "type": "string" }
}
}
},
"required": ["email", "preferences"]
}
Output Format:
{
"email": "alice@example.com",
"preferences": {
"work_hours": {
"monday": { "enabled": true, "start": "09:00", "end": "17:00" }
},
"timezone": "America/New_York",
"buffer_minutes": 15
},
"updated_at": "2025-01-20T10:30:00Z"
}
Error Codes
Standard JSON-RPC 2.0 error codes:
Request is not a valid JSON-RPC 2.0 request
The requested method does not exist
Invalid method parameters
Error Response Example
{
"jsonrpc": "2.0",
"id": 3,
"error": {
"code": -32602,
"message": "Invalid params",
"data": {
"field": "attendees",
"reason": "Must provide at least 2 attendees"
}
}
}
Implementation Example
Python
import json
import subprocess
import sys
def send_request(process, method, params, request_id):
request = {
"jsonrpc": "2.0",
"id": request_id,
"method": method,
"params": params
}
# Send request
process.stdin.write(json.dumps(request) + "\n")
process.stdin.flush()
# Read response
response_line = process.stdout.readline()
return json.loads(response_line)
# Start MCP server
process = subprocess.Popen(
["npx", "-y", "@kekwanulabs/syncline-mcp-server"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
env={"SYNCLINE_API_KEY": "sk_live_your_key"}
)
# Initialize
response = send_request(process, "initialize", {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "my-agent", "version": "1.0.0"}
}, 1)
print("Initialized:", response)
# List tools
response = send_request(process, "tools/list", {}, 2)
print("Tools:", [tool["name"] for tool in response["result"]["tools"]])
# Call tool
response = send_request(process, "tools/call", {
"name": "find_mutual_availability",
"arguments": {
"attendees": ["alice@example.com", "bob@example.com"],
"duration_minutes": 30
}
}, 3)
print("Result:", response["result"]["content"][0]["text"])
# Cleanup
process.terminate()
Node.js
import { spawn } from "child_process";
import readline from "readline";
const process = spawn("npx", ["-y", "@kekwanulabs/syncline-mcp-server"], {
env: { ...process.env, SYNCLINE_API_KEY: "sk_live_your_key" }
});
const rl = readline.createInterface({
input: process.stdout,
output: process.stdin
});
function sendRequest(method, params, id) {
const request = {
jsonrpc: "2.0",
id,
method,
params
};
process.stdin.write(JSON.stringify(request) + "\n");
}
rl.on("line", (line) => {
const response = JSON.parse(line);
console.log("Response:", response);
});
// Initialize
sendRequest("initialize", {
protocolVersion: "2024-11-05",
capabilities: {},
clientInfo: { name: "my-agent", version: "1.0.0" }
}, 1);
// List tools
sendRequest("tools/list", {}, 2);
// Call tool
sendRequest("tools/call", {
name: "find_mutual_availability",
arguments: {
attendees: ["alice@example.com", "bob@example.com"],
duration_minutes: 30
}
}, 3);
Best Practices
Request IDs
Use unique, incrementing request IDs:
let requestId = 1;
function callTool(name, args) {
const id = requestId++;
sendRequest("tools/call", { name, arguments: args }, id);
return id;
}
Error Handling
Always check for error responses:
response = send_request(process, "tools/call", {...}, 1)
if "error" in response:
print(f"Error {response['error']['code']}: {response['error']['message']}")
else:
result = response["result"]
Timeout Handling
Implement timeouts for requests:
const timeout = 30000; // 30 seconds
const responsePromise = new Promise((resolve) => {
rl.once("line", (line) => resolve(JSON.parse(line)));
});
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error("Request timeout")), timeout);
});
try {
const response = await Promise.race([responsePromise, timeoutPromise]);
} catch (error) {
console.error("Request failed:", error);
}