@dollhousemcp/mcp-server 2.0.15 → 2.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md.backup +18 -0
- package/dist/elements/base/BaseElementManager.d.ts.map +1 -1
- package/dist/elements/base/BaseElementManager.js +17 -1
- package/dist/elements/memories/MemoryManager.d.ts.map +1 -1
- package/dist/elements/memories/MemoryManager.js +13 -2
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.js +3 -3
- package/dist/handlers/ElementCRUDHandler.d.ts.map +1 -1
- package/dist/handlers/ElementCRUDHandler.js +7 -3
- package/dist/handlers/element-crud/createElement.d.ts.map +1 -1
- package/dist/handlers/element-crud/createElement.js +6 -2
- package/dist/handlers/element-crud/editElement.d.ts.map +1 -1
- package/dist/handlers/element-crud/editElement.js +6 -2
- package/dist/handlers/element-crud/helpers.d.ts +2 -0
- package/dist/handlers/element-crud/helpers.d.ts.map +1 -1
- package/dist/handlers/element-crud/helpers.js +21 -2
- package/dist/handlers/mcp-aql/IntrospectionResolver.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/IntrospectionResolver.js +34 -7
- package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/MCPAQLHandler.js +51 -20
- package/dist/handlers/mcp-aql/OperationSchema.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/OperationSchema.js +6 -4
- package/dist/handlers/mcp-aql/evaluatePermission.d.ts +2 -1
- package/dist/handlers/mcp-aql/evaluatePermission.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/evaluatePermission.js +23 -11
- package/dist/handlers/mcp-aql/policies/ElementPolicies.d.ts +8 -0
- package/dist/handlers/mcp-aql/policies/ElementPolicies.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/policies/ElementPolicies.js +26 -1
- package/dist/handlers/strategies/BaseActivationStrategy.d.ts.map +1 -1
- package/dist/handlers/strategies/BaseActivationStrategy.js +12 -3
- package/dist/handlers/strategies/PersonaActivationStrategy.js +2 -2
- package/dist/utils/permissionHooks.d.ts +74 -0
- package/dist/utils/permissionHooks.d.ts.map +1 -0
- package/dist/utils/permissionHooks.js +771 -0
- package/dist/web/public/index.html +12 -6
- package/dist/web/public/permissions.css +11 -0
- package/dist/web/public/permissions.js +78 -35
- package/dist/web/public/setup.css +172 -1
- package/dist/web/public/setup.js +644 -38
- package/dist/web/routes/permissionRoutes.d.ts.map +1 -1
- package/dist/web/routes/permissionRoutes.js +95 -27
- package/dist/web/routes/setupRoutes.d.ts +4 -0
- package/dist/web/routes/setupRoutes.d.ts.map +1 -1
- package/dist/web/routes/setupRoutes.js +122 -39
- package/package.json +8 -1
- package/scripts/pretooluse-codex.sh +6 -0
- package/scripts/pretooluse-cursor.sh +6 -0
- package/scripts/pretooluse-dollhouse.sh +110 -0
- package/scripts/pretooluse-gemini.sh +6 -0
- package/scripts/pretooluse-vscode.sh +163 -0
- package/scripts/pretooluse-windsurf.sh +168 -0
- package/server.json +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dollhousemcp/mcp-server",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.17",
|
|
4
4
|
"description": "DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -133,6 +133,12 @@
|
|
|
133
133
|
"dist/**/*.d.ts.map",
|
|
134
134
|
"dist/web/public/**",
|
|
135
135
|
"dist/seed-elements/**",
|
|
136
|
+
"scripts/pretooluse-dollhouse.sh",
|
|
137
|
+
"scripts/pretooluse-vscode.sh",
|
|
138
|
+
"scripts/pretooluse-cursor.sh",
|
|
139
|
+
"scripts/pretooluse-windsurf.sh",
|
|
140
|
+
"scripts/pretooluse-gemini.sh",
|
|
141
|
+
"scripts/pretooluse-codex.sh",
|
|
136
142
|
"data/personas/**/*.md",
|
|
137
143
|
"data/skills/**/*.md",
|
|
138
144
|
"data/templates/**/*.md",
|
|
@@ -174,6 +180,7 @@
|
|
|
174
180
|
"otpauth": "^9.5.0",
|
|
175
181
|
"posthog-node": "^5.24.17",
|
|
176
182
|
"qrcode": "^1.5.4",
|
|
183
|
+
"smol-toml": "^1.6.1",
|
|
177
184
|
"uuid": "^11.1.0",
|
|
178
185
|
"zod": "^4.3.6"
|
|
179
186
|
},
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# pretooluse-dollhouse.sh — PreToolUse hook for DollhouseMCP permission evaluation
|
|
3
|
+
#
|
|
4
|
+
# Routes permission checks through DollhouseMCP's evaluate_permission endpoint.
|
|
5
|
+
# The DollhouseMCP web server runs alongside the MCP stdio server on a dynamic port.
|
|
6
|
+
# Port discovery via ~/.dollhouse/run/permission-server.port
|
|
7
|
+
#
|
|
8
|
+
# Input: JSON on stdin. Claude Code uses { tool_name, tool_input }.
|
|
9
|
+
# Other clients may expose { toolName, toolInput } or { tool, input }.
|
|
10
|
+
# Output: JSON on stdout (platform-specific hook response; Claude Code expects
|
|
11
|
+
# hookSpecificOutput.permissionDecision for PreToolUse)
|
|
12
|
+
#
|
|
13
|
+
# Fail-open: if the server is unreachable or returns an error, the hook allows
|
|
14
|
+
# the action rather than blocking the user.
|
|
15
|
+
#
|
|
16
|
+
# Set DOLLHOUSE_HOOK_DEBUG=1 for debug logging to stderr.
|
|
17
|
+
# Set DOLLHOUSE_HOOK_PLATFORM to override the platform sent to the server.
|
|
18
|
+
|
|
19
|
+
PORT_FILE="$HOME/.dollhouse/run/permission-server.port"
|
|
20
|
+
MAX_RETRIES=2
|
|
21
|
+
INITIAL_TIMEOUT=5
|
|
22
|
+
HOOK_PLATFORM="${DOLLHOUSE_HOOK_PLATFORM:-claude_code}"
|
|
23
|
+
|
|
24
|
+
# Debug logging helper — writes to stderr so it doesn't pollute stdout
|
|
25
|
+
debug() {
|
|
26
|
+
if [[ "${DOLLHOUSE_HOOK_DEBUG:-0}" == "1" ]]; then
|
|
27
|
+
echo "[pretooluse] $*" >&2
|
|
28
|
+
fi
|
|
29
|
+
return 0
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Discover the port from the port file
|
|
33
|
+
if [[ -f "$PORT_FILE" ]]; then
|
|
34
|
+
PORT=$(cat "$PORT_FILE" 2>/dev/null)
|
|
35
|
+
debug "Port file found: $PORT"
|
|
36
|
+
else
|
|
37
|
+
debug "No port file at $PORT_FILE — fail open"
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Validate port is a number
|
|
42
|
+
if ! [[ "$PORT" =~ ^[0-9]+$ ]]; then
|
|
43
|
+
debug "Invalid port value: $PORT — fail open"
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
ENDPOINT="http://127.0.0.1:${PORT}/api/evaluate_permission"
|
|
48
|
+
debug "Endpoint: $ENDPOINT"
|
|
49
|
+
|
|
50
|
+
# Read the hook input from stdin
|
|
51
|
+
INPUT=$(cat)
|
|
52
|
+
|
|
53
|
+
# Extract tool_name and tool_input from the hook payload
|
|
54
|
+
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // .toolName // .tool // .name // empty' 2>/dev/null)
|
|
55
|
+
TOOL_INPUT=$(echo "$INPUT" | jq -c '.tool_input // .toolInput // .input // {}' 2>/dev/null)
|
|
56
|
+
|
|
57
|
+
# If we can't parse the input, fail open
|
|
58
|
+
if [[ -z "$TOOL_NAME" ]]; then
|
|
59
|
+
debug "Could not parse tool_name from input — fail open"
|
|
60
|
+
exit 0
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
debug "Evaluating: $TOOL_NAME"
|
|
64
|
+
debug "Platform: $HOOK_PLATFORM"
|
|
65
|
+
|
|
66
|
+
if [[ -n "${DOLLHOUSE_SESSION_ID:-}" ]]; then
|
|
67
|
+
debug "Using DOLLHOUSE_SESSION_ID=${DOLLHOUSE_SESSION_ID}"
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
PAYLOAD=$(jq -cn \
|
|
71
|
+
--arg tool_name "$TOOL_NAME" \
|
|
72
|
+
--arg platform "$HOOK_PLATFORM" \
|
|
73
|
+
--arg session_id "${DOLLHOUSE_SESSION_ID:-}" \
|
|
74
|
+
--argjson input "$TOOL_INPUT" \
|
|
75
|
+
'{
|
|
76
|
+
tool_name: $tool_name,
|
|
77
|
+
input: $input,
|
|
78
|
+
platform: $platform
|
|
79
|
+
} + (if ($session_id | length) > 0 then { session_id: $session_id } else {} end)')
|
|
80
|
+
|
|
81
|
+
# Call the DollhouseMCP permission evaluation endpoint with exponential backoff.
|
|
82
|
+
# Retry on transient failures (connection refused, timeout) but not on HTTP errors.
|
|
83
|
+
ATTEMPT=0
|
|
84
|
+
TIMEOUT=$INITIAL_TIMEOUT
|
|
85
|
+
|
|
86
|
+
while [[ $ATTEMPT -le $MAX_RETRIES ]]; do
|
|
87
|
+
RESPONSE=$(curl -s --max-time "$TIMEOUT" -X POST "$ENDPOINT" \
|
|
88
|
+
-H "Content-Type: application/json" \
|
|
89
|
+
-d "$PAYLOAD" \
|
|
90
|
+
2>/dev/null)
|
|
91
|
+
CURL_EXIT=$?
|
|
92
|
+
|
|
93
|
+
if [[ $CURL_EXIT -eq 0 ]] && [[ -n "$RESPONSE" ]]; then
|
|
94
|
+
debug "Response (attempt $((ATTEMPT+1))): $RESPONSE"
|
|
95
|
+
echo "$RESPONSE"
|
|
96
|
+
exit 0
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
ATTEMPT=$((ATTEMPT + 1))
|
|
100
|
+
if [[ $ATTEMPT -le $MAX_RETRIES ]]; then
|
|
101
|
+
BACKOFF=$((TIMEOUT * ATTEMPT))
|
|
102
|
+
debug "Attempt $ATTEMPT failed (curl exit $CURL_EXIT) — retrying in ${BACKOFF}s (timeout ${TIMEOUT}s → $((TIMEOUT * 2))s)"
|
|
103
|
+
sleep "$BACKOFF"
|
|
104
|
+
TIMEOUT=$((TIMEOUT * 2))
|
|
105
|
+
fi
|
|
106
|
+
done
|
|
107
|
+
|
|
108
|
+
# All retries exhausted — fail open
|
|
109
|
+
debug "All $((MAX_RETRIES + 1)) attempts failed — fail open"
|
|
110
|
+
exit 0
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# pretooluse-vscode.sh — VS Code / Copilot hook wrapper for DollhouseMCP
|
|
3
|
+
#
|
|
4
|
+
# VS Code supports Claude-compatible PreToolUse hooks, but its tool names and
|
|
5
|
+
# tool_input field names differ from Claude Code. This adapter normalizes the
|
|
6
|
+
# most relevant built-in tool names into Dollhouse's existing permission model.
|
|
7
|
+
|
|
8
|
+
PORT_FILE="$HOME/.dollhouse/run/permission-server.port"
|
|
9
|
+
MAX_RETRIES=2
|
|
10
|
+
INITIAL_TIMEOUT=5
|
|
11
|
+
HOOK_PLATFORM="vscode"
|
|
12
|
+
|
|
13
|
+
debug() {
|
|
14
|
+
if [[ "${DOLLHOUSE_HOOK_DEBUG:-0}" == "1" ]]; then
|
|
15
|
+
echo "[pretooluse-vscode] $*" >&2
|
|
16
|
+
fi
|
|
17
|
+
return 0
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if [[ -f "$PORT_FILE" ]]; then
|
|
21
|
+
PORT=$(cat "$PORT_FILE" 2>/dev/null)
|
|
22
|
+
else
|
|
23
|
+
debug "No port file at $PORT_FILE — fail open"
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
if ! [[ "$PORT" =~ ^[0-9]+$ ]]; then
|
|
28
|
+
debug "Invalid port value: $PORT — fail open"
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
ENDPOINT="http://127.0.0.1:${PORT}/api/evaluate_permission"
|
|
33
|
+
INPUT=$(cat)
|
|
34
|
+
|
|
35
|
+
RAW_TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // .toolName // .tool // .name // empty' 2>/dev/null)
|
|
36
|
+
TOOL_NAME="$RAW_TOOL_NAME"
|
|
37
|
+
TOOL_INPUT=$(echo "$INPUT" | jq -c '.tool_input // .toolInput // .input // {}' 2>/dev/null)
|
|
38
|
+
|
|
39
|
+
case "$RAW_TOOL_NAME" in
|
|
40
|
+
runTerminalCommand|run_terminal_command|run_in_terminal|terminal_command)
|
|
41
|
+
TOOL_NAME='Bash'
|
|
42
|
+
TOOL_INPUT=$(echo "$INPUT" | jq -c '
|
|
43
|
+
. as $root
|
|
44
|
+
| {
|
|
45
|
+
command: (
|
|
46
|
+
$root.tool_input.command
|
|
47
|
+
// $root.tool_input.commandLine
|
|
48
|
+
// $root.toolInput.command
|
|
49
|
+
// $root.toolInput.commandLine
|
|
50
|
+
// $root.input.command
|
|
51
|
+
// $root.input.commandLine
|
|
52
|
+
// ""
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
| if ($root.cwd // $root.working_directory // $root.workingDirectory) != null
|
|
56
|
+
then . + { cwd: ($root.cwd // $root.working_directory // $root.workingDirectory) }
|
|
57
|
+
else .
|
|
58
|
+
end
|
|
59
|
+
' 2>/dev/null)
|
|
60
|
+
;;
|
|
61
|
+
createFile|create_file|writeFile|write_file)
|
|
62
|
+
TOOL_NAME='Write'
|
|
63
|
+
;;
|
|
64
|
+
editFile|edit_file|editFiles|replace_string_in_file|multi_edit)
|
|
65
|
+
TOOL_NAME='Edit'
|
|
66
|
+
;;
|
|
67
|
+
readFile|read_file|openFile|open_file)
|
|
68
|
+
TOOL_NAME='Read'
|
|
69
|
+
;;
|
|
70
|
+
findFiles|find_files|glob_search)
|
|
71
|
+
TOOL_NAME='Glob'
|
|
72
|
+
;;
|
|
73
|
+
searchWorkspace|search_workspace|searchInFiles|grep_search)
|
|
74
|
+
TOOL_NAME='Grep'
|
|
75
|
+
;;
|
|
76
|
+
fetchWebPage|fetch_web_page|fetch_webpage)
|
|
77
|
+
TOOL_NAME='WebFetch'
|
|
78
|
+
;;
|
|
79
|
+
searchWeb|search_web)
|
|
80
|
+
TOOL_NAME='WebSearch'
|
|
81
|
+
;;
|
|
82
|
+
*)
|
|
83
|
+
;;
|
|
84
|
+
esac
|
|
85
|
+
|
|
86
|
+
if [[ -z "$TOOL_NAME" ]]; then
|
|
87
|
+
debug "Could not parse VS Code tool name — fail open"
|
|
88
|
+
exit 0
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
if [[ -z "$TOOL_INPUT" ]]; then
|
|
92
|
+
TOOL_INPUT='{}'
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
PAYLOAD=$(jq -cn \
|
|
96
|
+
--arg tool_name "$TOOL_NAME" \
|
|
97
|
+
--arg platform "$HOOK_PLATFORM" \
|
|
98
|
+
--arg session_id "${DOLLHOUSE_SESSION_ID:-}" \
|
|
99
|
+
--argjson input "$TOOL_INPUT" \
|
|
100
|
+
'{
|
|
101
|
+
tool_name: $tool_name,
|
|
102
|
+
input: $input,
|
|
103
|
+
platform: $platform
|
|
104
|
+
} + (if ($session_id | length) > 0 then { session_id: $session_id } else {} end)')
|
|
105
|
+
|
|
106
|
+
ATTEMPT=0
|
|
107
|
+
TIMEOUT=$INITIAL_TIMEOUT
|
|
108
|
+
|
|
109
|
+
while [[ $ATTEMPT -le $MAX_RETRIES ]]; do
|
|
110
|
+
RESPONSE=$(curl -s --max-time "$TIMEOUT" -X POST "$ENDPOINT" \
|
|
111
|
+
-H "Content-Type: application/json" \
|
|
112
|
+
-d "$PAYLOAD" \
|
|
113
|
+
2>/dev/null)
|
|
114
|
+
CURL_EXIT=$?
|
|
115
|
+
|
|
116
|
+
if [[ $CURL_EXIT -eq 0 ]] && [[ -n "$RESPONSE" ]]; then
|
|
117
|
+
HOOK_RESPONSE=$(echo "$RESPONSE" | jq -c '
|
|
118
|
+
def decision_from_response:
|
|
119
|
+
if (.hookSpecificOutput.permissionDecision? | type) == "string" then .hookSpecificOutput.permissionDecision
|
|
120
|
+
elif (.decision? | type) == "string" then .decision
|
|
121
|
+
elif (.allowed? == true) then "allow"
|
|
122
|
+
elif (.allowed? == false) then "deny"
|
|
123
|
+
else empty
|
|
124
|
+
end;
|
|
125
|
+
def reason_from_response:
|
|
126
|
+
.hookSpecificOutput.permissionDecisionReason
|
|
127
|
+
// .reason
|
|
128
|
+
// .hookSpecificOutput.reason
|
|
129
|
+
// empty;
|
|
130
|
+
|
|
131
|
+
(decision_from_response) as $decision
|
|
132
|
+
| if ($decision | type) == "string" and ($decision | length) > 0 then
|
|
133
|
+
{
|
|
134
|
+
hookSpecificOutput:
|
|
135
|
+
({
|
|
136
|
+
hookEventName: "PreToolUse",
|
|
137
|
+
permissionDecision: $decision
|
|
138
|
+
} + (if (reason_from_response | type) == "string" and (reason_from_response | length) > 0
|
|
139
|
+
then { permissionDecisionReason: reason_from_response }
|
|
140
|
+
else {}
|
|
141
|
+
end))
|
|
142
|
+
}
|
|
143
|
+
else empty
|
|
144
|
+
end
|
|
145
|
+
' 2>/dev/null)
|
|
146
|
+
|
|
147
|
+
if [[ -n "$HOOK_RESPONSE" ]]; then
|
|
148
|
+
echo "$HOOK_RESPONSE"
|
|
149
|
+
else
|
|
150
|
+
debug "Permission evaluation returned an unrecognized response — fail open"
|
|
151
|
+
fi
|
|
152
|
+
exit 0
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
ATTEMPT=$((ATTEMPT + 1))
|
|
156
|
+
if [[ $ATTEMPT -le $MAX_RETRIES ]]; then
|
|
157
|
+
sleep $((TIMEOUT * ATTEMPT))
|
|
158
|
+
TIMEOUT=$((TIMEOUT * 2))
|
|
159
|
+
fi
|
|
160
|
+
done
|
|
161
|
+
|
|
162
|
+
debug "Permission evaluation failed — fail open"
|
|
163
|
+
exit 0
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# pretooluse-windsurf.sh — Windsurf hook wrapper for DollhouseMCP
|
|
3
|
+
#
|
|
4
|
+
# Windsurf pre-hooks are binary: exit 0 to allow, exit 2 to block.
|
|
5
|
+
# This wrapper translates Windsurf hook events into Dollhouse permission
|
|
6
|
+
# evaluations and then maps the response back to Windsurf exit codes.
|
|
7
|
+
|
|
8
|
+
PORT_FILE="$HOME/.dollhouse/run/permission-server.port"
|
|
9
|
+
MAX_RETRIES=2
|
|
10
|
+
INITIAL_TIMEOUT=5
|
|
11
|
+
HOOK_PLATFORM="windsurf"
|
|
12
|
+
|
|
13
|
+
debug() {
|
|
14
|
+
if [[ "${DOLLHOUSE_HOOK_DEBUG:-0}" == "1" ]]; then
|
|
15
|
+
echo "[pretooluse-windsurf] $*" >&2
|
|
16
|
+
fi
|
|
17
|
+
return 0
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if [[ -f "$PORT_FILE" ]]; then
|
|
21
|
+
PORT=$(cat "$PORT_FILE" 2>/dev/null)
|
|
22
|
+
else
|
|
23
|
+
debug "No port file at $PORT_FILE — fail open"
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
if ! [[ "$PORT" =~ ^[0-9]+$ ]]; then
|
|
28
|
+
debug "Invalid port value: $PORT — fail open"
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
ENDPOINT="http://127.0.0.1:${PORT}/api/evaluate_permission"
|
|
33
|
+
INPUT=$(cat)
|
|
34
|
+
|
|
35
|
+
EVENT_NAME=$(echo "$INPUT" | jq -r '
|
|
36
|
+
.hook_event_name
|
|
37
|
+
// .hookEventName
|
|
38
|
+
// .event_name
|
|
39
|
+
// .eventName
|
|
40
|
+
// .event
|
|
41
|
+
// empty
|
|
42
|
+
' 2>/dev/null)
|
|
43
|
+
|
|
44
|
+
TOOL_NAME=''
|
|
45
|
+
TOOL_INPUT='{}'
|
|
46
|
+
|
|
47
|
+
case "$EVENT_NAME" in
|
|
48
|
+
pre_run_command)
|
|
49
|
+
TOOL_NAME='Bash'
|
|
50
|
+
TOOL_INPUT=$(echo "$INPUT" | jq -c '
|
|
51
|
+
. as $root
|
|
52
|
+
| {
|
|
53
|
+
command: (
|
|
54
|
+
$root.tool_info.command_line
|
|
55
|
+
// $root.toolInfo.commandLine
|
|
56
|
+
// $root.command_line
|
|
57
|
+
// $root.commandLine
|
|
58
|
+
// $root.command
|
|
59
|
+
// $root.input.command
|
|
60
|
+
// $root.tool_input.command
|
|
61
|
+
// ""
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
| if ($root.cwd // $root.working_directory // $root.workingDirectory // $root.tool_info.cwd // $root.toolInfo.cwd) != null
|
|
65
|
+
then . + { cwd: ($root.cwd // $root.working_directory // $root.workingDirectory // $root.tool_info.cwd // $root.toolInfo.cwd) }
|
|
66
|
+
else .
|
|
67
|
+
end
|
|
68
|
+
' 2>/dev/null)
|
|
69
|
+
;;
|
|
70
|
+
pre_mcp_tool_use)
|
|
71
|
+
TOOL_NAME=$(echo "$INPUT" | jq -r '
|
|
72
|
+
.tool_name
|
|
73
|
+
// .toolName
|
|
74
|
+
// .tool.name
|
|
75
|
+
// .tool_info.name
|
|
76
|
+
// .toolInfo.name
|
|
77
|
+
// .name
|
|
78
|
+
// .mcp_tool_name
|
|
79
|
+
// empty
|
|
80
|
+
' 2>/dev/null)
|
|
81
|
+
TOOL_INPUT=$(echo "$INPUT" | jq -c '
|
|
82
|
+
. as $root
|
|
83
|
+
| (
|
|
84
|
+
$root.tool_arguments
|
|
85
|
+
// $root.toolArgs
|
|
86
|
+
// $root.input.arguments
|
|
87
|
+
// $root.arguments
|
|
88
|
+
// $root.tool_input
|
|
89
|
+
// $root.input
|
|
90
|
+
// {}
|
|
91
|
+
)
|
|
92
|
+
| if ($root.server_name // $root.serverName // $root.mcp_server_name) != null
|
|
93
|
+
then . + { server_name: ($root.server_name // $root.serverName // $root.mcp_server_name) }
|
|
94
|
+
else .
|
|
95
|
+
end
|
|
96
|
+
' 2>/dev/null)
|
|
97
|
+
;;
|
|
98
|
+
*)
|
|
99
|
+
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // .toolName // .tool // .name // empty' 2>/dev/null)
|
|
100
|
+
TOOL_INPUT=$(echo "$INPUT" | jq -c '.tool_input // .toolInput // .input // {}' 2>/dev/null)
|
|
101
|
+
;;
|
|
102
|
+
esac
|
|
103
|
+
|
|
104
|
+
if [[ -z "$TOOL_NAME" ]]; then
|
|
105
|
+
debug "Could not parse Windsurf tool name — fail open"
|
|
106
|
+
exit 0
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
PAYLOAD=$(jq -cn \
|
|
110
|
+
--arg tool_name "$TOOL_NAME" \
|
|
111
|
+
--arg platform "$HOOK_PLATFORM" \
|
|
112
|
+
--arg session_id "${DOLLHOUSE_SESSION_ID:-}" \
|
|
113
|
+
--argjson input "$TOOL_INPUT" \
|
|
114
|
+
'{
|
|
115
|
+
tool_name: $tool_name,
|
|
116
|
+
input: $input,
|
|
117
|
+
platform: $platform
|
|
118
|
+
} + (if ($session_id | length) > 0 then { session_id: $session_id } else {} end)')
|
|
119
|
+
|
|
120
|
+
ATTEMPT=0
|
|
121
|
+
TIMEOUT=$INITIAL_TIMEOUT
|
|
122
|
+
|
|
123
|
+
while [[ $ATTEMPT -le $MAX_RETRIES ]]; do
|
|
124
|
+
RESPONSE=$(curl -s --max-time "$TIMEOUT" -X POST "$ENDPOINT" \
|
|
125
|
+
-H "Content-Type: application/json" \
|
|
126
|
+
-d "$PAYLOAD" \
|
|
127
|
+
2>/dev/null)
|
|
128
|
+
CURL_EXIT=$?
|
|
129
|
+
|
|
130
|
+
if [[ $CURL_EXIT -eq 0 ]] && [[ -n "$RESPONSE" ]]; then
|
|
131
|
+
ALLOWED=$(echo "$RESPONSE" | jq -r '
|
|
132
|
+
if .allowed == true then "true"
|
|
133
|
+
elif .allowed == false then "false"
|
|
134
|
+
elif .decision == "allow" then "true"
|
|
135
|
+
elif .decision == "deny" or .decision == "ask" then "false"
|
|
136
|
+
elif .hookSpecificOutput.permissionDecision == "allow" then "true"
|
|
137
|
+
elif .hookSpecificOutput.permissionDecision == "deny" or .hookSpecificOutput.permissionDecision == "ask" then "false"
|
|
138
|
+
else "unknown"
|
|
139
|
+
end
|
|
140
|
+
' 2>/dev/null)
|
|
141
|
+
|
|
142
|
+
if [[ "$ALLOWED" == "true" ]]; then
|
|
143
|
+
exit 0
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
if [[ "$ALLOWED" == "false" ]]; then
|
|
147
|
+
REASON=$(echo "$RESPONSE" | jq -r '
|
|
148
|
+
.reason
|
|
149
|
+
// .hookSpecificOutput.reason
|
|
150
|
+
// .hookSpecificOutput.permissionDecisionReason
|
|
151
|
+
// empty
|
|
152
|
+
' 2>/dev/null)
|
|
153
|
+
if [[ -n "$REASON" ]]; then
|
|
154
|
+
echo "$REASON" >&2
|
|
155
|
+
fi
|
|
156
|
+
exit 2
|
|
157
|
+
fi
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
ATTEMPT=$((ATTEMPT + 1))
|
|
161
|
+
if [[ $ATTEMPT -le $MAX_RETRIES ]]; then
|
|
162
|
+
sleep $((TIMEOUT * ATTEMPT))
|
|
163
|
+
TIMEOUT=$((TIMEOUT * 2))
|
|
164
|
+
fi
|
|
165
|
+
done
|
|
166
|
+
|
|
167
|
+
debug "Permission evaluation failed — fail open"
|
|
168
|
+
exit 0
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.DollhouseMCP/mcp-server",
|
|
4
4
|
"title": "DollhouseMCP",
|
|
5
5
|
"description": "OSS to create Personas, Skills, Templates, Agents, and Memories to customize your AI experience.",
|
|
6
|
-
"version": "2.0.
|
|
6
|
+
"version": "2.0.17",
|
|
7
7
|
"homepage": "https://dollhousemcp.com",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
{
|
|
30
30
|
"registryType": "npm",
|
|
31
31
|
"identifier": "@dollhousemcp/mcp-server",
|
|
32
|
-
"version": "2.0.
|
|
32
|
+
"version": "2.0.17",
|
|
33
33
|
"transport": {
|
|
34
34
|
"type": "stdio"
|
|
35
35
|
}
|