Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion .mise-tasks/seed.mts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { projectsRead } from "@gram/client/funcs/projectsRead.js";
import { toolsList } from "@gram/client/funcs/toolsList.js";
import { toolsetsCreate } from "@gram/client/funcs/toolsetsCreate.js";
import { toolsetsUpdateBySlug } from "@gram/client/funcs/toolsetsUpdateBySlug.js";
import { mcpMetadataSet } from "@gram/client/funcs/mcpMetadataSet.js";
import { ServiceError } from "@gram/client/models/errors";
import { $ } from "zx";

Expand All @@ -27,6 +28,8 @@ type Asset = {
slug: string;
filename: string;
storybookDefault?: boolean;
docsUrl?: string;
docsBtnText?: string;
};

const SEED_PROJECTS: {
Expand All @@ -47,6 +50,8 @@ const SEED_PROJECTS: {
slug: "kitchen-sink",
filename: path.join("local", "openapi", "kitchen-sink.json"),
storybookDefault: true,
docsUrl: "https://docs.getgram.ai",
docsBtnText: "Gram Docs",
},
{
type: "openapi",
Expand Down Expand Up @@ -149,6 +154,8 @@ async function seed() {
projectSlug,
assetSlug: asset.slug,
mcpPublic,
docsUrl: asset.docsUrl,
docsBtnText: asset.docsBtnText,
});
verb = toolset.created ? "Created" : "Updated";
log.info(
Expand Down Expand Up @@ -339,8 +346,10 @@ async function upsertToolset(init: {
projectSlug: string;
assetSlug: string;
mcpPublic: boolean;
docsUrl?: string;
docsBtnText?: string;
}): Promise<Toolset> {
const { gram, serverURL, sessionId, projectSlug, assetSlug, mcpPublic } =
const { gram, serverURL, sessionId, projectSlug, assetSlug, mcpPublic, docsUrl, docsBtnText } =
init;
const toolRes = await toolsList(
gram,
Expand Down Expand Up @@ -469,6 +478,29 @@ async function upsertToolset(init: {

log.info(`${toolset.mcpURL} visibility was changed to public`);

// Set MCP metadata if docs URL is provided
if (docsUrl) {
const metadataRes = await mcpMetadataSet(
gram,
{
setMcpMetadataRequestBody: {
toolsetSlug: toolset.slug,
externalDocumentationUrl: docsUrl,
externalDocumentationText: docsBtnText,
},
},
{
sessionHeaderGramSession: sessionId,
projectSlugHeaderGramProject: projectSlug,
},
);
if (!metadataRes.ok) {
log.warn(`Failed to set MCP metadata for toolset '${toolset.slug}': ${metadataRes.error}`);
} else {
log.info(`Set MCP metadata for toolset '${toolset.slug}' (docs: ${docsUrl})`);
}
}

return toolset;
}

Expand Down
1 change: 1 addition & 0 deletions server/database/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,7 @@ CREATE TABLE IF NOT EXISTS mcp_metadata (
toolset_id UUID NOT NULL,
project_id UUID NOT NULL,
external_documentation_url TEXT,
external_documentation_text TEXT,
logo_id UUID,
instructions TEXT,
header_display_names JSONB NOT NULL DEFAULT '{}'::JSONB, -- DEPRECATED: use mcp_environment_configs table instead
Expand Down
2 changes: 2 additions & 0 deletions server/design/mcpmetadata/design.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var McpMetadata = Type("McpMetadata", func() {
Attribute("external_documentation_url", String, "A link to external documentation for the MCP install page", func() {
Format(FormatURI)
})
Attribute("external_documentation_text", String, "Custom text for the external documentation link button")
Attribute("instructions", String, "Server instructions returned in the MCP initialize response")
Attribute("header_display_names", MapOf(String, String), "Maps security scheme keys to user-friendly display names")
Attribute("created_at", String, "When the metadata entry was created", func() {
Expand Down Expand Up @@ -75,6 +76,7 @@ var _ = Service("mcpMetadata", func() {
Attribute("toolset_slug", shared.Slug, "The slug of the toolset associated with this install page metadata")
Attribute("logo_asset_id", String, "The asset ID for the MCP install page logo")
Attribute("external_documentation_url", String, "A link to external documentation for the MCP install page")
Attribute("external_documentation_text", String, "Custom text for the external documentation link button")
Attribute("instructions", String, "Server instructions returned in the MCP initialize response")

Required("toolset_slug")
Expand Down
21 changes: 11 additions & 10 deletions server/internal/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion server/internal/mcpmetadata/hosted_page.html.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,7 @@ http_headers = { {{ range $i, $input := .SecurityInputs }}{{- if $i }}, {{ end }
target="_blank"
rel="noopener noreferrer"
>
View Docs
{{- if .DocsBtnText }}{{ .DocsBtnText }}{{- else }}View Docs{{- end }}
</a>
{{- end }}
<div class="popover">
Expand Down
2 changes: 2 additions & 0 deletions server/internal/mcpmetadata/impl.go

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 SetMcpMetadata doesn't handle ExternalDocumentationText payload field

The SetMcpMetadata function doesn't process the payload.ExternalDocumentationText field and doesn't pass it to the UpsertMetadataParams.

Click to expand

Impact

The API design at server/design/mcpmetadata/design.go:178 defines the payload attribute:

Attribute("external_documentation_text", String, "Custom text for the external documentation link button")

But SetMcpMetadata in impl.go only handles these fields from the payload:

  • ExternalDocumentationURL (line 211-214)
  • Instructions (line 216-219)
  • LogoAssetID, DefaultEnvironmentID, InstallationOverrideURL, etc.

The ExternalDocumentationText field is never read from the payload and never passed to UpsertMetadataParams at lines 235-243.

Expected behavior

The function should extract payload.ExternalDocumentationText and include it in the UpsertMetadataParams struct passed to s.repo.UpsertMetadata().

(Refers to lines 235-243)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ type hostedPageData struct {
SiteURL string
LogoAssetURL string
DocsURL string
DocsSlug string
Instructions string
IsPublic bool
}
Expand Down Expand Up @@ -473,6 +474,7 @@ func (s *Service) ServeInstallPage(w http.ResponseWriter, r *http.Request) error
SiteURL: s.siteURL.String(),
LogoAssetURL: logoAssetURL,
DocsURL: docsURL,
DocsSlug: "",
Instructions: instructions,
IsPublic: toolset.McpIsPublic,
}
Expand Down
21 changes: 11 additions & 10 deletions server/internal/mcpmetadata/repo/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions server/internal/mcpmetadata/repo/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Modify "mcp_metadata" table
ALTER TABLE "mcp_metadata" ADD COLUMN "external_documentation_text" text NULL;
3 changes: 2 additions & 1 deletion server/migrations/atlas.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
h1:Ah6FwNY+7w3q4GD+RVg4p37x0+s4EanTIw7Z1FM6Z90=
h1:m1lX8VXzuTZ+5vTa+8ZPZZqjTvTg+Th0gJuZo4dkg1w=
20250502122425_initial-tables.sql h1:Hu3O60/bB4fjZpUay8FzyOjw6vngp087zU+U/wVKn7k=
20250502130852_initial-indexes.sql h1:oYbnwi9y9PPTqu7uVbSPSALhCY8XF3rv03nDfG4b7mo=
20250502154250_relax-http-security-fields.sql h1:0+OYIDq7IHmx7CP5BChVwfpF2rOSrRDxnqawXio2EVo=
Expand Down Expand Up @@ -92,3 +92,4 @@ h1:Ah6FwNY+7w3q4GD+RVg4p37x0+s4EanTIw7Z1FM6Z90=
20260122192347_chat-content-raw-columns.sql h1:Y1XDsAX1O+f1hsJWFf3IG6pC33h9mtqWidy7RAm/4NI=
20260127002212_mcp_env_vars.sql h1:SyyU7ZXDITVxMGsSPCAjuBBNXNgxfm+3DjmV5YDV/FQ=
20260127183030_add_header_definitions_for_external_mcp.sql h1:zhgPD7ecRzM2VFj67jchsx0TiBLpLD4QoIvgT+7TKSw=
20260129185604_add-mcp-metadata-title-slug.sql h1:wfv8feFSIkRsB9YaooeRJGektgxqlHGwqJFKNVYOfMw=
Loading