Skip to main content

Creating an MCP service

This guide walks through creating a new MCP service using @evolve-packages/mcp-core. The mcp-customer service serves as the reference implementation.

info

This guide assumes that @evolve-packages/mcp-core is already installed in your project. It is included in the Evolve platform by default.

1. Scaffold the service

Start by copying the existing mcp-customer service as a template:

cp -r backend/services/mcp-customer backend/services/mcp-my-service

Update package.json with your service name:

{
"name": "@evolve-platform/mcp-my-service",
"version": "1.0.0",
"description": "MCP server for my use case"
}

2. Configure the service

Update src/config.ts to set the component name and port:

import { MCPCoreConfig } from "@evolve-packages/mcp-core";

export class Config extends MCPCoreConfig {
override COMPONENT_NAME = "mcp-my-service";
override HTTP_PORT = 6001; // Use a unique port
}

3. Define your tools

Create or update operations.graphql with your GraphQL operations. Each operation that should become an MCP tool needs the @mcpTool directive. These operations must correspond to the supergraph schema: you can use fewer fields than the supergraph exposes, but you cannot query fields that don't exist in it. During code generation, your operations are validated against the supergraph.

query GetProductDetailPage(
$slug: String! @mcpToolVariable(description: "The product slug to look up")
$skuId: String @mcpToolVariable(description: "Optional specific SKU ID")
) @mcpTool(description: "Get detailed product information by its URL slug") {
product(slug: $slug, skuId: $skuId) {
name
description
slug
variants {
sku
name
price {
centAmount
currencyCode
}
images {
url
}
availability {
isOnStock
}
}
}
}
info

Every variable should have an @mcpToolVariable(description: ...) annotation. These descriptions are what AI clients see when deciding how to call the tool. Clear, specific descriptions lead to better tool usage.

4. Configure code generation

Update codegen.ts to point at your operations and include any plugin operations you need:

import type { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
schema: "../../schema.graphql",
documents: [
"src/**/*.graphql",
// Include plugin operations if using customer-auth
"@evolve-packages/mcp-core/plugins/customer-auth/operations.graphql",
],
generates: {
// ... type generation config
},
};

export default config;

5. Set up the server

In src/create-server.ts, compose the server from mcp-core building blocks:

import {
createToolFromGenerated,
registerTools,
createCustomerAuthPlugin,
} from "@evolve-packages/mcp-core";

export async function createServer(config: Config) {
// Load generated tools
const generatedTools = await loadGeneratedTools(
"#generated/mcp-tools.generated.ts"
);
const tools = generatedTools.map(createToolFromGenerated);

// Set up plugins (optional)
const customerAuthPlugin = createCustomerAuthPlugin(
graphqlClient,
tokenConfig,
generatedTools
);

// Register tools with the MCP server
registerTools({
mcp,
tools,
graphqlClient,
getSessionContext,
setSessionAuth,
plugins: [customerAuthPlugin],
ensureRefreshTokens,
createGuestSession,
});
}

6. Generate and run

# Generate tool definitions from GraphQL operations
pnpm codegen

# Start with HTTP transport (for web clients)
pnpm dev

# Or start with stdio transport (for Claude Desktop)
pnpm dev:stdio

Testing your tools

You can test your MCP server using the MCP Inspector:

npx @modelcontextprotocol/inspector http://localhost:6001/mcp

Or connect it to Claude Desktop by adding it to your Claude Desktop configuration:

{
"mcpServers": {
"evolve": {
"command": "node",
"args": ["backend/services/mcp-my-service/dist/server.js"],
"transport": "stdio"
}
}
}