{"id":51039283,"url":"https://github.com/brandonkramer/mcpkit","last_synced_at":"2026-06-22T09:30:27.490Z","repository":{"id":361571593,"uuid":"1254938744","full_name":"brandonkramer/mcpkit","owner":"brandonkramer","description":"Adds structured agent tool results, optional proxy-tool plumbing, and list/preview helpers.","archived":false,"fork":false,"pushed_at":"2026-05-31T08:29:54.000Z","size":83,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-31T10:12:54.285Z","etag":null,"topics":["agents","ai-agents","go","golang","library","mcp","model-context-protocol","tools"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brandonkramer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-31T07:26:26.000Z","updated_at":"2026-05-31T09:01:07.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/brandonkramer/mcpkit","commit_stats":null,"previous_names":["brandonkramer/mcpkit"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/brandonkramer/mcpkit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonkramer%2Fmcpkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonkramer%2Fmcpkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonkramer%2Fmcpkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonkramer%2Fmcpkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brandonkramer","download_url":"https://codeload.github.com/brandonkramer/mcpkit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonkramer%2Fmcpkit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34643409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agents","ai-agents","go","golang","library","mcp","model-context-protocol","tools"],"created_at":"2026-06-22T09:30:26.817Z","updated_at":"2026-06-22T09:30:27.486Z","avatar_url":"https://github.com/brandonkramer.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mcpkit\n\nAgent-facing MCP ergonomics built on [modelcontextprotocol/go-sdk](https://github.com/modelcontextprotocol/go-sdk).\n\nIt adds structured agent tool results, optional proxy-tool plumbing, and list/preview helpers.\n\n**Single runtime dependency:** `modelcontextprotocol/go-sdk`\n\n## Install\n\nFrom [pkg.go.dev](https://pkg.go.dev/github.com/brandonkramer/mcpkit):\n\n```bash\ngo get github.com/brandonkramer/mcpkit\n```\n\n---\n\n| Level | Packages | When |\n| --- | --- | --- |\n| **Minimal** | `envelope`, `adapter` | Hand-written tool handlers; you build the envelope yourself |\n| **Proxy** | + `summarize`, `tool` | Tools call a backend (RPC, DB, HTTP); shared normalize→present→envelope pipeline |\n| **Full** | + `present`, `server` | Capped list payloads, previews, stdio bootstrap |\n\n---\n\n## Minimal: envelope + adapter\n\nRegister tools directly with go-sdk \n\n```go\nsdkmcp.AddTool(server, \u0026sdkmcp.Tool{\n    Name: \"ping\", Description: \"Health check\",\n}, func(ctx context.Context, _ *sdkmcp.CallToolRequest, _ struct{}) (*sdkmcp.CallToolResult, any, error) {\n    env := envelope.Success(\"ping\").\n        Summary(\"pong\").\n        Data(map[string]string{\"status\": \"ok\"}).\n        Build()\n    return adapter.FromEnvelope(\u0026env)\n})\n```\n\nShorthand helpers (same envelope shape, less boilerplate):\n\n```go\nreturn adapter.OK(\"notes.list\", \"2 note(s)\", data, \"notes.create title=\\\"...\\\"\")\nreturn adapter.ErrorCode(\"not_found\", err)\n```\n\nOn error without a code:\n\n```go\nreturn adapter.Error(err)\n```\n\n**Text mode** for clients that only read `content` text (structured envelope still in `structuredContent`):\n\n```go\nadapter.OKWithOptions(\"notes.get\", \"note 01\", data, adapter.Options{Text: adapter.TextSummary})\n// TextFull (default): full envelope JSON in text\n// TextSummary: summary line only\n// TextNone: no text content\n```\n\nNo `summarize.Registry`, no `tool.Bridge`, no `server` helper required.\n\n---\n\n## Proxy: backend + registry\n\nWhen tools proxy to a service and share summarization logic:\n\n```go\nreg := summarize.Passthrough() // or your own Registry; Passthrough() for day-one proxy wiring\n\nbridge := \u0026tool.Bridge{\n    Backend:   tool.FuncBackend(myBackend.Call),\n    Responder: summarize.NewResponder(reg),\n}\n\ntool.AddProxy(server, bridge, tool.ProxySpec[CreateArgs, Item]{\n    Name: \"items.create\", Description: \"Create an item\",\n    Prepare: func(_ *tool.Bridge, args CreateArgs) (CreateArgs, summarize.Meta, error) {\n        return tool.PrepareWorkDir(defaultWorkDir, args, setWorkDir, getWorkDir)\n    },\n})\n```\n\n`WorkDir` is app-specific — use `tool.ResolveWorkDir` / `tool.PrepareWorkDir` in your `prepare` hooks, not on `Bridge`.\n\nList tool summarization:\n\n```go\nsummary, next := present.SummarizeToolList(data, meta, summarize.ToolListSummary[Item]{\n    CountLabel: \"item(s)\",\n    Next:       []string{\"items.create title=\\\"...\\\"\"},\n    PageHint:   \"narrow filter=... or use CLI for full list\",\n    NextFor: func(item Item) []string {\n        return []string{envelope.Hint(\"items.get\", envelope.HintParam(\"id\", item.ID))}\n    },\n})\n```\n\n---\n\n## `summarize.Meta`\n\n`Meta` passes context from `prepare` / `present` hooks to summarizers.\n\n| Field | Purpose |\n| --- | --- |\n| `Limit` | List cap applied during present (used by `SummarizeToolList`) |\n| `SinceSeq` | Optional paging cursor (ignore if unused) |\n| `RunID` | Optional entity id context (ignore if unused) |\n| `Extra` | Open bag: `meta.Put(\"table\", \"notes\")`, read with `meta.String(\"table\")` |\n\nOnly use the fields your app needs. A replay/poll proxy might use `Limit`, `SinceSeq`, and `RunID`; a notes MCP might only set `Limit` or use `Extra` alone.\n\n---\n\n## Transport\n\n| Transport | Use |\n| --- | --- |\n| **Stdio** | `server.ServeStdio(server.Config{...})` |\n| **HTTP / streamable** | go-sdk — mcpkit does not wrap HTTP |\n\nBuild once with `server.New`, then serve over any go-sdk transport:\n\n```go\nserver, _, err := mcpserver.New(mcpserver.Config{\n    Name: \"notes\", Version: \"1.0.0\",\n    Register: func(s *sdkmcp.Server, _ string) { registerNotesTools(s, db) },\n})\n\n// Stdio\n_ = server.Run(ctx, \u0026sdkmcp.StdioTransport{})\n\n// HTTP (go-sdk) — see modelcontextprotocol/go-sdk StreamableHTTPHandler\nhandler := sdkmcp.NewStreamableHTTPHandler(func(_ *http.Request) *sdkmcp.Server {\n    return server\n}, nil)\n_ = http.ListenAndServe(\":8080\", handler)\n```\n\n---\n\n## Packages\n\n| Package | Purpose |\n| --- | --- |\n| `envelope` | `ok`, `summary`, `subjects`, `data`, `next_actions`, diagnostics |\n| `adapter` | `OK`, `ErrorCode`, text modes; map envelopes to `CallToolResult` |\n| `summarize` | `Passthrough`, `ToolSummaries`, `ToolListItems`, `Meta` |\n| `present` | `ToolListData`, `WrapToolList`, `ToolListItems`, `MapCapList`, `RedactText` |\n| `tool` | Proxy pipeline, `ResolveWorkDir`, `PrepareWorkDir`, `NormalizeField`, `NormalizeID` |\n| `server` | Stdio bootstrap via `ServeStdio` / `New` |\n\n---\n\n## Development\n\nLefthook and golangci-lint are pinned in `go.mod` as **tools** (dev-only). Install git hooks once per clone:\n\n```bash\nmake install-hooks\n```\n\nHooks and `make lint` use `go tool` binaries from `go.mod`. Pre-commit lints staged `.go` files; pre-push runs `./scripts/check.sh`. CI runs the same checks.\n\n```bash\nmake check    # full local CI script\nmake test\nmake lint\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrandonkramer%2Fmcpkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrandonkramer%2Fmcpkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrandonkramer%2Fmcpkit/lists"}