{"id":23479549,"url":"https://github.com/strowk/foxy-contexts","last_synced_at":"2025-04-09T05:34:12.971Z","repository":{"id":265844198,"uuid":"896729097","full_name":"strowk/foxy-contexts","owner":"strowk","description":"Foxy contexts is a library for building context servers supporting Model Context Protocol","archived":false,"fork":false,"pushed_at":"2025-03-30T21:16:41.000Z","size":1668,"stargazers_count":70,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-30T21:26:54.992Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://foxy-contexts.str4.io","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/strowk.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}},"created_at":"2024-12-01T06:23:37.000Z","updated_at":"2025-03-30T21:16:44.000Z","dependencies_parsed_at":"2024-12-17T19:18:47.666Z","dependency_job_id":"5f174c62-6785-4327-a719-1c5a0e4042a5","html_url":"https://github.com/strowk/foxy-contexts","commit_stats":null,"previous_names":["strowk/foxy-contexts"],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strowk%2Ffoxy-contexts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strowk%2Ffoxy-contexts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strowk%2Ffoxy-contexts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strowk%2Ffoxy-contexts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/strowk","download_url":"https://codeload.github.com/strowk/foxy-contexts/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247987060,"owners_count":21028891,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-12-24T19:30:13.226Z","updated_at":"2025-04-09T05:34:12.963Z","avatar_url":"https://github.com/strowk.png","language":"Go","funding_links":[],"categories":["Frameworks \u0026 SDKs","📚 Projects (1974 total)","Frameworks for Servers","Frameworks","⚙️ DevOps","フレームワーク","Language-Specific SDKs","SDKs","Go","框架","Table of Contents"],"sub_categories":["Trading \u0026 Exchanges","MCP Servers","🛠️ \u003ca name=\"other-tools-and-integrations\"\u003e\u003c/a\u003eOther Tools and Integrations","🎧 \u003ca name=\"text-to-speech\"\u003e\u003c/a\u003eテキスト読み上げ","Frameworks","Go","AI Services"],"readme":"\r\n\u003ch1 align=\"center\"\u003e\r\n\r\n   \u003cimg alt=\"main logo\" src=\"./docs/content/assets/logo.png\" width=\"150\"/\u003e\r\n   \r\n   \u003cbr/\u003e\r\n   Foxy Contexts\r\n\u003c/h1\u003e\r\n\r\n\u003c!-- --8\u003c-- [start:content] --\u003e\r\n\r\n\u003ch4 align=\"center\"\u003eBuild MCP Servers Declaratively in Golang\u003c/h4\u003e\r\n\r\n\u003cp align=\"center\"\u003e\r\n\t\u003ca href=\"https://pkg.go.dev/github.com/strowk/foxy-contexts\"\u003e\u003cimg src=\"https://pkg.go.dev/badge/github.com/strowk/foxy-contexts.svg\" alt=\"Go Reference\"\u003e\u003c/a\u003e\r\n\t\u003ca href=\"https://goreportcard.com/report/github.com/strowk/foxy-contexts\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/strowk/foxy-contexts\" alt=\"Go Reference\"\u003e\u003c/a\u003e\r\n\t\u003ca href=\"https://github.com/strowk/foxy-contexts/actions/workflows/test.yaml\"\u003e\u003cimg src=\"https://github.com/strowk/foxy-contexts/actions/workflows/test.yaml/badge.svg\"/\u003e\u003c/a\u003e\r\n\t\u003ca href=\"https://github.com/strowk/foxy-contexts/actions/workflows/golangci-lint.yaml\"\u003e\u003cimg src=\"https://github.com/strowk/foxy-contexts/actions/workflows/golangci-lint.yaml/badge.svg\"/\u003e\u003c/a\u003e\r\n\u003c/p\u003e\r\n\r\n\u003cp align=\"center\"\u003e\r\n  \u003ca href=\"#features\"\u003eFeatures\u003c/a\u003e 🦊\r\n  \u003ca href=\"#tool-example\"\u003eTool Example\u003c/a\u003e 🦊\r\n  \u003ca href=\"https://foxy-contexts.str4.io\"\u003eDocs\u003c/a\u003e 🦊\r\n  \u003ca href=\"https://github.com/strowk/foxy-contexts\"\u003eSources\u003c/a\u003e\r\n\u003c/p\u003e\r\n\r\nFoxy contexts is a Golang library for building context servers supporting [Model Context Protocol](https://modelcontextprotocol.io/).\r\n\r\nThis library only supports server side of the protocol. Using it you can build context servers using declarative approach, by defining [tools](https://modelcontextprotocol.io/docs/concepts/tools), [resources](https://modelcontextprotocol.io/docs/concepts/resources) and [prompts](https://modelcontextprotocol.io/docs/concepts/prompts) and then registering them with your app.Builder, which is using [uber's fx](https://github.com/uber-go/fx) App under the hood and you can inject into its container as well.\r\n\r\nWith this approach you can easily colocate call/read/get logic and definitions of your tools/resources/prompts in a way that every tool/resource/prompt is placed in a separate place, while Dependency Injection allows you to reuse shared parts like clients, database connections, etc.\r\n\r\n## Features\r\n\r\nHere is list of features that are implemented and planned:\r\n\r\n- [x] Base (lifecycle/ping)\r\n\t- [ ] Progress (planned)\r\n- [x] Transports\r\n\t- [x] Stdio Transport\r\n\t- [x] SSE Transport\r\n\t- [x] Streamable HTTP Transport (beta)\r\n- [x] Tools\r\n    - [x] Package toolinput helps define tools input schema and validate arriving input\r\n- [ ] Resources\r\n\t- [x] Resources - static\r\n\t- [x] Resources - dynamic via Resource Providers\r\n\t- [ ] Resources - dynamic via Resource Templates (planned)\r\n\t- [ ] Resource Templates completion (planned)\r\n\t- [ ] Resource subscriptions\r\n- [x] Prompts\r\n- [x] Prompts Completion\r\n- [x] Functional Testing package foxytest\r\n- [x] Simple building of your MCP server with the power of Dependency Injection\r\n- [ ] Logging via MCP (planned)\r\n- [ ] Sampling (planned)\r\n- [ ] Roots (planned)\r\n- [ ] Pagination (planned)\r\n- [ ] Notifications list_changed (planned)\r\n- [x] Testing - functional tests with foxytest package\r\n\r\nCheck [docs](https://foxy-contexts.str4.io/) and [examples](https://github.com/strowk/foxy-contexts/tree/main/examples) to know more.\r\n\r\n## Tool Example\r\n\r\nFor example try following\r\n\r\n```bash\r\ngit clone https://github.com/strowk/foxy-contexts\r\ncd foxy-contexts/examples/list_current_dir_files_tool\r\nnpx @modelcontextprotocol/inspector go run main.go\r\n```\r\n, then once inspector is started in browser open http://localhost:5173 and try to use list-current-dir-files.\r\n\r\nHere's the code of that example from [examples/list_current_dir_files_tool/main.go](https://github.com/strowk/foxy-contexts/blob/main/examples/list_current_dir_files_tool/main.go) (in real world application you would probably want to split it into multiple files):\r\n\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"os\"\r\n\r\n\t\"github.com/strowk/foxy-contexts/pkg/app\"\r\n\t\"github.com/strowk/foxy-contexts/pkg/fxctx\"\r\n\t\"github.com/strowk/foxy-contexts/pkg/mcp\"\r\n\t\"github.com/strowk/foxy-contexts/pkg/stdio\"\r\n\t\"go.uber.org/fx\"\r\n\t\"go.uber.org/fx/fxevent\"\r\n\t\"go.uber.org/zap\"\r\n)\r\n\r\n// This example defines list-current-dir-files tool for MCP server, that prints files in the current directory\r\n// , run it with:\r\n// npx @modelcontextprotocol/inspector go run main.go\r\n// , then in browser open http://localhost:5173\r\n// , then click Connect\r\n// , then click List Tools\r\n// , then click list-current-dir-files\r\n\r\n// NewListCurrentDirFilesTool defines a tool that lists files in the current directory\r\nfunc NewListCurrentDirFilesTool() fxctx.Tool {\r\n\treturn fxctx.NewTool(\r\n\t\t// This information about the tool would be used when it is listed:\r\n\t\t\u0026mcp.Tool{\r\n\t\t\tName:        \"list-current-dir-files\",\r\n\t\t\tDescription: Ptr(\"Lists files in the current directory\"),\r\n\t\t\tInputSchema: mcp.ToolInputSchema{\r\n\t\t\t\tType:       \"object\",\r\n\t\t\t\tProperties: map[string]map[string]interface{}{},\r\n\t\t\t\tRequired:   []string{},\r\n\t\t\t},\r\n\t\t},\r\n\r\n\t\t// This is the callback that would be executed when the tool is called:\r\n\t\tfunc(_ context.Context, args map[string]interface{}) *mcp.CallToolResult {\r\n\t\t\tfiles, err := os.ReadDir(\".\")\r\n\t\t\tif err != nil {\r\n\t\t\t\treturn \u0026mcp.CallToolResult{\r\n\t\t\t\t\tIsError: Ptr(true),\r\n\t\t\t\t\tMeta:    map[string]interface{}{},\r\n\t\t\t\t\tContent: []interface{}{\r\n\t\t\t\t\t\tmcp.TextContent{\r\n\t\t\t\t\t\t\tType: \"text\",\r\n\t\t\t\t\t\t\tText: fmt.Sprintf(\"failed to read dir: %v\", err),\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t},\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tvar contents []interface{} = make([]interface{}, len(files))\r\n\t\t\tfor i, f := range files {\r\n\t\t\t\tcontents[i] = mcp.TextContent{\r\n\t\t\t\t\tType: \"text\",\r\n\t\t\t\t\tText: f.Name(),\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn \u0026mcp.CallToolResult{\r\n\t\t\t\tMeta:    map[string]interface{}{},\r\n\t\t\t\tContent: contents,\r\n\t\t\t\tIsError: Ptr(false),\r\n\t\t\t}\r\n\t\t},\r\n\t)\r\n}\r\n\r\nfunc main() {\r\n\tapp.\r\n\t\tNewBuilder().\r\n\t\t// adding the tool to the app\r\n\t\tWithTool(NewListCurrentDirFilesTool).\r\n\t\t// setting up server\r\n\t\tWithName(\"list-current-dir-files\").\r\n\t\tWithVersion(\"0.0.1\").\r\n\t\tWithTransport(stdio.NewTransport()).\r\n\t\t// Configuring fx logging to only show errors\r\n\t\tWithFxOptions(fx.Provide(func() *zap.Logger {\r\n\t\t\t\tcfg := zap.NewDevelopmentConfig()\r\n\t\t\t\tcfg.Level.SetLevel(zap.ErrorLevel)\r\n\t\t\t\tlogger, _ := cfg.Build()\r\n\t\t\t\treturn logger\r\n\t\t\t}),\r\n\t\t\tfx.Option(fx.WithLogger(\r\n\t\t\t\tfunc(logger *zap.Logger) fxevent.Logger {\r\n\t\t\t\t\treturn \u0026fxevent.ZapLogger{Logger: logger}\r\n\t\t\t\t},\r\n\t\t\t)),\r\n\t\t).\r\n\t\tRun()\r\n}\r\n\r\nfunc Ptr[T any](v T) *T {\r\n\treturn \u0026v\r\n}\r\n\r\n```\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrowk%2Ffoxy-contexts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstrowk%2Ffoxy-contexts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrowk%2Ffoxy-contexts/lists"}