A minimal, reusable Model Context Protocol (MCP) server template designed for use with OpenAI Agent Builder and other MCP-compatible AI platforms. This template uses Streamable HTTP transport for broad compatibility.
This template is intentionally minimal and UI-agnostic. It provides only the MCP server infrastructure, allowing you to:
- Connect it to any AI interface (OpenAI Agent Builder, Claude, custom UIs, etc.)
- Build your own frontend or use existing AI chat interfaces.
- Focus on your business logic without UI constraints.
- Deploy as a standalone microservice.
The template includes a working example (Lebanon, NH zoning lookup) that demonstrates the pattern. Replace it with your own data source and tools.
npm install
npm startThe server runs on port 5000. The MCP endpoint is available at POST /mcp.
When forking this template, update the following:
-
config.js- Update all values:SERVER_NAME- Your project name (e.g., "anytown-permits")LOCATION_NAME- Your municipality/region (e.g., "Anytown, USA")DATA_SOURCES- Your data source namesTOOL_DESCRIPTIONS- Descriptions for your toolsERROR_EXAMPLES- Example values for your locationZONING_LAYER,ADDRESS_LAYER- Your layer IDs
-
Secrets - Add required secrets:
ARCGIS_BASE_URL- Your FeatureServer endpoint URL (see Environment Variables section)
-
package.json- Update:name- Your package namedescription- What your server doesauthor- Your name or organizationkeywords- Relevant keywords
-
mcp-server.js- Update business logic:- Modify
lookupZoningByCoordinates()andlookupZoningByAddress()for your data - Update
TOOLSarray with your tool definitions - Update
TOOL_HANDLERSto map tools to functions
- Modify
-
.env- Copy from.env.exampleand set your environment variables -
README.md- Update documentation for your use case
- Deploy this server to a publicly accessible URL (e.g., using Replit Deployments)
- In OpenAI Agent Builder, add a new MCP tool
- Enter your server URL with the
/mcpendpoint (e.g.,https://your-app.replit.app/mcp) - The Agent Builder will automatically discover your available tools
config.js # All customizable configuration (START HERE)
mcp-server.js # Main server file with business logic
package.json # Dependencies and scripts
.env.example # Example environment variables
.gitignore # Git ignore rules
All location-specific strings and API endpoints are centralized in config.js:
export const SERVER_NAME = "my-city-lookup";
export const LOCATION_NAME = "My City, ST";
export const DATA_SOURCES = {
zoningLayer: "My City Zoning Data",
addressTable: "My City Address Database",
};The server is organized into sections:
Section 1: Business Logic Functions Implement your tool functions here. Each function should:
- Accept the parameters defined in your tool's inputSchema
- Return a result object (will be JSON stringified for the AI)
- Throw an Error with a helpful message if something goes wrong
Section 2: Tool Definitions Define your MCP tools with:
name: Unique identifier (snake_case recommended)description: What the tool does (imported from config.js)inputSchema: JSON Schema defining the parameters
Then add handlers in TOOL_HANDLERS to connect tools to your functions.
Section 3: MCP Boilerplate Standard MCP protocol handling. Rarely needs modification.
const TOOLS = [
{
name: "my_custom_tool",
description: "Description of what this tool does",
inputSchema: {
type: "object",
properties: {
param1: {
type: "string",
description: "Description of param1",
},
},
required: ["param1"],
},
},
];
const TOOL_HANDLERS = {
my_custom_tool: async (args) => {
return await myFunction(args.param1);
},
};| Endpoint | Method | Description |
|---|---|---|
/mcp |
POST | Main MCP endpoint (initialize, tools/list, tools/call) |
/mcp |
GET | Server info (without session) or SSE stream (with session) |
/mcp |
DELETE | Session termination |
/health |
GET | Health check |
When an AI calls your tool, it receives a JSON response:
{
"found": true,
"district": "R-1",
"attributes": { ... },
"source": "Your Data Source"
}This server requires the data source URL to be stored as a secret (not in code):
| Secret Name | Description |
|---|---|
ARCGIS_BASE_URL |
Your FeatureServer endpoint URL (required) |
On Replit: Add this in the Secrets tab (padlock icon in the Tools panel).
Why a secret? While the endpoint may be publicly accessible, storing it as a secret keeps it out of the public codebase and prevents unintended discovery.
These can be set as regular environment variables or secrets:
PORT=5000 # Server port (default: 5000)
ZONING_LAYER=24 # Your zoning layer ID
ADDRESS_LAYER=6 # Your address layer ID- Streamable HTTP Transport: Works with OpenAI Agent Builder and MCP Inspector
- Stateless Client Support: Auto-initializes sessions for clients that don't handle the MCP handshake
- CORS Enabled: Ready for cross-origin requests
- Health Check Endpoint: For monitoring and load balancers
- Centralized Configuration: Easy customization via
config.js
@modelcontextprotocol/sdk: MCP protocol implementationexpress: HTTP servercors: Cross-origin support
ISC License - See LICENSE file for details.