{{ message }}
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathannotations_mcp.md.CmleKmhL.js
More file actions
29 lines (29 loc) · 20.7 KB
/
Copy pathannotations_mcp.md.CmleKmhL.js
File metadata and controls
29 lines (29 loc) · 20.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import{_ as s,c as t,o as a,a5 as n}from"./chunks/framework.CgT1UzWm.js";const m=JSON.parse('{"title":"MCP Annotation","titleTemplate":"NpgsqlRest","description":"Opt a PostgreSQL routine in as a Model Context Protocol (MCP) tool. Expose functions to AI agents for discovery and execution, with an optional MCP-only (no HTTP route) mode.","frontmatter":{"outline":[2,3],"title":"MCP Annotation","titleTemplate":"NpgsqlRest","description":"Opt a PostgreSQL routine in as a Model Context Protocol (MCP) tool. Expose functions to AI agents for discovery and execution, with an optional MCP-only (no HTTP route) mode.","head":[["meta",{"name":"keywords","content":"npgsqlrest mcp annotation, model context protocol postgresql, expose function as mcp tool, ai agent tools, postgresql mcp server, mcp tool name"}],["meta",{"property":"og:title","content":"NpgsqlRest MCP Annotation"}],["meta",{"property":"og:description","content":"Opt a PostgreSQL routine in as an MCP tool for AI agents in NpgsqlRest."}],["meta",{"property":"og:type","content":"article"}],["link",{"rel":"canonical","href":"https://npgsqlrest.github.io/annotations/mcp.html"}],["meta",{"property":"og:url","content":"https://npgsqlrest.github.io/annotations/mcp.html"}],["meta",{"property":"og:image","content":"https://npgsqlrest.github.io/og-image.png"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:title","content":"NpgsqlRest MCP Annotation"}],["meta",{"name":"twitter:description","content":"Opt a PostgreSQL routine in as an MCP tool for AI agents in NpgsqlRest."}],["meta",{"name":"twitter:image","content":"https://npgsqlrest.github.io/og-image.png"}]]},"headers":[],"relativePath":"annotations/mcp.md","filePath":"annotations/mcp.md","lastUpdated":1780482668000}'),i={name:"annotations/mcp.md"};function o(l,e,r,p,c,d){return a(),t("div",null,e[0]||(e[0]=[n(`<h1 id="mcp" tabindex="-1">MCP <a class="header-anchor" href="#mcp" aria-label="Permalink to "MCP""></a></h1><div class="tip custom-block"><p class="custom-block-title">New in 3.17.0</p><p>The <code>@mcp</code> annotation and the <code>NpgsqlRest.Mcp</code> plugin were added in version 3.17.0. It implements the <a href="https://modelcontextprotocol.io/specification/2025-11-25" target="_blank" rel="noreferrer">Model Context Protocol</a> specification <strong>2025-11-25</strong>.</p></div><p>Opt a routine in as an <strong>MCP tool</strong> so an AI agent can discover it (<code>tools/list</code>) and execute it (<code>tools/call</code>) over the <a href="./../config/mcp.html">MCP server endpoint</a>.</p><p>Exposure is <strong>never automatic</strong> — a routine becomes a tool only when its comment carries <code>@mcp</code>. When the <a href="./../config/mcp.html">MCP plugin</a> is not loaded (or <code>McpOptions.Enabled</code> is <code>false</code>), the annotation is a no-op — safe to leave on a routine regardless of how the host is configured.</p><h2 id="syntax" tabindex="-1">Syntax <a class="header-anchor" href="#syntax" aria-label="Permalink to "Syntax""></a></h2><details class="code-collapsible" open><summary>code</summary><div class="language- vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes catppuccin-latte catppuccin-mocha vp-code" tabindex="0"><code><span class="line"><span>@mcp # expose as a tool; description from the comment prose</span></span>
<span class="line"><span>@mcp <text> # expose; <text> is an inline (explicit) tool description</span></span>
<span class="line"><span>@mcp_description <text> # expose; explicit, authoritative description (alias: @mcp_desc)</span></span>
<span class="line"><span>@mcp_name <name> # override the tool name (default: the routine name)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div></details><h3 id="description-precedence" tabindex="-1">Description precedence <a class="header-anchor" href="#description-precedence" aria-label="Permalink to "Description precedence""></a></h3><p>The tool's <code>description</code> uses a <strong>fixed priority</strong> — the highest-priority source that is present wins, <strong>regardless of the order the lines appear</strong> in the comment — and an explicit description <strong>suppresses</strong> the comment-prose fallback (so unrelated comment lines never leak into it):</p><ol><li><strong><code>@mcp_description <text></code></strong> — explicit and authoritative. Always wins when present, even if it appears <em>after</em> an <code>@mcp <text></code> line.</li><li><strong>inline <code>@mcp <text></code></strong> — explicit.</li><li><strong>comment prose</strong> — the routine's free-text comment lines (those that aren't annotations). Used only when no explicit description is given.</li><li><strong>the routine name</strong> — last resort (a warning is logged).</li></ol><p>So if you give <em>any</em> explicit description, the rest of your comment is just a comment. (Order only matters when you repeat the <em>same</em> annotation — the last occurrence wins.) Provide a description explicitly (preferably <code>@mcp_description</code>) whenever your comment also contains notes you don't want an agent to see; let the prose fallback do the work when your comment <em>is</em> the description.</p><h2 id="mcp-only-tools-no-http-route" tabindex="-1">MCP-only tools (no HTTP route) <a class="header-anchor" href="#mcp-only-tools-no-http-route" aria-label="Permalink to "MCP-only tools (no HTTP route)""></a></h2><p><strong>The HTTP tag controls the REST route; <code>@mcp</code> controls the tool — independently.</strong> A bare <code>@mcp</code> with <strong>no HTTP tag</strong> exposes the routine <strong>only</strong> as an MCP tool, with no public REST endpoint:</p><details class="code-collapsible" open><summary>sql</summary><div class="language-sql vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki shiki-themes catppuccin-latte catppuccin-mocha vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;">comment on function summarize_account(_account_id int) is </span><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">'</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">@mcp Summarize an account for the agent, including balance and recent activity.</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">'</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;">;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div></details><p>The routine is callable via <code>tools/call</code> but has no HTTP route — an endpoint that exists only because <code>@mcp</code> requested it is internal-only by default, so opting into MCP never silently widens your HTTP surface. (Requires the comment-gated modes — <code>OnlyAnnotated</code>, the client default, or <code>OnlyWithHttpTag</code>. A debug log notes the defaulting at startup.)</p><p>The full matrix:</p><div class="table-container"><div class="table-wrapper"><table tabindex="0"><thead><tr><th>Comment carries</th><th>Result</th></tr></thead><tbody><tr><td><code>HTTP GET</code> + <code>@mcp</code></td><td>REST endpoint <strong>and</strong> MCP tool</td></tr><tr><td><code>@mcp</code> only</td><td><strong>MCP-only</strong> (no REST route)</td></tr><tr><td><code>HTTP GET</code> only</td><td>REST-only (no tool)</td></tr><tr><td><code>HTTP GET</code> + <code>@mcp</code> + <a href="./internal.html"><code>@internal</code></a></td><td>MCP-only (<code>@internal</code> hides the declared route)</td></tr></tbody></table></div></div><p>This works identically for <strong>SQL file endpoints</strong>: a <code>.sql</code> file whose comment carries <code>@mcp</code> but no <code>HTTP</code> tag becomes an MCP-only tool (without <code>@mcp</code> such a file is skipped as a non-endpoint script, as before).</p><p>All other annotations apply equally — most usefully <a href="./authorize.html"><code>@authorize</code></a>: when a tool runs, the caller's authenticated identity is forwarded, so role checks are enforced exactly as they would be for the HTTP endpoint.</p><h2 id="examples" tabindex="-1">Examples <a class="header-anchor" href="#examples" aria-label="Permalink to "Examples""></a></h2><h3 id="expose-a-routine-as-a-tool-http-and-mcp" tabindex="-1">Expose a routine as a tool (HTTP <strong>and</strong> MCP) <a class="header-anchor" href="#expose-a-routine-as-a-tool-http-and-mcp" aria-label="Permalink to "Expose a routine as a tool (HTTP **and** MCP)""></a></h3><details class="code-collapsible" open><summary>sql</summary><div class="language-sql vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki shiki-themes catppuccin-latte catppuccin-mocha vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;">create</span><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;"> function</span><span style="--shiki-light:#1E66F5;--shiki-light-font-style:italic;--shiki-dark:#89B4FA;--shiki-dark-font-style:italic;"> get_weather</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;">(_city </span><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;">text</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;">)</span></span>
<span class="line"><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;">returns</span><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;"> text</span></span>
<span class="line"><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;">language</span><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;"> sql</span><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;"> as</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;"> $$</span></span>
<span class="line"><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;"> select</span><span style="--shiki-light:#1E66F5;--shiki-light-font-style:italic;--shiki-dark:#89B4FA;--shiki-dark-font-style:italic;"> format</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;">(</span><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">'Weather for %s: sunny, 22C'</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;">, _city);</span></span>
<span class="line"><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;">$$;</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;">comment on function get_weather(_city text) is </span><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">'</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">HTTP GET /api/weather</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">@mcp Get the current weather for a city.</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">'</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;">;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div></details><p>The routine is reachable at <code>GET /api/weather</code> <strong>and</strong> advertised as the <code>get_weather</code> MCP tool with the description <em>"Get the current weather for a city."</em> and an input schema derived from its parameters (<code>{ "city": { "type": "string" } }</code>).</p><h3 id="description-from-comment-prose" tabindex="-1">Description from comment prose <a class="header-anchor" href="#description-from-comment-prose" aria-label="Permalink to "Description from comment prose""></a></h3><details class="code-collapsible" open><summary>sql</summary><div class="language-sql vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki shiki-themes catppuccin-latte catppuccin-mocha vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;">comment on function list_open_tickets() is </span><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">'</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">HTTP GET /api/tickets/open</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">List all currently open support tickets for triage.</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">@mcp</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">'</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;">;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div></details><p>With a bare <code>@mcp</code>, the description is taken from the prose line — <em>"List all currently open support tickets for triage."</em></p><h3 id="explicit-description-with-a-private-note-that-stays-out-of-it" tabindex="-1">Explicit description, with a private note that stays out of it <a class="header-anchor" href="#explicit-description-with-a-private-note-that-stays-out-of-it" aria-label="Permalink to "Explicit description, with a private note that stays out of it""></a></h3><details class="code-collapsible" open><summary>sql</summary><div class="language-sql vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki shiki-themes catppuccin-latte catppuccin-mocha vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;">comment on function rebuild_search_index() is </span><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">'</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">HTTP POST</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">@mcp Rebuild the product search index. Safe to call; runs in the background.</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">@mcp_description Rebuild the product search index. Returns immediately.</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">TODO: revisit batch size — internal note, must NOT reach the agent.</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">'</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;">;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div></details><p>Because <code>@mcp_description</code> is present, it is the description verbatim — the inline <code>@mcp</code> text and the <code>TODO:</code> prose line are both ignored. (For SQL-file endpoints, also see <a href="./../config/sql-file-source.html"><code>SqlFileSource.CommentScope</code></a>, which controls <em>which</em> comments are parsed at all.)</p><h3 id="override-the-tool-name" tabindex="-1">Override the tool name <a class="header-anchor" href="#override-the-tool-name" aria-label="Permalink to "Override the tool name""></a></h3><details class="code-collapsible" open><summary>sql</summary><div class="language-sql vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki shiki-themes catppuccin-latte catppuccin-mocha vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;">comment on function fn_q1_report() is </span><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">'</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">@mcp Quarterly revenue report.</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">@mcp_name quarterly_report</span></span>
<span class="line"><span style="--shiki-light:#40A02B;--shiki-dark:#A6E3A1;">'</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;">;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div></details><p>The tool is published as <code>quarterly_report</code> rather than <code>fn_q1_report</code> — and since there is no HTTP tag, it is <a href="#mcp-only-tools-no-http-route">MCP-only</a> (no REST route).</p><p><strong>As a SQL file endpoint</strong> (<code>sql/quarterly-report.sql</code>):</p><details class="code-collapsible" open><summary>sql</summary><div class="language-sql vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki shiki-themes catppuccin-latte catppuccin-mocha vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#9CA0B0;--shiki-light-font-style:italic;--shiki-dark:#6C7086;--shiki-dark-font-style:italic;">-- @mcp Quarterly revenue report.</span></span>
<span class="line"><span style="--shiki-light:#9CA0B0;--shiki-light-font-style:italic;--shiki-dark:#6C7086;--shiki-dark-font-style:italic;">-- @mcp_name quarterly_report</span></span>
<span class="line"><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;">select</span><span style="--shiki-light:#179299;--shiki-dark:#94E2D5;"> *</span><span style="--shiki-light:#8839EF;--shiki-dark:#CBA6F7;"> from</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;"> generate_quarterly_report</span><span style="--shiki-light:#7C7F93;--shiki-dark:#9399B2;">()</span><span style="--shiki-light:#4C4F69;--shiki-dark:#CDD6F4;">;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div></details><h2 id="recognized-keywords" tabindex="-1">Recognized keywords <a class="header-anchor" href="#recognized-keywords" aria-label="Permalink to "Recognized keywords""></a></h2><div class="table-container"><div class="table-wrapper"><table tabindex="0"><thead><tr><th>Form</th><th>Action</th></tr></thead><tbody><tr><td><code>@mcp</code></td><td>Expose as a tool; description from comment prose</td></tr><tr><td><code>@mcp <text></code></td><td>Expose as a tool; <code><text></code> is an inline (explicit) description</td></tr><tr><td><code>@mcp_description <text></code></td><td>Expose as a tool; explicit, authoritative description (alias <code>@mcp_desc</code>) — suppresses comment prose</td></tr><tr><td><code>@mcp_name <name></code></td><td>Override the tool name</td></tr></tbody></table></div></div><h2 id="related" tabindex="-1">Related <a class="header-anchor" href="#related" aria-label="Permalink to "Related""></a></h2><ul><li><a href="./../config/mcp.html">MCP Configuration</a> - Enable the MCP server endpoint, set server name/version/instructions</li><li><a href="./internal.html">internal annotation</a> - Hide a declared HTTP route (a bare <code>@mcp</code> with no HTTP tag is already MCP-only)</li><li><a href="./authorize.html">authorize annotation</a> - Role checks are enforced on tool calls via the forwarded identity</li><li><a href="./../guide/annotations.html">Comment Annotations Guide</a> - How annotations work</li><li><a href="./../blog/mcp-server-postgresql-ai-tools-npgsqlrest.html">Blog: Turn PostgreSQL into MCP Tools an AI Agent Can Call</a> - A complete walkthrough with a real Claude agent driving the store</li></ul>`,37)]))}const u=s(i,[["render",o]]);export{m as __pageData,u as default};
You can’t perform that action at this time.
