Content
# Railway MCP Template
Forkable TypeScript MCP server template for the same implementation pattern used by the neighboring MCP repos.
## What It Includes
- local MCP over `stdio`
- hosted MCP over Streamable HTTP at `POST /mcp`
- shared-client OAuth for Claude custom connectors
- password-protected `/authorize` login flow
- file-backed OAuth state for persistent Railway volumes
- zod-based tool factories
- Docker and Railway deployment config
- a pure `template-echo` tool and an API-backed `template-api-get` example tool
## Fork Checklist
After forking or copying this template for a new MCP:
1. Rename package and server identifiers:
- `railway-mcp-template`
- `Template MCP`
- `template-*`
- `TEMPLATE_*`
2. Replace `src/clients/template-client.ts` with the target API client.
3. Replace `src/tools/example/*` with product-specific tool groups.
4. Register the new groups in `src/tools/tool-factory.ts`.
5. Update `.env.example` and this README with the target service variables.
6. Keep the shared HTTP/OAuth files unless the connector needs a different auth policy.
## Environment
Required for the example API-backed tool:
- `TEMPLATE_API_KEY`
Optional:
- `TEMPLATE_API_BASE_URL`, defaults to `https://api.example.com`
- `TEMPLATE_REQUEST_TIMEOUT_MS`, defaults to `30000`
Hosted HTTP/OAuth:
- `PUBLIC_BASE_URL`
- `MCP_OAUTH_CLIENT_ID`
- `MCP_OAUTH_CLIENT_SECRET`
- `MCP_LOGIN_USERNAME`
- `MCP_LOGIN_PASSWORD`
- `MCP_OAUTH_STATE_FILE` (required for the recommended Railway deployment)
## Local stdio
```bash
npm install
npm run build
npm run start:stdio
```
The `template-echo` tool works without external credentials. The example `template-api-get` tool requires `TEMPLATE_API_KEY`.
## Local hosted HTTP
```bash
PUBLIC_BASE_URL=http://127.0.0.1:3000/ \
MCP_OAUTH_CLIENT_ID=your_shared_client_id \
MCP_OAUTH_CLIENT_SECRET=your_shared_client_secret \
MCP_LOGIN_USERNAME=admin \
MCP_LOGIN_PASSWORD=change_me \
MCP_OAUTH_STATE_FILE=/tmp/template-mcp-oauth-state.json \
npm run build && npm run start:http
```
That server exposes:
- `POST /mcp`
- `GET /health`
- OAuth metadata and auth endpoints at the app root
- password-protected authorization at `GET /authorize`
## Railway
Use the included `Dockerfile` and `railway.json`. This template is intended to run with Railway sleeping enabled, and `railway.json` enables it by default.
### Railway deployment setup
For persistent connector authentication:
1. Attach a Railway volume to the service.
2. Mount the volume at `/data`.
3. Set `MCP_OAUTH_STATE_FILE=/data/oauth-state.json`.
Configure these Railway variables:
- `PUBLIC_BASE_URL`
- `MCP_OAUTH_CLIENT_ID`
- `MCP_OAUTH_CLIENT_SECRET`
- `MCP_LOGIN_USERNAME`
- `MCP_LOGIN_PASSWORD`
- service-specific API credentials such as `TEMPLATE_API_KEY`
- `MCP_OAUTH_STATE_FILE=/data/oauth-state.json`
This is the intended Railway deployment configuration. The volume preserves OAuth state across sleeping, waking, restarts, and redeployments.
## Source Layout
```text
src/
clients/ API clients for tool handlers
helpers/ shared formatting and utility helpers
server/ MCP server factory and OAuth support
tools/
example/ replace with product-specific tool groups
responses.ts common text/json MCP responses
tool-factory.ts registers every tool group
types.ts shared tool definition types
http.ts Streamable HTTP entrypoint
index.ts stdio entrypoint
```
## Tool Pattern
Each tool module exports a factory:
```ts
export function exampleTool(): TemplateToolDefinition<typeof exampleSchema> {
return {
name: "service-resource-action",
description: "Clear user-facing tool description.",
schema: exampleSchema,
handler: async (args) => {
// call a client and return textResponse/jsonResponse
},
};
}
```
Tool groups export arrays from `index.ts`, and `src/tools/tool-factory.ts` registers them with the MCP server.