AgentStack
MCP verified MIT Self-run

Mcp Apex Sdk

mcp-bfmvsa-mcp-apex-sdk · by bfmvsa

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

No reviews yet
0 installs
7 views
0.0% view→install

Install

$ agentstack add mcp-bfmvsa-mcp-apex-sdk

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Mcp Apex Sdk? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

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

[](https://login.salesforce.com/packaging/installPackage.apexp?p0=04tN2000000mUAHIA2)

[](https://test.salesforce.com/packaging/installPackage.apexp?p0=04tN2000000mUAHIA2)

/packaging/installPackage.apexp?p0=04tN2000000mUAHIA2

Quick Start

  1. [Install](#installation-links) the package in your Salesforce org
  2. [Deploy](force-app/main/example/classes) the demo classes from the force-app/main/example/ folder
  3. [Expose](#how-to-expose-server) the DemoServer from the example folder as a REST resource
  4. [Test](#testing-the-mcp-server) 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:

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 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 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 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 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);
  }

  // ...
}

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 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;
  }
}

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.