@dollhousemcp/mcp-server 2.0.16 → 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 +6 -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/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 +19 -4
- package/dist/handlers/mcp-aql/OperationSchema.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/OperationSchema.js +3 -2
- package/dist/handlers/mcp-aql/evaluatePermission.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/evaluatePermission.js +2 -1
- 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/utils/permissionHooks.d.ts +39 -3
- package/dist/utils/permissionHooks.d.ts.map +1 -1
- package/dist/utils/permissionHooks.js +651 -74
- package/dist/web/public/permissions.js +38 -26
- package/dist/web/public/setup.js +367 -94
- package/dist/web/routes/permissionRoutes.d.ts.map +1 -1
- package/dist/web/routes/permissionRoutes.js +32 -13
- package/dist/web/routes/setupRoutes.d.ts +1 -0
- package/dist/web/routes/setupRoutes.d.ts.map +1 -1
- package/dist/web/routes/setupRoutes.js +113 -41
- package/package.json +3 -1
- package/scripts/pretooluse-vscode.sh +163 -0
- package/scripts/pretooluse-windsurf.sh +166 -4
- 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",
|
|
@@ -134,6 +134,7 @@
|
|
|
134
134
|
"dist/web/public/**",
|
|
135
135
|
"dist/seed-elements/**",
|
|
136
136
|
"scripts/pretooluse-dollhouse.sh",
|
|
137
|
+
"scripts/pretooluse-vscode.sh",
|
|
137
138
|
"scripts/pretooluse-cursor.sh",
|
|
138
139
|
"scripts/pretooluse-windsurf.sh",
|
|
139
140
|
"scripts/pretooluse-gemini.sh",
|
|
@@ -179,6 +180,7 @@
|
|
|
179
180
|
"otpauth": "^9.5.0",
|
|
180
181
|
"posthog-node": "^5.24.17",
|
|
181
182
|
"qrcode": "^1.5.4",
|
|
183
|
+
"smol-toml": "^1.6.1",
|
|
182
184
|
"uuid": "^11.1.0",
|
|
183
185
|
"zod": "^4.3.6"
|
|
184
186
|
},
|
|
@@ -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
|
|
@@ -1,6 +1,168 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# pretooluse-windsurf.sh —
|
|
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.
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
}
|