mcp_lite 2.0.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +584 -0
- data/Rakefile +9 -0
- data/lib/mcp_lite/completion.rb +21 -0
- data/lib/mcp_lite/configuration.rb +22 -0
- data/lib/mcp_lite/executor/resource_reader.rb +70 -0
- data/lib/mcp_lite/executor/tool_executor.rb +102 -0
- data/lib/mcp_lite/message/audio.rb +22 -0
- data/lib/mcp_lite/message/image.rb +24 -0
- data/lib/mcp_lite/message/resource.rb +24 -0
- data/lib/mcp_lite/message/text.rb +20 -0
- data/lib/mcp_lite/prompt/base.rb +52 -0
- data/lib/mcp_lite/resource/base.rb +79 -0
- data/lib/mcp_lite/schema/base.rb +141 -0
- data/lib/mcp_lite/schema/method.rb +20 -0
- data/lib/mcp_lite/server/error_code.rb +14 -0
- data/lib/mcp_lite/server/fetcher.rb +55 -0
- data/lib/mcp_lite/server/method.rb +18 -0
- data/lib/mcp_lite/server/protocol_handler.rb +200 -0
- data/lib/mcp_lite/server/stdio_connection.rb +21 -0
- data/lib/mcp_lite/server.rb +81 -0
- data/lib/mcp_lite/tool/base.rb +68 -0
- data/lib/mcp_lite/version.rb +3 -0
- data/lib/mcp_lite.rb +21 -0
- metadata +78 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
module McpLite
|
2
|
+
module Executor
|
3
|
+
class ResourceReader
|
4
|
+
def initialize(schema:, context: {})
|
5
|
+
@schema = schema
|
6
|
+
@context = context
|
7
|
+
end
|
8
|
+
|
9
|
+
def read(uri:)
|
10
|
+
unless uri
|
11
|
+
return {
|
12
|
+
isError: true,
|
13
|
+
contents: []
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
resource = @schema.visible_resources.find do |r|
|
18
|
+
r.uri == uri
|
19
|
+
end
|
20
|
+
|
21
|
+
unless resource
|
22
|
+
return {
|
23
|
+
isError: true,
|
24
|
+
contents: []
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
if resource.class.respond_to?(:visible?) && !resource.class.visible?(context: @context)
|
29
|
+
return {
|
30
|
+
isError: true,
|
31
|
+
contents: []
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
begin
|
36
|
+
if resource.respond_to?(:text) && (content = resource.content)
|
37
|
+
{
|
38
|
+
contents: [
|
39
|
+
{
|
40
|
+
uri:,
|
41
|
+
mimeType: resource.class.mime_type_value,
|
42
|
+
text: content
|
43
|
+
}
|
44
|
+
]
|
45
|
+
}
|
46
|
+
elsif (content = resource.blob)
|
47
|
+
{
|
48
|
+
contents: [
|
49
|
+
{
|
50
|
+
uri:,
|
51
|
+
mimeType: resource.class.mime_type_value,
|
52
|
+
blob: Base64.strict_encode64(content)
|
53
|
+
}
|
54
|
+
]
|
55
|
+
}
|
56
|
+
end
|
57
|
+
rescue
|
58
|
+
{
|
59
|
+
isError: true,
|
60
|
+
contents: []
|
61
|
+
}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
attr_reader :schema, :context
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module McpLite
|
2
|
+
module Executor
|
3
|
+
class ToolExecutor
|
4
|
+
def initialize(schema:, context: {})
|
5
|
+
@schema = schema
|
6
|
+
@context = context
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute(name:, arguments: nil)
|
10
|
+
unless name
|
11
|
+
return {
|
12
|
+
isError: true,
|
13
|
+
content: [
|
14
|
+
{
|
15
|
+
type: "text",
|
16
|
+
text: "Invalid params: missing tool name"
|
17
|
+
}
|
18
|
+
]
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
tool = schema.visible_tools&.find do |tc|
|
23
|
+
tc.class.tool_name_value == name
|
24
|
+
end
|
25
|
+
|
26
|
+
unless tool
|
27
|
+
return {
|
28
|
+
isError: true,
|
29
|
+
content: [
|
30
|
+
{
|
31
|
+
type: "text",
|
32
|
+
text: "Tool not found: #{name}"
|
33
|
+
}
|
34
|
+
]
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
unless tool.class.visible?(context:)
|
39
|
+
return {
|
40
|
+
isError: true,
|
41
|
+
content: [
|
42
|
+
{
|
43
|
+
type: "text",
|
44
|
+
text: "Unauthorized: Access to tool '#{name}' denied"
|
45
|
+
}
|
46
|
+
]
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
args = if arguments.is_a?(String)
|
51
|
+
JSON.parse(arguments, symbolize_names: true)
|
52
|
+
elsif arguments.respond_to?(:to_hash)
|
53
|
+
arguments.to_hash.transform_keys(&:to_sym)
|
54
|
+
else
|
55
|
+
{}
|
56
|
+
end
|
57
|
+
|
58
|
+
args = args.transform_values do |value|
|
59
|
+
if !value.is_a?(String)
|
60
|
+
value
|
61
|
+
else
|
62
|
+
/^\d+$/.match?(value) ? value.to_i : value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
validation_result = tool.validate(args, @context)
|
67
|
+
|
68
|
+
if validation_result.is_a?(Hash) && validation_result[:error]
|
69
|
+
return {
|
70
|
+
isError: true,
|
71
|
+
content: [
|
72
|
+
{
|
73
|
+
type: "text",
|
74
|
+
text: validation_result[:error]
|
75
|
+
}
|
76
|
+
]
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
begin
|
81
|
+
{
|
82
|
+
content: tool.call(**args, context:)
|
83
|
+
}
|
84
|
+
rescue => e
|
85
|
+
{
|
86
|
+
isError: true,
|
87
|
+
content: [
|
88
|
+
{
|
89
|
+
type: "text",
|
90
|
+
text: "Error: #{e.message}"
|
91
|
+
}
|
92
|
+
]
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
attr_reader :schema, :context
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module McpLite
|
2
|
+
module Message
|
3
|
+
class Audio
|
4
|
+
def initialize(role:, data:, mime_type:)
|
5
|
+
@role = role
|
6
|
+
@data = data
|
7
|
+
@mime_type = mime_type
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_h
|
11
|
+
{
|
12
|
+
role: @role,
|
13
|
+
content: {
|
14
|
+
type: "audio",
|
15
|
+
data: Base64.strict_encode64(@data),
|
16
|
+
mimeType: @mime_type
|
17
|
+
}
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module McpLite
|
4
|
+
module Message
|
5
|
+
class Image
|
6
|
+
def initialize(role:, data:, mime_type:)
|
7
|
+
@role = role
|
8
|
+
@data = data
|
9
|
+
@mime_type = mime_type
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_h
|
13
|
+
{
|
14
|
+
role: @role,
|
15
|
+
content: {
|
16
|
+
type: "image",
|
17
|
+
data: Base64.strict_encode64(@data),
|
18
|
+
mimeType: @mime_type
|
19
|
+
}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module McpLite
|
2
|
+
module Message
|
3
|
+
class Resource
|
4
|
+
def initialize(role:, resource:)
|
5
|
+
@role = role
|
6
|
+
@resource = resource
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_h
|
10
|
+
{
|
11
|
+
role: @role,
|
12
|
+
content: {
|
13
|
+
type: "resource",
|
14
|
+
resource: {
|
15
|
+
uri: @resource.uri,
|
16
|
+
mimeType: @resource.class.mime_type_value,
|
17
|
+
text: @resource.content
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module McpLite
|
2
|
+
module Prompt
|
3
|
+
class Base
|
4
|
+
class << self
|
5
|
+
attr_reader :prompt_name_value, :description_value, :arguments
|
6
|
+
|
7
|
+
def prompt_name(value)
|
8
|
+
@prompt_name_value = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def description(value)
|
12
|
+
@description_value = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def argument(name, required: false, description: "", complete: -> {})
|
16
|
+
@arguments ||= []
|
17
|
+
|
18
|
+
@arguments << {
|
19
|
+
name:,
|
20
|
+
description:,
|
21
|
+
required:,
|
22
|
+
complete:
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(*args, context: {})
|
28
|
+
@context = context
|
29
|
+
end
|
30
|
+
|
31
|
+
def prompt_name_value
|
32
|
+
self.class.prompt_name_value
|
33
|
+
end
|
34
|
+
|
35
|
+
def description_value
|
36
|
+
self.class.description_value
|
37
|
+
end
|
38
|
+
|
39
|
+
def arguments
|
40
|
+
self.class.arguments
|
41
|
+
end
|
42
|
+
|
43
|
+
def visible?(context: {})
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
def messages(**args)
|
48
|
+
raise NotImplementedError, "#{self.class.name}#messages must be implemented"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "json-schema"
|
2
|
+
|
3
|
+
module McpLite
|
4
|
+
module Resource
|
5
|
+
class Base
|
6
|
+
class << self
|
7
|
+
attr_reader :resource_template_name_value, :description_value, :mime_type_value, :uri_template_value, :schema, :arguments
|
8
|
+
|
9
|
+
def resource_template_name(value)
|
10
|
+
@resource_template_name_value = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def uri_template(value)
|
14
|
+
@uri_template_value = value
|
15
|
+
end
|
16
|
+
|
17
|
+
def description(value)
|
18
|
+
@description_value = value
|
19
|
+
end
|
20
|
+
|
21
|
+
def mime_type(value)
|
22
|
+
@mime_type_value = value
|
23
|
+
end
|
24
|
+
|
25
|
+
def argument(name, complete:)
|
26
|
+
@arguments = {}
|
27
|
+
@arguments[name] = complete
|
28
|
+
end
|
29
|
+
|
30
|
+
def visible?(context: {})
|
31
|
+
true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
end
|
37
|
+
|
38
|
+
def visible?(context: {})
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
def resource_template_name_value
|
43
|
+
self.class.resource_template_name_value
|
44
|
+
end
|
45
|
+
|
46
|
+
def description_value
|
47
|
+
self.class.description_value
|
48
|
+
end
|
49
|
+
|
50
|
+
def mime_type_value
|
51
|
+
self.class.mime_type_value
|
52
|
+
end
|
53
|
+
|
54
|
+
def uri_template_value
|
55
|
+
self.class.uri_template_value
|
56
|
+
end
|
57
|
+
|
58
|
+
def resource_name
|
59
|
+
end
|
60
|
+
|
61
|
+
def uri
|
62
|
+
end
|
63
|
+
|
64
|
+
def description
|
65
|
+
end
|
66
|
+
|
67
|
+
def content
|
68
|
+
case text
|
69
|
+
when String
|
70
|
+
text
|
71
|
+
when Hash
|
72
|
+
text.to_json
|
73
|
+
else
|
74
|
+
text.to_s
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require_relative "method"
|
2
|
+
require_relative "../executor/resource_reader"
|
3
|
+
require_relative "../executor/tool_executor"
|
4
|
+
|
5
|
+
module McpLite
|
6
|
+
module Schema
|
7
|
+
class Base
|
8
|
+
class << self
|
9
|
+
attr_reader :tools, :resources, :prompts, :context
|
10
|
+
|
11
|
+
def tool(value)
|
12
|
+
@tools ||= []
|
13
|
+
@tools << value
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource(value, items: [])
|
17
|
+
@resources ||= []
|
18
|
+
@resources << {klass: value, items:}
|
19
|
+
end
|
20
|
+
|
21
|
+
def prompt(value)
|
22
|
+
@prompts ||= []
|
23
|
+
@prompts << value
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute(params:, context: {})
|
27
|
+
@context = context
|
28
|
+
|
29
|
+
case params[:method]
|
30
|
+
when Method::INITIALIZE
|
31
|
+
{
|
32
|
+
result: {
|
33
|
+
protocolVersion: "0.1.0",
|
34
|
+
capabilities: {
|
35
|
+
resources: {},
|
36
|
+
tools: {},
|
37
|
+
prompts: {}
|
38
|
+
},
|
39
|
+
serverInfo: {
|
40
|
+
name: "McpLite",
|
41
|
+
version: "1.0.0"
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
when Method::INITIALIZED
|
46
|
+
{result: {}}
|
47
|
+
when Method::CANCELLED
|
48
|
+
{result: {}}
|
49
|
+
when Method::RESOURCES_LIST
|
50
|
+
resources = visible_resources.map { |r| {name: r.resource_name, uri: r.uri, description: r.description, mimeType: r.class.mime_type_value } }
|
51
|
+
{result: {resources: resources}}
|
52
|
+
when Method::RESOURCES_TEMPLATES_LIST
|
53
|
+
templates = visible_resource_templates.map { |r| {uriTemplate: r.uri_template_value, name: r.resource_template_name_value} }
|
54
|
+
{result: {resourceTemplates: templates}}
|
55
|
+
when Method::RESOURCES_READ
|
56
|
+
uri = params.dig(:params, :uri)
|
57
|
+
resource = resource_reader.read(uri:)
|
58
|
+
{result: resource}
|
59
|
+
when Method::TOOLS_LIST
|
60
|
+
tools = visible_tools.map do |tool|
|
61
|
+
{
|
62
|
+
name: tool.class.tool_name_value,
|
63
|
+
description: tool.class.description_value,
|
64
|
+
inputSchema: tool.class.render_schema(context),
|
65
|
+
}
|
66
|
+
end
|
67
|
+
{result: {tools: tools}}
|
68
|
+
when Method::TOOLS_CALL
|
69
|
+
name = params.dig(:params, :name)
|
70
|
+
arguments = params.dig(:params, :arguments)
|
71
|
+
unless arguments.is_a?(Hash)
|
72
|
+
arguments = arguments.permit!.to_hash.symbolize_keys
|
73
|
+
end
|
74
|
+
result = tool_executor.execute(name:, arguments:)
|
75
|
+
{result:}
|
76
|
+
when Method::COMPLETION_COMPLETE
|
77
|
+
type = params.dig(:params, :ref, :type)
|
78
|
+
completion = McpLite::Completion.new.complete(
|
79
|
+
params: params[:params],
|
80
|
+
context:,
|
81
|
+
refs: (type == "ref/resource") ? visible_resource_templates : visible_prompts
|
82
|
+
)
|
83
|
+
{result: {completion: completion}}
|
84
|
+
when Method::PROMPTS_LIST
|
85
|
+
prompts = visible_prompts.map do |prompt|
|
86
|
+
{
|
87
|
+
name: prompt.prompt_name_value,
|
88
|
+
description: prompt.description_value,
|
89
|
+
arguments: prompt.arguments.map { _1.except(:complete) }
|
90
|
+
}
|
91
|
+
end
|
92
|
+
{result: {prompts: prompts}}
|
93
|
+
when Method::PROMPTS_GET
|
94
|
+
prompt = visible_prompts&.find { _1.prompt_name_value == params[:params][:name] }
|
95
|
+
arguments = params.dig(:params, :arguments)
|
96
|
+
unless arguments.is_a?(Hash)
|
97
|
+
arguments = arguments.permit!.to_h.symbolize_keys
|
98
|
+
end
|
99
|
+
messages = prompt.new.messages(**arguments)
|
100
|
+
{result: {messages: messages.map(&:to_h)}}
|
101
|
+
else
|
102
|
+
{result: {}}
|
103
|
+
い end
|
104
|
+
end
|
105
|
+
|
106
|
+
def visible_resources
|
107
|
+
resources&.filter do |resource|
|
108
|
+
resource[:klass].visible?(context: @context)
|
109
|
+
end&.map do |resource|
|
110
|
+
resource[:items].map do |item|
|
111
|
+
resource[:klass].new(**item)
|
112
|
+
end
|
113
|
+
end&.flatten || []
|
114
|
+
end
|
115
|
+
|
116
|
+
def visible_resource_templates
|
117
|
+
visibles = resources&.filter do |resource|
|
118
|
+
resource[:klass].uri_template_value && resource[:klass].visible?(context: @context)
|
119
|
+
end
|
120
|
+
visibles&.map { _1[:klass] } || []
|
121
|
+
end
|
122
|
+
|
123
|
+
def visible_tools
|
124
|
+
tools&.map(&:new) || []
|
125
|
+
end
|
126
|
+
|
127
|
+
def visible_prompts
|
128
|
+
prompts || []
|
129
|
+
end
|
130
|
+
|
131
|
+
def resource_reader
|
132
|
+
@resource_reader ||= Executor::ResourceReader.new(schema: self, context:)
|
133
|
+
end
|
134
|
+
|
135
|
+
def tool_executor
|
136
|
+
@tool_executor ||= Executor::ToolExecutor.new(schema: self, context:)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module McpLite
|
4
|
+
module Schema
|
5
|
+
module Method
|
6
|
+
INITIALIZE = "initialize"
|
7
|
+
INITIALIZED = "notifications/initialized"
|
8
|
+
CANCELLED = "notifications/cancelled"
|
9
|
+
PING = "ping"
|
10
|
+
TOOLS_LIST = "tools/list"
|
11
|
+
TOOLS_CALL = "tools/call"
|
12
|
+
RESOURCES_LIST = "resources/list"
|
13
|
+
RESOURCES_READ = "resources/read"
|
14
|
+
RESOURCES_TEMPLATES_LIST = "resources/templates/list"
|
15
|
+
COMPLETION_COMPLETE = "completion/complete"
|
16
|
+
PROMPTS_LIST = "prompts/list"
|
17
|
+
PROMPTS_GET = "prompts/get"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module McpLite
|
4
|
+
module ErrorCode
|
5
|
+
NOT_INITIALIZED = -32_002
|
6
|
+
ALREADY_INITIALIZED = -32_002
|
7
|
+
|
8
|
+
PARSE_ERROR = -32_700
|
9
|
+
INVALID_REQUEST = -32_600
|
10
|
+
METHOD_NOT_FOUND = -32_601
|
11
|
+
INVALID_PARAMS = -32_602
|
12
|
+
INTERNAL_ERROR = -32_603
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module McpLite
|
2
|
+
class Server
|
3
|
+
class Fetcher
|
4
|
+
def initialize(base_uri: nil, headers: {})
|
5
|
+
@base_uri = base_uri
|
6
|
+
|
7
|
+
if headers.is_a?(Hash)
|
8
|
+
@headers = headers
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(params:)
|
13
|
+
return unless @base_uri
|
14
|
+
|
15
|
+
require "net/http"
|
16
|
+
|
17
|
+
unless @base_uri.is_a?(URI) || @base_uri.is_a?(String)
|
18
|
+
Server.log_error("Invalid URI type", StandardError.new("URI must be a String or URI object"))
|
19
|
+
return
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
uri = URI.parse(@base_uri.to_s)
|
24
|
+
|
25
|
+
unless uri.scheme =~ /\Ahttps?\z/ && !uri.host.nil?
|
26
|
+
Server.log_error("Invalid URI", StandardError.new("URI must have a valid scheme and host"))
|
27
|
+
return
|
28
|
+
end
|
29
|
+
rescue URI::InvalidURIError => e
|
30
|
+
Server.log_error("Invalid URI format", e)
|
31
|
+
return
|
32
|
+
end
|
33
|
+
|
34
|
+
request = Net::HTTP::Post.new(uri)
|
35
|
+
request.body = JSON.generate(params)
|
36
|
+
request["Content-Type"] = "application/json"
|
37
|
+
request["Accept"] = "application/json"
|
38
|
+
@headers.each do |key, value|
|
39
|
+
request[key] = value
|
40
|
+
end
|
41
|
+
|
42
|
+
begin
|
43
|
+
response = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
44
|
+
http.request(request)
|
45
|
+
end
|
46
|
+
|
47
|
+
JSON.parse(response.body, symbolize_names: true)
|
48
|
+
rescue => e
|
49
|
+
Server.log_error("Error fetching resource_templates", e)
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module McpLite
|
4
|
+
module Method
|
5
|
+
INITIALIZE = "initialize"
|
6
|
+
INITIALIZED = "notifications/initialized"
|
7
|
+
CANCELLED = "notifications/cancelled"
|
8
|
+
PING = "ping"
|
9
|
+
TOOLS_LIST = "tools/list"
|
10
|
+
TOOLS_CALL = "tools/call"
|
11
|
+
RESOURCES_LIST = "resources/list"
|
12
|
+
RESOURCES_READ = "resources/read"
|
13
|
+
RESOURCES_TEMPLATES_LIST = "resources/templates/list"
|
14
|
+
COMPLETION_COMPLETE = "completion/complete"
|
15
|
+
PROMPTS_LIST = "prompts/list"
|
16
|
+
PROMPTS_GET = "prompts/get"
|
17
|
+
end
|
18
|
+
end
|