Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- Feat: add teams direct-member endpoint support (`POST /teams/{team_id}/members`)

### Changed
- Build: run integration harness against ContextForge v1.0.0-RC1

### Documentation
- Docs: update tested-against version to ContextForge v1.0.0-RC1

## [0.9.0] - 2026-02-09

### Added
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ Some integration tests are skipped due to confirmed bugs in the upstream Context
| CONTEXTFORGE-001 | Toggle endpoints return stale state | 4 tests |
| CONTEXTFORGE-002 | API accepts empty template string | 1 test |
| CONTEXTFORGE-003 | Toggle returns 400 instead of 404 | 1 test |
| CONTEXTFORGE-004 | Teams endpoints reject valid auth | 12 tests |
| CONTEXTFORGE-005 | Teams slug field ignored | 2 tests |
| CONTEXTFORGE-007 | Gateway tags not persisted | 2 tests |
| CONTEXTFORGE-008 | Agent bearer auth requires auth_token | 1 test |
Expand All @@ -262,6 +261,7 @@ Some integration tests are skipped due to confirmed bugs in the upstream Context
**Resolved Issues (tests re-enabled):**
| Bug ID | Summary | Resolution |
|--------|---------|------------|
| CONTEXTFORGE-004 | Teams endpoints reject valid auth | Fixed in ContextForge v1.0.0-RC1 |
| CONTEXTFORGE-006 | 422 for validation errors | By design (FastAPI standard)

To re-enable a skipped test once the upstream bug is fixed:
Expand Down
26 changes: 16 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ For more information about the A2A protocol, see the [official specification](ht

### Compatibility

This SDK is tested against **ContextForge v1.0.0-BETA-2** (PyPI: `mcpgateway==1.0.0b2`).
This SDK is tested against **ContextForge v1.0.0-RC1** (PyPI: `mcp-contextforge-gateway==1.0.0rc1`).

## Installation

Expand Down Expand Up @@ -682,6 +682,12 @@ _, err = client.Teams.Delete(ctx, "team-id")
// List team members
members, _, err := client.Teams.ListMembers(ctx, "team-id")

// Add a direct member
member, _, err := client.Teams.AddMember(ctx, "team-id", &contextforge.TeamMemberAdd{
Email: "user@example.com",
Role: "member",
})

// Update member role (uses email as identifier)
memberUpdate := &contextforge.TeamMemberUpdate{
Role: "owner", // "owner" | "member"
Expand Down Expand Up @@ -909,6 +915,7 @@ if resp.Rate.Limit > 0 {
| `Update(ctx, teamID, team)` | Update team |
| `Delete(ctx, teamID)` | Delete team |
| `ListMembers(ctx, teamID)` | List team members |
| `AddMember(ctx, teamID, add)` | Add member directly by email |
| `UpdateMember(ctx, teamID, email, update)` | Update member role (uses email) |
| `RemoveMember(ctx, teamID, email)` | Remove member (uses email) |
| `InviteMember(ctx, teamID, invite)` | Invite user to team |
Expand Down Expand Up @@ -1229,25 +1236,24 @@ This SDK follows the service-oriented architecture pattern established by [googl

### Upstream ContextForge API Bugs

The SDK integration tests have identified six bugs in ContextForge (confirmed in both v0.8.0 and v1.0.0-BETA-1; revalidation against v1.0.0-BETA-2 is pending in this repository). These bugs are in the upstream API, not the SDK implementation. Affected tests are skipped and will be re-enabled once upstream bugs are fixed.
The SDK integration tests currently document several upstream ContextForge API bugs. These bugs are in the upstream API, not the SDK implementation. Affected tests are skipped and will be re-enabled once upstream fixes land; see the linked reports for the latest validated version for each issue.

**CONTEXTFORGE-001: Toggle Endpoints Return Stale State**
The `POST /prompts/{id}/toggle` and `POST /resources/{id}/toggle` endpoints return stale `isActive` state despite correctly updating the database. See [`docs/upstream-bugs/contextforge-001-prompt-toggle.md`](docs/upstream-bugs/contextforge-001-prompt-toggle.md).

**CONTEXTFORGE-002: Prompts API Accepts Empty Template Field**
The `POST /prompts` endpoint accepts prompt creation without the `template` field, allowing semantically invalid prompts. See [`docs/upstream-bugs/contextforge-002-prompt-validation-missing-template.md`](docs/upstream-bugs/contextforge-002-prompt-validation-missing-template.md).

**CONTEXTFORGE-003: Prompts Toggle Returns 400 Instead of 404**
The `POST /prompts/{id}/toggle` endpoint returns HTTP 400 for non-existent prompts instead of 404. See [`docs/upstream-bugs/contextforge-003-prompt-toggle-error-code.md`](docs/upstream-bugs/contextforge-003-prompt-toggle-error-code.md).

**CONTEXTFORGE-004: Teams Individual Resource Endpoints Reject Valid Authentication**
Individual team endpoints (`GET/PUT/DELETE /teams/{id}/*`) reject valid JWT tokens with 401 Unauthorized, despite list/create working correctly. See [`docs/upstream-bugs/contextforge-004-teams-auth-individual-endpoints.md`](docs/upstream-bugs/contextforge-004-teams-auth-individual-endpoints.md).

**CONTEXTFORGE-005: Teams API Ignores User-Provided Slug Field**
The `POST /teams` endpoint ignores the `slug` field and always auto-generates from team name. See [`docs/upstream-bugs/contextforge-005-teams-slug-ignored.md`](docs/upstream-bugs/contextforge-005-teams-slug-ignored.md).

**CONTEXTFORGE-006: Teams API Returns 422 Instead of 400 for Validation Errors**
The `POST /teams` endpoint returns HTTP 422 (Unprocessable Entity) for validation errors instead of 400 (Bad Request). See [`docs/upstream-bugs/contextforge-006-teams-validation-error-code.md`](docs/upstream-bugs/contextforge-006-teams-validation-error-code.md).
**CONTEXTFORGE-008: Agent Bearer Auth Field Name Mismatch**
The A2A agent API still expects `auth_token` for bearer auth instead of the SDK’s `auth_value` field. See [`docs/upstream-bugs/contextforge-008-agent-auth-field-name.md`](docs/upstream-bugs/contextforge-008-agent-auth-field-name.md).

**CONTEXTFORGE-010: Team ID Filter Returns Permission Error**
The tools list API still returns a `403` for some team-scoped filter combinations that should succeed. See [`docs/upstream-bugs/contextforge-010-team-id-filter-permission-error.md`](docs/upstream-bugs/contextforge-010-team-id-filter-permission-error.md).

Resolved in current RC1 validation: `CONTEXTFORGE-004` team endpoint auth failures no longer reproduce. Historical and resolved reports remain under [`docs/upstream-bugs/`](docs/upstream-bugs/).

All bug reports include root cause analysis, proposed solutions, and workarounds.

Expand Down
18 changes: 18 additions & 0 deletions contextforge/teams.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,24 @@ func (s *TeamsService) ListMembers(ctx context.Context, teamID string) ([]*TeamM
return members, resp, nil
}

// AddMember adds a user to a team.
func (s *TeamsService) AddMember(ctx context.Context, teamID string, add *TeamMemberAdd) (*TeamMember, *Response, error) {
u := fmt.Sprintf("teams/%s/members/", url.PathEscape(teamID))

req, err := s.client.NewRequest(http.MethodPost, u, add)
if err != nil {
return nil, nil, err
}

var member *TeamMember
resp, err := s.client.Do(ctx, req, &member)
if err != nil {
return nil, resp, err
}

return member, resp, nil
}

// UpdateMember updates a team member's role.
// Note: Uses email as the member identifier, not ID.
func (s *TeamsService) UpdateMember(ctx context.Context, teamID, userEmail string, update *TeamMemberUpdate) (*TeamMember, *Response, error) {
Expand Down
44 changes: 44 additions & 0 deletions contextforge/teams_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,50 @@ func TestTeamsService_ListMembers(t *testing.T) {
}
}

func TestTeamsService_AddMember(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()

input := &TeamMemberAdd{
Email: "newuser@test.local",
Role: "member",
}

mux.HandleFunc("/teams/123/members/", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")

var body TeamMemberAdd
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Errorf("Request body decode error: %v", err)
}

if body.Email != input.Email {
t.Errorf("Request body email = %q, want %q", body.Email, input.Email)
}
if body.Role != input.Role {
t.Errorf("Request body role = %q, want %q", body.Role, input.Role)
}

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
fmt.Fprint(w, `{"id":"1","team_id":"123","user_email":"newuser@test.local","role":"member","is_active":true}`)
})

ctx := context.Background()
member, _, err := client.Teams.AddMember(ctx, "123", input)

if err != nil {
t.Errorf("Teams.AddMember returned error: %v", err)
}

if member.UserEmail != input.Email {
t.Errorf("Teams.AddMember returned email %q, want %q", member.UserEmail, input.Email)
}
if member.Role != input.Role {
t.Errorf("Teams.AddMember returned role %q, want %q", member.Role, input.Role)
}
}

func TestTeamsService_UpdateMember(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
Expand Down
6 changes: 6 additions & 0 deletions contextforge/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,12 @@ type TeamMember struct {
IsActive bool `json:"is_active"`
}

// TeamMemberAdd represents the request body for adding a team member.
type TeamMemberAdd struct {
Email string `json:"email"`
Role string `json:"role"`
}

// TeamMemberUpdate represents the request body for updating a team member's role.
type TeamMemberUpdate struct {
Role string `json:"role"`
Expand Down
11 changes: 7 additions & 4 deletions docs/agents/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,18 @@ Known skipped issue IDs:

- `CONTEXTFORGE-001`
- `CONTEXTFORGE-002`
- `CONTEXTFORGE-005`
- `CONTEXTFORGE-008`
- `CONTEXTFORGE-010`

Resolved issue IDs:

- `CONTEXTFORGE-003`
- `CONTEXTFORGE-004`
- `CONTEXTFORGE-005`
- `CONTEXTFORGE-007`
- `CONTEXTFORGE-008`
- `CONTEXTFORGE-009`
- `CONTEXTFORGE-010`

Resolved issue:
Informational:

- `CONTEXTFORGE-006` (validation error behavior is by design)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

**Bug ID:** CONTEXTFORGE-004
**Component:** ContextForge MCP Gateway
**Affected Version:** v0.8.0, v1.0.0-BETA-1, v1.0.0-BETA-2
**Affected Version:** v0.8.0, v1.0.0-BETA-1, v1.0.0-BETA-2 (fixed in v1.0.0-RC1)
**Severity:** High
**Status:** Confirmed in v1.0.0-BETA-2 (still valid)
**Status:** FIXED in v1.0.0-RC1
**Reported:** 2025-11-09
**Last Validated:** 2026-02-06
**Last Validated:** 2026-03-05

## Summary

Individual team resource endpoints (`GET/PUT/DELETE /teams/{id}/*`) reject valid JWT authentication tokens with "Invalid token" (401 Unauthorized) errors, despite the same token working correctly for team list and create operations. This prevents any read, update, or delete operations on individual teams.
In affected versions, individual team resource endpoints (`GET/PUT/DELETE /teams/{id}/*`) reject valid JWT authentication tokens with "Invalid token" (401 Unauthorized) errors, despite the same token working correctly for team list and create operations. This issue is fixed in ContextForge v1.0.0-RC1.

## Affected Endpoints

Expand Down Expand Up @@ -441,19 +441,33 @@ async def get_team(team_id: str, current_user_ctx: dict = Depends(get_current_us

**Report Generated:** 2025-11-09
**Tested Against:** ContextForge v0.8.0
**Validated Against:** ContextForge v1.0.0-BETA-2
**Validated Against:** ContextForge v1.0.0-RC1
**Reporter:** go-contextforge SDK Team

---

## v1.0.0-RC1 Revalidation Notes

**Validated:** 2026-03-05

- **Still Valid?** No. The issue no longer reproduces in the RC1 integration harness.
- **Observed behavior:** `GET`, `PUT`, `DELETE`, member management, invitations, and discovery routes all completed successfully under authenticated SDK calls.
- **SDK action:** Removed the `CONTEXTFORGE-004` skips from team integration coverage and re-enabled the affected scenarios.

### Evidence

- `TestTeamsService_BasicCRUD` passed for get, update, and delete operations.
- `TestTeamsService_Members`, `TestTeamsService_Invitations`, and `TestTeamsService_Discovery` all passed against the RC1 harness.
- The full `make integration-test-all` run passed with the RC1 harness after switching tests to reuse the pre-generated setup token.

## v1.0.0-BETA-2 Revalidation Notes

**Validated:** 2026-02-06

- **Still Valid?** Yes. Individual teams endpoints remain broken under valid auth contexts.
- **Is it actually a bug?** Yes. Authenticated users should not receive auth failures for valid routes/permissions.

### Evidence
### Historical Evidence

- `teams.get_team(...)` still raises authentication errors in live checks.
- Route order still allows `/{team_id}` to shadow `/discover` in `mcpgateway/routers/teams.py`.
Expand Down
24 changes: 16 additions & 8 deletions docs/upstream-sync/reconcile-report.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
# ContextForge Upstream Reconciliation Report

- Generated: 2026-02-05T23:02:44-05:00
- Generated: 2026-03-05T23:05:14-05:00
- SDK root: `/Users/lee/Dev/leefowlercu/go-contextforge`
- Upstream: `https://github.com/IBM/mcp-context-forge.git`
- Channel: `all semver tags`

## Version Discovery

- README tested-against: `v1.0.0-BETA-2` (high)
- CLAUDE.md mention: `v0.8.0` (low)
- README tested-against: `v1.0.0-RC1` (high)
- CLAUDE.md mention: `v1.0.0` (low)
- CLAUDE.md mention: `v0.8.0` (low)
- CLAUDE.md mention: `v1.0.0-BETA-1` (low)
- CLAUDE.md mention: `v1.0.0-RC1` (low)

- Selected current tag: `v1.0.0-BETA-2`
- Selected from: README tested-against (`v1.0.0-BETA-2`)
- Selected target tag: `v1.0.0-BETA-2`
- Latest upstream semver tag: `v1.0.0-BETA-2`
- Selected from: override (`v1.0.0-BETA-2`)
- Selected target tag: `v1.0.0-RC1`
- Latest upstream semver tag: `v1.0.0-RC1`
- Latest upstream stable tag: `v0.9.0`

## Newer Tags

- None
- `v1.0.0-RC1`

## Service Delta

- Added services: none
- Removed services: none
- Changed existing services: 0
- Changed existing services: 5

### Endpoint Changes by Service

- `admin`: +13 / -0
- `auth`: +4 / -0
- `roots`: +3 / -0
- `.well-known`: +1 / -0
- `teams`: +1 / -0

## SDK Mapping Impact

Expand Down
Loading