MCP server by NickyHeC
mcp-template
A starter template for building MCP (Model Context Protocol) servers with the dedalus_mcp framework. Authentication is handled by DAuth (Dedalus Auth).
This template supports three auth frameworks — No Auth, API Key, and OAuth. Each has its own src-* folder with a complete, ready-to-run server. You can either use the CLI to scaffold a new project automatically, or clone this repo and rename a folder manually.
What is DAuth?
DAuth is a multi-tenant authentication layer for MCP servers built by Dedalus Labs. It solves a core problem in the MCP ecosystem: most servers require API keys or tokens, but the MCP spec doesn't define how non-OAuth credentials should be handled securely. Without DAuth, developers either build their own auth infrastructure or pass raw secrets around — both are bad options.
DAuth is zero-trust and host-blind — Dedalus never sees your raw API keys. Here's how it works:
- The SDK encrypts credentials client-side before they leave your device.
- When a request reaches your MCP server, it acts as a standard OAuth 2.1 Resource Server — access is verified without touching the credential.
- Authenticated requests are forwarded to the Enclave, a network-isolated, hardware-secured execution environment written in Rust.
- Inside the Enclave, the credential is decrypted for milliseconds, used to call the external API, then zeroed from memory.
- Only the API response is returned — the raw secret is never exposed to your server code, to Dedalus, or to the network.
This means your MCP server only holds an opaque connection handle, never a raw key. DAuth is built into the dedalus_mcp SDK and works across all auth types (Bearer tokens, API keys, OAuth, etc.).
Quick Start
Option A: CLI (recommended)
Scaffold a new project with one command. The CLI prompts for your project name, auth type, and package manager, then generates a ready-to-run project with dependencies installed.
npx create-dmcp
Or pass the project name directly:
npx create-dmcp my-mcp-server
Requires Node.js >= 18. The generated project is pure Python.
Option B: Clone and rename
Clone this repo and rename the src-* folder that matches your auth type:
git clone https://github.com/NickyHeC/mcp-template.git my-mcp-server
cd my-mcp-server
mv src-api-key src
rm -rf src-no-auth src-oauth
pip install -e .
Project Structure
project-root/
├── cli/ # CLI scaffolding tool (npx create-dmcp)
│ └── index.ts
├── src-no-auth/ # No Auth — self-contained tools, no credentials
│ ├── main.py
│ ├── tools.py
│ └── client.py
├── src-api-key/ # API Key — static credential via DAuth
│ ├── main.py
│ ├── tools.py
│ └── client.py
├── src-oauth/ # OAuth — browser-based auth via DAuth
│ ├── main.py
│ ├── tools.py
│ └── client.py
├── pyproject.toml # Python dependencies and build config
├── package.json # Node.js config for the CLI
├── tsconfig.json # TypeScript config for the CLI
├── .env.example # Environment variable reference (per auth type)
├── PROJECT.md # Platform research notepad (for you / your AI agent)
├── LICENSE
└── README.md
Each src-* folder is a complete, self-contained server. If using the CLI, it copies the right template into <project>/src/ automatically. If cloning manually, rename the folder you want:
mv src-api-key src # rename your chosen template to src/
The server code expects to live in a folder called src/ — all internal imports use from src.tools import ... and from src.main import .... After renaming (or CLI scaffolding), the server is ready to configure and run.
Choose Your Auth Framework
Pick the framework that matches your target platform's authentication method.
| Framework | When to use | Folder |
|-----------|-------------|--------|
| No Auth | Tools that don't call external APIs — calculators, formatters, local utilities | src-no-auth/ |
| API Key | Platforms that use static credentials — API keys, personal access tokens, bot tokens (e.g. GitHub, Slack, Discord) | src-api-key/ |
| OAuth | Platforms that require browser-based user authorization — OAuth 2.0 flows (e.g. Gmail, Linear, Spotify, Google Calendar) | src-oauth/ |
No Auth
Use when your tools are self-contained and don't need to call any external API.
- No
Connectionobject needed - No DAuth configuration
- No environment variables beyond basic server settings
- Tools are simple decorated functions
from dedalus_mcp import MCPServer, tool
@tool(description="Add two numbers")
def add(a: float, b: float) -> float:
return a + b
server = MCPServer("my-mcp")
server.collect(add)
To use: mv src-no-auth src
API Key
Use when the platform authenticates with a static credential that the user provides once (API key, personal access token, bot token, etc.).
Connection+SecretKeysdeclares the credential name- DAuth encrypts and manages the credential in its enclave
- Tools can use
ctx.dispatch()for authenticated requests, or call APIs directly - Environment variables:
DEDALUS_AS_URL, your platform's token
from dedalus_mcp.auth import Connection, SecretKeys
platform_connection = Connection(
name="github",
secrets=SecretKeys(token="GITHUB_TOKEN"),
base_url="https://api.github.com",
auth_header_format="token {api_key}",
)
To use: mv src-api-key src
OAuth
Use when the platform requires a browser-based OAuth flow where users authorize your application to act on their behalf.
Connection+SecretKeysdeclares the token name (same as API Key from code perspective)- The Dedalus platform handles the full OAuth token exchange externally
- OAuth configuration (client ID, client secret, authorize/token URLs, scopes) is set via environment variables
- Important: OAuth environment variables must be baked into the server when deploying to ensure the connection works
- Tools use
ctx.dispatch()for authenticated requests through the DAuth enclave
from dedalus_mcp.auth import Connection, SecretKeys
platform_connection = Connection(
name="linear-mcp",
secrets=SecretKeys(token="LINEAR_ACCESS_TOKEN"),
base_url="https://api.linear.app",
auth_header_format="Bearer {api_key}",
)
Note on OAuth with DAuth: Your Python server code looks nearly identical to the API Key template. The difference is that the Dedalus platform reads the
OAUTH_*environment variables to orchestrate the browser-based OAuth flow and token refresh. Your server code never manages OAuth tokens directly — it just callsctx.dispatch()and DAuth applies the token inside the enclave.
To use: mv src-oauth src
How to Build an MCP Server from This Template
If you used the CLI (
npx create-dmcp), steps 2 is already done — the CLI chose the template, renamed it tosrc/, and installed dependencies. You still need to fill in.env(step 3) and configure the server (step 4).
1. Research the Target Platform API
Read the API docs for the platform you want to integrate. Note:
- Available endpoints and features
- Authentication method (Bearer token, API key, OAuth, etc.)
- Rate limits and restrictions
- Response formats
Save your notes in PROJECT.md — it serves as context for you and for AI coding agents in later steps. The file is pre-formatted with sections for all the information you'll need.
Tip: Once your PROJECT.md is filled in, you can hand the project off to an AI coding agent with a prompt like: "Build my MCP server based on this template and the notes in PROJECT.md." The agent can read the template files, your research notes, and this README to implement the full server with minimal back-and-forth.
2. Choose an Auth Framework and Rename the Folder
Skip this step if you used the CLI — it already did this for you.
Based on your research, pick the right auth framework from the table above. Rename the chosen folder to src/ and remove the others:
# Example: using the OAuth template
mv src-oauth src
rm -rf src-no-auth src-api-key
3. Set Up Environment Variables
Skip cp if you used the CLI — .env.example is already in your project.
cp .env.example .env
Fill in only the variables for your chosen auth framework. See .env.example for which variables belong to which framework.
- No Auth: No environment variables needed.
- API Key: Set
DEDALUS_AS_URLand your platform's token (e.g.GITHUB_TOKEN). - OAuth: Set
DEDALUS_AS_URL,DEDALUS_API_KEY, and allOAUTH_*variables. These must also be configured in the deployment environment.
4. Configure the Server (src/main.py)
Customize main.py with your platform's details:
- Connection name — Change
"platform"to your platform's identifier (e.g."github","linear","spotify"). - Secret key — Update
SecretKeys(token="...")to match your credential name. The API Key template uses"API_TOKEN"; the OAuth template uses"ACCESS_TOKEN". Rename to match your platform (e.g."GITHUB_TOKEN","LINEAR_ACCESS_TOKEN"). - Base URL — Set to the platform's API root (e.g.
"https://api.github.com"). - Auth header format — Set how the credential is attached. Common formats:
"Bearer {api_key}","token {api_key}","Bot {api_key}". - Server name — Change
"my-mcp"to something descriptive (e.g."github-mcp"). The CLI does this automatically.
5. Implement Tools (src/tools.py)
Define the tools your server will expose:
- Result models — Create Pydantic
BaseModelsubclasses for structured return values. - Request helper — For API Key and OAuth templates, use the
api_request()helper (which wrapsctx.dispatch()) to make authenticated calls through DAuth. - Tool functions — Decorate functions with
@tool(description="..."). Use type hints for parameters and return a Pydantic model. - Tool registry — Add every tool to the
toolslist at the bottom of the file.
The template files include example tools demonstrating each pattern.
6. Test Locally
Install dependencies:
pip install -e .
Test your connection first (API Key and OAuth only). Before starting the server, verify that your Connection config and credentials actually work:
python -m src.client --test-connection
This uses ConnectionTester from dedalus_mcp.testing to make a real API call to your target platform — no running server needed. Edit the test path in client.py to match a lightweight endpoint from your platform (e.g. /user for GitHub, /v1/me for Spotify). If it prints OK, your connection is good.
OAuth note: For local testing you need a valid access token in
.env. Obtain one from the platform's OAuth playground or developer console. When deployed on Dedalus, DAuth handles the full OAuth flow automatically.
Then start the server and test tools:
python -m src.main
The server starts on port 8080. Use the client to verify your tools:
python -m src.client
Update src/client.py to call your tools by name with the correct arguments.
7. Document Your Project
Update this README with:
- What your server does
- Available tools and their parameters
- Configuration and environment variables
- Usage examples
8. Clean Up Template Scaffolding
Once your server is built and working, remove leftover template files so the repo only contains your project code. If you're using an AI coding agent, ask it to perform this cleanup as a final step.
Files to remove:
PROJECT.md— your research notes; no longer needed in the final repo- Any remaining
src-*folders (e.g.src-no-auth/,src-api-key/,src-oauth/) that weren't chosen cli/,package.json,tsconfig.json— CLI scaffolding tools, not part of your server.env.example— once your.envis set up (optional, some teams keep this for onboarding)
Files to clean up:
src/tools.py— removeExampleResultandexample_tool; only your real tools should remainsrc/client.py— update to call your actual tools with real arguments, or remove if not neededsrc/main.py— remove the placeholder inline comments (e.g.# A short identifier for this connection...) once the values are filled inREADME.md— replace the template guide with project-specific documentation (see step 7)pyproject.toml— update the projectnameanddescriptionto match your server
9. Deploy to Dedalus Labs
Upload your server to dedaluslabs.ai. DAuth handles credential security automatically in production.
Important for OAuth servers: Make sure all OAUTH_* environment variables are configured in the deployment environment. These variables are consumed by the Dedalus platform to handle the OAuth flow — they must be baked into the server at deploy time.
Making Authenticated API Calls with ctx.dispatch()
For API Key and OAuth servers, use ctx.dispatch() to make authenticated requests through DAuth. The framework applies the credential inside the enclave so your code never touches raw secrets.
from dedalus_mcp import tool, get_context, HttpMethod, HttpRequest
from src.main import platform_connection
@tool(description="Fetch user profile")
async def get_profile() -> dict:
ctx = get_context()
req = HttpRequest(method=HttpMethod.GET, path="/user/profile")
resp = await ctx.dispatch(platform_connection, req)
if resp.success and resp.response is not None:
return {"success": True, "data": resp.response.body}
error = resp.error.message if resp.error else "Request failed"
return {"success": False, "error": error}
The path is appended to the base_url configured in your Connection object. DAuth attaches the credential to the request using the auth_header_format you specified.
Environment Variables Reference
| Variable | Auth Framework | Description |
|----------|----------------|-------------|
| DEDALUS_AS_URL | API Key, OAuth | Dedalus authorization server URL (default: https://as.dedaluslabs.ai) |
| DEDALUS_API_KEY | API Key, OAuth | Your Dedalus platform API key |
| DEDALUS_API_URL | API Key, OAuth | Dedalus API URL (default: https://api.dedaluslabs.ai) |
| API_TOKEN | API Key | The platform credential (rename to match your platform, e.g. GITHUB_TOKEN) |
| OAUTH_ENABLED | OAuth | Set to true to enable OAuth flow |
| OAUTH_AUTHORIZE_URL | OAuth | Platform's OAuth authorization endpoint |
| OAUTH_TOKEN_URL | OAuth | Platform's OAuth token exchange endpoint |
| OAUTH_CLIENT_ID | OAuth | Your OAuth app's client ID |
| OAUTH_CLIENT_SECRET | OAuth | Your OAuth app's client secret |
| OAUTH_SCOPES_AVAILABLE | OAuth | Comma-separated list of OAuth scopes |
| OAUTH_BASE_URL | OAuth | Platform's API base URL for OAuth requests |
See .env.example for a copy-paste-ready version with sections marked by framework.
Requirements
- Python >= 3.10 — for the MCP server
- Node.js >= 18 — only needed if using the CLI (
npx create-dmcp) - uv (recommended) or pip — for Python dependency management