Skip to main content
Glama

Basic MCP Server

by gurdasnijor
AGENTS.md16.4 kB
--- title: Smithery TypeScript MCP Server Scaffold description: TypeScript MCP server template with tools, resources, prompts, and session configuration. overview: Complete scaffold for building production-ready MCP servers. Run `npm run dev` to start or `npm run build` for production. version: "1.0.0" --- # AGENTS.md Welcome to the **Smithery TypeScript MCP Server Scaffold**! This is the template project that gets cloned when you run `npx create-smithery`. It provides everything you need to build, test, and deploy a Model Context Protocol (MCP) server with Smithery. ## Table of Contents - [Project Structure](#project-structure) - [Quick Start Commands](#quick-start-commands) - [smithery.yaml Configuration](#smitheryyaml-configuration) - [Concepts](#concepts) - [Development Workflow](#development-workflow) - [Deployment & CI/CD](#deployment--cicd) - [Troubleshooting](#troubleshooting) - [Resources](#resources) - [Community & Support](#community--support) ### Project Structure ``` your-server/ ├── package.json # Project dependencies and scripts ├── smithery.yaml # Runtime specification (runtime: typescript) ├── src/ │ └── index.ts # Main server implementation └── README.md ``` ## Quick Start Commands ```bash # Run development server (streamable HTTP on port 8081) # Opens interactive Smithery playground in your browser for testing npm run dev # or: bun run dev, pnpm run dev, yarn dev # Run on a custom port npm run dev -- --port 3000 # Kill existing process if port 8081 is in use lsof -ti:8081 | xargs kill # Build for production npm run build # or: bun run build, pnpm run build, yarn build ``` ## smithery.yaml Configuration The `smithery.yaml` file configures how your server runs. For this TypeScript setup, it only needs: ### Required Field ```yaml runtime: typescript ``` This tells Smithery to use the TypeScript runtime for your server. ### Optional Fields #### target (optional) Specifies where your server runs and determines the transport protocol. Can be `local` or `remote`: ```yaml runtime: typescript target: remote # Options: remote (default) or local ``` - `local`: Server runs on the user's machine using stdio transport. When published, bundled into `.mcpb` file for distribution - `remote`: Server runs on Smithery's infrastructure using HTTP transport (default) See [Transports](#transports) for more details on how this affects your server's communication protocol. #### env (optional) Environment variables to inject when running your server. Available for both runtime types: ```yaml runtime: typescript env: NODE_ENV: "production" DEBUG: "true" LOG_LEVEL: "info" ``` ## Concepts ### Core Components: Tools, Resources, and Prompts MCP servers expose three types of components that AI applications can interact with. Learn when to use each and how they work together to build powerful integrations. #### Tools: Executable Functions Tools are executable functions that AI applications can invoke to perform actions: ```typescript // Add a tool server.registerTool( "hello", { title: "Hello Tool", description: "Say hello to someone", inputSchema: { name: z.string().describe("Name to greet") }, }, async ({ name }) => { return { content: [{ type: "text", text: `Hello, ${name}!` }], } }, ) ``` #### Resources: Read-Only Data Sources Resources provide read-only data that gives AI applications context to work with. Unlike tools, resources do not perform actions—they simply return information: ```typescript // Add a resource server.registerResource( "hello-world-history", "history://hello-world", { title: "Hello World History", description: "The origin story of the famous 'Hello, World' program", }, async uri => ({ contents: [ { uri: uri.href, text: '"Hello, World" first appeared in a 1972 Bell Labs memo by Brian Kernighan and later became the iconic first program for beginners in countless languages.', mimeType: "text/plain", }, ], }), ) ``` #### Prompts: Reusable Message Templates Prompts are predefined message templates that help structure conversations. Use them to guide AI applications toward consistent interaction patterns: ```typescript // Add a prompt server.registerPrompt( "greet", { title: "Hello Prompt", description: "Say hello to someone", argsSchema: { name: z.string().describe("Name of the person to greet"), }, }, async ({ name }) => { return { messages: [ { role: "user", content: { type: "text", text: `Say hello to ${name}`, }, }, ], } }, ) ``` #### When to Use Each Component - **Tools**: Perform actions (create/update/delete, API calls, computations, database operations) - **Resources**: Provide read-only data (documentation, reference info, context without side effects) - **Prompts**: Guide conversation patterns (reusable templates, multi-step workflows, consistent interactions) ### Session Configuration Pass personalized settings to each connection—API keys, preferences, and user-specific configuration—without affecting other sessions. **Why configuration matters:** - **Multi-user support**: Different users have different API keys and settings - **Security**: API keys stay session-scoped, not stored server-wide - **Flexibility**: Users customize behavior at connection time without code changes When you define a configuration schema using Zod, Smithery automatically generates a configuration UI with appropriate input types, passes configurations as URL parameters to your server, and applies default values and enforces required fields. Each session gets isolated configuration—Session A and Session B don't interfere with each other. #### How Session Config Works 1. **Define config schema** - Example weather server where different users have different settings: ```typescript import { z } from "zod" export const configSchema = z.object({ // Required field - users must provide this weatherApiKey: z.string().describe("Your OpenWeatherMap API key"), // Optional fields with defaults - users can customize or use defaults temperatureUnit: z.enum(["celsius", "fahrenheit"]).default("celsius").describe("Temperature unit"), defaultLocation: z.string().default("New York").describe("Default city for weather queries"), }) ``` 2. **Pass config via URL parameters**: ``` http://localhost:3000/mcp?weatherApiKey=abc123&temperatureUnit=fahrenheit ``` 3. **Use config in your server**: ```typescript export default function createServer({ config }: { config: z.infer<typeof configSchema> }) { const server = new McpServer({ name: "Weather Server", version: "1.0.0" }) server.registerTool("get-weather", { /* ... */ }, async ({ city }) => { // Access session-specific config const temp = await fetchWeather(city, config.weatherApiKey) return formatTemp(temp, config.temperatureUnit) }) return server.server } ``` Each user gets personalized weather data without affecting others #### Configuration Management in Production Once your server is published to Smithery, users can securely manage their configurations through a configuration UI. Saved configurations are automatically applied whenever they connect to your server in any client—no need to manually pass config parameters each time. ### Transports Transports define how your MCP server communicates with clients. The transport protocol is determined by the `target` field in your `smithery.yaml` file. #### stdio Transport (Local Servers) When `target: local`, your server uses **stdio transport**: ```yaml runtime: typescript target: local ``` **How it works:** - Server communicates via standard input/output (stdin/stdout) - Runs as a local process on the user's machine - When published to Smithery, your server is bundled into a `.mcpb` file for distribution - Users install and run it locally through their MCP client **Best for:** - File system access - Local development tools - Privacy-sensitive operations - Servers that need direct access to user's machine #### HTTP Transport (Remote Servers - Default) When `target: remote` (or omitted, as remote is the default), your server uses **HTTP transport** and is hosted by Smithery: ```yaml runtime: typescript target: remote ``` **How it works:** - Server communicates over HTTP/HTTPS - Hosted on Smithery's infrastructure - Accessible from anywhere via URL - Smithery handles deployment, scaling, and availability **Best for:** - API integrations - Cloud service wrappers - Servers that don't need local file access - Multi-user shared resources **Note:** During development with `npm run dev`, all servers use HTTP transport (port 8081) regardless of the target setting. The target setting only affects production deployment. ### Stateful vs Stateless Servers The TypeScript SDK provides two server patterns. **Servers are stateful by default.** Choose based on your needs. #### Stateful Servers (Default) Stateful servers maintain state between calls within a session: ```typescript export default function createServer({ sessionId, config }) { const server = new McpServer({ name: "My Stateful App", version: "1.0.0" }) console.log(`Session ${sessionId} started`) // Store session-specific state // Example: const sessionState = getOrCreateState(sessionId) return server.server } ``` **Use stateful for:** Chat conversations, multi-step workflows, game servers, session analytics, or any scenario requiring persistent state. #### Stateless Servers Stateless servers create a fresh instance for each request—no session state is maintained: ```typescript // Explicitly mark as stateless (opt-in behavior) export const stateless = true export default function createServer({ config }) { const server = new McpServer({ name: "My App", version: "1.0.0" }) // Add tools, resources, prompts... return server.server } ``` **Use stateless for:** Simple API integrations, one-off database queries, file operations, or servers that don't need session tracking. ## Development Workflow ### Customizing Your Project **Customize the scaffold to match your actual project:** 1. **Update package.json:** ```json { "name": "your-project-name", "description": "Your MCP server description", "author": "Your Name" } ``` 2. **Choose stateless or stateful:** See [Stateful vs Stateless Servers](#stateful-vs-stateless-servers) for details. Servers are stateful by default. For stateless, export `export const stateless = true`. 3. **Define your config schema (optional):** ```typescript // With config schema export const configSchema = z.object({ apiKey: z.string().describe("Your API key"), debug: z.boolean().default(false).describe("Enable debug mode"), }) export default function createServer({ config, }: { config: z.infer<typeof configSchema> }) { const server = new McpServer({ name: "Your Server Name", version: "1.0.0", }) // Add your tools, resources, and prompts here return server.server } // Without config schema: omit configSchema export and createServer takes no parameters ``` ### Testing Your Server: Three Approaches Your MCP server can be tested in three different ways depending on your needs. All approaches require running `npm run dev` first to start the server. #### Smithery Playground ```bash npm run dev # Actually runs: npx @smithery/cli dev ``` Starts your server on port 8081 with hot reload and opens an interactive playground in your browser: - Test your tools with a user-friendly UI - Explore resources - Try prompts - Configure session settings in real-time - View request/response details **Best for:** Quick iteration, UI testing, tool validation #### Custom Clients Connect any MCP client to your server. Two options depending on your client type: ##### Option A: Local HTTP Clients Connect to `http://127.0.0.1:8081/mcp` with config as URL parameters: ``` http://127.0.0.1:8081/mcp?apiKey=your_key&debug=true ``` ##### Option B: Browser/Remote Clients (ngrok Tunnel) 1. Look for the ngrok tunnel URL in the console output (e.g., `https://abcd-1234-5678.ngrok.io`) 2. Connect your browser client to: `https://your-ngrok-id.ngrok.io/mcp` 3. Pass config as URL parameters: ``` https://your-ngrok-id.ngrok.io/mcp?apiKey=your_key&debug=true ``` **Best for:** Testing with remote clients, browser-based integrations, sharing with team members #### Direct Protocol Testing For deep debugging or understanding the MCP protocol: 1. Initialize connection (always include config params): ```bash curl -X POST "http://127.0.0.1:8081/mcp?debug=true" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"clientInfo":{"name":"test-client","version":"1.0.0"}}}' ``` 2. Send initialized notification: ```bash curl -X POST "http://127.0.0.1:8081/mcp?debug=true" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","method":"notifications/initialized"}' ``` 3. List available tools: ```bash curl -X POST "http://127.0.0.1:8081/mcp?debug=true" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' ``` 4. Call a tool from the list (replace `tool-name` and arguments with your actual tool): ```bash curl -X POST "http://127.0.0.1:8081/mcp?debug=true" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"tool-name","arguments":{"key":"value"}}}' ``` **Best for:** Protocol debugging, understanding MCP internals, automated testing scripts ## Deployment & CI/CD Once you're ready to share your MCP server with the world, deploy it to Smithery: 1. **Publish your server**: Visit [smithery.ai/new](https://smithery.ai/new) 2. **Connect your repository**: Authorize Smithery to access your GitHub repository 3. **Automatic deployments**: By default, your server automatically deploys on every commit to the `main` branch 4. **Server scanning**: Smithery automatically discovers and indexes your tools, resources, and prompts You can customize deployment settings (branch name, deployment triggers) in your Smithery dashboard after publishing. ## Troubleshooting ### Port Issues - Default port is **8081** - Kill existing process: `lsof -ti:8081 | xargs kill` ### Config Issues ```bash # Check your configuration schema node -e "import('./src/index.ts').then(m => console.log(JSON.stringify(m.configSchema._def, null, 2)))" ``` ### Import Issues - Ensure you're in the project root directory - Run `npm install` to install dependencies - Check that your TypeScript configuration is correct - Verify Node.js version is 18 or higher ### TypeScript Issues - Run `npx tsc --noEmit` to check for TypeScript errors - Ensure all imports use `.js` extensions (TypeScript + ESM requirement) - Check that your `package.json` has `"type": "module"` ## Resources - **Documentation**: [smithery.ai/docs](https://smithery.ai/docs) - **MCP Protocol**: [modelcontextprotocol.io](https://modelcontextprotocol.io) - **TypeScript Quickstart**: [smithery.ai/docs/getting_started/quickstart_build_typescript.md](https://smithery.ai/docs/getting_started/quickstart_build_typescript.md) - **GitHub**: [github.com/smithery-ai/sdk](https://github.com/smithery-ai/sdk) - **Registry**: [smithery.ai](https://smithery.ai) for discovering and deploying MCP servers ## Community & Support - **Discord**: Join our community for help and discussions: [discord.gg/Afd38S5p9A](https://discord.gg/Afd38S5p9A) - **Bug Reports**: Found an issue? Report it on GitHub: [github.com/smithery-ai/sdk/issues](https://github.com/smithery-ai/sdk/issues) - **Feature Requests**: Suggest new features on our GitHub discussions: [github.com/smithery-ai/sdk/discussions](https://github.com/smithery-ai/sdk/discussions)

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/gurdasnijor/server-quality-harness'

If you have feedback or need assistance with the MCP directory API, please join our Discord server