Skip to content

Commit 0906d28

Browse files
INONONO66eXamadeus
andauthored
Fix: PascalCase tool names to match Claude Code convention (#81)
* PascalCase tool names after mcp_ prefix to match Claude Code convention * Adjust tool names to PascalCase format Update tool names to PascalCase to align with Claude Code convention. Signed-off-by: Julian Coy <julian@juliancoy.com> * Change version type for opencode-anthropic-auth Updated version from patch to minor for the package. Signed-off-by: Julian Coy <julian@juliancoy.com> --------- Signed-off-by: Julian Coy <julian@juliancoy.com> Co-authored-by: Julian Coy <julian@juliancoy.com>
1 parent d7b6736 commit 0906d28

5 files changed

Lines changed: 40 additions & 19 deletions

File tree

.changeset/modern-terms-peel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@ex-machina/opencode-anthropic-auth": minor
3+
---
4+
5+
PascalCase tool names after mcp_ prefix to match Claude Code convention

src/tests/__snapshots__/transform.test.ts.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,15 +292,15 @@ You are a Claude agent, built on Anthropic's Claude Agent SDK."
292292
],
293293
"tools": [
294294
{
295-
"name": "mcp_bash",
295+
"name": "mcp_Bash",
296296
"type": "function",
297297
},
298298
{
299-
"name": "mcp_read",
299+
"name": "mcp_Read",
300300
"type": "function",
301301
},
302302
{
303-
"name": "mcp_edit",
303+
"name": "mcp_Edit",
304304
"type": "function",
305305
},
306306
],

src/tests/index.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ describe('auth.loader', () => {
206206

207207
const parsedBody = JSON.parse(capturedBody!)
208208
// Tool name should be prefixed
209-
expect(parsedBody.tools[0].name).toBe('mcp_bash')
209+
expect(parsedBody.tools[0].name).toBe('mcp_Bash')
210210
// After relocation, system should only contain the identity block
211211
expect(parsedBody.system).toHaveLength(1)
212212
expect(parsedBody.system[0].text).toBe(

src/tests/transform.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,8 @@ describe('prefixToolNames', () => {
147147
],
148148
})
149149
const result = JSON.parse(prefixToolNames(body))
150-
expect(result.tools[0].name).toBe('mcp_read_file')
151-
expect(result.tools[1].name).toBe('mcp_write_file')
150+
expect(result.tools[0].name).toBe('mcp_Read_file')
151+
expect(result.tools[1].name).toBe('mcp_Write_file')
152152
})
153153

154154
test('prefixes tool_use block names in messages', () => {
@@ -164,7 +164,7 @@ describe('prefixToolNames', () => {
164164
],
165165
})
166166
const result = JSON.parse(prefixToolNames(body))
167-
expect(result.messages[0].content[0].name).toBe('mcp_bash')
167+
expect(result.messages[0].content[0].name).toBe('mcp_Bash')
168168
expect(result.messages[0].content[1].type).toBe('text')
169169
})
170170

@@ -670,7 +670,7 @@ describe('rewriteRequestBody', () => {
670670
system: 'You are a helpful assistant.',
671671
})
672672
const result = JSON.parse(rewriteRequestBody(body))
673-
expect(result.tools[0].name).toBe('mcp_bash')
673+
expect(result.tools[0].name).toBe('mcp_Bash')
674674
expect(result.system[0].text).toContain(CLAUDE_CODE_IDENTITY)
675675
})
676676

@@ -777,7 +777,7 @@ describe('rewriteRequestBody', () => {
777777
"content": [
778778
{
779779
"id": "tool_1",
780-
"name": "mcp_bash",
780+
"name": "mcp_Bash",
781781
"type": "tool_use",
782782
},
783783
{
@@ -974,8 +974,8 @@ describe('rewriteRequestBody', () => {
974974
})
975975
const result = JSON.parse(rewriteRequestBody(body))
976976

977-
expect(result.tools[0].name).toBe('mcp_bash')
978-
expect(result.messages[1].content[0].name).toBe('mcp_bash')
977+
expect(result.tools[0].name).toBe('mcp_Bash')
978+
expect(result.messages[1].content[0].name).toBe('mcp_Bash')
979979
})
980980
})
981981
})

src/transform.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@ import {
1010
USER_AGENT,
1111
} from './constants'
1212

13+
/**
14+
* Prefix a tool name with TOOL_PREFIX and uppercase the first character.
15+
* Claude Code uses PascalCase tool names (e.g. mcp_Bash, mcp_Read);
16+
* lowercase names (mcp_bash, mcp_read) are flagged as non-Claude-Code clients.
17+
*/
18+
function prefixName(name: string): string {
19+
return `${TOOL_PREFIX}${name.charAt(0).toUpperCase()}${name.slice(1)}`
20+
}
21+
22+
/**
23+
* Reverse prefixName: strip TOOL_PREFIX and restore the original leading case.
24+
*/
25+
function unprefixName(name: string): string {
26+
return `${name.charAt(0).toLowerCase()}${name.slice(1)}`
27+
}
28+
1329
export type FetchInput = string | URL | Request
1430

1531
/**
@@ -90,7 +106,7 @@ export function prefixToolNames(body: string): string {
90106
parsed.tools = parsed.tools.map(
91107
(tool: { name?: string; [k: string]: unknown }) => ({
92108
...tool,
93-
name: tool.name ? `${TOOL_PREFIX}${tool.name}` : tool.name,
109+
name: tool.name ? prefixName(tool.name) : tool.name,
94110
}),
95111
)
96112
}
@@ -108,10 +124,7 @@ export function prefixToolNames(body: string): string {
108124
if (msg.content && Array.isArray(msg.content)) {
109125
msg.content = msg.content.map((block) => {
110126
if (block.type === 'tool_use' && block.name) {
111-
return {
112-
...block,
113-
name: `${TOOL_PREFIX}${block.name}`,
114-
}
127+
return { ...block, name: prefixName(block.name) }
115128
}
116129
return block
117130
})
@@ -131,7 +144,10 @@ export function prefixToolNames(body: string): string {
131144
* Strip TOOL_PREFIX from tool names in streaming response text.
132145
*/
133146
export function stripToolPrefix(text: string): string {
134-
return text.replace(/"name"\s*:\s*"mcp_([^"]+)"/g, '"name": "$1"')
147+
return text.replace(
148+
/"name"\s*:\s*"mcp_([^"]+)"/g,
149+
(_match, name: string) => `"name": "${unprefixName(name)}"`,
150+
)
135151
}
136152

137153
/**
@@ -406,7 +422,7 @@ export function rewriteRequestBody(body: string): string {
406422
parsed.tools = parsed.tools.map(
407423
(tool: { name?: string; [k: string]: unknown }) => ({
408424
...tool,
409-
name: tool.name ? `${TOOL_PREFIX}${tool.name}` : tool.name,
425+
name: tool.name ? prefixName(tool.name) : tool.name,
410426
}),
411427
)
412428
}
@@ -424,7 +440,7 @@ export function rewriteRequestBody(body: string): string {
424440
if (msg.content && Array.isArray(msg.content)) {
425441
msg.content = msg.content.map((block) => {
426442
if (block.type === 'tool_use' && block.name) {
427-
return { ...block, name: `${TOOL_PREFIX}${block.name}` }
443+
return { ...block, name: prefixName(block.name) }
428444
}
429445
return block
430446
})

0 commit comments

Comments
 (0)