1. Conduid
  2. AI
  3. Apex SDK
MCP server · AI

Apex SDK

Apex SDK for building Model Context Protocol (MCP) servers natively in Salesforce

Unclaimed ai
39Low

Scored 6 months ago · breakdown

About Apex SDK

Apex SDK is an MCP server in the AI category: apex SDK for building Model Context Protocol (MCP) servers natively in Salesforce.

Install

From source
git clone https://github.com/bfmvsa/mcp-apex-sdk

This server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.

Ask AI

✦

Ask AI about Apex SDK

Powered by Claude · Grounded in docs

I know everything about Apex SDK. Ask me about installation, configuration, usage, or troubleshooting.

Security checks

  • ✓README presentThe repository ships documentation.

5 checks have not been run yet.

README

MCP Apex SDK

Overview

The Model Context Protocol (MCP) provides a standardized way for applications to supply context to LLMs, separating context provision from LLM interaction.

This Apex SDK implements the MCP specification, enabling you to:

  • Create MCP servers that expose resources, tools, and prompts as primitives
  • Use standard Streamable HTTP transport
  • Handle MCP protocol messages

Installation Links

Static Badge

Static Badge

/packaging/installPackage.apexp?p0=04tN2000000mUAHIA2

Quick Start

  1. Install the package in your Salesforce org
  2. Deploy the demo classes from the force-app/main/example/ folder
  3. Expose the DemoServer from the example folder as a REST resource
  4. Test the functionality using the MCP Inspector tool

How to Expose an MCP Server

To expose the server to guest users, create a site and enable the DemoServer class for guest users:

  1. Navigate to Setup > User Interface > Sites and Domains > Sites
  2. Click New and enter the Site Label and Site Name, then click Save
  3. On the site details page, click Activate, then click Public Access Settings
  4. In the Enabled Apex Class Access section, add DemoServer to the Enabled Apex Classes
  5. Return to Setup > User Interface > Sites and Domains > Sites, find your newly created site, and copy its Site URL
  6. Append /services/apexrest/mcp to the copied Site URL to get the full URL for your MCP server

[!NOTE] If your org has a namespace, the URL will be {site_url}/services/apexrest/{namespace}/mcp.

Testing the MCP Server

To test the server, use the MCP Inspector tool.

Connecting to Your Server

  1. Select Transport Type: Streamable HTTP
  2. Enter your server URL (e.g., https://{instance_url}/services/apexrest/mcp)
  3. Click Connect

After a successful connection, you'll see the list of available resources, tools, and prompts, as shown in the screenshot below:

MCP Inspector

Core Concepts

Server

There are several ways to create an MCP server:

1. With Required Fields Only

ctx.Server server = new ctx.Server('1.0.0', 'autocare-plus-mcp-server');

2. With All Available Fields

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. Using Method Chaining

ctx.Server server = new ctx.Server('1.0.0', 'autocare-plus-mcp-server')
        .setInstructions(instructions)
        .setTitle(serverTitle);

Tools

1. Creating a Tool with Required Fields Only

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. Using All Available Constructor Fields

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. Adding Properties

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. Working with Properties

public with sharing class WeatherTool extends ctx.Tool {
  //...

  public override String call(Map<String, Object> input) {
    String cityName = (String) input.get('cityName');

    // Perform logic here...
    String result = 'The weather in ' + cityName + ' is perfect!';

    return result;
  }
}

Resources

1. Creating a Resource (Required Fields Only)

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. Creating a Resource (All Available Fields)

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. Creating a Resource Using Method Chaining

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. Retrieving Resource Data

public with sharing class CarServiceResource extends ctx.Resource {
  // ...

  public override List<ctx.Resource.Content> read() {
    // This method MUST return List<ctx.Resource.Content>
    List<String> services = new List<String>{ 'Oil Change', 'Battery Check' };

    List<ctx.Resource.Content> result = new List<ctx.Resource.Content>();
    for (String service : services) {
      result.add(new ctx.Resource.Content(this.uri, service));
    }

    return result;
  }
}

4.1 Creating ctx.Resource.Content (Required Fields Only)

ctx.Resource.Content content = new ctx.Resource.Content('uri', 'text-data');

4.2 Creating ctx.Resource.Content (All Fields)

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 Creating ctx.Resource.Content Using Method Chaining

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 Creating ctx.Resource.Content with Binary Content

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. Adding Resource Annotations

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<String> audience = new List<String>{ '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);
  }

  // ...
}

Prompts

1. Creating a Prompt (Required Fields Only)

public with sharing class CodeReviewPrompt extends ctx.Prompt {
  public CodeReviewPrompt() {
    super('code-review');
  }

  // ...
}

2. Creating a Prompt (All Available Fields)

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. Creating a Prompt Using Method Chaining

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. Adding Prompt Arguments

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. Retrieving Prompt Messages

public with sharing class CodeReviewPrompt extends ctx.Prompt {
  // ...

  public override List<ctx.Prompt.Message> get(Map<String, Object> input) {
    String code = (String) input.get('code');

    List<ctx.Prompt.Message> messages = new List<ctx.Prompt.Message>();

    messages.add(new ctx.Prompt.Message('user', 'Review the following code and suggest improvements: ' + code));

    return messages;
  }
}

README copy captured when this server was indexed; it may lag the repository. The original is authoritative.

Questions

About Apex SDK

How do I install Apex SDK?

No package has been published for this server, so install it from source: clone the repository and follow its README.

Is Apex SDK safe to use with an AI agent?

Its trust score is 39 out of 100 (low). It passes 1 of the 1 static security checks run so far. It has no ConduID identity yet, so agent calls to it are not receipted.

Is Apex SDK still maintained?

Conduid hasn't recorded a commit date for this repository yet. Check the repository directly for recent activity.