Merge pull request #908 from gilbrotheraway/fix/skill-mcp-args
fix(skill-mcp): allow object args and strip quotes
This commit is contained in:
commit
485bc73437
@ -21,10 +21,10 @@ function validateOperationParams(args: SkillMcpArgs): OperationType {
|
||||
if (operations.length === 0) {
|
||||
throw new Error(
|
||||
`Missing operation. Exactly one of tool_name, resource_name, or prompt_name must be specified.\n\n` +
|
||||
`Examples:\n` +
|
||||
` skill_mcp(mcp_name="sqlite", tool_name="query", arguments='{"sql": "SELECT * FROM users"}')\n` +
|
||||
` skill_mcp(mcp_name="memory", resource_name="memory://notes")\n` +
|
||||
` skill_mcp(mcp_name="helper", prompt_name="summarize", arguments='{"text": "..."}')`
|
||||
`Examples:\n` +
|
||||
` skill_mcp(mcp_name="sqlite", tool_name="query", arguments='{"sql": "SELECT * FROM users"}')\n` +
|
||||
` skill_mcp(mcp_name="memory", resource_name="memory://notes")\n` +
|
||||
` skill_mcp(mcp_name="helper", prompt_name="summarize", arguments='{"text": "..."}')`,
|
||||
)
|
||||
}
|
||||
|
||||
@ -33,12 +33,14 @@ function validateOperationParams(args: SkillMcpArgs): OperationType {
|
||||
args.tool_name && `tool_name="${args.tool_name}"`,
|
||||
args.resource_name && `resource_name="${args.resource_name}"`,
|
||||
args.prompt_name && `prompt_name="${args.prompt_name}"`,
|
||||
].filter(Boolean).join(", ")
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(", ")
|
||||
|
||||
throw new Error(
|
||||
`Multiple operations specified. Exactly one of tool_name, resource_name, or prompt_name must be provided.\n\n` +
|
||||
`Received: ${provided}\n\n` +
|
||||
`Use separate calls for each operation.`
|
||||
`Received: ${provided}\n\n` +
|
||||
`Use separate calls for each operation.`,
|
||||
)
|
||||
}
|
||||
|
||||
@ -47,7 +49,7 @@ function validateOperationParams(args: SkillMcpArgs): OperationType {
|
||||
|
||||
function findMcpServer(
|
||||
mcpName: string,
|
||||
skills: LoadedSkill[]
|
||||
skills: LoadedSkill[],
|
||||
): { skill: LoadedSkill; config: NonNullable<LoadedSkill["mcpConfig"]>[string] } | null {
|
||||
for (const skill of skills) {
|
||||
if (skill.mcpConfig && mcpName in skill.mcpConfig) {
|
||||
@ -75,7 +77,10 @@ function parseArguments(argsJson: string | Record<string, unknown> | undefined):
|
||||
return argsJson
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(argsJson)
|
||||
// Strip outer single quotes if present (common in LLM output)
|
||||
const jsonStr = argsJson.startsWith("'") && argsJson.endsWith("'") ? argsJson.slice(1, -1) : argsJson
|
||||
|
||||
const parsed = JSON.parse(jsonStr)
|
||||
if (typeof parsed !== "object" || parsed === null) {
|
||||
throw new Error("Arguments must be a JSON object")
|
||||
}
|
||||
@ -84,8 +89,8 @@ function parseArguments(argsJson: string | Record<string, unknown> | undefined):
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
throw new Error(
|
||||
`Invalid arguments JSON: ${errorMessage}\n\n` +
|
||||
`Expected a valid JSON object, e.g.: '{"key": "value"}'\n` +
|
||||
`Received: ${argsJson}`
|
||||
`Expected a valid JSON object, e.g.: '{"key": "value"}'\n` +
|
||||
`Received: ${argsJson}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -95,10 +100,8 @@ export function applyGrepFilter(output: string, pattern: string | undefined): st
|
||||
try {
|
||||
const regex = new RegExp(pattern, "i")
|
||||
const lines = output.split("\n")
|
||||
const filtered = lines.filter(line => regex.test(line))
|
||||
return filtered.length > 0
|
||||
? filtered.join("\n")
|
||||
: `[grep] No lines matched pattern: ${pattern}`
|
||||
const filtered = lines.filter((line) => regex.test(line))
|
||||
return filtered.length > 0 ? filtered.join("\n") : `[grep] No lines matched pattern: ${pattern}`
|
||||
} catch {
|
||||
return output
|
||||
}
|
||||
@ -114,8 +117,14 @@ export function createSkillMcpTool(options: SkillMcpToolOptions): ToolDefinition
|
||||
tool_name: tool.schema.string().optional().describe("MCP tool to call"),
|
||||
resource_name: tool.schema.string().optional().describe("MCP resource URI to read"),
|
||||
prompt_name: tool.schema.string().optional().describe("MCP prompt to get"),
|
||||
arguments: tool.schema.string().optional().describe("JSON string of arguments"),
|
||||
grep: tool.schema.string().optional().describe("Regex pattern to filter output lines (only matching lines returned)"),
|
||||
arguments: tool.schema
|
||||
.union([tool.schema.string(), tool.schema.record(tool.schema.string(), tool.schema.unknown())])
|
||||
.optional()
|
||||
.describe("JSON string or object of arguments"),
|
||||
grep: tool.schema
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Regex pattern to filter output lines (only matching lines returned)"),
|
||||
},
|
||||
async execute(args: SkillMcpArgs) {
|
||||
const operation = validateOperationParams(args)
|
||||
@ -125,9 +134,10 @@ export function createSkillMcpTool(options: SkillMcpToolOptions): ToolDefinition
|
||||
if (!found) {
|
||||
throw new Error(
|
||||
`MCP server "${args.mcp_name}" not found.\n\n` +
|
||||
`Available MCP servers in loaded skills:\n` +
|
||||
formatAvailableMcps(skills) + `\n\n` +
|
||||
`Hint: Load the skill first using the 'skill' tool, then call skill_mcp.`
|
||||
`Available MCP servers in loaded skills:\n` +
|
||||
formatAvailableMcps(skills) +
|
||||
`\n\n` +
|
||||
`Hint: Load the skill first using the 'skill' tool, then call skill_mcp.`,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user