Skip to content

Commit 8b8161f

Browse files
committed
feat: modernize MCP SDK to v1.23.0 with registerTool API
- Migrate from deprecated server.tool() to modern server.registerTool() - Add title field to all tool registrations for UI display names - Update @modelcontextprotocol/sdk from ^1.17.5 to ^1.23.0 - Update Zod from ^3.25.76 to ^4.1.13 - Fix Zod v4 breaking changes: z.record() now requires 2 arguments - Update STYLE_GUIDE.md with SDK v1.22.0+ best practices Tested: All 36 unit tests pass, curl integration tests pass
1 parent 5eba963 commit 8b8161f

5 files changed

Lines changed: 260 additions & 70 deletions

File tree

STYLE_GUIDE.md

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,76 @@
11
# MCP Server Style Guide
22

3-
Based on the patterns observed and best practices, I recommend adopting the following consistent style guide across all your MCP servers:
3+
Based on the MCP SDK v1.22.0+ best practices and observed patterns, this guide ensures consistency across all MCP servers.
4+
5+
## Naming Conventions
46

57
| Element | Convention | Rationale / Examples |
68
| :------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ |
79
| **CLI Commands** | `verb-noun` in `kebab-case`. Use the shortest unambiguous verb (`ls`, `get`, `create`, `add`, `exec`, `search`). | `ls-repos`, `get-pr`, `create-comment`, `exec-command` |
810
| **CLI Options** | `--kebab-case`. Be specific (e.g., `--workspace-slug`, not just `--slug`). | `--project-key-or-id`, `--source-branch` |
911
| **MCP Tool Names** | `<namespace>_<verb>_<noun>` in `snake_case`. Use a concise 2-4 char namespace. Avoid noun repetition. | `bb_ls_repos` (Bitbucket list repos), `conf_get_page` (Confluence get page), `aws_exec_command` (AWS execute command). Avoid `ip_ip_get_details`. |
12+
| **MCP Resource Names**| `kebab-case`. Descriptive identifier for the resource type. | `ip-lookup`, `user-profile`, `config-data` |
1013
| **MCP Arguments** | `camelCase`. Suffix identifiers consistently (e.g., `Id`, `Key`, `Slug`). Avoid abbreviations unless universal. | `workspaceSlug`, `pullRequestId`, `sourceBranch`, `pageId`. |
1114
| **Boolean Args** | Use verb prefixes for clarity (`includeXxx`, `launchBrowser`). Avoid bare adjectives (`--https`). | `includeExtendedData: boolean`, `launchBrowser: boolean` |
1215
| **Array Args** | Use plural names (`spaceIds`, `labels`, `statuses`). | `spaceIds: string[]`, `labels: string[]` |
1316
| **Descriptions** | **Start with an imperative verb.** Keep the first sentence concise (≤120 chars). Add 1-2 sentences detail. Mention pre-requisites/notes last. | `List available Confluence spaces. Filters by type, status, or query. Returns formatted list including ID, key, name.` |
1417
| **Arg Descriptions** | Start lowercase, explain purpose clearly. Mention defaults or constraints. | `numeric ID of the page to retrieve (e.g., "456789"). Required.` |
1518
| **ID/Key Naming** | Use consistent suffixes like `Id`, `Key`, `Slug`, `KeyOrId` where appropriate. | `pageId`, `projectKeyOrId`, `workspaceSlug` |
1619

20+
## SDK Best Practices (v1.22.0+)
21+
22+
### Title vs Name
23+
24+
All registrations (`registerTool`, `registerResource`, `registerPrompt`) support both `name` and `title`:
25+
26+
| Field | Purpose | Example |
27+
| :---- | :------ | :------ |
28+
| `name` | Unique identifier for programmatic use | `jira_get` |
29+
| `title` | Human-readable display name for UI | `Jira GET Request` |
30+
31+
**Always provide both** - `name` for code, `title` for user interfaces.
32+
33+
### Modern Registration APIs
34+
35+
Use the modern `register*` methods instead of deprecated alternatives:
36+
37+
| Deprecated | Modern (SDK v1.22.0+) |
38+
| :--------- | :-------------------- |
39+
| `server.tool()` | `server.registerTool()` |
40+
| `server.resource()` | `server.registerResource()` |
41+
| `server.prompt()` | `server.registerPrompt()` |
42+
43+
### Resource Templates
44+
45+
Use `ResourceTemplate` for parameterized resource URIs:
46+
47+
```typescript
48+
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
49+
50+
// Static resource - fixed URI
51+
server.registerResource('config', 'config://app', { ... }, handler);
52+
53+
// Dynamic resource - parameterized URI
54+
server.registerResource(
55+
'user-profile',
56+
new ResourceTemplate('users://{userId}/profile', { list: undefined }),
57+
{ title: 'User Profile', description: '...' },
58+
async (uri, variables) => {
59+
const userId = variables.userId as string;
60+
// ...
61+
}
62+
);
63+
```
64+
65+
### Error Handling
66+
67+
Use `isError: true` for tool execution failures:
68+
69+
```typescript
70+
return {
71+
content: [{ type: 'text', text: 'Error: Something went wrong' }],
72+
isError: true
73+
};
74+
```
75+
1776
Adopting this guide will make the tools more predictable and easier for both humans and AI agents to understand and use correctly.

package-lock.json

Lines changed: 121 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,15 @@
9595
"access": "public"
9696
},
9797
"dependencies": {
98-
"@modelcontextprotocol/sdk": "^1.17.5",
98+
"@modelcontextprotocol/sdk": "^1.23.0",
9999
"@toon-format/toon": "^2.0.1",
100100
"commander": "^14.0.0",
101101
"cors": "^2.8.5",
102102
"dotenv": "^17.2.2",
103103
"express": "^5.1.0",
104104
"jmespath": "^0.16.0",
105105
"turndown": "^7.2.1",
106-
"zod": "^3.25.76"
106+
"zod": "^4.1.13"
107107
},
108108
"directories": {
109109
"example": "examples"

0 commit comments

Comments
 (0)