GitHub
Connect AI assistants to GitHub - manage repos, issues, PRs, and workflows through natural language.
作者提供的说明(英文原文)
TypeScript template for building MCP servers with declarative tooling, observability, and auth.
这三项永远不会合并成一个分数:意见、测量和人气是不同的东西。
我们还没有为它写通俗的介绍。下面是我们从注册中心读取到的事实。
选择你使用的 AI 应用,然后复制设置。
MCP_LOG_LEVEL你需要
你用的是哪个应用?
在上方选择你的应用。我们会记住它,下次按钮会显示“安装到 …”。
打开 Claude Desktop → Settings → Developer → Edit Config,把下面的内容粘贴到 claude_desktop_config.json
{
"mcpServers": {
"ts-template": {
"command": "npx",
"args": [
"-y",
"mcp-ts-template",
"run",
"start:stdio"
],
"env": {
"MCP_LOG_LEVEL": "your-value"
}
}
}
}在终端中运行这条命令
claude mcp add ts-template --env MCP_LOG_LEVEL=your-value -- npx -y mcp-ts-template run start:stdio运行前请先填写空着的值。
粘贴到项目中的 .cursor/mcp.json,或 ~/.cursor/mcp.json
{
"mcpServers": {
"ts-template": {
"command": "npx",
"args": [
"-y",
"mcp-ts-template",
"run",
"start:stdio"
],
"env": {
"MCP_LOG_LEVEL": "your-value"
}
}
}
}浏览器会先询问是否打开应用,然后应用会显示设置并请你确认。密钥的值会留空,由你自己填写。
粘贴到项目中的 .vscode/mcp.json
{
"servers": {
"ts-template": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"mcp-ts-template",
"run",
"start:stdio"
],
"env": {
"MCP_LOG_LEVEL": "your-value"
}
}
}
}浏览器会先询问是否打开应用,然后应用会显示设置并请你确认。密钥的值会留空,由你自己填写。
这个服务器在你的电脑上运行,而 ChatGPT 只能连接互联网上的服务器。请选择其他应用。
你的选择通过 Cookie 保存在这台设备上,无需账户。
MCP_LOG_LEVEL env这些设置是根据作者在注册中心的条目生成的。如果 README 的写法不同,请以 README 为准。
它在你的电脑上运行;安装后,工具列表会显示在你的 AI 应用中。
我们检查的是任何人都能看到的信息;我们没有阅读代码。不适用的检查项不计入总数。 · 检查于 2026年11月8日
注册名称已通过 GitHub 账户 cyanheads 验证,该账户拥有此仓库
我们还没有从 GitHub 读取这个仓库
我们还没有从 GitHub 读取这个仓库
它在你的电脑上运行,没有互联网端点
在你的电脑上运行,改用本地设置
它在你的电脑上运行;我们只能读取互联网端点的工具列表
与注册中心里这个分类中所有活跃的服务器比较。只有当发布者拥有该仓库时,星标数才计入。
它在 1 项适用的基础检查中通过了 1 项。我们没有阅读代码。在添加密钥或令牌之前,请先看看这个服务器要求哪些权限,并使用只具备所需权限的密钥。
注册中心没有列出必需的密钥,不过有些服务器会在首次使用时要求你登录。
它在你的电脑上运行。你的 AI 应用会在需要时启动它,数据不会经过作者的服务器(除非它自己调用在线服务)。
GitHub 仓库最后更新于–,最新版本(3.0.9)于8个月前进入注册中心。
支持 MCP 的应用,例如 Claude Desktop、Claude Code、Cursor 和 VS Code。你的电脑上还需要有 Node.js。
同一分类中有:GitHub, Desktop Commander, Cloudflare MCP
同一分类中其他作者的服务器,按星标数排序。
如何看卡片:↓ 每周下载量i★ GitHub 星标i三大支柱:评价 · 检查 · 使用情况i更新 = 最新版本发布到注册中心的时间i
Connect AI assistants to GitHub - manage repos, issues, PRs, and workflows through natural language.
MCP server for terminal commands, file operations, and process management
按原文从作者的仓库复制。PopNx MCP 没有审查或背书其内容。HTML、图片和脚本已被移除。链接会离开本站。
@cyanheads/mcp-ts-core Agent-native TypeScript framework for building MCP servers. Runtime infrastructure for your server, and the agent skills to build, test, and ship it.
Quick start · Capabilities · API reference · Examples
Connect an API, a dataset, or a workflow to an AI agent through the Model Context Protocol (MCP). Your project holds the domain code; @cyanheads/mcp-ts-core handles the auth, storage, logging, and transports underneath it.
Agent-native. Every scaffold ships the framework reference and a set of Agent Skills: workflows for designing tools, writing tests, reviewing security, and cutting releases. You decide what the server does; your agent follows the skills to build it.
The framework stays a dependency. Infrastructure fixes arrive as package upgrades. Run the maintenance skill and your agent bumps core, syncs the latest skills, and adopts what changed.
Servers run on Bun, Node.js 24+, or Cloudflare Workers.
bunx @cyanheads/mcp-ts-core init my-mcp-server
cd my-mcp-server bun install
The scaffold includes a source tree, build and test configuration, CLAUDE.md/AGENTS.md, Agent Skills, and plugin metadata for Claude Code and Codex. Open it in Claude Code, Codex, or another agent and describe what you want:
Build an MCP server for my team's inventory API. We need to find products, check stock across warehouses, investigate stock movements, and record adjustments and transfers. Let's get started.
Already have a TypeScript project? Run bun add @cyanheads/mcp-ts-core and register your definitions with createApp().
This is a complete server that searches a three-item catalog. To try it, replace the scaffold's src/index.ts with it:
import { createApp, tool, z } from '@cyanheads/mcp-ts-core';
const catalog = ['Notebook', 'Mechanical pencil', 'Desk lamp'];
const search = tool('catalog_search', { description: 'Search catalog item names. An empty query lists all items.', annotations: { readOnlyHint: true }, input: z.object({ query: z.string().describe('Text to find in an item name'), }), output: z.object({ items: z.array(z.string()).describe('Matching item names'), }), async handler({ query }) { return { items: catalog.filter((name) => name.toLowerCase().includes(query.toLowerCase()), ), }; }, });
await createApp({ name: 'catalog-mcp-server', title: 'catalog-mcp-server', tools: [search] });
Build and run it over HTTP:
bun run rebuild
bun run start:http
Point your MCP client at http://127.0.0.1:3010/mcp (Streamable HTTP), or have the client launch it over stdio with bun /absolute/path/to/dist/index.js.
| You need to… | The framework provides |
|---|---|
| Give an assistant useful capabilities | Typed builders for tools, resources, prompts, and interactive MCP Apps |
| Help an agent use those capabilities correctly | Server instructions, result enrichment, and declared errors with recovery guidance |
| Control access and keep state | JWT/OAuth, per-definition scopes, and tenant-scoped storage with swappable backends |
| Run locally or host a service | stdio and HTTP on Bun/Node.js; a separate entry point for Cloudflare Workers |
| Understand failures and catch mistakes | Structured logs, optional OpenTelemetry, definition linting, contract tests, and fuzz testing |
Optional integrations (DuckDB, Supabase, the OpenTelemetry SDK) are peer dependencies; install them when you need them.
Two declared contracts shape what an agent gets back. enrichment carries success-path context (totals, the parsed query, empty-result notices), populated with ctx.enrich(). errors lists each expected failure with its recovery guidance, and the handler throws one with the typed ctx.fail().
runSearch(query, limit) stands in for your search backend. It returns { items, total, parsed }, or null when the index is down:
import { createApp, tool, z } from '@cyanheads/mcp-ts-core';
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
const search = tool('search', { description: 'Search the catalog and return ranked matches.', annotations: { readOnlyHint: true }, input: z.object({ query: z.string().describe('Search terms'), limit: z.number().int().min(1).default(10).describe('Max results'), }), output: z.object({ items: z.array(z.string()).describe('Matching item names, best first'), }), enrichment: { effectiveQuery: z.string().describe('Query as the server parsed it'), totalCount: z.number().describe('Total matches before the limit'), notice: z.string().optional().describe('Guidance when nothing matched'), }, errors: [ { reason: 'index_unavailable', code: JsonRpcErrorCode.ServiceUnavailable, when: 'The upstream search index is unreachable.', retryable: true, recovery: 'Retry in a few seconds — the index may be briefly unavailable.', }, ], handler: async (input, ctx) => { const res = await runSearch(input.query, input.limit); if (!res) throw ctx.fail('index_unavailable'); ctx.enrich({ effectiveQuery: res.parsed, totalCount: res.total }); if (res.items.length === 0) { ctx.enrich({ notice: No matches for "${input.query}". Try broader terms. }); } return { items: res.items }; // enrichment never rides in the domain return }, });
await createApp({ tools: [search] });
Both contracts are advertised in tools/list, so clients see them before calling, and the definition linter checks the handler against them. A failure with a declared reason reaches the client carrying that entry's recovery hint, and every tool error carries the request ID its server log records share.
MCP hosts differ in which part of a tool result they hand the agent: structuredContent (JSON), content[] (text), or both. The framework fills both with the same data, so the agent sees the same result on any host.
format() renders the text side; without one, content[] gets JSON. The format-parity lint rule fails lint:mcp if any output field is missing from the rendered text. Enrichment needs no format() entry, because the framework adds it to both surfaces. This formatter renders the items as a markdown list:
format: (result) => [{
type: 'text', text: result.items.length > 0 ? result.items.map((name) => - ${name}).join('\n') : 'No matching items.', }],
Resources expose data at a URI. This one reads from your own getItem() service:
import { resource, z } from '@cyanheads/mcp-ts-core';
export const itemData = resource('items://{itemId}', { description: 'Retrieve item data by ID.', params: z.object({ itemId: z.string().describe('Item ID'), }), async handler(params) { return await getItem(params.itemId); }, });
Everything registers through createApp() in your entry point:
await createApp({
name: 'my-mcp-server', title: 'my-mcp-server', // display name in client UIs tools: allToolDefinitions, resources: allResourceDefinitions, prompts: allPromptDefinitions, instructions: 'Brief composition hints for the model.', // optional, sent on every initialize skills: 'skills', // optional, serves root skills/ over the SEP-2640 Skills extension });
On Cloudflare Workers, createWorkerHandler() takes the same definitions from a separate entry point.
auth: ['scope'] on a definition and the scope is checked, under JWT or OAuth, before the handler runs. ctx.state is tenant-scoped storage over in-memory, filesystem, Supabase, or Cloudflare D1/KV/R2, chosen by config.ctx.requestInput(...) to ask the user for input, the client's model for a sample, or the client for its roots. The handler runs again with the answers on ctx.inputs._meta envelope) and session-based 2025-era clients. The SDK's compatibility layer handles input requests for the older ones.instructions gives the model server-wide guidance once, at initialize, instead of in every tool description. Identity fields (title, websiteUrl, description, icons) populate the client's server info, the /.well-known/mcp.json server card, and the HTTP landing page. skills: 'skills' serves the Agent Skills the server publishes in root skills/ through the SEP-2640 Skills extension (skills/list, skills/get), checked at build time by lint:packaging.lint:mcp checks names, schemas, scopes, annotations, format parity, and JSON Schema portability. It runs at build time, never at startup, so a new rule can't break a deployed server.CANVAS_PROVIDER_TYPE=duckdb and @duckdb/node-api (Bun or Node.js only). brapi-mcp-server walks through loading API results into a dataframe and querying it./mirror module keeps a persistent local copy of a bulk upstream dataset in embedded SQLite with an optional FTS5 index, so tools query it locally instead of paging the live API on every call. You write the sync ingester and the schema; the framework handles storage, resumable initial loads, and incremental refreshes. Bun or Node.js only (better-sqlite3 is an optional peer on Node). faa-aircraft-registry-mcp-server serves the full FAA registry this way.See the framework reference for configuration and handler patterns, and the observability guide for Pino logging and OpenTelemetry traces and metrics.
my-mcp-server/
src/ index.ts # createApp() entry point worker.ts # createWorkerHandler() (optional) config/ server-config.ts # Server-specific env vars services/ [domain]/ # Domain services (init/accessor pattern) mcp-server/ tools/definitions/ # Tool definitions (.tool.ts) resources/definitions/ # Resource definitions (.resource.ts) prompts/definitions/ # Prompt definitions (.prompt.ts) package.json tsconfig.json # extends @cyanheads/mcp-ts-core/tsconfig.base.json CLAUDE.md / AGENTS.md # Server conventions; points to core's framework reference
Framework infrastructure lives in node_modules; your source t
只显示了开头部分;其余内容请在仓库中阅读