Skip to content

Commit 42a19f1

Browse files
fix: unify response handling across all tools and resources
- Resources now use normalizeResponse() for consistent JSON structure - check_domain uses shared normalizer instead of manual parsing - Help tool uses createToolError() for structured error responses - All endpoints now return { success: true/false, ... } format Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent dfa459d commit 42a19f1

3 files changed

Lines changed: 40 additions & 55 deletions

File tree

src/resources.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
22
import { getClient } from './client.js';
3+
import { normalizeResponse } from './normalize.js';
34

45
export function registerAllResources(server: McpServer): void {
56
// Account information resource
@@ -13,12 +14,13 @@ export function registerAllResources(server: McpServer): void {
1314
async () => {
1415
const client = getClient();
1516
const result = await client.execute('account_info');
17+
const normalized = normalizeResponse('account_info', result);
1618
return {
1719
contents: [
1820
{
1921
uri: 'account://info',
2022
mimeType: 'application/json',
21-
text: JSON.stringify(result, null, 2),
23+
text: JSON.stringify(normalized, null, 2),
2224
},
2325
],
2426
};
@@ -36,12 +38,13 @@ export function registerAllResources(server: McpServer): void {
3638
async () => {
3739
const client = getClient();
3840
const result = await client.execute('list_domain');
41+
const normalized = normalizeResponse('list_domain', result);
3942
return {
4043
contents: [
4144
{
4245
uri: 'domains://list',
4346
mimeType: 'application/json',
44-
text: JSON.stringify(result, null, 2),
47+
text: JSON.stringify(normalized, null, 2),
4548
},
4649
],
4750
};
@@ -59,12 +62,13 @@ export function registerAllResources(server: McpServer): void {
5962
async () => {
6063
const client = getClient();
6164
const result = await client.execute('contact_list');
65+
const normalized = normalizeResponse('contact_list', result);
6266
return {
6367
contents: [
6468
{
6569
uri: 'contacts://list',
6670
mimeType: 'application/json',
67-
text: JSON.stringify(result, null, 2),
71+
text: JSON.stringify(normalized, null, 2),
6872
},
6973
],
7074
};
@@ -82,12 +86,13 @@ export function registerAllResources(server: McpServer): void {
8286
async () => {
8387
const client = getClient();
8488
const result = await client.execute('folder_list');
89+
const normalized = normalizeResponse('folder_list', result);
8590
return {
8691
contents: [
8792
{
8893
uri: 'folders://list',
8994
mimeType: 'application/json',
90-
text: JSON.stringify(result, null, 2),
95+
text: JSON.stringify(normalized, null, 2),
9196
},
9297
],
9398
};

src/tools/check-domain.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
22
import { z } from 'zod';
33
import { getClient } from '../client.js';
4+
import { normalizeResponse } from '../normalize.js';
45

56
const inputSchema = {
67
domain: z.string().describe('Domain to check (e.g., example.com)'),
@@ -30,26 +31,23 @@ export function registerCheckDomainTool(server: McpServer): void {
3031
}
3132

3233
const response = await client.execute('search', params);
34+
const normalized = normalizeResponse('search', response) as {
35+
success: boolean;
36+
results?: Array<{ domain: string; available: boolean; price?: string }>;
37+
};
3338

34-
// Parse response - Dynadot returns SearchResponse with search results
35-
const searchResults = response.SearchResponse as
36-
| { SearchResults?: Array<{ Domain?: string; Available?: string; Price?: string }> }
37-
| undefined;
38-
const results = searchResults?.SearchResults ?? [];
39-
const result = results[0];
40-
41-
const available = result?.Available === 'yes';
42-
const price = result?.Price;
39+
const result = normalized.results?.[0];
4340

4441
return {
4542
content: [
4643
{
4744
type: 'text',
4845
text: JSON.stringify(
4946
{
47+
success: normalized.success,
5048
domain,
51-
available,
52-
...(showPrice && price ? { price } : {}),
49+
available: result?.available ?? false,
50+
...(showPrice && result?.price ? { price: result.price } : {}),
5351
},
5452
null,
5553
2,

src/tools/help.ts

Lines changed: 22 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
22
import { z } from 'zod';
3+
import { createToolError } from '../errors.js';
34
import { compositeTools } from '../schemas/index.js';
45

56
const inputSchema = {
@@ -49,40 +50,27 @@ export function registerHelpTool(server: McpServer): void {
4950

5051
if (query === 'actions') {
5152
if (!toolName) {
53+
const error = createToolError('Missing tool parameter', {
54+
type: 'MISSING_PARAM',
55+
param: 'tool',
56+
tool: 'dynadot_help',
57+
});
5258
return {
53-
content: [
54-
{
55-
type: 'text',
56-
text: JSON.stringify(
57-
{
58-
success: false,
59-
error: 'Please specify a tool name with the "tool" parameter',
60-
},
61-
null,
62-
2,
63-
),
64-
},
65-
],
59+
content: [{ type: 'text', text: error.toJSON() }],
60+
isError: true,
6661
};
6762
}
6863

6964
const tool = compositeTools.find((t) => t.name === toolName);
7065
if (!tool) {
66+
const error = createToolError(`Tool "${toolName}" not found`, {
67+
type: 'VALIDATION_ERROR',
68+
tool: 'dynadot_help',
69+
});
70+
error.suggestions = [`Available tools: ${compositeTools.map((t) => t.name).join(', ')}`];
7171
return {
72-
content: [
73-
{
74-
type: 'text',
75-
text: JSON.stringify(
76-
{
77-
success: false,
78-
error: `Tool "${toolName}" not found`,
79-
availableTools: compositeTools.map((t) => t.name),
80-
},
81-
null,
82-
2,
83-
),
84-
},
85-
],
72+
content: [{ type: 'text', text: error.toJSON() }],
73+
isError: true,
8674
};
8775
}
8876

@@ -136,20 +124,14 @@ export function registerHelpTool(server: McpServer): void {
136124
};
137125
}
138126

127+
const error = createToolError('Invalid query', {
128+
type: 'VALIDATION_ERROR',
129+
tool: 'dynadot_help',
130+
});
131+
error.suggestions = ['Use query: "tools", "actions", or "examples"'];
139132
return {
140-
content: [
141-
{
142-
type: 'text',
143-
text: JSON.stringify(
144-
{
145-
success: false,
146-
error: 'Invalid query. Use: tools, actions, or examples',
147-
},
148-
null,
149-
2,
150-
),
151-
},
152-
],
133+
content: [{ type: 'text', text: error.toJSON() }],
134+
isError: true,
153135
};
154136
},
155137
);

0 commit comments

Comments
 (0)