MCP Apex SDK
概述
这 模型上下文协议(MCP) 为应用程序向LLM提供上下文提供了一种标准化的方法,将 LLM交互提供上下文。
此Apex SDK实现了MCP规范,使您能够:
- 创建MCP服务器,将资源、工具和提示作为原语公开
- 使用标准流式HTTP传输
- 处理MCP协议消息
安装链接
](https://login.salesforce.com/packaging/installPackage.apexp?p0=04tN2000000mUAHIA2)
](https://test.salesforce.com/packaging/installPackage.apexp?p0=04tN2000000mUAHIA2)
/packaging/installPackage.apexp?p0=04tN2000000mUAHIA2
快速开始
这 MCP检查员 工具
如何暴露MCP服务器
要将服务器暴露给访客用户,请创建一个站点并启用 DemoServer 访客用户类:
- 引导到
Setup > User Interface > Sites and Domains > Sites - 点击
New并输入Site Label和Site Name,然后单击Save - 在网站详细信息页面上,单击
Activate,然后单击Public Access Settings - 在
Enabled Apex Class Access节,添加DemoServer到Enabled Apex Classes - 返回
Setup > User Interface > Sites and Domains > Sites,找到您新创建的网站,并复制其Site URL - 追加
/services/apexrest/mcp到复制Site URL获取MCP服务器的完整URL
\[!注意\] 如果你的组织有一个命名空间,URL将是 {site_url}/services/apexrest/{namespace}/mcp.测试MCP服务器
要测试服务器,请使用 MCP检查员 工具。
连接到您的服务器
- 选择 传输类型:流式HTTP
- 输入您的服务器URL(例如。,
https://{instance_url}/services/apexrest/mcp) - 点击 连接
成功连接后,您将看到可用资源、工具和提示的列表,如所示 下面的屏幕截图:

核心概念
服务器
有几种方法可以创建MCP服务器:
1.仅限必填字段
ctx.Server server = new ctx.Server('1.0.0', 'autocare-plus-mcp-server');2.所有可用字段
String version = '1.0.0';
String serverName = 'autocare-plus-mcp-server';
String serverTitle = 'AutoCare Plus MCP Server';
String instructions = 'AutoCare Plus car service that exposes a list of available services and a tool to book appointments.';
ctx.Server server = new ctx.Server(version, serverName, serverTitle, instructions);3.使用链式方法
ctx.Server server = new ctx.Server('1.0.0', 'autocare-plus-mcp-server')
.setInstructions(instructions)
.setTitle(serverTitle);工具
1.创建仅包含必填字段的工具
public with sharing class GetAvailableCarServicesTool extends ctx.Tool {
public static final String toolName = 'get-available-car-services-tool';
public static final String toolDescription = 'Retrieves all available car services with their Salesforce record IDs.';
public GetAvailableCarServicesTool() {
super(toolName, toolDescription);
}
//...
}2.使用所有可用的构造函数字段
public with sharing class GetAvailableCarServicesTool extends ctx.Tool {
public static final String toolName = 'get-available-car-services-tool';
public static final String toolTitle = 'Get Available Car Services';
public static final String toolDescription = 'Retrieves all available car services with their Salesforce record IDs.';
public GetAvailableCarServicesTool() {
super(toolName, toolTitle, toolDescription);
}
//...
}3.添加属性
public with sharing class WeatherTool extends ctx.Tool {
public WeatherTool() {
super('get-weather-details', 'Get weather details for a specific city');
ctx.Tool.Property cityName = new ctx.Tool.Property(
'cityName', // Property name
'string', // Property type
'The name of the city', // Property description
true // true if property is required, false if optional
);
this.addProperty(cityName);
}
//...
}4.处理物业
public with sharing class WeatherTool extends ctx.Tool {
//...
public override String call(Map input) {
String cityName = (String) input.get('cityName');
// Perform logic here...
String result = 'The weather in ' + cityName + ' is perfect!';
return result;
}
}资源
1.创建资源(仅限必填字段)
public with sharing class CarServiceResource extends ctx.Resource {
public static final String uri = '@server://services';
public static final String resourceName = 'service-catalog';
public CarServiceResource() {
super(uri, resourceName);
}
// ...
}2.创建资源(所有可用字段)
public with sharing class CarServiceResource extends ctx.Resource {
public static final String uri = '@server://services';
public static final String resourceName = 'service-catalog';
public static final String resourceTitle = 'Catalog of Services';
public static final String resourceDescription = 'List of all available car services';
public static final String resourceMimeType = 'application/json';
public static Long resourceSize = 65536;
public CarServiceResource() {
super(uri, resourceName, resourceTitle, resourceDescription, resourceMimeType, resourceSize);
}
// ...
}3.使用方法链创建资源
public with sharing class CarServiceResource extends ctx.Resource {
public static final String uri = '@server://services';
public static final String resourceName = 'service-catalog';
public static final String resourceTitle = 'Catalog of Services';
public static final String resourceDescription = 'List of all available car services';
public static final String resourceMimeType = 'application/json';
public static Long resourceSize = 65536;
public CarServiceResource() {
super(uri, resourceName);
this.setTitle(resourceTitle)
.setDescription(resourceDescription)
.setMimeType(resourceMimeType)
.setSize(resourceSize);
}
// ...
}4.检索资源数据
public with sharing class CarServiceResource extends ctx.Resource {
// ...
public override List read() {
// This method MUST return List
List services = new List{ 'Oil Change', 'Battery Check' };
List result = new List();
for (String service : services) {
result.add(new ctx.Resource.Content(this.uri, service));
}
return result;
}
}4.1创建ctx。资源。内容(仅限必填字段)
ctx.Resource.Content content = new ctx.Resource.Content('uri', 'text-data');4.2创建ctx。资源。内容(所有字段)
String uri = '@server://service/oil-change';
String name = 'oil-change';
String title = 'Oil Change';
String text = 'Oil Change Service';
ctx.Resource.Content content = new ctx.Resource.Content(uri, name, title, text);4.3创建ctx。资源。内容使用方法链接
String uri = '@server://service/oil-change';
String name = 'oil-change';
String title = 'Oil Change';
String text = 'Oil Change Service';
ctx.Resource.Content content = new ctx.Resource.Content(uri, text)
.setTitle(title)
.setMimeType('text/plain')
.setText(text);4.4创建ctx。资源。包含二进制内容的内容
String uri = '@file:///example.png';
String name = 'example.png';
String title = 'Example Image';
ctx.Resource.Content content = new ctx.Resource.Content(uri)
.setName(name)
.setTitle(title)
.setMimeType('image/png')
.setBlobData('base64-encoded-data');5.添加资源注释
public with sharing class CarServiceResource extends ctx.Resource {
public static final String uri = '@server://services';
public static final String resourceName = 'service-catalog';
public CarServiceResource() {
super(uri, resourceName);
List audience = new List{ 'user', 'assistant' }; // "user" or "assistant" or both
Decimal priority = 0.8; // Value between 0 and 1
Datetime lastModified = System.now(); // ISO 8601 formatted timestamp
ctx.Resource.Annotations annotations = new ctx.Resource.Annotations(audience, priority, lastModified);
this.setAnnotations(annotations);
}
// ...
}提示
1.创建提示(仅限必填字段)
public with sharing class CodeReviewPrompt extends ctx.Prompt {
public CodeReviewPrompt() {
super('code-review');
}
// ...
}2.创建提示(所有可用字段)
public with sharing class CodeReviewPrompt extends ctx.Prompt {
public CodeReviewPrompt() {
super('code-review', 'Code Review', 'Asks the LLM to analyze code quality and suggest improvements');
}
// ...
}3.使用方法链创建提示
public with sharing class CodeReviewPrompt extends ctx.Prompt {
public CodeReviewPrompt() {
super('code-review');
this.setTitle('Code Review').setDescription('Asks the LLM to analyze code quality and suggest improvements');
}
// ...
}4.添加提示参数
public with sharing class CodeReviewPrompt extends ctx.Prompt {
public CodeReviewPrompt() {
super('code-review', 'Code Review', 'Asks the LLM to analyze code quality and suggest improvements');
ctx.Prompt.Argument code = new ctx.Prompt.Argument('code', 'The code to review', true);
this.addArgument(code);
}
// ...
}5.检索提示消息
public with sharing class CodeReviewPrompt extends ctx.Prompt {
// ...
public override List get(Map input) {
String code = (String) input.get('code');
List messages = new List();
messages.add(new ctx.Prompt.Message('user', 'Review the following code and suggest improvements: ' + code));
return messages;
}
}