feat(code): add MCP server integration for core CLI (#112)
Add MCP server that exposes core CLI commands as tools: - core_go_test: Run Go tests with filter and coverage options - core_dev_health: Check development environment health - core_dev_commit: Create commits with message and repo selection Returns structured JSON responses for AI agent consumption. Migrated from core-claude PR #56. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
20359e22d4
commit
7571ef62fc
2 changed files with 153 additions and 0 deletions
21
claude/code/commands/serve-mcp.md
Normal file
21
claude/code/commands/serve-mcp.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
name: serve-mcp
|
||||
description: Starts the MCP server for the core CLI.
|
||||
args: ""
|
||||
---
|
||||
|
||||
# MCP Server
|
||||
|
||||
Starts the MCP server to expose core CLI commands as tools.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/code:serve-mcp
|
||||
```
|
||||
|
||||
## Action
|
||||
|
||||
```bash
|
||||
"${CLAUDE_PLUGIN_ROOT}/scripts/mcp/run.sh"
|
||||
```
|
||||
132
claude/code/scripts/mcp/run.sh
Executable file
132
claude/code/scripts/mcp/run.sh
Executable file
|
|
@ -0,0 +1,132 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# MCP Server script for the core-claude plugin.
|
||||
# This script reads a JSON MCP request from stdin, executes the corresponding
|
||||
# core CLI command, and prints a JSON response to stdout.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
# Read the entire input from stdin
|
||||
request_json=$(cat)
|
||||
|
||||
# --- Input Validation ---
|
||||
if ! echo "$request_json" | jq . > /dev/null 2>&1; then
|
||||
echo '{"status": "error", "message": "Invalid JSON request."}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Request Parsing ---
|
||||
tool_name=$(echo "$request_json" | jq -r '.tool_name')
|
||||
params=$(echo "$request_json" | jq '.parameters')
|
||||
|
||||
# --- Command Routing ---
|
||||
case "$tool_name" in
|
||||
"core_go_test")
|
||||
filter=$(echo "$params" | jq -r '.filter // ""')
|
||||
coverage=$(echo "$params" | jq -r '.coverage // false')
|
||||
|
||||
# Build the command
|
||||
cmd_args=("go" "test")
|
||||
[ -n "$filter" ] && cmd_args+=("--filter=$filter")
|
||||
[ "$coverage" = "true" ] && cmd_args+=("--coverage")
|
||||
;;
|
||||
|
||||
"core_dev_health")
|
||||
cmd_args=("dev" "health")
|
||||
;;
|
||||
|
||||
"core_dev_commit")
|
||||
message=$(echo "$params" | jq -r '.message // ""')
|
||||
if [ -z "$message" ]; then
|
||||
echo '{"status": "error", "message": "Missing required parameter: message"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cmd_args=("dev" "commit" "-m" "$message")
|
||||
|
||||
repos=$(echo "$params" | jq -r '.repos // "[]"')
|
||||
if [ "$(echo "$repos" | jq 'length')" -gt 0 ]; then
|
||||
# Read repos into a bash array
|
||||
mapfile -t repo_array < <(echo "$repos" | jq -r '.[]')
|
||||
cmd_args+=("${repo_array[@]}")
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "{\"status\": \"error\", \"message\": \"Unknown tool: $tool_name\"}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Command Execution ---
|
||||
# The 'core' command is expected to be in the PATH of the execution environment.
|
||||
output=$(core "${cmd_args[@]}" 2>&1)
|
||||
exit_code=$?
|
||||
|
||||
# --- Response Formatting ---
|
||||
if [ $exit_code -eq 0 ]; then
|
||||
status="success"
|
||||
else
|
||||
status="error"
|
||||
fi
|
||||
|
||||
# Default response is just the raw output
|
||||
result_json=$(jq -n --arg raw "$output" '{raw: $raw}')
|
||||
|
||||
# Structured Response Parsing
|
||||
if [ "$tool_name" = "core_go_test" ]; then
|
||||
if [ "$status" = "success" ]; then
|
||||
# Use awk for more robust parsing of the test output.
|
||||
# This is less brittle than grepping for exact lines.
|
||||
outcome=$(printf "%s" "$output" | awk '/^PASS$/ {print "PASS"}')
|
||||
coverage=$(printf "%s" "$output" | awk '/coverage:/ {print $2}')
|
||||
summary=$(printf "%s" "$output" | awk '/^ok\s/ {print $0}')
|
||||
|
||||
result_json=$(jq -n \
|
||||
--arg outcome "${outcome:-UNKNOWN}" \
|
||||
--arg coverage "${coverage:--}" \
|
||||
--arg summary "${summary:--}" \
|
||||
--arg raw_output "$output" \
|
||||
'{
|
||||
outcome: $outcome,
|
||||
coverage: $coverage,
|
||||
summary: $summary,
|
||||
raw_output: $raw_output
|
||||
}')
|
||||
else
|
||||
# In case of failure, the output is less predictable.
|
||||
# We'll grab what we can, but the raw output is most important.
|
||||
outcome=$(printf "%s" "$output" | awk '/^FAIL$/ {print "FAIL"}')
|
||||
summary=$(printf "%s" "$output" | awk '/^FAIL\s/ {print $0}')
|
||||
result_json=$(jq -n \
|
||||
--arg outcome "${outcome:-FAIL}" \
|
||||
--arg summary "${summary:--}" \
|
||||
--arg raw_output "$output" \
|
||||
'{
|
||||
outcome: $outcome,
|
||||
summary: $summary,
|
||||
raw_output: $raw_output
|
||||
}')
|
||||
fi
|
||||
elif [ "$tool_name" = "core_dev_health" ]; then
|
||||
if [ "$status" = "success" ]; then
|
||||
# Safely parse the "key: value" output into a JSON array of objects.
|
||||
# This uses jq to be robust against special characters in the output.
|
||||
result_json=$(printf "%s" "$output" | jq -R 'capture("(?<name>[^:]+):\\s*(?<status>.*)")' | jq -s '{services: .}')
|
||||
else
|
||||
# On error, just return the raw output
|
||||
result_json=$(jq -n --arg error "$output" '{error: $error}')
|
||||
fi
|
||||
elif [ "$tool_name" = "core_dev_commit" ]; then
|
||||
if [ "$status" = "success" ]; then
|
||||
result_json=$(jq -n --arg message "$output" '{message: $message}')
|
||||
else
|
||||
result_json=$(jq -n --arg error "$output" '{error: $error}')
|
||||
fi
|
||||
fi
|
||||
|
||||
response=$(jq -n --arg status "$status" --argjson result "$result_json" '{status: $status, result: $result}')
|
||||
echo "$response"
|
||||
|
||||
exit 0
|
||||
Loading…
Add table
Reference in a new issue