{"kind":"AgentDefinition","metadata":{"namespace":"community","name":"typescript-mcp-server","version":"0.1.0"},"spec":{"agents_md":"---\ndescription: 'Instructions for building Model Context Protocol (MCP) servers using the TypeScript SDK'\napplyTo: '**/*.ts, **/*.js, **/package.json'\n---\n\n# TypeScript MCP Server Development\n\n## Instructions\n\n- Use the **@modelcontextprotocol/sdk** npm package: `npm install @modelcontextprotocol/sdk`\n- Import from specific paths: `@modelcontextprotocol/sdk/server/mcp.js`, `@modelcontextprotocol/sdk/server/stdio.js`, etc.\n- Use `McpServer` class for high-level server implementation with automatic protocol handling\n- Use `Server` class for low-level control with manual request handlers\n- Use **zod** for input/output schema validation: `npm install zod@3`\n- Always provide `title` field for tools, resources, and prompts for better UI display\n- Use `registerTool()`, `registerResource()`, and `registerPrompt()` methods (recommended over older APIs)\n- Define schemas using zod: `{ inputSchema: { param: z.string() }, outputSchema: { result: z.string() } }`\n- Return both `content` (for display) and `structuredContent` (for structured data) from tools\n- For HTTP servers, use `StreamableHTTPServerTransport` with Express or similar frameworks\n- For local integrations, use `StdioServerTransport` for stdio-based communication\n- Create new transport instances per request to prevent request ID collisions (stateless mode)\n- Use session management with `sessionIdGenerator` for stateful servers\n- Enable DNS rebinding protection for local servers: `enableDnsRebindingProtection: true`\n- Configure CORS headers and expose `Mcp-Session-Id` for browser-based clients\n- Use `ResourceTemplate` for dynamic resources with URI parameters: `new ResourceTemplate('resource://{param}', { list: undefined })`\n- Support completions for better UX using `completable()` wrapper from `@modelcontextprotocol/sdk/server/completable.js`\n- Implement sampling with `server.server.createMessage()` to request LLM completions from clients\n- Use `server.server.elicitInput()` to request additional user input during tool execution\n- Enable notification debouncing for bulk updates: `debouncedNotificationMethods: ['notifications/tools/list_changed']`\n- Dynamic updates: call `.enable()`, `.disable()`, `.update()`, or `.remove()` on registered items to emit `listChanged` notifications\n- Use `getDisplayName()` from `@modelcontextprotocol/sdk/shared/metadataUtils.js` for UI display names\n- Test servers with MCP Inspector: `npx @modelcontextprotocol/inspector`\n\n## Best Practices\n\n- Keep tool implementations focused on single responsibilities\n- Provide clear, descriptive titles and descriptions for LLM understanding\n- Use proper TypeScript types for all parameters and return values\n- Implement comprehensive error handling with try-catch blocks\n- Return `isError: true` in tool results for error conditions\n- Use async/await for all asynchronous operations\n- Close database connections and clean up resources properly\n- Validate input parameters before processing\n- Use structured logging for debugging without polluting stdout/stderr\n- Consider security implications when exposing file system or network access\n- Implement proper resource cleanup on transport close events\n- Use environment variables for configuration (ports, API keys, etc.)\n- Document tool capabilities and limitations clearly\n- Test with multiple clients to ensure compatibility\n\n## Common Patterns\n\n### Basic Server Setup (HTTP)\n```typescript\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport express from 'express';\n\nconst server = new McpServer({\n    name: 'my-server',\n    version: '1.0.0'\n});\n\nconst app = express();\napp.use(express.json());\n\napp.post('/mcp', async (req, res) =\u003e {\n    const transport = new StreamableHTTPServerTransport({\n        sessionIdGenerator: undefined,\n        enableJsonResponse: true\n    });\n    \n    res.on('close', () =\u003e transport.close());\n    \n    await server.connect(transport);\n    await transport.handleRequest(req, res, req.body);\n});\n\napp.listen(3000);\n```\n\n### Basic Server Setup (stdio)\n```typescript\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\n\nconst server = new McpServer({\n    name: 'my-server',\n    version: '1.0.0'\n});\n\n// ... register tools, resources, prompts ...\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n```\n\n### Simple Tool\n```typescript\nimport { z } from 'zod';\n\nserver.registerTool(\n    'calculate',\n    {\n        title: 'Calculator',\n        description: 'Perform basic calculations',\n        inputSchema: { a: z.number(), b: z.number(), op: z.enum(['+', '-', '*', '/']) },\n        outputSchema: { result: z.number() }\n    },\n    async ({ a, b, op }) =\u003e {\n        const result = op === '+' ? a + b : op === '-' ? a - b : \n                      op === '*' ? a * b : a / b;\n        const output = { result };\n        return {\n            content: [{ type: 'text', text: JSON.stringify(output) }],\n            structuredContent: output\n        };\n    }\n);\n```\n\n### Dynamic Resource\n```typescript\nimport { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nserver.registerResource(\n    'user',\n    new ResourceTemplate('users://{userId}', { list: undefined }),\n    {\n        title: 'User Profile',\n        description: 'Fetch user profile data'\n    },\n    async (uri, { userId }) =\u003e ({\n        contents: [{\n            uri: uri.href,\n            text: `User ${userId} data here`\n        }]\n    })\n);\n```\n\n### Tool with Sampling\n```typescript\nserver.registerTool(\n    'summarize',\n    {\n        title: 'Text Summarizer',\n        description: 'Summarize text using LLM',\n        inputSchema: { text: z.string() },\n        outputSchema: { summary: z.string() }\n    },\n    async ({ text }) =\u003e {\n        const response = await server.server.createMessage({\n            messages: [{\n                role: 'user',\n                content: { type: 'text', text: `Summarize: ${text}` }\n            }],\n            maxTokens: 500\n        });\n        \n        const summary = response.content.type === 'text' ? \n            response.content.text : 'Unable to summarize';\n        const output = { summary };\n        return {\n            content: [{ type: 'text', text: JSON.stringify(output) }],\n            structuredContent: output\n        };\n    }\n);\n```\n\n### Prompt with Completion\n```typescript\nimport { completable } from '@modelcontextprotocol/sdk/server/completable.js';\n\nserver.registerPrompt(\n    'review',\n    {\n        title: 'Code Review',\n        description: 'Review code with specific focus',\n        argsSchema: {\n            language: completable(z.string(), value =\u003e \n                ['typescript', 'python', 'javascript', 'java']\n                    .filter(l =\u003e l.startsWith(value))\n            ),\n            code: z.string()\n        }\n    },\n    ({ language, code }) =\u003e ({\n        messages: [{\n            role: 'user',\n            content: {\n                type: 'text',\n                text: `Review this ${language} code:\\n\\n${code}`\n            }\n        }]\n    })\n);\n```\n\n### Error Handling\n```typescript\nserver.registerTool(\n    'risky-operation',\n    {\n        title: 'Risky Operation',\n        description: 'An operation that might fail',\n        inputSchema: { input: z.string() },\n        outputSchema: { result: z.string() }\n    },\n    async ({ input }) =\u003e {\n        try {\n            const result = await performRiskyOperation(input);\n            const output = { result };\n            return {\n                content: [{ type: 'text', text: JSON.stringify(output) }],\n                structuredContent: output\n            };\n        } catch (err: unknown) {\n            const error = err as Error;\n            return {\n                content: [{ type: 'text', text: `Error: ${error.message}` }],\n                isError: true\n            };\n        }\n    }\n);\n```\n","description":"Instructions for building Model Context Protocol (MCP) servers using the TypeScript SDK","import":{"commit_sha":"541b7819d8c3545c6df122491af4fa1eae415779","imported_at":"2026-05-18T20:05:35Z","license_text":"MIT License\n\nCopyright GitHub, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.","owner":"github","repo":"github/awesome-copilot","source_url":"https://github.com/github/awesome-copilot/blob/541b7819d8c3545c6df122491af4fa1eae415779/instructions/typescript-mcp-server.instructions.md"},"manifest":{}},"content_hash":[172,9,115,212,105,67,188,76,189,237,201,93,214,5,227,249,45,116,30,179,3,39,148,11,9,157,34,143,100,206,30,121],"trust_level":"unsigned","yanked":false}
