@kitae9999/openlog-cli 1.0.0 → 1.1.0
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/README.md +20 -11
- package/dist/api-client.js +15 -1
- package/dist/config.js +4 -0
- package/dist/index.js +12 -32
- package/dist/mcp-install.js +5 -1
- package/dist/mcp-permissions-command.js +45 -0
- package/dist/mcp-permissions.js +103 -0
- package/dist/mcp-server.js +89 -93
- package/dist/mcp-toolkit.js +115 -0
- package/dist/mcp-workspace-tools.js +645 -0
- package/package.json +1 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { hasMcpCapability, } from "./mcp-permissions.js";
|
|
2
|
+
export const READ_TOOL_ANNOTATIONS = {
|
|
3
|
+
readOnlyHint: true,
|
|
4
|
+
destructiveHint: false,
|
|
5
|
+
idempotentHint: true,
|
|
6
|
+
openWorldHint: true,
|
|
7
|
+
};
|
|
8
|
+
export const WRITE_TOOL_ANNOTATIONS = {
|
|
9
|
+
readOnlyHint: false,
|
|
10
|
+
destructiveHint: false,
|
|
11
|
+
idempotentHint: false,
|
|
12
|
+
openWorldHint: true,
|
|
13
|
+
};
|
|
14
|
+
export const IDEMPOTENT_WRITE_TOOL_ANNOTATIONS = {
|
|
15
|
+
...WRITE_TOOL_ANNOTATIONS,
|
|
16
|
+
idempotentHint: true,
|
|
17
|
+
};
|
|
18
|
+
export const DELETE_TOOL_ANNOTATIONS = {
|
|
19
|
+
readOnlyHint: false,
|
|
20
|
+
destructiveHint: true,
|
|
21
|
+
idempotentHint: false,
|
|
22
|
+
openWorldHint: true,
|
|
23
|
+
};
|
|
24
|
+
export class McpToolRegistry {
|
|
25
|
+
server;
|
|
26
|
+
permissions;
|
|
27
|
+
createAuthenticatedClient;
|
|
28
|
+
toolNames = [];
|
|
29
|
+
constructor(server, permissions, createAuthenticatedClient) {
|
|
30
|
+
this.server = server;
|
|
31
|
+
this.permissions = permissions;
|
|
32
|
+
this.createAuthenticatedClient = createAuthenticatedClient;
|
|
33
|
+
}
|
|
34
|
+
registerAuthenticated(name, capability, config, handler) {
|
|
35
|
+
// 허용되지 않은 도구는 MCP tools/list 응답에도 나타나지 않게 등록 자체를 생략한다.
|
|
36
|
+
if (!hasMcpCapability(this.permissions, capability)) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const callback = (async (args) => {
|
|
40
|
+
// 목록 노출 여부와 별개로 실행 직전에도 권한을 확인해 우회 호출을 막는다.
|
|
41
|
+
if (!hasMcpCapability(this.permissions, capability)) {
|
|
42
|
+
return permissionDeniedResult(name, capability);
|
|
43
|
+
}
|
|
44
|
+
return withAuthenticatedClient(this.createAuthenticatedClient, (client) => handler(client, args));
|
|
45
|
+
});
|
|
46
|
+
this.server.registerTool(name, config, callback);
|
|
47
|
+
this.toolNames.push(name);
|
|
48
|
+
}
|
|
49
|
+
registerLocal(name, capability, config, handler) {
|
|
50
|
+
// 인증이 필요 없는 로컬 도구도 동일한 capability 정책을 적용한다.
|
|
51
|
+
if (!hasMcpCapability(this.permissions, capability)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const callback = (async (args) => {
|
|
55
|
+
if (!hasMcpCapability(this.permissions, capability)) {
|
|
56
|
+
return permissionDeniedResult(name, capability);
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
return textResult(await handler(args));
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return errorResult(error);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
this.server.registerTool(name, config, callback);
|
|
66
|
+
this.toolNames.push(name);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export async function withAuthenticatedClient(createAuthenticatedClient, callback) {
|
|
70
|
+
try {
|
|
71
|
+
const client = await createAuthenticatedClient();
|
|
72
|
+
return textResult(await callback(client));
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
// API·인증 오류를 throw하지 않고 MCP 표준 isError 응답으로 정규화한다.
|
|
76
|
+
return errorResult(error);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export function textResult(value) {
|
|
80
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
81
|
+
return {
|
|
82
|
+
content: [
|
|
83
|
+
{
|
|
84
|
+
type: "text",
|
|
85
|
+
text: serialized ?? "null",
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export function createContentPreview(content) {
|
|
91
|
+
const preview = content.replace(/\s+/g, " ").trim();
|
|
92
|
+
return preview.length > 500 ? `${preview.slice(0, 497)}...` : preview;
|
|
93
|
+
}
|
|
94
|
+
function permissionDeniedResult(name, capability) {
|
|
95
|
+
return {
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: "text",
|
|
99
|
+
text: `MCP tool ${name} requires the ${capability} capability. Change the profile with \`openlog mcp permissions set\` and restart the MCP server.`,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
isError: true,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function errorResult(error) {
|
|
106
|
+
return {
|
|
107
|
+
content: [
|
|
108
|
+
{
|
|
109
|
+
type: "text",
|
|
110
|
+
text: error instanceof Error ? error.message : String(error),
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
isError: true,
|
|
114
|
+
};
|
|
115
|
+
}
|