@@ -205,6 +205,43 @@ export function buildMcpServer(options = {}) {
205205 return server ;
206206}
207207
208+ // Static server card for registries that prefer not to (or can't)
209+ // auto-scan via Streamable HTTP — e.g. Smithery's fallback path
210+ // described in https://smithery.ai/docs/build/publish#server-scanning,
211+ // and SEP-1649 well-known discovery.
212+ //
213+ // Kept in sync with registerTools() by reading the tool definitions
214+ // from the server instance at startup. The Caddy layer serves this at
215+ // /.well-known/mcp/server-card.json on mcp.seneschal.space.
216+ export function getStaticServerCard ( ) {
217+ return {
218+ serverInfo : {
219+ name : 'Seneschal Data API' ,
220+ version : '0.1.0' ,
221+ vendor : 'Seneschal' ,
222+ homepage : 'https://seneschal.space'
223+ } ,
224+ authentication : { required : false } ,
225+ transport : {
226+ type : 'streamable-http' ,
227+ url : 'https://mcp.seneschal.space/'
228+ } ,
229+ tools : [
230+ { name : 'seneschal_health' , description : 'Service liveness plus row counts and data-source mtimes.' } ,
231+ { name : 'seneschal_list_at_risk_borrowers' , description : 'Borrowers across Aave/Morpho/Spark below max_hf, sorted ascending.' } ,
232+ { name : 'seneschal_list_borrowers' , description : 'Generic discovery surface with HF + debt range filters, sort, offset.' } ,
233+ { name : 'seneschal_recent_liquidations' , description : 'Recent on-chain liquidation events.' } ,
234+ { name : 'seneschal_get_borrower' , description : 'Latest snapshot for one borrower across protocols.' } ,
235+ { name : 'seneschal_get_borrower_history' , description : 'Time-series HF traces for one borrower.' } ,
236+ { name : 'seneschal_builder_leaderboard' , description : 'Ground-truth Ethereum builder market share.' } ,
237+ { name : 'seneschal_stats_overview' , description : 'Aggregate snapshot powering the public stats dashboard.' } ,
238+ { name : 'seneschal_flashloan_providers' , description : 'Curated catalogue of mainnet flash-loan providers including FlashBank.' }
239+ ] ,
240+ resources : [ ] ,
241+ prompts : [ ]
242+ } ;
243+ }
244+
208245// HTTP listener creating a fresh stateless transport per request.
209246// This is the recommended pattern from the MCP SDK docs for stateless
210247// public servers — no session affinity required, trivial to put
@@ -232,6 +269,18 @@ export function startMcpHttpServer(options = {}) {
232269 return ;
233270 }
234271
272+ // MCP discovery via SEP-1649 static server card. Used by
273+ // registry scanners (Smithery, Glama, etc.) that don't want to
274+ // run a full MCP initialize() to enumerate tools.
275+ if ( req . url === '/.well-known/mcp/server-card.json' && req . method === 'GET' ) {
276+ res . writeHead ( 200 , {
277+ 'content-type' : 'application/json' ,
278+ 'cache-control' : 'public, max-age=300'
279+ } ) ;
280+ res . end ( JSON . stringify ( getStaticServerCard ( ) , null , '\t' ) ) ;
281+ return ;
282+ }
283+
235284 // MCP root: only POST /, GET /, DELETE / are valid per the spec.
236285 if ( req . url !== '/' && req . url !== '/mcp' ) {
237286 res . writeHead ( 404 , { 'content-type' : 'application/json' } ) ;
0 commit comments