MCP JSAPI
JavaScript API for MCP (Model Context Protocol) clients in Yao.
Quick Start
Recommended: Using Use() for Automatic Resource Management
The Use() function automatically handles resource cleanup with a callback pattern:
// Simple and clean - resources are automatically released
Use(MCP, "client_id", (client) => {
const tools = client.ListTools();
const result = client.CallTool("tool_name", { arg: "value" });
return result;
});
// client.__release() is automatically called after the callback, even if an error occurs
Alternative: Manual Resource Management
For cases where you need explicit control or complex control flow:
const client = new MCP("client_id");
try {
// Use the client...
const result = client.CallTool("tool_name", { arg: "value" });
return result;
} finally {
client.Release(); // Manually release resources
}
Resource Management
MCP clients hold Go resources that must be released. Two approaches:
✅ Recommended: Use() Function
Pros:
- Automatic cleanup - no need to remember
Release()
- Less boilerplate code
- Always releases resources, even on errors
- Cleaner, more readable code
When to use:
- Most cases
- When resource lifetime matches callback scope
- When you want guaranteed cleanup with minimal code
Use(MCP, "dsl", (client) => {
// Use client here
return client.CallTool("validate", { schema: data });
});
Alternative: Manual try-finally
Pros:
- Explicit control over resource lifetime
- Suitable for complex control flow
- No callback nesting
When to use:
- Resource needs to be used across multiple scopes
- Complex error handling requirements
- Performance-critical code (minimal overhead difference)
const client = new MCP("dsl");
try {
// Use client
} finally {
client.Release();
}
API Reference
// List available tools
Use(MCP, "client_id", (client) => {
const tools = client.ListTools();
console.log(tools.tools); // Array of tool definitions
});
// Call a single tool
Use(MCP, "client_id", (client) => {
const result = client.CallTool("tool_name", {
arg1: "value1",
arg2: 123,
});
return result;
});
// Call multiple tools sequentially
Use(MCP, "client_id", (client) => {
const results = client.CallTools([
{ name: "tool1", arguments: { foo: "bar" } },
{ name: "tool2", arguments: { baz: 42 } },
]);
return results;
});
// Call multiple tools in parallel
Use(MCP, "client_id", (client) => {
const results = client.CallToolsParallel([
{ name: "tool1", arguments: { foo: "bar" } },
{ name: "tool2", arguments: { baz: 42 } },
]);
return results;
});
Resource Operations
// List available resources
Use(MCP, "customer", (client) => {
const resources = client.ListResources();
return resources.resources;
});
// Read a resource by URI
Use(MCP, "customer", (client) => {
const content = client.ReadResource("customers://123");
return content.contents;
});
Prompt Operations
// List available prompts
Use(MCP, "client_id", (client) => {
const prompts = client.ListPrompts();
return prompts.prompts;
});
// Get a prompt template with arguments
Use(MCP, "client_id", (client) => {
const prompt = client.GetPrompt("prompt_name", {
arg1: "value1",
});
return prompt.messages;
});
Sample Operations
// List samples for a tool
Use(MCP, "client_id", (client) => {
const samples = client.ListSamples("tool", "tool_name");
return samples.samples;
});
// Get a specific sample by index
Use(MCP, "client_id", (client) => {
const sample = client.GetSample("tool", "tool_name", 0);
return { input: sample.input, output: sample.output };
});
// List samples for a resource
Use(MCP, "client_id", (client) => {
return client.ListSamples("resource", "resource_name");
});
Complete Examples
Example 1: Using Use() (Recommended)
function processCustomer(customerId) {
return Use(MCP, "customer", (mcp) => {
// List available tools
const tools = mcp.ListTools();
console.log(
"Available tools:",
tools.tools.map((t) => t.name)
);
// Read customer resource
const customer = mcp.ReadResource(`customers://${customerId}`);
// Call a tool
const result = mcp.CallTool("update_customer", {
id: customerId,
status: "active",
});
return result;
}); // Automatic cleanup happens here
}
Example 2: Nested MCP Clients
function validateAndProcess(schema, customerId) {
return Use(MCP, "dsl", (dslClient) => {
// Validate schema
const validation = dslClient.CallTool("validate_schema", { schema });
if (!validation.isValid) {
throw new Error("Invalid schema");
}
// Process customer with another MCP client
return Use(MCP, "customer", (customerClient) => {
return customerClient.CallTool("process", {
id: customerId,
schema: validation.normalized,
});
});
});
}
Example 3: Error Handling with Use()
function safeToolCall(toolName, args) {
try {
return Use(MCP, "client_id", (client) => {
// Errors are properly propagated
return client.CallTool(toolName, args);
});
// client.__release() is still called even if an error occurs
} catch (error) {
console.error("Tool call failed:", error.message);
return { error: error.message };
}
}
Example 4: Manual Resource Management
For complex scenarios where Use() doesn't fit:
function complexWorkflow(customerId) {
const mcp = new MCP("customer");
try {
// Step 1: Read customer
const customer = mcp.ReadResource(`customers://${customerId}`);
// Step 2: Some complex logic...
if (customer.status === "inactive") {
return null; // Early return
}
// Step 3: Update customer
const result = mcp.CallTool("update_customer", {
id: customerId,
lastAccess: new Date().toISOString(),
});
return result;
} finally {
// Always release resources
mcp.Release();
}
}
API Methods
Constructor
new MCP(clientId: string) - Creates a new MCP client instance
Properties
id: string - The client ID
ListTools(cursor?: string): ListToolsResponse - List all available tools
CallTool(name: string, arguments?: object): CallToolResponse - Call a single tool
CallTools(toolCalls: ToolCall[]): CallToolsResponse - Call multiple tools sequentially
CallToolsParallel(toolCalls: ToolCall[]): CallToolsResponse - Call multiple tools in parallel
Resource Methods
ListResources(cursor?: string): ListResourcesResponse - List all available resources
ReadResource(uri: string): ReadResourceResponse - Read a resource by URI
Prompt Methods
ListPrompts(cursor?: string): ListPromptsResponse - List all available prompts
GetPrompt(name: string, arguments?: object): GetPromptResponse - Get a prompt template
Sample Methods
ListSamples(itemType: "tool"|"resource", itemName: string): ListSamplesResponse - List samples for a tool or resource
GetSample(itemType: "tool"|"resource", itemName: string, index: number): SampleData - Get a specific sample by index
Resource Management Methods
Release() - Manually release Go resources (required when not using Use())
__release() - Internal method called automatically by Use() or V8 GC (do not call directly)
Best Practices
- Use
Use() by default - It's cleaner and safer than manual resource management
- Handle errors with try-catch - Wrap
Use() calls when you need error handling
- Nest
Use() calls - For multiple MCP clients, nest them naturally
- Use manual
try-finally only when needed - For complex control flow or explicit lifetime control
- Never forget to release - If not using
Use(), always call Release() in a finally block
Notes
- The MCP client must be loaded in Go before creating a JavaScript instance
- All methods are synchronous in the current implementation
- Errors are thrown as JavaScript exceptions
Use() ensures resources are released even when errors occur
- When using
Use(), the callback return value becomes the return value of Use()
- The
__release() method is internal - use Release() for manual cleanup or Use() for automatic cleanup