Skip to content

Commit 715b3f0

Browse files
Copilotgh-aw-bot
andauthored
Fix Linear MCP inspection
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
1 parent 3ce7dc0 commit 715b3f0

3 files changed

Lines changed: 59 additions & 2 deletions

File tree

‎docs/src/content/docs/reference/frontmatter-full.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4049,7 +4049,7 @@ tools:
40494049
# Optional Linear API key or OAuth access token secret reference. Defaults to ${{
40504050
# secrets.LINEAR_API_KEY }}.
40514051
# (optional)
4052-
token: "example-value"
4052+
token: "${{ secrets.LINEAR_API_KEY }}"
40534053

40544054
# Linear MCP toolset name(s) to enable. Toolsets are expanded to gateway-enforced
40554055
# allowed tools.
@@ -4068,7 +4068,7 @@ tools:
40684068
# List of allowed Linear MCP tool names or wildcard patterns. When toolsets are
40694069
# set, every pattern must match a tool in those toolsets.
40704070
# (optional)
4071-
allowed: []
4071+
allowed: ["*"]
40724072
# Array of strings
40734073

40744074
# Whether failure to connect to Linear should fail MCP gateway startup. Defaults

‎pkg/cli/mcp_validation.go‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,15 @@ func validateServerSecrets(config parser.RegistryMCPServerConfig, verbose bool,
139139
missingSecrets = append(missingSecrets, secret)
140140
}
141141
}
142+
for _, secret := range availableSecrets {
143+
if secret.Value == "" {
144+
continue
145+
}
146+
for key, value := range config.Headers {
147+
expression := "${{ secrets." + secret.Name + " }}"
148+
config.Headers[key] = strings.ReplaceAll(value, expression, secret.Value)
149+
}
150+
}
142151

143152
// Display information about secrets
144153
if verbose {

‎pkg/parser/mcp.go‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,12 +298,16 @@ func buildLinearBuiltinConfig(toolValue any) (*RegistryMCPServerConfig, error) {
298298
if !ok {
299299
return nil, errors.New("tools.linear must be an object")
300300
}
301+
if _, expanded := toolConfig["type"]; expanded {
302+
return buildExpandedLinearBuiltinConfig(toolConfig)
303+
}
301304
for field := range toolConfig {
302305
switch field {
303306
case "token", "toolsets", "allowed", "required":
304307
default:
305308
return nil, fmt.Errorf("unknown tools.linear property %q", field)
306309
}
310+
307311
}
308312

309313
token := constants.LinearMCPDefaultTokenExpr
@@ -343,6 +347,50 @@ func buildLinearBuiltinConfig(toolValue any) (*RegistryMCPServerConfig, error) {
343347
return config, nil
344348
}
345349

350+
func buildExpandedLinearBuiltinConfig(toolConfig map[string]any) (*RegistryMCPServerConfig, error) {
351+
for field := range toolConfig {
352+
switch field {
353+
case "type", "url", "headers", "allowed", "required":
354+
default:
355+
return nil, fmt.Errorf("unknown expanded tools.linear property %q", field)
356+
}
357+
}
358+
typeName, ok := toolConfig["type"].(string)
359+
if !ok || typeName != "http" {
360+
return nil, errors.New("expanded tools.linear type must be http")
361+
}
362+
url, ok := toolConfig["url"].(string)
363+
if !ok || url == "" {
364+
return nil, errors.New("expanded tools.linear url must be a non-empty string")
365+
}
366+
config := &RegistryMCPServerConfig{
367+
BaseMCPServerConfig: types.BaseMCPServerConfig{Type: typeName, URL: url, Headers: map[string]string{}},
368+
Name: "linear",
369+
}
370+
if headers, ok := toolConfig["headers"].(map[string]any); ok {
371+
for key, value := range headers {
372+
header, ok := value.(string)
373+
if !ok {
374+
return nil, fmt.Errorf("expanded tools.linear header %q must be a string", key)
375+
}
376+
config.Headers[key] = header
377+
}
378+
}
379+
allowed, err := buildLinearAllowedTools(toolConfig)
380+
if err != nil {
381+
return nil, err
382+
}
383+
config.Allowed = allowed
384+
if requiredValue, exists := toolConfig["required"]; exists {
385+
required, ok := requiredValue.(bool)
386+
if !ok {
387+
return nil, errors.New("tools.linear.required must be a boolean")
388+
}
389+
config.Required = &required
390+
}
391+
return config, nil
392+
}
393+
346394
func buildLinearAllowedTools(toolConfig map[string]any) ([]string, error) {
347395
var toolsetTools []string
348396
if toolsetsValue, exists := toolConfig["toolsets"]; exists {

0 commit comments

Comments
 (0)